*, ::before, ::after {
  --tw-border-spacing-x: 0;
  --tw-border-spacing-y: 0;
  --tw-translate-x: 0;
  --tw-translate-y: 0;
  --tw-rotate: 0;
  --tw-skew-x: 0;
  --tw-skew-y: 0;
  --tw-scale-x: 1;
  --tw-scale-y: 1;
  --tw-pan-x:  ;
  --tw-pan-y:  ;
  --tw-pinch-zoom:  ;
  --tw-scroll-snap-strictness: proximity;
  --tw-gradient-from-position:  ;
  --tw-gradient-via-position:  ;
  --tw-gradient-to-position:  ;
  --tw-ordinal:  ;
  --tw-slashed-zero:  ;
  --tw-numeric-figure:  ;
  --tw-numeric-spacing:  ;
  --tw-numeric-fraction:  ;
  --tw-ring-inset:  ;
  --tw-ring-offset-width: 0px;
  --tw-ring-offset-color: #fff;
  --tw-ring-color: rgb(59 130 246 / 0.5);
  --tw-ring-offset-shadow: 0 0 #0000;
  --tw-ring-shadow: 0 0 #0000;
  --tw-shadow: 0 0 #0000;
  --tw-shadow-colored: 0 0 #0000;
  --tw-blur:  ;
  --tw-brightness:  ;
  --tw-contrast:  ;
  --tw-grayscale:  ;
  --tw-hue-rotate:  ;
  --tw-invert:  ;
  --tw-saturate:  ;
  --tw-sepia:  ;
  --tw-drop-shadow:  ;
  --tw-backdrop-blur:  ;
  --tw-backdrop-brightness:  ;
  --tw-backdrop-contrast:  ;
  --tw-backdrop-grayscale:  ;
  --tw-backdrop-hue-rotate:  ;
  --tw-backdrop-invert:  ;
  --tw-backdrop-opacity:  ;
  --tw-backdrop-saturate:  ;
  --tw-backdrop-sepia:  ;
  --tw-contain-size:  ;
  --tw-contain-layout:  ;
  --tw-contain-paint:  ;
  --tw-contain-style:  ;
}

::backdrop {
  --tw-border-spacing-x: 0;
  --tw-border-spacing-y: 0;
  --tw-translate-x: 0;
  --tw-translate-y: 0;
  --tw-rotate: 0;
  --tw-skew-x: 0;
  --tw-skew-y: 0;
  --tw-scale-x: 1;
  --tw-scale-y: 1;
  --tw-pan-x:  ;
  --tw-pan-y:  ;
  --tw-pinch-zoom:  ;
  --tw-scroll-snap-strictness: proximity;
  --tw-gradient-from-position:  ;
  --tw-gradient-via-position:  ;
  --tw-gradient-to-position:  ;
  --tw-ordinal:  ;
  --tw-slashed-zero:  ;
  --tw-numeric-figure:  ;
  --tw-numeric-spacing:  ;
  --tw-numeric-fraction:  ;
  --tw-ring-inset:  ;
  --tw-ring-offset-width: 0px;
  --tw-ring-offset-color: #fff;
  --tw-ring-color: rgb(59 130 246 / 0.5);
  --tw-ring-offset-shadow: 0 0 #0000;
  --tw-ring-shadow: 0 0 #0000;
  --tw-shadow: 0 0 #0000;
  --tw-shadow-colored: 0 0 #0000;
  --tw-blur:  ;
  --tw-brightness:  ;
  --tw-contrast:  ;
  --tw-grayscale:  ;
  --tw-hue-rotate:  ;
  --tw-invert:  ;
  --tw-saturate:  ;
  --tw-sepia:  ;
  --tw-drop-shadow:  ;
  --tw-backdrop-blur:  ;
  --tw-backdrop-brightness:  ;
  --tw-backdrop-contrast:  ;
  --tw-backdrop-grayscale:  ;
  --tw-backdrop-hue-rotate:  ;
  --tw-backdrop-invert:  ;
  --tw-backdrop-opacity:  ;
  --tw-backdrop-saturate:  ;
  --tw-backdrop-sepia:  ;
  --tw-contain-size:  ;
  --tw-contain-layout:  ;
  --tw-contain-paint:  ;
  --tw-contain-style:  ;
}

/*
! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com
*/

/*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
*/

*,
::before,
::after {
  box-sizing: border-box;
  /* 1 */
  border-width: 0;
  /* 2 */
  border-style: solid;
  /* 2 */
  border-color: #e5e7eb;
  /* 2 */
}

::before,
::after {
  --tw-content: '';
}

/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
3. Use a more readable tab size.
4. Use the user's configured `sans` font-family by default.
5. Use the user's configured `sans` font-feature-settings by default.
6. Use the user's configured `sans` font-variation-settings by default.
7. Disable tap highlights on iOS
*/

html,
:host {
  line-height: 1.5;
  /* 1 */
  -webkit-text-size-adjust: 100%;
  /* 2 */
  -moz-tab-size: 4;
  /* 3 */
  -o-tab-size: 4;
     tab-size: 4;
  /* 3 */
  font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  /* 4 */
  font-feature-settings: normal;
  /* 5 */
  font-variation-settings: normal;
  /* 6 */
  -webkit-tap-highlight-color: transparent;
  /* 7 */
}

/*
1. Remove the margin in all browsers.
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
*/

body {
  margin: 0;
  /* 1 */
  line-height: inherit;
  /* 2 */
}

/*
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
3. Ensure horizontal rules are visible by default.
*/

hr {
  height: 0;
  /* 1 */
  color: inherit;
  /* 2 */
  border-top-width: 1px;
  /* 3 */
}

/*
Add the correct text decoration in Chrome, Edge, and Safari.
*/

abbr:where([title]) {
  -webkit-text-decoration: underline dotted;
          text-decoration: underline dotted;
}

/*
Remove the default font size and weight for headings.
*/

h1,
h2,
h3,
h4,
h5,
h6 {
  font-size: inherit;
  font-weight: inherit;
}

/*
Reset links to optimize for opt-in styling instead of opt-out.
*/

a {
  color: inherit;
  text-decoration: inherit;
}

/*
Add the correct font weight in Edge and Safari.
*/

b,
strong {
  font-weight: bolder;
}

/*
1. Use the user's configured `mono` font-family by default.
2. Use the user's configured `mono` font-feature-settings by default.
3. Use the user's configured `mono` font-variation-settings by default.
4. Correct the odd `em` font sizing in all browsers.
*/

code,
kbd,
samp,
pre {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  /* 1 */
  font-feature-settings: normal;
  /* 2 */
  font-variation-settings: normal;
  /* 3 */
  font-size: 1em;
  /* 4 */
}

/*
Add the correct font size in all browsers.
*/

small {
  font-size: 80%;
}

/*
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
*/

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}

sub {
  bottom: -0.25em;
}

sup {
  top: -0.5em;
}

/*
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
3. Remove gaps between table borders by default.
*/

table {
  text-indent: 0;
  /* 1 */
  border-color: inherit;
  /* 2 */
  border-collapse: collapse;
  /* 3 */
}

/*
1. Change the font styles in all browsers.
2. Remove the margin in Firefox and Safari.
3. Remove default padding in all browsers.
*/

button,
input,
optgroup,
select,
textarea {
  font-family: inherit;
  /* 1 */
  font-feature-settings: inherit;
  /* 1 */
  font-variation-settings: inherit;
  /* 1 */
  font-size: 100%;
  /* 1 */
  font-weight: inherit;
  /* 1 */
  line-height: inherit;
  /* 1 */
  letter-spacing: inherit;
  /* 1 */
  color: inherit;
  /* 1 */
  margin: 0;
  /* 2 */
  padding: 0;
  /* 3 */
}

/*
Remove the inheritance of text transform in Edge and Firefox.
*/

button,
select {
  text-transform: none;
}

/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/

button,
input:where([type='button']),
input:where([type='reset']),
input:where([type='submit']) {
  -webkit-appearance: button;
  /* 1 */
  background-color: transparent;
  /* 2 */
  background-image: none;
  /* 2 */
}

/*
Use the modern Firefox focus style for all focusable elements.
*/

:-moz-focusring {
  outline: auto;
}

/*
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
*/

:-moz-ui-invalid {
  box-shadow: none;
}

/*
Add the correct vertical alignment in Chrome and Firefox.
*/

progress {
  vertical-align: baseline;
}

/*
Correct the cursor style of increment and decrement buttons in Safari.
*/

::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
  height: auto;
}

/*
1. Correct the odd appearance in Chrome and Safari.
2. Correct the outline style in Safari.
*/

[type='search'] {
  -webkit-appearance: textfield;
  /* 1 */
  outline-offset: -2px;
  /* 2 */
}

/*
Remove the inner padding in Chrome and Safari on macOS.
*/

::-webkit-search-decoration {
  -webkit-appearance: none;
}

/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Change font properties to `inherit` in Safari.
*/

::-webkit-file-upload-button {
  -webkit-appearance: button;
  /* 1 */
  font: inherit;
  /* 2 */
}

/*
Add the correct display in Chrome and Safari.
*/

summary {
  display: list-item;
}

/*
Removes the default spacing and border for appropriate elements.
*/

blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
  margin: 0;
}

fieldset {
  margin: 0;
  padding: 0;
}

legend {
  padding: 0;
}

ol,
ul,
menu {
  list-style: none;
  margin: 0;
  padding: 0;
}

/*
Reset default styling for dialogs.
*/

dialog {
  padding: 0;
}

/*
Prevent resizing textareas horizontally by default.
*/

textarea {
  resize: vertical;
}

/*
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
2. Set the default placeholder color to the user's configured gray 400 color.
*/

input::-moz-placeholder, textarea::-moz-placeholder {
  opacity: 1;
  /* 1 */
  color: #9ca3af;
  /* 2 */
}

input::placeholder,
textarea::placeholder {
  opacity: 1;
  /* 1 */
  color: #9ca3af;
  /* 2 */
}

/*
Set the default cursor for buttons.
*/

button,
[role="button"] {
  cursor: pointer;
}

/*
Make sure disabled buttons don't get the pointer cursor.
*/

:disabled {
  cursor: default;
}

/*
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
   This can trigger a poorly considered lint error in some tools but is included by design.
*/

img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
  display: block;
  /* 1 */
  vertical-align: middle;
  /* 2 */
}

/*
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
*/

img,
video {
  max-width: 100%;
  height: auto;
}

/* Make elements with the HTML hidden attribute stay hidden by default */

[hidden]:where(:not([hidden="until-found"])) {
  display: none;
}

:root {
  --space-2xs: 0.25rem;
  --space-xs: 0.5rem;
  --space-sm: 0.75rem;
  --space-md: 1rem;
  --space-lg: 1.5rem;
  --space-xl: 2rem;
  --space-2xl: 3rem;
  --space-3xl: 4rem;
  /* Surfaces */
  --surface-base: oklch(1 0 0);
  --surface-raised: oklch(0.996 0.005 95);
  --surface-muted: oklch(1 0 0);
  --surface-soft: oklch(0.955 0.012 95);
  /* Lines */
  --line-soft: oklch(0.89 0.012 95);
  --line-softer: oklch(0.93 0.01 95);
  --line-strong: oklch(0.8 0.017 92);
  /* Ink */
  --ink-strong: oklch(0.28 0.02 70);
  --ink-base: oklch(0.4 0.017 72);
  --ink-soft: oklch(0.55 0.014 74);
  --ink-softest: oklch(0.7 0.012 74);
  --brand-color: oklch(0.55 0.014 74);
  /* Radii */
  --radius-sm: 0.5rem;
  --radius-md: 0.85rem;
  --radius-lg: 1.2rem;
  --radius-xl: 1.4rem;
  /* Transition timings */
  --t-fast: 120ms;
  --t-base: 180ms;
  --t-slow: 220ms;
  --ease: ease;
  /* Row padding token (used by aside/drawer rows) */
  --row-pad: 0.6rem;
  /* Eigenschaften-Bereich: paper-like surface tokens (Issue 1) */
  --eigen-bg: oklch(0.99 0.005 95);
  --eigen-field-bg: oklch(0.97 0.008 95);
  --eigen-field-border: oklch(0.88 0.015 95);
  --eigen-ink: oklch(0.28 0.02 74);
  /* Accent */
  --accent: oklch(0.62 0.085 220);
  --accent-strong: oklch(0.53 0.095 220);
  --accent-soft: oklch(0.859 0.0271 242.47 / 50%);
  /* Semantic */
  --danger: oklch(0.6 0.16 26);
  --danger-soft: oklch(0.96 0.03 26);
  --warning: oklch(0.68 0.11 75);
  --warning-soft: oklch(0.97 0.03 80);
  --success: oklch(0.62 0.12 150);
  --success-soft: oklch(0.96 0.03 150);
  /* Semantic mixes — derived from base hues to keep drift in check */
  --accent-border: color-mix(in srgb, var(--accent) 24%, white 76%);
  --accent-border-soft: color-mix(in srgb, var(--accent) 18%, white 82%);
  --accent-border-strong: color-mix(in srgb, var(--accent) 58%, white 42%);
  --danger-ink: color-mix(in srgb, var(--danger) 72%, black 28%);
  --danger-ink-strong: color-mix(in srgb, var(--danger) 80%, black 20%);
  --danger-strong: color-mix(in srgb, var(--danger) 86%, black 14%);
  --danger-strongest: color-mix(in srgb, var(--danger) 92%, black 8%);
  --danger-tint: color-mix(in srgb, var(--danger) 24%, white 76%);
  --warning-ink: color-mix(in srgb, var(--warning) 60%, black 40%);
  --warning-tint: color-mix(in srgb, var(--warning) 30%, white 70%);
  --warning-bg: color-mix(in srgb, var(--warning) 42%, white 58%);
  --warning-border-strong: color-mix(in srgb, var(--warning) 58%, white 42%);
  /* Raw palette — used to compose rgba() variants below */
  --_sand: 184 169 144;
  /* warm sand — borders, dividers */
  --_sand-mid: 188 172 148;
  /* slightly darker sand — internal dividers */
  --_shadow-warm: 67 55 35;
  /* warm brown — standard shadows */
  --_shadow-deep: 61 48 28;
  /* deep brown — dialog/card shadows */
  --_white: 255 255 255;
  /* pure white — glassy backgrounds */
  --_cream: 253 251 247;
  /* warm off-white — dialog/form panels */
  --_warm-bg: 246 242 236;
  /* warm tint — meta blocks, table headers */
  --_sand-muted: 200 193 182;
  /* muted sand — button-muted */
  --_disabled-bg: 221 214 202;
  /* disabled button fill */
  --_disabled-text: 100 89 71;
  /* disabled button text */
  /* Composed tokens — primary opacities (most common usage) */
  --border-sand: rgba(var(--_sand) / 0.24);
  --border-sand-soft: rgba(var(--_sand) / 0.2);
  --border-divider: rgba(var(--_sand-mid) / 0.2);
  --border-divider-faint: rgba(var(--_sand-mid) / 0.14);
  --border-divider-medium: rgba(var(--_sand-mid) / 0.22);
  --bg-card: rgba(var(--_white) / 0.72);
  --bg-card-light: rgba(var(--_white) / 0.74);
  --bg-card-medium: rgba(var(--_white) / 0.78);
  --bg-card-strong: rgba(var(--_white) / 0.8);
  --bg-card-solid: rgba(var(--_white) / 0.98);
  --bg-cream: rgba(var(--_cream) / 0.98);
  --bg-warm: rgba(var(--_warm-bg) / 0.9);
  --bg-warm-table: rgba(var(--_warm-bg) / 0.92);
  --shadow-sm: 0 1px 2px rgba(var(--_shadow-warm) / 0.05), 0 8px 24px rgba(var(--_shadow-warm) / 0.04);
  --shadow-md: 0 1px 2px rgba(var(--_shadow-warm) / 0.05), 0 16px 40px rgba(var(--_shadow-warm) / 0.08);
  --font-body: "Helvetica Neue", Arial, sans-serif;
  --font-heading: "Linux Biolinum", "Optima", "Georgia", Arial, sans-serif;
  --font-prominent: "Linux Biolinum", "Optima", Georgia, "Times New Roman", serif;
  --font-prominent-weight: 500;
  --font-placeholder: "Helvetica Neue", Arial, sans-serif;
  --color-placeholder: var(--ink-soft);
}

html {
  background-color: var(--surface-base);
  color: var(--ink-strong);
}

body {
  min-height: 100%;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  background:
      radial-gradient(circle at top left, rgba(151, 196, 216, 0.15), transparent 28%),
      radial-gradient(circle at top right, rgba(218, 198, 166, 0.16), transparent 24%),
      linear-gradient(180deg, rgba(255, 255, 255, 0.68), rgba(255, 255, 255, 0.2)),
      var(--surface-base);
  color: var(--ink-base);
  font-family: var(--font-body);
}

h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
  color: var(--ink-strong);
  font-family: var(--font-heading);
  font-weight: 600;
  letter-spacing: -0.02em;
}

h1 {
  font-size: 2rem;
}

h2 {
  font-size: 1.5rem;
  font-weight: 600;
  color: var(--ink-base);
}

h3 {
  font-size: 1rem;
  font-weight: 500;
  color: var(--ink-soft);
}

a {
  transition: color var(--t-base) var(--ease), opacity var(--t-base) var(--ease), background-color var(--t-base) var(--ease), border-color var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease), transform var(--t-base) var(--ease);
}

p {
  max-width: 72ch;
}

code,
  kbd,
  samp,
  pre {
  font-family: var(--font-body);
}

::-moz-selection {
  background: color-mix(in srgb, var(--accent-soft) 80%, white 20%);
}

::selection {
  background: color-mix(in srgb, var(--accent-soft) 80%, white 20%);
}

button,
  input,
  select,
  textarea {
  font: inherit;
}

/* :where() keeps these defaults at zero specificity so any component
     restyle (inline-document optic, pill/popover inputs) wins without
     selector arms races — the flattened Tailwind output has no @layer
     cascade to do that for us. */

input:where(:not([type="hidden"]):not([type="checkbox"]):not([type="radio"])),
  select,
  textarea {
  width: 100%;
  min-height: 2.875rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--surface-raised) 88%, white 12%);
  color: var(--ink-strong);
  padding: 0.75rem 0.95rem;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.6);
  transition: border-color var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease), background-color var(--t-base) var(--ease);
}

textarea {
  min-height: 7rem;
}

input::-moz-placeholder, textarea::-moz-placeholder {
  font-family: var(--font-placeholder);
  color: var(--color-placeholder);
}

input::placeholder,
  textarea::placeholder {
  font-family: var(--font-placeholder);
  color: var(--color-placeholder);
}

input:where(:not([type="hidden"]):not([type="checkbox"]):not([type="radio"])):focus,
  select:focus,
  textarea:focus {
  outline: none;
  border-color: var(--accent-border-strong);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent-soft) 82%, white 18%);
  background: var(--surface-raised);
}

input:where(:not([type="hidden"]):not([type="checkbox"]):not([type="radio"])):disabled,
  select:disabled,
  textarea:disabled {
  background: var(--surface-soft);
  color: var(--ink-soft);
  cursor: not-allowed;
}

input[type="checkbox"] {
  width: 1rem;
  height: 1rem;
  accent-color: var(--accent-strong);
}

dialog {
  margin: auto;
}

dialog::backdrop {
  background: rgba(71, 56, 34, 0.22);
  -webkit-backdrop-filter: blur(5px);
          backdrop-filter: blur(5px);
}

.\!container {
  width: 100% !important;
}

.container {
  width: 100%;
}

@media (min-width: 640px) {
  .\!container {
    max-width: 640px !important;
  }

  .container {
    max-width: 640px;
  }
}

@media (min-width: 768px) {
  .\!container {
    max-width: 768px !important;
  }

  .container {
    max-width: 768px;
  }
}

@media (min-width: 1024px) {
  .\!container {
    max-width: 1024px !important;
  }

  .container {
    max-width: 1024px;
  }
}

@media (min-width: 1280px) {
  .\!container {
    max-width: 1280px !important;
  }

  .container {
    max-width: 1280px;
  }
}

@media (min-width: 1536px) {
  .\!container {
    max-width: 1536px !important;
  }

  .container {
    max-width: 1536px;
  }
}

/* ----------------------------------------------------------------------
     Collapsible-Strip: side column that toggles between a narrow 38px rail
     (with vertical label + toggle button) and an expanded content panel.
     See CONTEXT.md → UI patterns.

     Per-instance specifics (expanded width, border side) live on the
     consuming class (e.g. .detail-aside) — this block only owns the
     toggle mechanic and rail styling.

     Pre-hydration: each strip's inline script sets [data-pre-expanded] on
     its own element during the document-parse stream, so the first paint
     already matches the persisted state. detail-persistence.js then
     swaps to .is-expanded after wireDom.
  ---------------------------------------------------------------------- */

.collapsible-strip {
  --strip-expanded-width: 320px;
  flex: 0 0 38px;
  background: var(--surface-raised);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: flex-basis var(--t-base) var(--ease);
}

.collapsible-strip.is-expanded,
  .collapsible-strip[data-pre-expanded] {
  flex: 0 0 var(--strip-expanded-width);
  overflow-y: auto;
}

.collapsible-strip__rail {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0;
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  border: none;
  background: transparent;
  cursor: pointer;
  width: 100%;
}

.collapsible-strip.is-expanded .collapsible-strip__rail,
  .collapsible-strip[data-pre-expanded] .collapsible-strip__rail {
  display: none;
}

.collapsible-strip:not(.is-expanded):not([data-pre-expanded]) .collapsible-strip__content {
  display: none;
}

.collapsible-strip__rail-toggle {
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  background: transparent;
  border: none;
  cursor: pointer;
  font-size: 1.1rem;
  color: var(--ink-soft);
  padding: 0.2rem;
  line-height: 1;
}

.collapsible-strip__rail-label {
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--ink-soft);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  writing-mode: vertical-rl;
}

.app-shell {
  min-height: 100%;
}

.app-shell-fixed {
  display: flex;
  flex-direction: column;
  height: 100dvh;
  overflow: hidden;
  /* Slice 07: Papier-Palette — scoped overrides of the shared surface/
       line/ink/accent tokens so the Inline-Dokument detail page gets the
       paper-and-ink look without recoloring Login/Projektliste/Klassen-Editor,
       which share these tokens via :root. */
  --surface-base: #fffcf6;
  --surface-raised: #f8f6f1;
  --surface-soft: #eaeee1;
  --surface-overlay: #fffdf8;
  --eigen-bg: #fffcf6;
  --line-soft: rgba(42, 39, 34, 0.13);
  --line-softer: rgba(42, 39, 34, 0.13);
  --line-strong: rgba(42, 39, 34, 0.20);
  --ink-strong: #2a2722;
  --ink-base: #5c574e;
  --ink-soft: #8c867a;
  --ink-softest: #b3ad9f;
  --accent: #4f7a28;
  --accent-strong: #4f7a28;
  --accent-soft: color-mix(in srgb, #4f7a28 22%, white 78%);
  --accent-border: color-mix(in srgb, #4f7a28 24%, white 76%);
  --accent-border-soft: color-mix(in srgb, #4f7a28 18%, white 82%);
  --accent-border-strong: color-mix(in srgb, #4f7a28 58%, white 42%);
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: #f7f5f0;
  -webkit-backdrop-filter: blur(14px);
          backdrop-filter: blur(14px);
  /* needed for ::after gradient line */
  isolation: isolate;
}

.topbar::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(
      90deg,
      rgba(199, 166, 115, 0.61) 0%,
      rgba(8, 59, 71, 0.15) 50%,
      rgba(199, 166, 115, 0.61) 100%
    );
}

.topbar-inner {
  display: flex;
  align-items: center;
  /* Fixed bar height across all pages: tall enough for the record-nav /
       focus-mode controls (30px), so pages without them match exactly. */
  min-height: 46px;
  gap: 0.4rem;
  padding-inline: clamp(1rem, 2.5vw, 2rem);
  padding-block: .5rem;
}

.topbar-project {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  text-decoration: none;
}

.topbar-project:hover {
  color: var(--ink-strong);
}

.topbar-breadcrumbs {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 0.4rem;
  min-width: 0;
  overflow: hidden;
  font-size: 0.78rem;
  color: var(--ink-soft);
}

.topbar-crumb-link {
  color: rgb(104, 104, 104);
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}

.topbar-crumb-link:hover {
  color: var(--ink-strong);
  font-weight: 700;
}

.topbar-crumb-current {
  color: var(--ink-base);
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.topbar-crumb-separator {
  color: color-mix(in srgb, var(--line-strong) 68%, white 32%);
  font-size: 0.78rem;
}

.topbar-search {
  flex: 1 1 auto;
  display: flex;
  min-width: 0;
}

.topbar-search[hidden] {
  display: none;
}

.topbar .topbar-search input[type="search"] {
  width: 100%;
  max-width: 28rem;
  height: 1.8rem;
  min-height: 0;
  padding: 0.4rem 0.8rem;
  border: 1px solid var(--line-soft, #fcfcfc);
  border-radius: 2rem;
  background: var(--bg-soft, #ffffff);
  box-shadow: none;
  font-size: 0.9rem;
  color: var(--ink);
  transition: none;
}

.topbar .topbar-search input[type="search"]:focus {
  outline: none;
  border-color: var(--line-soft, #ffffff);
  box-shadow: none;
  background: var(--bg-soft, #ffffff);
}

.brand-link {
  display: inline-flex;
  align-items: baseline;
  gap: 0.75rem;
  color: var(--brand-color);
  text-decoration: none;
}

.brand-mark {
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 999px;
  background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 85%, white 15%), var(--warning-bg));
  box-shadow: 0 0 0 5px rgba(125, 159, 178, 0.11);
}

.brand-copy {
  display: grid;
  gap: 0.15rem;
}

.brand-title {
  font-size: 1rem;
  font-weight: 700;
  line-height: 1;
}

.topbar-meta {
  display: flex;
  align-items: center;
  gap: 1rem;
  color: var(--ink-soft);
  font-size: 0.85rem;
  margin-inline-start: auto;
}

/* Fokus-Modus toggle (Slice 08): 30x30 ghost icon button, accent-tinted
     when active (aria-pressed=true). The hairline separator sits between it
     and the user menu. */

.topbar-focus-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
  transition: background-color 140ms ease, color 140ms ease;
}

.topbar-focus-toggle:hover {
  background: color-mix(in srgb, var(--ink-soft) 10%, transparent);
  color: var(--ink-strong);
}

.topbar-focus-toggle[aria-pressed="true"] {
  background: color-mix(in srgb, var(--accent-soft) 80%, white 20%);
  color: var(--accent-strong);
}

.topbar-sep {
  width: 1px;
  align-self: stretch;
  margin-block: 0.35rem;
  background: var(--line-softer);
}

/* Datensatz-Navigation ‹ › (Slice 09): two quiet 28x28 ghost chevrons with
     a hairline divider between them. Disabled position renders greyed and
     non-interactive (no wrap-around). */

.topbar-record-nav {
  display: inline-flex;
  align-items: center;
}

.topbar-record-nav-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-sm);
  color: var(--ink-soft);
  transition: background-color 140ms ease, color 140ms ease;
}

.topbar-record-nav-btn:hover {
  background: color-mix(in srgb, var(--ink-soft) 10%, transparent);
  color: var(--ink-strong);
}

.topbar-record-nav-btn.is-disabled {
  color: var(--line-soft);
  pointer-events: none;
}

.topbar-record-nav-sep {
  width: 1px;
  align-self: stretch;
  margin-block: 0.4rem;
  background: var(--line-softer);
}

.page-shell {
  margin-left: auto;
  margin-right: auto;
  max-width: 80rem;
  padding-inline: clamp(1rem, 2.5vw, 2rem);
  padding-block: clamp(1.5rem, 2vw, 2.5rem);
}

.page-stack {
  display: grid;
  gap: clamp(1.5rem, 2vw, 2rem);
}

.page-section {
  display: grid;
  gap: clamp(1rem, 1.6vw, 1.5rem);
}

.page-header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-lg);
}

.page-heading {
  display: grid;
  gap: 0.45rem;
  flex: 1;
  min-width: 0;
}

.page-eyebrow {
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.page-title {
  line-height: 1.08;
}

.page-subtitle {
  color: var(--ink-soft);
  font-size: 0.96rem;
  line-height: 1.6;
}

.page-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
}

.notice {
  display: grid;
  gap: 0.4rem;
  border-radius: var(--radius-lg);
  border: 1px solid var(--line-soft);
  padding: .4rem 1rem;
  background: color-mix(in srgb, var(--surface-raised) 82%, white 18%);
}

.notice-danger {
  border-color: var(--danger-tint);
  background: var(--danger-soft);
  color: var(--danger-ink);
}

.notice-warning {
  border-color: var(--warning-tint);
  background: var(--warning-soft);
  color: var(--warning-ink);
}

.notice-success {
  border-color: color-mix(in srgb, var(--success) 30%, white 70%);
  background: var(--success-soft);
  color: color-mix(in srgb, var(--success) 58%, black 42%);
}

.notice-inline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

/* Fixed host for HTMX server/network error banners (see base.html). Empty
     until a 5xx or send error fires, so it never affects normal layout. */

.app-error-toast:not(:empty) {
  position: fixed;
  top: 1rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 60;
  width: min(40rem, calc(100% - 2rem));
}

.app-error-toast .notice {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  box-shadow: 0 10px 30px rgb(0 0 0 / 18%);
}

/* Transient success toast (oben mittig). Empty until a save redirect fires;
     fades + slides in, auto-dismisses via the script in base.html. */

.app-success-toast:not(:empty) {
  position: fixed;
  top: 1rem;
  left: 50%;
  transform: translate(-50%, -0.5rem);
  z-index: 60;
  width: -moz-max-content;
  width: max-content;
  max-width: calc(100% - 2rem);
  opacity: 0;
  pointer-events: none;
  transition:
      opacity 0.18s ease,
      transform 0.18s ease;
}

.app-success-toast.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
}

.app-success-toast .notice {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  box-shadow: 0 10px 30px rgb(0 0 0 / 18%);
}

@media (prefers-reduced-motion: reduce) {
  .app-success-toast:not(:empty) {
    transition: opacity 0.18s ease;
    transform: translate(-50%, 0);
  }
}

.surface {
  border: 1px solid var(--border-sand);
  border-radius: var(--radius-xl);
  background: transparent;
  box-shadow: none;
}

.surface-pad {
  padding: clamp(0.1rem, 0vw, 0rem);
}

.surface-body {
  display: grid;
  gap: var(--space-lg);
  padding: clamp(1.35rem, 2vw, 1.75rem);
}

.surface-title {
  font-size: 1.2rem;
  line-height: 1.15;
}

.tile-grid {
  display: grid;
  gap: clamp(1rem, 1.5vw, 1.4rem);
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}

.tile-link,
  .tile-panel {
  display: grid;
  gap: 0.75rem;
  align-content: start;
  min-height: 100%;
  padding: 1.2rem;
  border: 1px solid var(--border-sand);
  border-radius: var(--radius-lg);
  background: var(--bg-card);
  box-shadow: 0 1px 2px rgba(var(--_shadow-warm) / 0.04);
}

.tile-link:hover {
  transform: translateY(-1px);
  border-color: var(--accent-border);
  box-shadow: var(--shadow-md);
}

.tile-panel {
  background: transparent;
}

.tile-head {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
}

.tile-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface-soft) 68%, white 32%);
  font-size: 1.2rem;
}

.tile-copy {
  display: grid;
  gap: 0.3rem;
  min-width: 0;
}

.tile-title {
  font-size: 1.05rem;
  line-height: 1.2;
}

.tile-subtitle {
  color: var(--ink-soft);
  font-size: 0.9rem;
  line-height: 1.55;
}

.mono {
  font-family: var(--font-body);
}

.project-meta-inline {
  margin-top: 0.75rem;
  font-size: 0.78rem;
  color: var(--ink-soft);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 2.75rem;
  padding-inline: 1rem;
  border-radius: 999px;
  border: 1px solid transparent;
  font-size: 0.9rem;
  font-weight: 600;
  white-space: nowrap;
}

.button-primary {
  background: color-mix(in srgb, var(--accent-strong) 88%, black 12%);
  color: white;
  box-shadow: 0 10px 24px rgba(86, 122, 151, 0.18);
}

.button-primary:hover {
  background: color-mix(in srgb, var(--accent-strong) 94%, black 6%);
}

.button-secondary {
  border-color: rgba(var(--_sand) / 0.32);
  background: rgba(var(--_white) / 0.75);
  color: var(--ink-base);
}

.button-secondary:hover {
  border-color: var(--accent-border-soft);
  background: rgba(var(--_white) / 0.92);
  color: var(--ink-strong);
}

.button-warning {
  border-color: var(--warning-tint);
  background: color-mix(in srgb, var(--warning-soft) 82%, white 18%);
  color: var(--warning-ink);
}

.button-warning:hover {
  background: color-mix(in srgb, var(--warning-soft) 62%, white 38%);
}

.button-danger {
  background: var(--danger-strong);
  color: white;
}

.button-danger:hover {
  background: var(--danger-strongest);
}

.button-muted {
  background: rgba(var(--_sand-muted) / 0.45);
  color: var(--ink-soft);
  border-color: rgba(var(--_sand) / 0.3);
}

.button-muted:hover {
  background: rgba(var(--_sand-muted) / 0.65);
  color: var(--ink-strong);
}

.button-ghost {
  background: transparent;
  color: var(--ink-soft);
  padding-inline: 0;
  min-height: auto;
}

.button-ghost:hover {
  color: var(--ink-strong);
}

.button:disabled,
  .button-primary:disabled,
  .button-secondary:disabled,
  .button-warning:disabled,
  .button-danger:disabled {
  background: rgba(var(--_disabled-bg) / 0.75);
  border-color: transparent;
  color: rgba(var(--_disabled-text) / 0.7);
  box-shadow: none;
  cursor: not-allowed;
}

/* Animated dots for buttons during running submit requests.
     Aktiv, sobald raumbuchMarkFormPending() das Attribut setzt. */

.button[data-busy-dots]::after {
  content: "";
  display: inline-block;
  width: 1.2em;
  text-align: left;
  animation: raumbuch-busy-dots 1.2s steps(4, end) infinite;
}

@keyframes raumbuch-busy-dots {
  0%   {
    content: "";
  }

  25%  {
    content: ".";
  }

  50%  {
    content: "..";
  }

  75%  {
    content: "...";
  }

  100% {
    content: "";
  }
}

@media (prefers-reduced-motion: reduce) {
  .button[data-busy-dots]::after {
    animation: none;
    content: "…";
  }
}

.badge {
  display: inline-flex;
  align-items: center;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  font-size: 0.76rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.badge-neutral {
  background: rgba(240, 235, 228, 0.9);
  color: var(--ink-base);
}

.badge-warning {
  background: color-mix(in srgb, var(--warning-soft) 72%, white 28%);
  color: var(--warning-ink);
}

.badge-success {
  background: color-mix(in srgb, var(--success-soft) 72%, white 28%);
  color: color-mix(in srgb, var(--success) 58%, black 42%);
}

.table-scroll {
  overflow-x: auto;
}

.data-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
}

.data-table thead th {
  padding: 0.95rem 1.25rem;
  background: var(--bg-warm-table);
  color: var(--ink-soft);
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-align: left;
  text-transform: uppercase;
}

.data-table thead th:last-child,
  .data-table tbody td:last-child {
  text-align: right;
}

.data-table tbody tr {
  transition: background-color var(--t-base) var(--ease);
}

.data-table tbody tr:hover {
  background: rgba(246, 250, 253, 0.75);
}

.data-table tbody td {
  padding: 1rem 1.25rem;
  border-top: 1px solid var(--border-divider-faint);
  color: var(--ink-base);
  font-size: 0.92rem;
  vertical-align: top;
}

.table-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.75rem;
}

.form-stack {
  display: grid;
  gap: 1.4rem;
}

.form-inline {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.field-stack {
  display: grid;
  gap: 0.5rem;
}

/* ---------------------------------------------------------------
     Object-Detail Standard Shell (Issue 1 redesign).

     Flex-column layout: topbar → breadcrumb → header → main-row → drawer.
     The main-row itself is a flex-row: tree | properties-scroller | aside.
  --------------------------------------------------------------- */

.detail-shell {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}

.detail-object-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.6rem 1.25rem;
  border-bottom: 1px solid var(--line-softer);
  background: var(--surface-raised);
  gap: 1rem;
}

.detail-class-tag {
  font-size: 0.5rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  padding: 0.1rem 0.5rem;
  background: white;
  color: var(--ink-strong);
  border: 1px solid transparent;
  text-transform: uppercase;
  border-radius: var(--radius-sm);
  white-space: nowrap;
  flex-shrink: 0;
}

/* When a class color is provided via --class-color, render the tag as a
     translucent chip — same pattern as hotspot pins, but using color-mix
     with transparent so only the background is translucent (text stays
     sharp). Text color comes from --class-text-color (server-computed
     black/white contrast). */

.detail-class-tag[style*="--class-color"] {
  background-color: color-mix(in srgb, var(--class-color) 50%, transparent);
  color: var(--class-text-color, var(--ink-strong));
}

.detail-object-identifier {
  font-size: 1.4rem;
  color: var(--accent-strong);
  font-weight: 600;
  font-family: var(--font-prominent);
  letter-spacing: -0.005em;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.detail-object-header-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}

/* Compact, hierarchy-aware header buttons — only inside the detail header.
     Outside (dialogs, lists) the global .button pill (2.75rem) stays. */

.detail-object-header-actions .button {
  min-height: 2rem;
  padding: 0.4rem 1rem;
  font-size: 0.875rem;
  box-shadow: none;
}

.detail-object-header-actions .button-secondary {
  border-color: var(--line-soft);
  background: white;
  color: var(--ink-base);
}

.detail-object-header-actions .button-secondary:hover {
  border-color: color-mix(in srgb, var(--accent) 24%, var(--line-soft) 76%);
  background: white;
  color: var(--ink-strong);
}

.detail-object-header-actions .button-warning {
  border-color: var(--warning-bg);
  background: white;
  color: var(--warning-ink);
}

.detail-object-header-actions .button-warning:hover {
  border-color: var(--warning-border-strong);
  background: color-mix(in srgb, var(--warning-soft) 50%, white 50%);
}

/* Inline-Dokument · Slice 06 — Objekt-Header as a quiet title block.
     The standard detail header drops the chrome bar (border/raised bg) and
     aligns to the document measure (780px column, 44px side padding) so it sits
     flush with the spy nav + document below. File detail keeps the plain
     .detail-object-header bar (this scopes everything under .doc-header). */

.detail-object-header.doc-header {
  display: block;
  max-width: 780px;
  margin: 0 auto;
  padding: 1.5rem 44px 0.75rem;
  width: 100%;
  background: var(--eigen-bg);
  border-bottom: none;
}

.doc-header-meta {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.25rem;
}

.doc-header-dates {
  font-size: 11.5px;
  color: var(--ink-softest);
}

.doc-header-titlebar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}

.doc-header-kennung {
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.15;
  color: var(--ink-strong);
  /* Override the inherited .detail-object-identifier serif/accent styles. */
  font-family: inherit;
  margin: 0;
  /* Baseline-align the trailing Bezeichnung. */
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.6rem;
  min-width: 0;
}

.doc-header-bezeichnung {
  font-size: 18px;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--ink-soft);
}

/* In the file-class centre column the header sits above a full-width toolbar
     + file stage, so it spans the column (left-aligned) instead of centring on
     the 780px document measure used by the standard detail document. */

.detail-file-center .detail-object-header.doc-header {
  max-width: none;
  margin: 0;
  padding: 1rem 0.75rem 0.75rem;
}

/* Speichern — filled accent button, 30px tall, radius 7. */

.inline-header-save {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  height: 30px;
  min-height: 30px;
  padding: 0 0.85rem;
  border: none;
  border-radius: 12px;
  background: var(--accent-strong);
  color: white;
  font-size: 0.875rem;
  font-weight: 600;
  box-shadow: none;
  cursor: pointer;
}

.inline-header-save:hover {
  background: color-mix(in srgb, var(--accent-strong) 88%, black 12%);
}

.inline-header-save-icon {
  width: 1rem;
  height: 1rem;
}

/* Kebab — 30×30 tinted toggle bundling the rarer actions in a popover. */

.inline-header-kebab {
  position: relative;
}

.inline-header-kebab-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  background: #dcd7cc;
  color: var(--ink-base);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  list-style: none;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}

/* Hide the native disclosure triangle (WebKit + standards). */

.inline-header-kebab-toggle::-webkit-details-marker {
  display: none;
}

.inline-header-kebab-toggle:hover {
  background: color-mix(in srgb, #dcd7cc 80%, black 12%);
}

.inline-header-menu {
  position: absolute;
  top: calc(100% + 0.4rem);
  right: 0;
  z-index: 30;
  min-width: 248px;
  padding: 0.35rem;
  background: var(--surface-raised);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-md);
  box-shadow: 0 12px 28px rgba(42, 39, 34, 0.16);
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.inline-header-menu-item {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  width: 100%;
  padding: 0.5rem 0.6rem;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--ink-strong);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.inline-header-menu-item:hover {
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}

.inline-header-menu-icon {
  width: 1.1rem;
  height: 1.1rem;
  flex-shrink: 0;
  margin-top: 0.1rem;
  color: var(--ink-soft);
}

.inline-header-menu-text {
  display: flex;
  flex-direction: column;
  line-height: 1.2;
}

.inline-header-menu-label {
  font-size: 0.875rem;
  font-weight: 600;
}

.inline-header-menu-hint {
  font-size: 11.5px;
  color: var(--ink-softest);
}

.inline-header-menu-rule {
  margin: 0.3rem 0.2rem;
  border: none;
  border-top: 1px solid var(--line-softer);
}

.inline-header-menu-item-danger {
  color: var(--warning-ink);
}

.inline-header-menu-item-danger .inline-header-menu-icon {
  color: var(--warning-ink);
}

.inline-header-menu-item-danger:hover {
  background: color-mix(in srgb, var(--warning-soft) 55%, transparent);
}

.detail-main-row {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
}

.detail-properties-scroller {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
  /* Stop scroll chaining: without this, overscrolling the document past its
       end bubbles to the root and the macOS rubber-band lifts the whole
       100dvh shell, exposing white page background below the drawer. */
  overscroll-behavior: contain;
  background: var(--eigen-bg);
  /* No top padding: the sticky spy nav must sit flush under the object
       header. A top gap here would be a transparent strip the document scrolls
       through, leaking field text above the links bar. */
  padding: 0 1.25rem 1.25rem;
  display: flex;
  flex-direction: column;
}

/* Only the document scroller scrolls; the header + spy nav above it stay
     fixed (like the standalone reference). The scroller must shrink within
     this flex column (min-height:0 on the scroller), otherwise .detail-main
     itself would scroll and carry the header out of view. */

.detail-main {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--eigen-bg);
}

/* Anhänge-Aside: .collapsible-strip instance on standard objects.
     Per-instance specs only — strip mechanic comes from .collapsible-strip. */

.detail-aside {
  position: relative;
  --strip-expanded-width: var(--detail-aside-w, 296px);
  border-left: 1px solid var(--line-softer);
}

/* Issue 8: Mobile breakpoints — flex-based, no grid-template-areas -------- */

@media (max-width: 780px) {
  .detail-main-row {
    flex-direction: column;
  }

  .detail-aside,
    .detail-aside.is-expanded {
    flex: 0 0 auto;
    width: 100%;
    border-left: none;
    border-top: 1px solid var(--line-softer);
  }
}

.detail-aside-header {
  display: flex;
  align-items: center;
  gap: 0.2rem;
  padding: 0.4rem 0.4rem;
}

.detail-aside-header .badge {
  margin-left: auto;
}

.detail-aside-toggle {
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  background: transparent;
  border: none;
  cursor: pointer;
  font: inherit;
  color: var(--ink-strong);
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.detail-aside-body {
  display: grid;
  gap: 0.75rem;
  padding-top: 0.6rem;
}

.detail-aside-card-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
}

.detail-aside-card {
  background: var(--surface-base);
  border: 0px solid var(--line-soft);
  border-radius: 0rem;
  padding: 0.5rem;
  display: grid;
  gap: 0.2rem;
}

.detail-aside-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.detail-aside-card-title {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  background: transparent;
  border: none;
  padding: 0;
  font-weight: 600;
  color: var(--ink-strong);
  font-size: 0.9rem;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
}

.detail-aside-card-title:hover {
  color: var(--ink-strong);
}

.detail-aside-card-caret {
  display: inline-block;
  font-size: 0.7rem;
  line-height: 1;
  color: var(--ink-soft);
  transition: transform var(--t-fast) var(--ease);
}

.detail-aside-card[data-collapsed="true"] .detail-aside-card-caret {
  transform: rotate(-90deg);
}

/* Collapse: hide everything in the card except its header. */

.detail-aside-card[data-collapsed="true"] > :not(.detail-aside-card-header) {
  display: none;
}

.detail-aside-card-add {
  padding: 0.1rem 0.45rem;
  font-size: 1rem;
  line-height: 1;
}

.detail-aside-item-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.35rem;
}

.detail-aside-item-link {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.4rem;
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--ink-strong);
}

.detail-aside-item-link:hover {
  background: var(--surface-soft);
}

.detail-aside-item-thumb {
  width: 2rem;
  height: 2rem;
  -o-object-fit: cover;
     object-fit: cover;
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}

.detail-aside-item-icon {
  width: 2rem;
  text-align: center;
}

.detail-aside-item-label {
  font-size: 0.85rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.detail-aside-card-empty {
  color: var(--ink-soft);
  font-size: 0.85rem;
  margin: 0;
}

/* Mode-toggle (Issue 06): single button that switches list <-> preview. */

.detail-aside-mode-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--line-softer);
  border-radius: var(--radius-sm);
  padding: 0.15rem 0.4rem;
  font-size: 0.85rem;
  line-height: 1;
  color: var(--ink-soft);
  cursor: pointer;
  margin-left: auto;
}

.detail-aside-mode-toggle:hover {
  background: var(--surface-soft);
  color: var(--ink-strong);
}

/* Mode-switching: show preview OR list view ---------------------- */

.detail-aside-card[data-aside-mode="preview"] .detail-aside-item-list {
  display: none;
}

.detail-aside-card[data-aside-mode="list"] .detail-aside-preview {
  display: none;
}

/* Preview mode (Issue 06) --------------------------------------- */

.detail-aside-preview {
  display: grid;
  gap: 0.4rem;
}

.detail-aside-hero {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--surface-soft);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.detail-aside-hero-link {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  text-decoration: none;
  color: inherit;
}

.detail-aside-hero-image {
  width: 100%;
  height: 100%;
  -o-object-fit: cover;
     object-fit: cover;
}

.detail-aside-hero-generic {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  color: var(--ink-soft);
}

.detail-aside-hero-generic-icon {
  font-size: 2.2rem;
  line-height: 1;
}

.detail-aside-hero-generic-label {
  font-size: 0.85rem;
}

.detail-aside-hero-badge {
  position: absolute;
  top: 0.4rem;
  left: 0.4rem;
  background: rgba(0, 0, 0, 0.65);
  color: white;
  font-size: 0.75rem;
  padding: 0.15rem 0.4rem;
  border-radius: var(--radius-sm);
  max-width: calc(100% - 4rem);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.detail-aside-hero-indicator {
  position: absolute;
  top: 0.4rem;
  right: 0.4rem;
  background: rgba(0, 0, 0, 0.65);
  color: white;
  font-size: 0.75rem;
  padding: 0.15rem 0.4rem;
  border-radius: var(--radius-sm);
}

.detail-aside-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background: rgba(0, 0, 0, 0.5);
  color: white;
  border: none;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.85rem;
}

.detail-aside-nav:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

.detail-aside-nav-prev {
  left: 0.3rem;
}

.detail-aside-nav-next {
  right: 0.3rem;
}

.detail-aside-thumb-strip {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(2.5rem, 1fr));
  gap: 0.25rem;
}

.detail-aside-thumb {
  aspect-ratio: 1 / 1;
  border-radius: var(--radius-sm);
  overflow: hidden;
  border: 2px solid transparent;
  background: var(--surface-soft);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.detail-aside-thumb.is-active {
  border-color: var(--ink-strong);
}

.detail-aside-thumb-image {
  width: 100%;
  height: 100%;
  -o-object-fit: cover;
     object-fit: cover;
}

.detail-aside-thumb-icon {
  font-size: 1rem;
  color: var(--ink-soft);
}

/* Tree-Panel ---------------------------------------------------- */

.tree-panel {
  position: relative;
  flex: 0 0 var(--detail-tree-w, 296px);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--surface-raised);
  border-right: 1px solid var(--line-softer);
  padding: 0.6rem 0.75rem;
  transition: flex-basis var(--t-base) var(--ease);
}

.tree-panel.is-collapsed {
  flex: 0 0 38px;
  overflow: hidden;
  padding: 0.5rem 0;
}

.tree-panel-collapsed-strip {
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0;
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  border: none;
  background: transparent;
  cursor: pointer;
  width: 100%;
}

.tree-panel.is-collapsed .tree-panel-collapsed-strip {
  display: flex;
}

.tree-panel.is-collapsed .tree-panel-header,
  .tree-panel.is-collapsed .tree-panel-trail {
  display: none;
}

/* Pre-hydration marker (see base.html inline script): mirrors .is-collapsed
     so the first paint matches the persisted state — no JS-driven flicker. */

html.pre-tree-collapsed .tree-panel {
  flex: 0 0 38px;
  overflow: hidden;
  padding: 0.5rem 0;
}

html.pre-tree-collapsed .tree-panel .tree-panel-collapsed-strip {
  display: flex;
}

html.pre-tree-collapsed .tree-panel .tree-panel-header,
  html.pre-tree-collapsed .tree-panel .tree-panel-trail {
  display: none;
}

.tree-panel-strip-toggle {
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  background: transparent;
  border: none;
  cursor: pointer;
  font-size: 1.1rem;
  color: var(--ink-soft);
  padding: 0.2rem;
  line-height: 1;
}

/* Fokus-Modus (Slice 08): hide all chrome so only the document remains. The
     class lives on <html> (persists across hx-boost). The properties scroller
     then spans the full width while .doc-column keeps its 780px centering. */

html.detail-focus-mode .tree-panel,
  html.detail-focus-mode .detail-drawer,
  html.detail-focus-mode .detail-aside,
  html.detail-focus-mode .detail-datei-liste-column,
  html.detail-focus-mode .detail-file-aside {
  display: none;
}

.tree-panel-strip-label {
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--ink-soft);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.tree-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0rem 0.1rem;
}

.tree-panel-toggle {
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  background: transparent;
  border: none;
  cursor: pointer;
  font: inherit;
  color: var(--ink-strong);
  font-weight: 600;
  width: 100%;
  text-align: left;
  padding: 0.25rem 0.1rem;
  display: flex;
  align-items: center;
  gap: 0.3rem;
}

.tree-panel-toggle [aria-hidden] {
  margin-left: auto;
}

.tree-panel-trail {
  list-style: none;
  margin: 0.4rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.1rem;
}

.tree-panel-step {
  padding-left: calc(var(--depth, 0) * 0.75rem);
}

.tree-panel-link {
  display: block;
  padding: 0.25rem 0.4rem;
  text-decoration: none;
  color: var(--ink-base);
  border-radius: var(--radius-sm);
  font-size: 0.85rem;
}

.tree-panel-link:hover {
  background: var(--surface-soft);
  color: var(--ink-strong);
}

.tree-panel-link-current {
  color: var(--ink-strong);
  font-weight: 600;
  background: var(--surface-soft);
}

.tree-panel-link {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.tree-panel-link-id {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tree-panel-class-tag {
  flex-shrink: 0;
  font-size: 0.55rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  padding: 0.15rem 0.75em;
  border-radius: var(--radius-sm);
  background: var(--surface-soft);
  color: var(--ink-soft);
}

.tree-panel-class-tag[style*="--class-color"] {
  background-color: color-mix(in srgb, var(--class-color) 35%, transparent);
  color: var(--class-text-color, var(--ink-strong));
}

.tree-panel-count {
  margin-left: 0.3rem;
  font-size: 0.75rem;
  color: var(--ink-soft);
  font-weight: 400;
}

.tree-panel-children {
  margin: 0;
  padding: 0;
  list-style: none;
}

.tree-panel-children-collapsed {
  display: none;
}

/* ---------------------------------------------------------------
     Datei-Detail Shell (PRD 2, Issue 3 / redesign Issue 9).

     Datei-Liste links (fixed width), Stage + Eigenschaften Mitte,
     Drawer unten (full width).  Built on the flex-column .detail-shell
     from Issue 1: an inner flex-row wraps Liste + Main side by side.
  --------------------------------------------------------------- */

.detail-shell-file {
  /* inherits flex-direction: column from .detail-shell */
}

/* Datei-Liste-Column: .collapsible-strip instance on file-class objects.
     Per-instance specs only — strip mechanic comes from .collapsible-strip. */

.detail-datei-liste-column {
  position: relative;
  --strip-expanded-width: var(--detail-datei-liste-w, 16rem);
  min-width: 0;
  border-right: 1px solid var(--line-softer);
}

/* Center column: holds object header + file stage.
     The center itself does not scroll; instead the inner stage-wrap owns
     the remaining height. This lets the hotspot-viewer fill the space
     between topbar/header and the (collapsed) drawer in preview-mode.
     In mosaic-mode the gallery inside scrolls. */

.detail-file-center {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.detail-file-stage-wrap {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Mosaic gallery scrolls inside the stage-wrap so the centre column
     stays anchored. */

.detail-file-stage-wrap > .detail-mosaic {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

/* In preview-mode the stage-wrap holds .file-stage > .file-stage-body >
     #file-widget > .file-filled > .hotspot-viewer. Propagate height through
     that chain so the viewer stage can fill the available room. Each link
     becomes a flex-column with `flex: 1 1 auto; min-height: 0` so a child
     can claim the leftover space. */

.detail-file-stage-wrap > .file-stage {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.detail-file-stage-wrap .file-stage-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.detail-file-stage-wrap #file-widget {
  flex: 1 1 auto;
  min-height: 0;
  margin-bottom: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.detail-file-stage-wrap #file-widget > .file-filled {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  /* `position: relative` so the bottom-left meta overlay anchors to the
       stage frame, not the page. */
  position: relative;
}

.detail-file-stage-wrap .hotspot-viewer {
  flex: 1 1 auto;
  min-height: 0;
}

/* 360° panorama viewer fills the stage like the 2D hotspot viewer.
     Overrides the standalone 480px fallback from the [data-panorama-viewer]
     rule below. Double selector matches the specificity boost used there so
     this rule wins inside the detail stage. */

.detail-file-stage-wrap [data-panorama-viewer][data-panorama-viewer] {
  flex: 1 1 auto;
  min-height: 0;
  height: auto;
}

/* Filename + size overlay (UI cleanup 2026-05). Floats on the bottom-left
     of the file stage so it costs no vertical space. Semi-transparent
     background so the underlying preview stays readable. */

.file-stage-meta-overlay {
  position: absolute;
  left: 0.75rem;
  bottom: 0.75rem;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.6rem;
  background: rgba(17, 24, 39, 0.72);
  color: #f8fafc;
  border-radius: var(--radius-sm);
  font-size: 0.8rem;
  pointer-events: none;
  z-index: 5;
  max-width: calc(100% - 1.5rem);
}

.file-stage-meta-overlay .file-stage-meta-name {
  color: #f8fafc;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.file-stage-meta-overlay .file-stage-meta-size {
  color: rgba(248, 250, 252, 0.78);
  font-size: 0.75rem;
}

/* Unified file-detail toolbar (UI cleanup 2026-05): one horizontal row
     containing the mode-toggle (left), the hotspot pin/zoom/filter/fit
     buttons (middle), and the per-file actions (right). The hotspot
     viewer template renders this element with both `.file-detail-toolbar`
     and `.hotspot-viewer-toolbar` so existing viewer-scoped JS keeps
     finding its buttons. `width: 100%` makes the row claim the full
     centre column — without it the row only stretches to fit its
     children and `margin-left:auto` on the right-cluster collapses. */

.file-detail-toolbar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  width: 100%;
  box-sizing: border-box;
}

.file-detail-toolbar-actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* Visual breather between logical button clusters (pin controls / zoom)
     in the file-detail toolbar. Uses left margin instead of a bigger gap
     so it only widens at that one spot, not between every button. */

.file-detail-toolbar-divider {
  width: 0;
  align-self: stretch;
  margin-left: 0.5rem;
}

.detail-mosaic {
  padding: 0.75rem;
}

/* Eigenschaften-Aside: .collapsible-strip instance on file-class objects.
     Per-instance specs only — strip mechanic comes from .collapsible-strip. */

.detail-file-aside {
  position: relative;
  --strip-expanded-width: var(--detail-file-aside-w, 22rem);
  border-left: 1px solid var(--line-softer);
}

.detail-file-aside-header {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 0.75rem 0.5rem 0.5rem;
  flex-shrink: 0;
}

.detail-file-aside-title {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--ink-strong);
}

.detail-file-aside-toggle {
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  background: transparent;
  border: none;
  cursor: pointer;
  font: inherit;
  color: var(--ink-strong);
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  width: 100%;
}

.detail-file-aside-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  padding: 1rem 1.1rem;
  gap: 0;
}

.detail-file-aside-body .surface-footer {
  margin-top: auto;
  padding-left: 0;
  padding-right: 0;
  border-top: 1px solid var(--border-divider);
}

@media (max-width: 1024px) {
  /* Only override the expanded width — collapsed rail keeps its 38px
       basis from .collapsible-strip. Without the :is() guard this rule
       would inflate the collapsed rail to 18rem at narrow viewports. */

  .detail-file-aside.is-expanded,
    .detail-file-aside[data-pre-expanded] {
    flex: 0 0 18rem;
  }
}

@media (max-width: 780px) {
  .detail-file-center,
    .detail-file-aside {
    flex: 0 0 auto;
    width: 100%;
    border-left: none;
  }

  .detail-file-aside {
    border-top: 1px solid var(--line-softer);
  }

  .detail-datei-liste-column {
    border-right: none;
    border-bottom: 1px solid var(--line-softer);
  }
}

.datei-liste-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.4rem 0.5rem 0.4rem 0.75rem;
  flex-shrink: 0;
}

.datei-liste-header-title {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink-strong);
}

.datei-liste-header-toggle {
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  background: transparent;
  border: none;
  cursor: pointer;
  font: inherit;
  color: var(--ink-strong);
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: space-between;
  line-height: 1;
  padding: 0.2rem;
  width: 100%;
}

.detail-datei-liste {
  display: grid;
  gap: 0.4rem;
  padding: 0.6rem 0.75rem;
}

.datei-liste-items {
  display: grid;
  gap: 0.2rem;
}

.datei-liste-item {
  display: grid;
  grid-template-columns: 2rem minmax(0, 1fr);
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.4rem;
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: inherit;
}

.datei-liste-item:hover {
  background: var(--surface-hover, rgba(0, 0, 0, 0.04));
}

.datei-liste-item.is-active {
  background: var(--surface-active, rgba(0, 0, 0, 0.07));
  font-weight: 600;
}

.datei-liste-thumb {
  width: 2rem;
  height: 2rem;
  -o-object-fit: cover;
     object-fit: cover;
  border-radius: var(--radius-sm);
  background: var(--surface-muted, oklch(1 0 0));
}

.datei-liste-thumb-placeholder {
  display: inline-block;
}

.datei-liste-identifier {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.85rem;
}

.datei-liste-more {
  padding-top: 0.4rem;
  display: grid;
}

/* Drawer -------------------------------------------------------- */

.detail-drawer {
  position: relative;
  flex-shrink: 0;
  border-top: 1px solid var(--line-softer);
  background: white;
  display: flex;
  flex-direction: column;
  /* Default = collapsed so server-rendered HTML matches the most common
       persisted state without a JS-driven post-render flicker. JS adds
       .is-expanded after reading localStorage. Tab switches don't resize
       the drawer; the panel area scrolls when content exceeds ~3 rows. */
  height: 36px;
  overflow: hidden;
  transition: height var(--t-slow) var(--ease);
}

.detail-drawer.is-expanded {
  height: var(--detail-drawer-h, 224px);
}

.app-shell-fixed .detail-drawer {
  background: #f7f4ee;
}

/* Pre-hydration marker (see base.html inline script): mirrors .is-expanded
     so the first paint matches the persisted state — no JS-driven flicker. */

html.pre-drawer-expanded .detail-drawer {
  height: var(--detail-drawer-h, 224px);
}

.detail-drawer-header {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.5rem 0.85rem;
  border-bottom: 1px solid var(--line-soft);
  background: var(--surface-raised);
}

/* Expanded: the tab strip carries the title + collapse chevron itself, so
     the slim collapsed bar is hidden. The pre-hydration marker mirrors this
     so a persisted-expanded drawer paints without a doubled header. */

.detail-drawer.is-expanded .detail-drawer-header,
  html.pre-drawer-expanded .detail-drawer .detail-drawer-header {
  display: none;
}

/* ----------------------------------------------------------------------
     Panel-Resize-Griff (Slice 10): an invisible hit strip on the panel's
     open edge with a centred grip pill. The strip is 8px under a fine
     pointer, 24px on coarse (touch) pointers. The pill is invisible at rest
     (mouse), faint grey at rest (touch), and accent on hover / drag / the
     touch reveal flash. Edge variants position the strip + orient the grip.

     The strip hugs the *inside* of the panel edge (offset 0, not a negative
     straddle): the host panels scroll (overflow auto/hidden), so anything
     past the padding edge would be clipped away and become unhittable. The
     1px border sits just outside; visually the grip still reads as "on the
     edge".
  ---------------------------------------------------------------------- */

.detail-resize-handle {
  position: absolute;
  z-index: 5;
  background: transparent;
  touch-action: none;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Right edge (tree): vertical strip on the panel's right border. */

.detail-resize-handle-right {
  top: 0;
  bottom: 0;
  right: 0;
  width: 8px;
  cursor: col-resize;
}

/* Left edge (aside): vertical strip on the panel's left border. */

.detail-resize-handle-left {
  top: 0;
  bottom: 0;
  left: 0;
  width: 8px;
  cursor: col-resize;
}

/* Top edge (drawer): horizontal strip on the panel's top border. */

.detail-resize-handle-top {
  left: 0;
  right: 0;
  top: 0;
  height: 8px;
  cursor: row-resize;
}

.detail-resize-grip {
  border-radius: 999px;
  background: var(--ink-soft);
  opacity: 0;
  transition:
      opacity var(--t-base) var(--ease),
      background var(--t-base) var(--ease);
}

/* Vertical edges → upright pill (4×42px, 5×60px while dragging). */

.detail-resize-handle-right .detail-resize-grip,
  .detail-resize-handle-left .detail-resize-grip {
  width: 4px;
  height: 42px;
}

/* Top edge → lying pill. */

.detail-resize-handle-top .detail-resize-grip {
  width: 42px;
  height: 4px;
}

.detail-resize-handle:hover .detail-resize-grip,
  .detail-resize-handle.is-dragging .detail-resize-grip,
  .detail-resize-handle.is-revealed .detail-resize-grip {
  opacity: 1;
  background: var(--accent);
}

.detail-resize-handle-right.is-dragging .detail-resize-grip,
  .detail-resize-handle-left.is-dragging .detail-resize-grip {
  width: 5px;
  height: 60px;
}

.detail-resize-handle-top.is-dragging .detail-resize-grip {
  width: 60px;
  height: 5px;
}

/* Coarse (touch) pointers: widen the hit strip to 24px and show a faint
     resting grip so the handle is discoverable on tablets. */

@media (pointer: coarse) {
  .detail-resize-handle-right,
    .detail-resize-handle-left {
    width: 24px;
  }

  .detail-resize-handle-top {
    height: 24px;
  }

  .detail-resize-grip {
    opacity: 0.35;
  }
}

/* Collapse interplay: a collapsed panel shows no handle, and its expanded
     size is restored automatically (the CSS var stays applied). */

.tree-panel.is-collapsed .detail-resize-handle,
  html.pre-tree-collapsed .tree-panel .detail-resize-handle,
  .detail-drawer:not(.is-expanded) .detail-resize-handle,
  .collapsible-strip:not(.is-expanded):not([data-pre-expanded]) .detail-resize-handle {
  display: none;
}

/* While dragging, freeze the collapse transitions so the panel tracks the
     pointer instantly instead of easing behind it. */

body.is-resizing-col .tree-panel,
  body.is-resizing-col .collapsible-strip,
  body.is-resizing-row .detail-drawer {
  transition: none;
}

/* Body-level cursor + selection lock during a drag (toggled by JS). */

body.is-resizing-col {
  cursor: col-resize;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}

body.is-resizing-row {
  cursor: row-resize;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}

.detail-drawer-toggle {
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  background: transparent;
  border: none;
  cursor: pointer;
  font: inherit;
  color: var(--ink-strong);
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  text-align: left;
}

.detail-drawer-title {
  font-size: 0.95rem;
}

.detail-drawer-body {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1 1 auto;
  overflow: hidden;
}

.detail-drawer-tabs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  padding: 0.1rem 0.85rem;
  color: var(--ink-strong);
}

/* Inline title that opens the tab row (design "Inline-Dokument"). */

.detail-drawer-tabs .detail-drawer-title {
  font-weight: 500;
  color: var(--ink-strong);
}

.detail-drawer-tab {
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  background: transparent;
  border: 1px solid transparent;
  cursor: pointer;
  font: inherit;
  color: var(--ink-soft);
  padding: 0.2rem 0.7rem;
  border-radius: var(--radius-sm);
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

.detail-drawer-tab:hover {
  color: var(--ink-strong);
  background: var(--surface-soft);
}

.detail-drawer-tab.is-active {
  color: var(--ink-strong);
  background: var(--surface-soft);
  font-weight: 500;
}

.detail-drawer-tab-arrow {
  color: var(--ink-softest);
  font-size: 0.85em;
  line-height: 1;
}

/* Connect button: pushed to the far right of the tab strip, quiet box
     rather than a loud pill — keeps its "+ Verbinden" wording. */

.detail-drawer-tab-new {
  margin-left: auto;
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  cursor: pointer;
  font: inherit;
  color: var(--ink-soft);
  background: transparent;
  border-radius: var(--radius-sm);
  padding: 0.2rem 0.5rem;
}

.detail-drawer-tab-new:hover {
  color: var(--ink-strong);
  background: var(--surface-soft);
  border-color: var(--line-strong);
}

/* Title + chevron form one collapse toggle at the head of the tab strip. */

.detail-drawer-collapse {
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  cursor: pointer;
  font: inherit;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-right: 0.5rem;
  color: var(--ink-strong);
  background: transparent;
  border: none;
  padding: 0.2rem 0.35rem;
  border-radius: var(--radius-sm);
}

.detail-drawer-collapse:hover {
  background: var(--surface-soft);
}

.detail-drawer-collapse-chevron {
  font-size: 1.05rem;
  line-height: 1;
  color: var(--ink-soft);
}

.detail-drawer-panels {
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 0;
  padding: 0.2rem 0.85rem;
}

.detail-drawer-panel[hidden] {
  display: none;
}

.detail-drawer-empty {
  padding: 0.85rem;
}

.detail-drawer-spinner {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}

.detail-drawer-spinner-dot {
  width: 0.85rem;
  height: 0.85rem;
  border: 2px solid var(--line-strong);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: raumbuch-spin 0.7s linear infinite;
}

@keyframes raumbuch-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Save button in-flight feedback: swap the check icon for a spinner while the
     boosted form submit is running (HTMX toggles .htmx-request on the button
     via hx-indicator="this"). */

.save-button-spinner {
  display: none;
  width: 1.25rem;
  height: 1.25rem;
  border: 2px solid color-mix(in srgb, currentColor 35%, transparent);
  border-top-color: currentColor;
  border-radius: 50%;
  animation: raumbuch-spin 0.7s linear infinite;
}

.save-button.htmx-request {
  pointer-events: none;
  opacity: 0.85;
}

.save-button.htmx-request .save-button-icon {
  display: none;
}

.save-button.htmx-request .save-button-spinner {
  display: block;
}

/* Collapsed state — generic for any element using data-persist-body. */

[data-persist-body][hidden] {
  display: none !important;
}

/* Inline-Dokument · Slice 01 — Dokument-Layout + Scroll-Spy ------------- */

/* Scroll-spy nav row above the document: same column width / alignment as
     the document below it. One item per group + the drawer toggle on the
     right. */

.doc-spy {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  max-width: 780px;
  margin: 0 auto;
  padding: 0 44px;
  width: 100%;
}

/* Keep the group links pinned while the document scrolls underneath
     (scoped to standard detail; file detail nav scrolls with its aside). */

.detail-properties-scroller .doc-spy {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--eigen-bg);
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
}

.doc-spy-item {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0;
  color: var(--ink-soft);
  text-decoration: none;
  font-size: 13.5px;
  line-height: 1;
  cursor: pointer;
}

.doc-spy-item:hover {
  color: var(--ink-strong);
}

/* Accent bar 3×15px — only visible on the active group. */

.doc-spy-bar {
  width: 3px;
  height: 15px;
  border-radius: 2px;
  background: var(--accent-strong);
  opacity: 0;
}

.doc-spy-item.is-active {
  color: var(--ink-strong);
  font-weight: 600;
}

.doc-spy-item.is-active .doc-spy-bar {
  opacity: 1;
}

.doc-spy-count {
  font-size: 11px;
  color: var(--ink-softest);
}

.doc-spy-drawer-toggle {
  margin-left: auto;
  width: 30px;
  height: 30px;
  border: none;
  background: transparent;
  cursor: pointer;
  align-self: center;
}

/* Document column: centred paper, 780px, generous side padding. */

/* The inline-document form (.form-stack grid) sits as a flex item in the
     properties scroller (standard) / file aside body. Its implicit single
     `auto` grid-track would otherwise grow to the widest field's *unwrapped*
     content width and push the whole column past the panel edge. min-width:0
     lets the flex item shrink to the panel; minmax(0,1fr) caps the track at
     the container so field values wrap inside instead of bursting out. */

.detail-properties-scroller > form,
  .detail-file-aside-body > form {
  min-width: 0;
  grid-template-columns: minmax(0, 1fr);
}

.doc-column {
  max-width: 780px;
  margin: 0 auto;
  padding: 8px 44px 72px;
  width: 100%;
  /* Grid item: stay shrinkable so the track (and the textarea/inputs inside
       it, which size to content) can never widen the panel. */
  min-width: 0;
}

/* Clear the sticky spy nav so a scrolled-to group header is not hidden. */

.doc-group {
  scroll-margin-top: 52px;
}

/* Group spacing: 42px between groups, 8px above the first. */

.doc-group + .doc-group {
  margin-top: 42px;
}

.doc-group-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  padding-bottom: 0.4rem;
  border-bottom: 1px solid rgba(42, 39, 34, 0.20);
  margin-bottom: 1.25rem;
}

.doc-group-name {
  font-family: var(--font-prominent);
  font-size: 20px;
  font-weight: 600;
  color: var(--ink-strong);
}

.doc-group-count {
  font-size: 11.5px;
  color: var(--ink-softest);
  white-space: nowrap;
}

/* Empty group: silent ghost hint instead of the old hint line. */

.doc-group-ghost {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-style: italic;
  color: var(--ink-softest);
  font-size: 0.9rem;
}

.doc-group-ghost-plus {
  font-style: normal;
  font-weight: 600;
}

/* Field rows inside a document group (Slice 02): each row pads 12px 16px
     with a -16px horizontal margin so the hover tint bleeds past the document
     edge while the label/value stay flush. Stacked layout: 4px label→value
     gap. Hover reveals a soft tint with an 8px radius — no layout jump. */

.doc-group .field-stack {
  gap: 4px;
  padding: 12px 16px;
  margin: 0 -16px;
  border-radius: 8px;
  transition: background var(--t-fast) var(--ease);
}

.doc-group .field-stack:hover {
  background: rgba(42, 39, 34, 0.035);
  border-radius: 8px;
}

.field-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

/* Inline-Dokument · Slice 02 — the field label is a quiet stacked caption:
     small muted Sans set above the value (4px gap from the .field-stack grid),
     not a bold heading. App-wide so Create-Form and Klassen-Editor share it. */

.field-label {
  display: flex;
  gap: 0.35rem;
  align-items: baseline;
  font-size: 13.5px;
  font-weight: 400;
  color: #8c867a;
}

/* Value + unit sit on one baseline; the unit is a quiet Sans suffix that
     trails the rendered value (Slice 02 — replaces the old `[m²]` in label). */

.field-value-row {
  display: flex;
  align-items: baseline;
  gap: 5px;
}

.field-unit {
  font-size: 12.5px;
  font-weight: 400;
  color: #8c867a;
}

/* While the value is being edited the unit steps aside: focusing the input
     lifts it onto the editing surface, and the trailing unit would otherwise
     sit awkwardly on that raised plane. It returns the moment focus leaves. */

.doc-group .field-value-row:focus-within .field-unit {
  display: none;
}

/* Inline-Dokument · Slice 03 — inline-editing optic.
     Scoped to .doc-group so the Create-form and Klassen-Editor keep their
     boxed inputs. The inputs never leave the DOM (CSS-only): at rest they
     read as the gesetzter --font-prominent 17px value (Slice 02). Their own padding
     is compensated by a negative margin so the value stays flush with the
     stacked label above it.
     Direct-child only: nested inputs (boolean checkbox-row, pill/popover
     Sonstiges slots) keep their own styling. The template-mode value input
     sits one level deeper and opts in explicitly. */

.doc-group .field-value-row > input,
  .doc-group .field-value-row > textarea,
  .doc-group .field-value-row input.select-template-value {
  min-height: 0;
  border: none;
  background: transparent;
  box-shadow: none;
  border-radius: 5px;
  padding: 2px 6px;
  margin: -2px -6px;
  font-family: var(--font-prominent);
  font-size: 17px;
  font-weight: var(--font-prominent-weight);
  line-height: 1.35;
  color: var(--ink-strong);
  transition:
      background var(--t-fast) var(--ease),
      box-shadow var(--t-fast) var(--ease);
}

/* The inline value sizes to its content instead of stretching the row:
     the field grows and shrinks with what's typed so the trailing unit
     follows the value's right edge. field-sizing keeps an empty field wide
     enough for its "Hinzufügen" hint (it sizes to the placeholder), so no
     explicit min-width floor is needed.
     Flex item: min-width:0 is required so a long single-line value can shrink
     to the row's max-width. Without it the default min-width:auto lets
     field-sizing's intrinsic content width win and the value overflows the
     column (same fix as the textarea below). */

.doc-group .field-value-row > input {
  field-sizing: content;
  /* The global input base sets `width: 100%` (Tailwind w-full); an explicit
       width overrides field-sizing's intrinsic sizing, so reset it to auto. */
  width: auto;
  min-width: 0;
  max-width: 100%;
}

.doc-group .field-value-row > textarea {
  field-sizing: content;
  width: 100%;
  /* Flex item: without min-width:0 the default min-width:auto lets
       field-sizing's intrinsic content width override width:100%, so a long
       value overflows the (narrow) column instead of wrapping. */
  min-width: 0;
  max-width: 100%;
}

/* Hover: a soft tint with a bottom hairline (inset box-shadow) signals the
     value is editable; the text cursor reinforces it. Disabled inputs are
     excluded so a readonly/archived value reads as final. */

.doc-group .field-value-row > input:not(:disabled):hover,
  .doc-group .field-value-row > textarea:not(:disabled):hover,
  .doc-group .field-value-row input.select-template-value:not(:disabled):hover {
  background: rgba(42, 39, 34, 0.06);
  box-shadow: inset 0 -1px 0 rgba(42, 39, 34, 0.13);
  cursor: text;
}

/* Focus: lift onto a lighter editing surface with a 2px accent ring and a
     soft shadow — the value "raises" itself to be edited. */

.doc-group .field-value-row > input:focus,
  .doc-group .field-value-row > textarea:focus,
  .doc-group .field-value-row input.select-template-value:focus {
  outline: none;
  background: #fffdf8;
  box-shadow:
      0 0 0 2px var(--accent),
      0 6px 18px rgba(42, 39, 34, 0.1);
}

/* Empty: an italic "Hinzufügen" hint (markup placeholder attribute) in the
     muted ink reads as a quiet invitation, not a boxed empty field. */

.doc-group .field-value-row > input::-moz-placeholder, .doc-group .field-value-row > textarea::-moz-placeholder, .doc-group .field-value-row input.select-template-value::-moz-placeholder {
  font-family: var(--font-prominent);
  font-weight: var(--font-prominent-weight);
  font-style: italic;
  color: #b3ad9f;
}

.doc-group .field-value-row > input::placeholder,
  .doc-group .field-value-row > textarea::placeholder,
  .doc-group .field-value-row input.select-template-value::placeholder {
  font-family: var(--font-prominent);
  font-weight: var(--font-prominent-weight);
  font-style: italic;
  color: #b3ad9f;
}

/* Longtext shares the inline states but stays multi-line with an open 1.62
     leading and a vertical resize handle. */

.doc-group .field-value-row > textarea {
  line-height: 1.62;
  resize: vertical;
}

/* Disabled (readonly/archived): plain typeset text, no edit affordance —
     overrides the global :disabled box and keeps the resting look. */

.doc-group .field-value-row > input:disabled,
  .doc-group .field-value-row > textarea:disabled,
  .doc-group .field-value-row input.select-template-value:disabled {
  background: transparent;
  color: var(--ink-strong);
  cursor: default;
  resize: none;
}

/* A readonly/archived empty field must not invite editing — hide the
     "Hinzufügen" placeholder so it reads as a final, empty value. */

.doc-group .field-value-row > input:disabled::-moz-placeholder, .doc-group .field-value-row > textarea:disabled::-moz-placeholder, .doc-group .field-value-row input.select-template-value:disabled::-moz-placeholder {
  color: transparent;
}

.doc-group .field-value-row > input:disabled::placeholder,
  .doc-group .field-value-row > textarea:disabled::placeholder,
  .doc-group .field-value-row input.select-template-value:disabled::placeholder {
  color: transparent;
}

/* Number fields: hide the browser spinner so the resting state is text-
     identical (Firefox via appearance:textfield, WebKit via the spin button). */

.doc-group .field-value-row > input[type="number"] {
  -webkit-appearance: textfield;
     -moz-appearance: textfield;
          appearance: textfield;
}

.doc-group .field-value-row > input[type="number"]::-webkit-inner-spin-button,
  .doc-group .field-value-row > input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
          appearance: none;
  margin: 0;
}

/* Hinweistext: small "?" badge next to a field label that toggles a
     popover with the field's free-text help. Uses the native Popover API
     (popovertarget / [popover]) — no JS needed. */

/* Slice 02: the help "?" is a 14px hairline circle that stays nearly
     invisible at rest (opacity .5), lifts to .72 when its row is hovered, and
     reaches full opacity on its own hover/open. */

.field-helptext-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  box-sizing: border-box;
  border: 1px solid rgba(42, 39, 34, 0.30);
  border-radius: 9999px;
  background: transparent;
  color: #8c867a;
  font-size: 9.5px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  opacity: 0.5;
  transition:
      opacity 0.14s var(--ease),
      background var(--t-fast) var(--ease),
      border-color var(--t-fast) var(--ease),
      color var(--t-fast) var(--ease);
}

.doc-group .field-stack:hover .field-helptext-trigger {
  opacity: 0.72;
}

.field-helptext-trigger:hover {
  opacity: 1;
  background: rgba(42, 39, 34, 0.06);
  border-color: var(--ink-softest);
  color: var(--ink-strong);
}

/* Slice 02: a typeset 252px help card — small Sans copy, soft shadow. */

.field-helptext-popover {
  width: 252px;
  margin: 0;
  padding: 11px 13px;
  border: none;
  border-radius: 9px;
  background: var(--surface-overlay, #fffdf8);
  color: var(--ink-base);
  font-size: 12.5px;
  line-height: 1.5;
  box-shadow:
      0 12px 36px rgba(42, 39, 34, 0.18),
      0 0 0 0.5px rgba(42, 39, 34, 0.20);
  white-space: pre-line;
  /* The per-field anchor name is set inline; the popover sits just below
       and to the right of its "?" trigger. Browsers without CSS anchor
       positioning fall back to the viewport-centred [popover] default. */
  position-area: bottom span-right;
  margin-top: 0.4rem;
}

/* Typ-Objekt 04 (ADR-0013): on an occurrence with a Typ-Beziehung a field is
     gebunden (its value still matches the type seed) or abweichend (locally
     adjusted). gebunden values render italic; abweichend stay upright and carry
     a "vom Typ übernehmen" refresh control styled like the help "?" badge. */

.field-row--gebunden .field-value-row input,
  .field-row--gebunden .field-value-row textarea {
  font-style: italic;
}

.field-type-reset-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  box-sizing: border-box;
  border: 1px solid rgba(42, 39, 34, 0.30);
  border-radius: 9999px;
  background: transparent;
  color: #8c867a;
  font-size: 10px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.5;
  transition:
      opacity 0.14s var(--ease),
      background var(--t-fast) var(--ease),
      border-color var(--t-fast) var(--ease),
      color var(--t-fast) var(--ease);
}

/* The refresh glyph is set via CSS so the button markup stays empty. */

.field-type-reset-trigger::before {
  content: "↻";
}

.doc-group .field-stack:hover .field-type-reset-trigger {
  opacity: 0.72;
}

.field-type-reset-trigger:hover {
  opacity: 1;
  background: rgba(42, 39, 34, 0.06);
  border-color: var(--ink-softest);
  color: var(--ink-strong);
}

.field-hint {
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--ink-soft);
}

.field-hint-error {
  color: var(--danger-ink);
}

.field-hint-success {
  color: color-mix(in srgb, var(--success) 58%, black 42%);
}

.checkbox-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 2.4rem;
}

.copy-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.copy-row input {
  flex: 1 1 0%;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.75rem;
  padding-top: 1.75rem;
}

.dialog-panel .form-actions {
  position: sticky;
  bottom: -1.35rem;
  margin-inline: -1.35rem;
  margin-bottom: -1.35rem;
  padding: 1rem 1.35rem 1.35rem;
  background: var(--bg-cream);
  border-top: 1px solid rgba(var(--_sand) / 0.14);
}

.empty-state {
  display: grid;
  place-items: center;
  gap: 0.55rem;
  min-height: 10rem;
  padding: 2rem;
  border: 1px dashed rgba(var(--_sand) / 0.45);
  border-radius: var(--radius-lg);
  background: rgba(252, 249, 245, 0.86);
  text-align: center;
  color: var(--ink-soft);
}

.empty-state-title {
  color: var(--ink-base);
  font-size: 1rem;
  font-weight: 600;
}

.history-list {
  display: grid;
  gap: 0.75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.history-entry {
  padding: 0.85rem 1rem;
  border: 1px solid var(--border-sand);
  border-radius: var(--radius-sm);
  background: var(--bg-card-light);
}

.history-entry-header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
}

.history-entry-action {
  font-weight: 600;
  color: var(--ink-base);
}

.history-entry-meta {
  font-size: 0.85rem;
  color: var(--ink-soft);
}

.history-entry-changes {
  display: grid;
  gap: 0.35rem;
  margin: 0.6rem 0 0;
}

.history-change {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.history-change-label {
  font-weight: 600;
  color: var(--ink-soft);
}

.history-change-value {
  margin: 0;
  color: var(--ink-base);
}

.section-stack {
  display: grid;
  gap: 1rem;
}

.record-list {
  overflow: hidden;
  border: 1px solid var(--border-sand);
  border-radius: var(--radius-sm);
  background: var(--bg-card-light);
}

.record-list > li {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 0.5rem;
}

.record-list > li + li {
  border-top: 1px solid rgba(var(--_sand-mid) / 0.16);
}

.drag-handle {
  cursor: grab;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
  color: var(--ink-soft);
  flex-shrink: 0;
  font-size: 0.9rem;
  line-height: 1;
  padding: 0 0.25rem;
}

.drag-handle:active {
  cursor: grabbing;
}

.drag-active {
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.18);
  background: rgba(var(--_white) / 0.95);
  opacity: 0.95;
}

.drag-placeholder {
  background: rgba(var(--_sand-mid) / 0.18);
  border: 1px dashed rgba(var(--_sand-mid) / 0.5);
  border-radius: var(--radius-sm);
  list-style: none;
}

.field-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.field-row {
  display: grid;
  grid-template-columns:
      1.5rem
      minmax(0, 2.5fr)
      minmax(0, 1.5fr)
      minmax(0, 0.8fr)
      minmax(0, 1fr)
      minmax(11rem, auto);
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 1rem;
  border-top: 1px solid rgba(var(--_sand-mid) / 0.16);
}

/* Relation-type table: handle + name + source→target + kind + cardinality + auto-show + actions */

.field-row--relation-type {
  display: grid;
  grid-template-columns:
      1.5rem
      minmax(0, 1.8fr)
      minmax(0, 2fr)
      minmax(0, 1.1fr)
      minmax(0, 0.9fr)
      minmax(0, 1fr)
      minmax(9rem, auto);
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 1rem;
  border-top: 1px solid rgba(var(--_sand-mid) / 0.16);
}

/* Read-only variant: no handle, no actions column */

.field-row--relation-type-ro {
  display: grid;
  grid-template-columns:
      minmax(0, 1.8fr)
      minmax(0, 2fr)
      minmax(0, 1.1fr)
      minmax(0, 0.9fr)
      minmax(0, 1fr);
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 1rem;
  border-top: 1px solid rgba(var(--_sand-mid) / 0.16);
}

/* Class-detail relation list: handle + name + kind + actions */

/* Read-only variant: no handle, no actions column */

.field-row-head {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-soft);
  background: rgba(var(--_sand-mid) / 0.06);
}

.field-cell {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.field-cell-actions {
  display: flex;
  gap: 0.25rem;
  justify-content: flex-end;
  flex-wrap: wrap;
  overflow: visible;
}

.field-cell-actions .button {
  padding-inline: 0.6rem;
  white-space: nowrap;
}

@media (max-width: 900px) {
  .field-row {
    grid-template-columns:
        1.5rem
        minmax(0, 2fr)
        minmax(0, 1.2fr)
        minmax(9.5rem, auto);
  }

  .field-cell-req,
    .field-cell-unit {
    display: none;
  }

  /* Relation-type: collapse kind + cardinality on tablet */

  .field-row--relation-type {
    grid-template-columns:
        1.5rem
        minmax(0, 1.6fr)
        minmax(0, 1.8fr)
        minmax(0, 1fr)
        minmax(8rem, auto);
  }

  .field-row--relation-type-ro {
    grid-template-columns:
        minmax(0, 1.6fr)
        minmax(0, 1.8fr)
        minmax(0, 1fr)
        minmax(0, 1fr);
  }

  .field-cell-rt-card,
    .field-cell-rt-show {
    display: none;
  }
}

@media (max-width: 600px) {
  .field-row {
    grid-template-columns: 1.5rem minmax(0, 1fr) minmax(8rem, auto);
    row-gap: 0.25rem;
    padding: 0.5rem 0.75rem;
  }

  .field-cell-type {
    grid-column: 2 / 3;
    font-size: 0.75rem;
  }

  .field-row-head .field-cell-type {
    display: none;
  }

  .field-cell-actions {
    grid-row: 1 / 3;
    grid-column: 3 / 4;
    align-self: center;
  }

  /* Relation-type: mobile — only name + target + actions */

  .field-row--relation-type {
    grid-template-columns: 1.5rem minmax(0, 1fr) minmax(7rem, auto);
    row-gap: 0.25rem;
    padding: 0.5rem 0.75rem;
  }

  .field-row--relation-type-ro {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 0.2rem;
    padding: 0.5rem 0.75rem;
  }

  .field-cell-rt-target {
    grid-column: 2 / 3;
    font-size: 0.8rem;
    color: var(--ink-soft);
  }

  .field-row--relation-type .field-cell-actions {
    grid-row: 1 / 3;
    grid-column: 3 / 4;
    align-self: center;
  }

  .field-cell-rt-kind {
    display: none;
  }
}

.record-main {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
}

.record-link {
  color: var(--accent-strong);
  font-weight: 600;
}

.record-link:hover {
  color: var(--ink-strong);
}

.record-meta {
  font-size: 0.8rem;
  color: var(--ink-soft);
}

.dialog-shell {
  width: min(100% - 1.5rem, 42rem);
  max-height: min(90svh, 56rem);
  border: 0;
  border-radius: var(--radius-xl);
  background: transparent;
  padding: 0;
  overflow: hidden;
  box-shadow: none;
}

.dialog-shell.dialog-wide {
  width: min(100% - 1.5rem, 52rem);
}

.dialog-panel {
  display: flex;
  flex-direction: column;
  max-height: min(90svh, 56rem);
  border-radius: var(--radius-xl);
  border: 1px solid rgba(var(--_sand) / 0.22);
  background: var(--bg-cream);
  box-shadow: 0 24px 80px rgba(var(--_shadow-deep) / 0.18);
  padding: 1.35rem;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.dialog-header {
  display: grid;
  gap: 0.4rem;
  margin-bottom: 1rem;
}

.dialog-title {
  font-size: 1.22rem;
  line-height: 1.15;
}

.dialog-copy {
  color: var(--ink-soft);
  font-size: 0.9rem;
  line-height: 1.55;
}

.auth-shell {
  display: flex;
  min-height: 100%;
  align-items: center;
  justify-content: center;
  padding: clamp(1.5rem, 4vw, 3rem);
}

.auth-card {
  width: min(100%, 28rem);
  border-radius: var(--radius-xl);
  border: 1px solid var(--border-sand-soft);
  background: var(--bg-card-strong);
  box-shadow: 0 28px 80px rgba(var(--_shadow-deep) / 0.14);
  padding: clamp(1.4rem, 3vw, 2rem);
}

.auth-copy {
  display: grid;
  gap: 0.45rem;
  margin-bottom: 1.35rem;
  text-align: left;
}

.auth-kicker {
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  font-weight: 700;
}

.toggle-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.toggle-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.5rem;
  padding-inline: 0.95rem;
  border-radius: 999px;
  border: 1px solid rgba(var(--_sand) / 0.26);
  background: var(--bg-card);
  color: var(--ink-base);
  font-size: 0.9rem;
  font-weight: 600;
}

.toggle-chip:hover {
  color: var(--ink-strong);
}

.toggle-chip.is-active {
  border-color: var(--accent-border);
  background: color-mix(in srgb, var(--accent-soft) 82%, white 18%);
  color: var(--accent-strong);
}

.autocomplete-list:empty {
  display: none;
}

.autocomplete-list {
  position: absolute;
  inset-inline: 0;
  top: calc(100% + 0.35rem);
  z-index: 10;
  overflow-y: auto;
  max-height: 14rem;
  border: 1px solid rgba(var(--_sand) / 0.28);
  border-radius: var(--radius-md);
  background: var(--bg-card-solid);
  box-shadow: 0 18px 40px rgba(var(--_shadow-warm) / 0.14);
}

.autocomplete-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  width: 100%;
  padding: 0.8rem 0.95rem;
  cursor: pointer;
}

.autocomplete-option:hover {
  background: color-mix(in srgb, var(--accent-soft) 55%, white 45%);
}

.autocomplete-empty {
  padding: 0.8rem 0.95rem;
  color: var(--ink-soft);
  font-size: 0.875rem;
  font-style: italic;
}

.req-star {
  color: #a8694a;
  font-weight: bold;
}

.field-error {
  color: var(--danger-ink);
}

.button-ghost-danger {
  background: transparent;
  color: var(--danger-ink-strong);
  padding-inline: 0;
  min-height: auto;
}

.button-ghost-danger:hover {
  color: var(--danger-strongest);
}

.mosaik-grid {
  display: grid;
  gap: 0.75rem;
  grid-template-columns: repeat(6, 1fr);
}

@media (max-width: 1024px) {
  .mosaik-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (max-width: 640px) {
  .mosaik-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

.mosaik-tile {
  display: block;
  border-radius: var(--radius-md);
  border: 1px solid var(--border-sand);
  background: var(--bg-card);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  transition: box-shadow var(--t-fast), transform var(--t-fast);
}

.mosaik-tile:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
  border-color: var(--accent-border);
}

.mosaik-tile.is-active {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent-soft) 80%, white 20%);
}

.mosaik-thumb {
  aspect-ratio: 1;
  width: 100%;
  -o-object-fit: cover;
     object-fit: cover;
  display: block;
  background: var(--surface-soft);
}

.mosaik-icon {
  aspect-ratio: 1;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.5rem;
  background: var(--surface-soft);
}

.mosaik-caption {
  padding: 0.4rem 0.5rem;
  font-size: 0.75rem;
  color: var(--ink-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 2D hotspot viewer (Issue #5) */

.hotspot-viewer {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  position: relative;
}

.hotspot-viewer-toolbar {
  display: flex;
  gap: 0.5rem;
}

/* Icon-only toolbar buttons (Issue 09).
     The shared `.hotspot-toolbar-icon-button` hook gives every toolbar
     trigger a 34x34 px tap target (WCAG 2.5.5 / Apple HIG) and resets the
     pill's horizontal padding so the icon centres in the square. The
     active state for toggle buttons is driven by [aria-pressed="true"] /
     [aria-expanded="true"] so we don't need a separate class. */

.hotspot-toolbar-icon-button {
  min-width: 28px;
  min-height: 28px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* `display: inline-flex` overrides the UA `[hidden] { display: none }` rule,
     so setting `el.hidden = true` in JS would have no visual effect without
     this explicit override. The filter button relies on it to disappear when
     the pin toggle is off. */

.hotspot-toolbar-icon-button[hidden] {
  display: none;
}

.hotspot-toolbar-icon-button[aria-pressed="true"],
  .hotspot-toolbar-icon-button[aria-expanded="true"] {
  background: var(--accent-soft);
  color: #fff;
  border-color: var(--accent-strong);
}

.hotspot-toolbar-icon {
  width: 20px;
  height: 20px;
  display: block;
}

.hotspot-viewer-stage {
  position: relative;
  overflow: hidden;
  flex: 1 1 auto;
  min-height: 20rem;
  touch-action: none;
  cursor: grab;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}

.hotspot-viewer-canvas {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
  will-change: transform;
}

.hotspot-viewer-image {
  display: block;
  max-width: none;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
  -webkit-user-drag: none;
}

.hotspot-viewer-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* Hint banner shown while in set- or move-mode on a 2D image — mirrors
     the Pannellum overlay (`.pano-add-mode-hint`) so both viewers give the
     same affordance during pin placement. */

.hotspot-viewer-hint {
  position: absolute;
  top: 0.75rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 25;
  background: rgba(0, 0, 0, 0.75);
  color: white;
  padding: 0.4rem 0.75rem;
  border-radius: var(--radius-sm);
  font-size: 0.85rem;
  pointer-events: none;
}

/* 360° panorama viewer (Issue 2) — Pannellum needs an explicit height.
     Pannellum injects `.pnlm-container` onto our wrapper at runtime, whose
     own rule (`height: 100%`) ties with `[data-panorama-viewer]` on
     specificity and wins by source order. The dual selector raises ours
     above the tie so 480px sticks. */

[data-panorama-viewer][data-panorama-viewer] {
  width: 100%;
  height: 480px;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--surface-soft);
}

/* Slice 07: pin-placement crosshair. Pannellum re-applies its `pnlm-grab`
     class (cursor: url(...)) on every mouseup, so the override has to be
     marked !important to outweigh the inline cursor URL. */

.pano-pin-placement-mode,
  .pano-pin-placement-mode * {
  cursor: crosshair !important;
}

/* Hint banner shown while in add- or move-mode. */

.pano-add-mode-hint {
  position: absolute;
  top: 3.5rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 25;
  background: rgba(0, 0, 0, 0.75);
  color: white;
  padding: 0.4rem 0.75rem;
  border-radius: var(--radius-sm);
  font-size: 0.85rem;
  pointer-events: none;
}

/* Slice 06–08: panorama pin marker. Pannellum's `.pnlm-hotspot-base` is
     position:absolute + visibility hidden until the renderer projects it
     into view; we layer our own marker on top inside createTooltipFunc.
     The class lets the marker have a fixed size and round shape. */

.raumbuch-pano-pin {
  /* Pannellum's stylesheet forces `box-sizing: content-box` on every
       descendant of `.pnlm-container` — override back so the 2px border
       does not inflate the box and skew the offset-based centering below. */
  box-sizing: border-box;
  width: 14px;
  height: 14px;
  /* No negative margins for centering: Pannellum already centres the
       hotspot element on yaw/pitch by subtracting half its offsetWidth/
       Height in the transform it sets each frame. Adding margins would
       shift the marker by half its size, which becomes very visible the
       further the pin sits from the canvas centre. */
  border-radius: 999px;
  border: 2px solid white;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
}

.raumbuch-pano-pin-icon {
  pointer-events: none;
}

/* Slice 09: "Pins ausblenden" toggle. Hides every Pannellum hotspot via
     CSS without removing it from the viewer — rotating/zooming keeps the
     state because Pannellum still owns the underlying hotspot entries. */

.pano-pins-hidden .raumbuch-pano-pin {
  display: none;
}

.hotspot-pin {
  pointer-events: auto;
  transform-origin: center center;
}

.hotspot-popover {
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: 0.5rem 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-width: 12rem;
  max-width: 18rem;
}

/* Defense-in-depth: the panorama wrapper is a flex column, so a popover
     without explicit positioning would push the Pannellum canvas down and
     shift hotspot projections. JS sets left/top per click; this rule keeps
     the popover out of flow even if a future caller forgets. */

.hotspot-popover.pano-active {
  position: absolute;
  z-index: 30;
}

.hotspot-popover-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

/* Name acts as the primary "Öffnen" action — full button affordance with
     icon, label and an arrow hint. Flex-1 so it absorbs the available width
     and the ⋮ menu hugs the right edge in the same row. */

.hotspot-popover-name {
  flex: 1 1 auto;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  text-decoration: none;
  text-align: left;
  justify-content: flex-start;
  font-weight: 600;
}

.hotspot-popover-name-text {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hotspot-popover-open-hint {
  flex: 0 0 auto;
  opacity: 0.8;
  font-weight: 400;
}

.hotspot-popover-menu-btn {
  flex: 0 0 auto;
}

/* Pin-Klassen-Filter (Issue 01 of pin-filter PRD).
     Popover anchors absolutely below the toolbar; the toolbar button
     toggles its hidden attribute. */

.hotspot-viewer-filter-popover {
  position: absolute;
  top: 3rem;
  left: 0;
  z-index: 25;
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: 0.5rem 0.75rem;
  min-width: 14rem;
  max-width: 22rem;
}

.hotspot-viewer-filter-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.hotspot-filter-pill {
  line-height: 1.2;
}

/* "Alle"-Toggle: three-state checkbox-styled trigger above the pills.
     The visible box reflects aria-checked: filled = all on, hollow = all off,
     half-filled bar = mixed. Painted via CSS only — JS just flips the attr.
     `min-height` reset overrides the global `button{min-height:2.75rem}`,
     and explicit `:hover`/`:active`/`:focus` rules keep the accent visible
     when the user interacts (otherwise UA defaults darken the button). */

.hotspot-viewer-filter-all-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  background: transparent !important;
  border: none;
  padding: 0.25rem 0;
  margin-bottom: 0.4rem;
  min-height: 0;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-strong);
  cursor: pointer;
}

.hotspot-viewer-filter-all-toggle:hover,
  .hotspot-viewer-filter-all-toggle:focus,
  .hotspot-viewer-filter-all-toggle:active {
  background: transparent !important;
  color: var(--text-strong);
  outline: none;
}

.hotspot-viewer-filter-all-toggle:focus-visible {
  outline: 2px solid var(--accent-soft);
  outline-offset: 2px;
}

.hotspot-viewer-filter-all-toggle-box {
  display: inline-block;
  width: 1rem;
  height: 1rem;
  border-radius: 3px;
  border: 1.5px solid var(--line-strong);
  background: var(--surface-raised);
  position: relative;
  flex-shrink: 0;
}

.hotspot-viewer-filter-all-toggle[aria-checked="true"] .hotspot-viewer-filter-all-toggle-box,
  .hotspot-viewer-filter-all-toggle[aria-checked="mixed"] .hotspot-viewer-filter-all-toggle-box {
  background: var(--accent-strong);
  border-color: var(--accent-strong);
}

.hotspot-viewer-filter-all-toggle[aria-checked="true"] .hotspot-viewer-filter-all-toggle-box::after {
  content: "";
  position: absolute;
  inset: 2px 3px;
  border: solid white;
  border-width: 0 0 2px 2px;
  transform: rotate(-45deg) translateY(-2px);
}

.hotspot-viewer-filter-all-toggle[aria-checked="mixed"] .hotspot-viewer-filter-all-toggle-box::after {
  content: "";
  position: absolute;
  left: 2px;
  right: 2px;
  top: 50%;
  height: 2px;
  margin-top: -1px;
  background: white;
}

/* "Linien anzeigen"-Toggle (Issue 07 of pin-filter PRD): two-state, painted
     identically to the "Alle"-toggle's filled/empty box. JS flips aria-checked
     and saveFilterState persists it alongside the class filter. */

.hotspot-viewer-filter-lines-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  background: transparent !important;
  border: none;
  padding: 0.25rem 0;
  margin-top: 0.4rem;
  min-height: 0;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-strong);
  cursor: pointer;
}

.hotspot-viewer-filter-lines-toggle:hover,
  .hotspot-viewer-filter-lines-toggle:focus,
  .hotspot-viewer-filter-lines-toggle:active {
  background: transparent !important;
  color: var(--text-strong);
  outline: none;
}

.hotspot-viewer-filter-lines-toggle:focus-visible {
  outline: 2px solid var(--accent-soft);
  outline-offset: 2px;
}

.hotspot-viewer-filter-lines-toggle-box {
  display: inline-block;
  width: 1rem;
  height: 1rem;
  border-radius: 3px;
  border: 1.5px solid var(--line-strong);
  background: var(--surface-raised);
  position: relative;
  flex-shrink: 0;
}

.hotspot-viewer-filter-lines-toggle[aria-checked="true"] .hotspot-viewer-filter-lines-toggle-box {
  background: var(--accent-strong);
  border-color: var(--accent-strong);
}

.hotspot-viewer-filter-lines-toggle[aria-checked="true"] .hotspot-viewer-filter-lines-toggle-box::after {
  content: "";
  position: absolute;
  inset: 2px 3px;
  border: solid white;
  border-width: 0 0 2px 2px;
  transform: rotate(-45deg) translateY(-2px);
}

/* Hierarchy lines SVG layer (Issue 07): spans the image bounds so its
     viewBox coordinates align with the pin overlay's percentage positions.
     pointer-events: none keeps clicks reaching pins below. */

.hotspot-viewer-lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: visible;
}

/* Accent indicator on the filter toolbar button (no number).
     Visible iff JS removes the `hidden` attribute. */

.hotspot-viewer-filter-button {
  position: relative;
}

.hotspot-viewer-filter-indicator {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent-strong);
  box-shadow: 0 0 0 1.5px var(--surface-raised);
  pointer-events: none;
}

/* Pill-Chip select/multiselect variant (Issue 01).
     Used by select_pills + multiselect_pills macros. The native
     radio/checkbox input lives inside the <label> but is visually hidden;
     the pill itself flips state via the input's `:checked` state,
     surfaced through CSS `:has(:checked)`. */

.pill-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.pill-chip-stack {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.pill-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.34rem 0.78rem;
  border: 1px solid var(--line-soft, var(--border-sand, #d8c9a8));
  background: transparent;
  color: var(--ink-soft);
  border-radius: 999px;
  font-size: 0.7969rem;
  /* 12.75px */
  font-weight: 500;
  line-height: 1.1;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
      color var(--t-fast) var(--ease);
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}

/* Ghost (unselected) hover lifts slightly. */

.pill-chip:hover {
  border-color: color-mix(in srgb, var(--accent, #083b47) 24%, transparent);
  color: var(--ink-strong, #2a2722);
}

/* Selected: accent-tinted fill, accent border, accent ink — color carries
     the state, plus a 5px accent dot on the left. `.is-on` is the class-driven
     alias for pills without a checkable input (multiselect custom values). */

.pill-chip:has(.pill-chip-input:checked),
  .pill-chip.is-on {
  background: color-mix(in srgb, var(--accent, #083b47) 12%, transparent);
  border-color: color-mix(in srgb, var(--accent, #083b47) 34%, transparent);
  color: var(--accent-strong, var(--accent, #083b47));
}

.pill-chip-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* 5px accent dot — only visible while the pill is selected. */

.pill-chip-dot {
  display: none;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent-strong, var(--accent, #083b47));
  flex-shrink: 0;
}

.pill-chip:has(.pill-chip-input:checked) .pill-chip-dot,
  .pill-chip.is-on .pill-chip-dot {
  display: block;
}

/* "Alle wählen" / "Auswahl aufheben" ghost-chip below multi-select pills */

.pill-chip-toggle-all {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.78rem;
  border: 1px solid var(--line-soft, var(--border-sand, #d8c9a8));
  background: transparent;
  color: var(--ink-soft);
  border-radius: 999px;
  font-size: 0.74rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  cursor: pointer;
}

.pill-chip-toggle-all-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Multiselect free-text "other" slot (always-visible input below pills). */

.pill-chip-other-input {
  border: none;
  background: transparent;
  color: inherit;
  font: inherit;
  outline: none;
  min-width: 8rem;
}

/* Sonstiges pill (single-select): a tristate group that flips between a
     dashed trigger, an inline input, and a selected custom-value pill. JS
     toggles is-empty / is-input / is-custom on the [data-pill-other] wrapper.
     The multiselect pills variant reuses the same classes per custom pill
     ([data-pill-ms-pill]) and for its repeatable add group ([data-pill-ms-add]). */

.pill-chip-other {
  display: inline-flex;
}

.pill-chip-other-trigger {
  border-style: dashed;
  color: var(--ink-soft);
  background: transparent;
}

.pill-chip-other-trigger:hover {
  border-color: color-mix(in srgb, var(--accent, #083b47) 30%, transparent);
  color: var(--accent-strong, var(--accent, #083b47));
}

/* The inline editing input replaces the trigger; accent inset ring. */

.pill-chip-other.is-input .pill-chip-other-input {
  display: inline-block;
  width: 150px;
  min-width: 0;
  padding: 0.34rem 0.7rem;
  border-radius: 999px;
  background: var(--surface-raised, #fff);
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--accent, #083b47) 45%, transparent);
}

/* Hide whichever facets don't match the current state. */

.pill-chip-other .pill-chip-other-input {
  display: none;
}

.pill-chip-other.is-input .pill-chip-other-trigger,
  .pill-chip-other.is-input .pill-chip-other-value,
  .pill-chip-other.is-custom .pill-chip-other-trigger,
  .pill-chip-other.is-custom .pill-chip-other-input,
  .pill-chip-other.is-empty .pill-chip-other-value {
  display: none;
}

/* Custom-value pill: a <label> wrapping the __other__ sentinel radio, so
     the shared .pill-chip :has(:checked) rules drive selected vs. ghost —
     no bespoke accent override. It only carries the remove-×. */

/* Click-to-edit affordance: while the custom value is selected its text
     edits in place (ghost pills re-select on click instead). */

.pill-chip-other-value:has(.pill-chip-other-radio:checked) .pill-chip-label,
  .pill-chip-other-value.is-on .pill-chip-label {
  cursor: text;
}

.pill-chip-remove {
  border: none;
  background: transparent;
  color: inherit;
  font: inherit;
  line-height: 1;
  padding: 0;
  margin-left: 0.1rem;
  cursor: pointer;
  opacity: 0.7;
}

.pill-chip-remove:hover {
  opacity: 1;
}

/* "— (keine Auswahl)" chip in optional single-select pill groups. */

.pill-chip-none {
  color: var(--ink-soft);
  font-style: italic;
  font-weight: 500;
}

.pill-chip[aria-disabled="true"],
  .pill-chip-input:disabled + .pill-chip {
  cursor: default;
  opacity: 0.6;
}

/* ===================================================================== */

/* Multiselect dropdown: Pills + Checklist-Popover (Inline-Dokument 05)   */

/* ===================================================================== */

.ms-checklist {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}

.ms-pill-row {
  display: contents;
}

/* Selected-value pill: accent tint, accent dot, remove-×. */

.ms-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.34rem 0.6rem 0.34rem 0.78rem;
  border: 1px solid color-mix(in srgb, var(--accent) 34%, transparent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--accent-strong, var(--accent));
  border-radius: 999px;
  font-size: 0.7969rem;
  /* 12.75px */
  font-weight: 500;
  line-height: 1.1;
}

.ms-pill .pill-chip-dot {
  display: block;
}

.ms-pill-remove {
  border: none;
  background: transparent;
  color: inherit;
  font: inherit;
  line-height: 1;
  padding: 0;
  cursor: pointer;
  opacity: 0.7;
}

.ms-pill-remove:hover {
  opacity: 1;
}

/* Dashed "+ Auswählen" / "+ Hinzufügen" trigger pill with a chevron. */

.ms-checklist-trigger {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.34rem 0.7rem;
  border: 1px dashed var(--line-soft);
  background: transparent;
  color: var(--ink-soft);
  border-radius: 999px;
  font-size: 0.7969rem;
  font-weight: 500;
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}

.ms-checklist-trigger:hover {
  border-color: color-mix(in srgb, var(--accent) 30%, transparent);
  color: var(--accent-strong, var(--accent));
}

.ms-checklist-chevron,
  .select-popover-chevron {
  width: 0.8rem;
  height: 0.8rem;
  flex-shrink: 0;
  transition: transform var(--t-fast) var(--ease);
}

.ms-checklist.is-open .ms-checklist-chevron,
  .select-popover.is-open .select-popover-chevron {
  transform: rotate(180deg);
}

/* Checklist popover card: white, soft shadow + 0.5px hairline ring. */

.ms-checklist-popover,
  .select-popover-panel {
  position: absolute;
  inset-inline-start: 0;
  top: calc(100% + 0.35rem);
  z-index: 30;
  min-width: 230px;
  max-height: 300px;
  overflow-y: auto;
  padding: 0.35rem;
  background: var(--surface-raised, #fff);
  border-radius: var(--radius-md);
  box-shadow: 0 0 0 0.5px var(--line-soft), var(--shadow-md);
  animation: select-popover-in 120ms var(--ease);
}

.ms-checklist-popover[hidden],
  .select-popover-panel[hidden] {
  display: none;
}

@keyframes select-popover-in {
  from {
    opacity: 0;
    transform: translateY(-3px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.ms-checklist-all,
  .ms-checklist-option,
  .select-popover-option {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  width: 100%;
  padding: 0.42rem 0.55rem;
  border: none;
  background: transparent;
  color: var(--ink-base);
  border-radius: 0.5rem;
  font: inherit;
  font-size: 0.85rem;
  text-align: start;
  cursor: pointer;
}

.ms-checklist-all {
  border-bottom: 1px solid var(--line-softer);
  border-radius: 0;
  font-style: italic;
  color: var(--ink-soft);
}

.ms-checklist-option:hover,
  .select-popover-option:hover {
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}

/* 16px checkbox, 5px radius, accent fill + white check when on. */

.ms-checklist-box {
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  margin: 0;
  border: 1.5px solid var(--line-strong);
  border-radius: 5px;
  background: transparent;
  cursor: pointer;
  position: relative;
}

.ms-checklist-box:checked {
  border-color: currentColor;
}

/* CSS-drawn check in the row's text color — readable on the light popover
     without depending on an accent fill behind a white glyph. */

.ms-checklist-box:checked::after {
  content: "";
  position: absolute;
  left: 4.5px;
  top: 1.5px;
  width: 4.5px;
  height: 8px;
  border: solid currentColor;
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg);
}

.ms-checklist-other,
  .select-popover-other {
  margin-top: 0.25rem;
  padding: 0.35rem 0.55rem 0.2rem;
  border-top: 1px solid var(--line-softer);
}

/* Repeatable "+ Sonstiges": dashed trigger toggles into an inline input. */

.ms-checklist-other-trigger {
  display: inline-flex;
  align-items: center;
  padding: 0.3rem 0.7rem;
  border: 1px dashed var(--line-soft);
  background: transparent;
  color: var(--ink-soft);
  border-radius: 999px;
  font-size: 0.7969rem;
  font-weight: 500;
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}

.ms-checklist-other-trigger:hover {
  border-color: color-mix(in srgb, var(--accent) 30%, transparent);
  color: var(--accent-strong, var(--accent));
}

.ms-checklist-other-trigger[hidden] {
  display: none;
}

.ms-checklist-other-input {
  width: 100%;
  padding: 0.34rem 0.7rem;
  border-radius: 999px;
  border: none;
  background: var(--surface-raised, #fff);
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--accent) 45%, transparent);
  color: inherit;
  font: inherit;
  font-size: 0.85rem;
  outline: none;
}

.ms-checklist-other-input[hidden] {
  display: none;
}

.select-popover-other-input {
  width: 100%;
  border: none;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 0.85rem;
  outline: none;
}

/* ===================================================================== */

/* Single-select dropdown: quiet custom popover (Inline-Dokument 05)      */

/* ===================================================================== */

.select-popover {
  position: relative;
}

.select-popover-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  min-width: 12rem;
  padding: 0.5rem 0.85rem;
  border: 1px solid var(--line-soft);
  background: color-mix(in srgb, var(--surface-raised) 88%, white 12%);
  color: var(--ink-strong);
  border-radius: var(--radius-md);
  font: inherit;
  text-align: start;
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}

.select-popover.is-open .select-popover-trigger {
  border-color: var(--accent-border-strong);
}

.select-popover-value {
  font-family: var(--font-prominent);
  font-size: 0.95rem;
  font-weight: 500;
}

.select-popover-value.is-placeholder,
  .select-popover-option-label.is-placeholder {
  color: var(--ink-soft);
  font-style: italic;
}

/* Accent check on the active option, pushed to the row's right edge. */

.select-popover-check {
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
  margin-inline-start: auto;
}

.select-popover-option[data-active] .select-popover-check {
  background:
      no-repeat center/0.85rem
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%234f7a28' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='2 6.5 5 9 10 3'/%3E%3C/svg%3E");
}

.select-popover-option[data-active] {
  color: var(--accent-strong, var(--accent));
}

/* Inline-Dokument: inside the document the trigger reads as the typeset
     value itself — no box at rest, hover tint like the text inputs (Slice 03),
     --font-prominent 17px. Elsewhere (Create-Form, Klassen-Editor) the boxed trigger
     above stays. */

.doc-group .select-popover-trigger {
  min-width: 0;
  border: none;
  background: transparent;
  padding: 2px 6px;
  margin: -2px -6px;
  border-radius: 5px;
  gap: 0.45rem;
  transition: background var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}

.doc-group .select-popover-trigger:hover {
  background: rgba(42, 39, 34, 0.06);
  box-shadow: inset 0 -1px 0 rgba(42, 39, 34, 0.13);
}

.doc-group .select-popover-value {
  font-size: 17px;
  font-weight: var(--font-prominent-weight);
  line-height: 1.35;
  color: var(--ink-strong);
}

.doc-group .select-popover-value.is-placeholder {
  color: var(--ink-soft);
}

.doc-group .select-popover-chevron {
  color: var(--ink-soft);
}

/* Template mode: the editable typeset value (the real submit input, inline
     optic via Slice 03 inside .doc-group) plus a quiet chevron trigger that
     opens the shared select-popover panel with the template options. */

.select-template {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  /* Flex item of .field-value-row: allow it to shrink so a long template
       value wraps within the row instead of pushing the column wider. */
  min-width: 0;
}

/* Like the plain text fields, the template value sizes to its content so the
     chevron trails the typed text instead of being pushed to the row's right
     edge. No grow; min-width:0 lets a long value shrink inside the row's
     max-width (field-sizing keeps the empty placeholder readable). */

.select-template-value {
  flex: 0 1 auto;
  field-sizing: content;
  width: auto;
  min-width: 0;
  max-width: 100%;
}

.select-template-trigger {
  display: inline-flex;
  border: none;
  background: transparent;
  padding: 0.2rem;
  border-radius: 4px;
  color: var(--ink-soft);
  cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}

.select-template-trigger:hover {
  color: var(--ink-strong);
  background: rgba(42, 39, 34, 0.06);
}

.select-template.is-open .select-popover-chevron {
  transform: rotate(180deg);
}

/* Pin-create popover: class pills + preloaded object list. Mirrors the
     "Tag setzen" popover from prototype/Repertum_latest.html — pill chips
     with a class-color dot, then a scrollable list filterable in-place. */

.hotspot-create-popover {
  background: var(--surface-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: 0.6rem 0.7rem 0.55rem;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  width: 17rem;
  max-width: calc(100% - 1rem);
  /* Safety net for the class-picker step if the JS clamp can't fully fit it
       on a very small viewer: never taller than the viewport, scroll instead
       of clipping. The new-object form uses the dedicated modal below. */
  max-height: calc(100vh - 1.5rem);
  overflow-y: auto;
}

/* Slice 06: primary "create new related object" action in the selection list. */

.hotspot-related-create-new {
  display: block;
  width: 100%;
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--accent-strong);
  border-radius: var(--radius-sm);
  background: var(--accent-strong);
  color: white;
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
  line-height: 1.2;
}

.hotspot-related-create-new:hover {
  background: color-mix(in srgb, var(--accent-strong) 88%, black);
}

/* Inline "Neues Objekt anlegen" Kennung prompt (blank-area pin-create).
     A single identifier field + actions rendered inside the object step,
     mirroring the relation drawer's "+ Neu" flow — no separate modal. */

.hotspot-related-new {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

.hotspot-related-identifier {
  width: 100%;
  padding: 0.4rem 0.55rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  background: var(--surface-base);
  color: var(--ink-base);
  font-size: 0.85rem;
}

.hotspot-related-new .hotspot-related-cancel {
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
  background: var(--surface-base);
  color: var(--ink-base);
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
  line-height: 1.2;
}

.hotspot-create-new-feedback {
  margin: 0;
  font-size: 0.8rem;
  color: var(--danger-strong, #b91c1c);
}

.hotspot-create-class-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
}

.hotspot-create-class-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.2rem 0.55rem;
  border: 1px solid var(--line-soft);
  background: var(--surface-base);
  color: var(--ink-base);
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 500;
  cursor: pointer;
  line-height: 1.2;
}

.hotspot-create-class-pill[aria-pressed="true"] {
  border-color: var(--accent-strong);
  background: color-mix(in srgb, var(--accent-strong) 10%, white);
  color: var(--accent-strong);
  font-weight: 600;
}

.hotspot-create-class-pill__dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 999px;
  flex-shrink: 0;
}

.hotspot-create-results {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 13rem;
  overflow-y: auto;
  border: 1px solid var(--line-softer);
  border-radius: var(--radius-sm);
}

.hotspot-create-result {
  padding: 0.35rem 0.55rem;
  font-size: 0.82rem;
  cursor: pointer;
  border-bottom: 1px solid var(--line-softer);
}

.hotspot-create-result:last-child {
  border-bottom: none;
}

.hotspot-create-result:hover {
  background: color-mix(in srgb, var(--accent-strong) 6%, white);
}

.hotspot-create-result--hint {
  font-style: italic;
  color: var(--ink-soft);
  cursor: default;
}

.hotspot-create-result--hint:hover {
  background: transparent;
}

.topbar-meta {
  align-self: center;
}

.surface-header,
    .surface-footer,
    .page-header {
  align-items: flex-start;
}

.data-table thead th,
    .data-table tbody td {
  padding-inline: 0.9rem;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

.visible {
  visibility: visible;
}

.invisible {
  visibility: hidden;
}

.collapse {
  visibility: collapse;
}

.static {
  position: static;
}

.fixed {
  position: fixed;
}

.absolute {
  position: absolute;
}

.relative {
  position: relative;
}

.sticky {
  position: sticky;
}

.mt-12 {
  margin-top: 3rem;
}

.mt-14 {
  margin-top: 3.5rem;
}

.mt-2 {
  margin-top: 0.5rem;
}

.mt-4 {
  margin-top: 1rem;
}

.mt-6 {
  margin-top: 1.5rem;
}

.mt-8 {
  margin-top: 2rem;
}

.line-clamp-2 {
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.block {
  display: block;
}

.inline {
  display: inline;
}

.flex {
  display: flex;
}

.inline-flex {
  display: inline-flex;
}

.table {
  display: table;
}

.grid {
  display: grid;
}

.\!hidden {
  display: none !important;
}

.hidden {
  display: none;
}

.h-full {
  height: 100%;
}

.w-full {
  width: 100%;
}

.transform {
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}

.resize {
  resize: both;
}

.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.border {
  border-width: 1px;
}

.text-sm {
  font-size: 0.875rem;
  line-height: 1.25rem;
}

.italic {
  font-style: italic;
}

.text-gray-600 {
  --tw-text-opacity: 1;
  color: rgb(75 85 99 / var(--tw-text-opacity, 1));
}

.outline {
  outline-style: solid;
}

.blur {
  --tw-blur: blur(8px);
  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);
}

.filter {
  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);
}

.transition {
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  transition-duration: 150ms;
}

/* Self-hosted Linux Biolinum (free Optima alternative, OFL/GPL+FE).
   Full glyph coverage incl. German umlauts/ß. Source TTFs live next to
   the woff2 in /static/fonts/biolinum/. */

@font-face {
  font-family: "Linux Biolinum";

  src: url("/static/fonts/biolinum/LinBiolinum_Rah.woff2") format("woff2");

  font-weight: 400;

  font-style: normal;

  font-display: swap;
}

@font-face {
  font-family: "Linux Biolinum";

  src: url("/static/fonts/biolinum/LinBiolinum_RBah.woff2") format("woff2");

  font-weight: 600 700;

  font-style: normal;

  font-display: swap;
}

@font-face {
  font-family: "Linux Biolinum";

  src: url("/static/fonts/biolinum/LinBiolinum_RIah.woff2") format("woff2");

  font-weight: 400;

  font-style: italic;

  font-display: swap;
}

@media (max-width: 640px) {
}
