/* Shadowrun 6 trade dress: near-black violet paper, magenta as the primary
   accent, cyan for data, and hard-cut corners instead of rounded ones. */

:root {
  --bg: #0a0711;
  --panel: #140e20;
  --panel-2: #1b1329;
  --line: #2c1f45;
  --line-bright: #462d6b;
  --text: #ece7f4;
  --muted: #9d90b5;
  --magenta: #e0197c;
  --magenta-soft: #ff4fa3;
  --cyan: #2fe3d5;
  --amber: #ffb020;
  --red: #ff4d6d;
  --green: #3fd18b;

  --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, "JetBrains Mono", "DejaVu Sans Mono", Consolas, monospace;

  /* One shared corner cut keeps every surface on the same grid. */
  --cut: 14px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background:
    radial-gradient(900px 500px at 15% -10%, #24123a 0%, transparent 60%),
    radial-gradient(700px 400px at 100% 0%, #3a0f36 0%, transparent 55%),
    var(--bg);
  background-attachment: fixed;
  color: var(--text);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.55;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* Wide enough for the catalogue to keep three columns of cards between the
   category sidebar and the character sheet. */
.shell { width: min(1440px, 100% - 3rem); margin-inline: auto; }

h1, h2, h3 {
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.15;
  margin: 0;
}
h1 { font-size: 1.6rem; }
h2 { font-size: 1.1rem; }
h3 { font-size: 1rem; letter-spacing: 0.04em; }

a { color: inherit; text-decoration: none; }
.muted { color: var(--muted); }
.small { font-size: 0.83rem; }

/* ---------- top bar ---------- */

.topbar {
  border-bottom: 1px solid var(--line);
  background: rgba(10, 7, 17, 0.92);
  backdrop-filter: blur(8px);
  position: sticky;
  top: 0;
  z-index: 10;
}
.topbar-inner {
  display: flex;
  align-items: center;
  gap: 2rem;
  padding: 0.85rem 0;
}
.brand { display: flex; align-items: center; gap: 0.7rem; }
.brand-mark {
  background: var(--magenta);
  color: #fff;
  font-weight: 800;
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  padding: 0.32rem 0.55rem;
  clip-path: polygon(0 0, 100% 0, 100% 65%, calc(100% - 8px) 100%, 0 100%);
}
.brand-text {
  text-transform: uppercase;
  letter-spacing: 0.22em;
  font-weight: 700;
  font-size: 0.92rem;
}

/* Four German nav words are wider than a phone. Wrapping is what keeps the
   page from scrolling sideways; on a desktop the line never fills. */
.nav { display: flex; flex-wrap: wrap; gap: 1.4rem; margin-right: auto; }
.nav a {
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: 0.8rem;
  color: var(--muted);
  padding-bottom: 2px;
  border-bottom: 2px solid transparent;
}
.nav a:hover { color: var(--text); border-bottom-color: var(--magenta); }

.account { display: flex; align-items: center; gap: 1.4rem; }
.wallet {
  text-align: right;
  border-left: 2px solid var(--cyan);
  padding-left: 0.8rem;
}
.wallet-label {
  display: block;
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--muted);
}
.wallet-value { font-family: var(--mono); font-size: 1.05rem; color: var(--cyan); white-space: nowrap; }
.wallet-over { border-left-color: var(--red); }
.wallet-over .wallet-value { color: var(--red); }

/* Same shape as the wallet, so the two read as one status block. */
.identity {
  text-align: right;
  border-left: 2px solid var(--line-bright);
  padding-left: 0.8rem;
}
.identity-label {
  display: block;
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--muted);
}
/* Named licences make this the widest thing in the bar. It gets a ceiling and
   trails off rather than pushing the wallet around; the title attribute has
   the full list either way. */
.identity-value {
  display: block;
  font-family: var(--mono);
  font-size: 0.9rem;
  max-width: 20rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* No SIN means licence-bound gear is locked — that is a state, not a detail. */
.identity-none { border-left-color: var(--amber); }
.identity-none .identity-value { color: var(--amber); }

.whoami { text-align: right; line-height: 1.3; }
.whoami-name { display: block; font-size: 0.85rem; white-space: nowrap; }

/* ---------- folds ---------- */

/* Everything in the app that folds says so the same way, with one drawn
   chevron: the browser's own triangle cannot be styled and is a different
   shape in every engine. It sits in front of a disclosure and turns from
   right to down, and behind the menu in the top bar, where it turns from
   down to up — each the way its own kind of control is read elsewhere. */
summary { cursor: pointer; list-style: none; }
summary::-webkit-details-marker { display: none; }

.buchregel-kopf::before,
.option-regel-kopf::before,
.klappe-kopf::before,
.sheet-upload summary::before,
.klapp-knopf::before,
.switcher summary::after {
  content: "";
  width: 0.42rem;
  height: 0.42rem;
  flex-shrink: 0;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transition: transform 0.15s ease;
}
summary::before { transform: rotate(-45deg); }
details[open] > summary::before { transform: rotate(45deg); }
summary::after { transform: rotate(45deg); }
details[open] > summary::after { transform: rotate(-135deg); }
/* Two folds in the app cannot be a <details>, and both fail on the same
   thing: they only exist on a phone. A <details> is open or shut in its
   markup, and the server does not know how wide the screen is, so a fold that
   has to be *gone* on a window can only be built out of something CSS can
   switch off — hence a checkbox, whose state a media query is free to ignore.
   The catalogue filter has a second reason: htmx swaps its whole block away
   on every pick, and a checkbox comes back shut, which is where a fold
   belongs once it has been used.

   Everything else about them is the app's ordinary fold: the same drawn
   chevron as every <details>, turning the same way. Only the state differs.

   Their two skins are .filter-* (the catalogue sidebar) and .menue-* (the top
   bar); both live in the phone section at the end of this file. */
.klapp-knopf::before { transform: rotate(-45deg); }
.klapp-schalter:checked + .klapp-knopf::before { transform: rotate(45deg); }
/* Off-screen rather than display:none: a hidden input takes no focus, and the
   fold would then be unreachable from a keyboard. */
.klapp-schalter { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.klapp-schalter:focus-visible + .klapp-knopf { outline: 2px solid var(--cyan); outline-offset: 2px; }
/* On a window there is nothing to fold. */
.klapp-knopf { display: none; }

/* ---------- surfaces ---------- */

.panel {
  background: linear-gradient(180deg, var(--panel-2), var(--panel));
  border: 1px solid var(--line);
  clip-path: polygon(
    0 0, calc(100% - var(--cut)) 0, 100% var(--cut),
    100% 100%, var(--cut) 100%, 0 calc(100% - var(--cut))
  );
  padding: 1.6rem;
}
.panel > h1, .panel > h2 { margin-bottom: 1rem; }
.panel-centered { text-align: center; display: grid; gap: 1rem; justify-items: center; }

/* Every page is the page itself plus the character sheet on the right. */
.layout { padding: 2rem 0 3rem; flex: 1; }
.layout-sheet {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 21rem;
  gap: 1.6rem;
  align-items: start;
}
.content { min-width: 0; }

.footer {
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 0.78rem;
  padding: 1.2rem 0;
  text-align: center;
}

/* ---------- forms ---------- */

.stack { display: grid; gap: 0.9rem; }
label > span {
  display: block;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted);
  margin-bottom: 0.35rem;
}

input[type="text"], input[type="password"], input[type="search"],
input[type="number"], input[type="file"], select {
  width: 100%;
  background: #0d0916;
  border: 1px solid var(--line-bright);
  color: var(--text);
  font: inherit;
  padding: 0.6rem 0.7rem;
}
input:focus, select:focus, button:focus-visible {
  outline: 2px solid var(--magenta);
  outline-offset: 1px;
}

.button {
  display: inline-block;
  background: transparent;
  border: 1px solid var(--line-bright);
  color: var(--text);
  font: inherit;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: 0.8rem;
  padding: 0.62rem 1.2rem;
  cursor: pointer;
  clip-path: polygon(0 0, calc(100% - 9px) 0, 100% 9px, 100% 100%, 9px 100%, 0 calc(100% - 9px));
  transition: background 0.15s, border-color 0.15s;
}
.button:hover:not(:disabled) { border-color: var(--magenta); background: rgba(224, 25, 124, 0.12); }
.button-primary { background: var(--magenta); border-color: var(--magenta); color: #fff; }
.button-primary:hover:not(:disabled) { background: var(--magenta-soft); border-color: var(--magenta-soft); }
/* A button the rules have closed has to look closed. Without this a disabled
   button kept its full contrast and even lit up on hover, so it invited the
   click it then refused. The pager uses the class form for the same look. */
.button:disabled, .button.is-disabled { opacity: 0.4; cursor: not-allowed; }
.button:disabled:hover, .button.is-disabled:hover {
  border-color: var(--line-bright);
  background: transparent;
}
.button.is-disabled { cursor: default; }
.linkish:disabled { opacity: 0.4; cursor: not-allowed; }
.linkish:disabled:hover { color: var(--muted); }

.linkish {
  background: none;
  border: 0;
  color: var(--muted);
  font: inherit;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  cursor: pointer;
  padding: 0;
}
.linkish:hover { color: var(--text); }
.danger:hover { color: var(--red); }

/* ---------- notices ---------- */

.notice {
  border-left: 3px solid var(--muted);
  background: rgba(255, 255, 255, 0.04);
  padding: 0.7rem 0.9rem;
  margin-bottom: 1rem;
  font-size: 0.88rem;
}
.notice a { color: var(--cyan); text-decoration: underline; }
.notice-ok { border-left-color: var(--green); }
.notice-warn { border-left-color: var(--amber); }
.notice-error { border-left-color: var(--red); }

/* ---------- login ---------- */

.panel-login {
  max-width: 25rem;
  margin: 4rem auto;
  text-align: center;
}
.panel-login .stack { text-align: left; margin-top: 1.4rem; }
.panel-login .button { width: 100%; }
.login-mark {
  display: inline-block;
  background: var(--magenta);
  color: #fff;
  font-weight: 800;
  letter-spacing: 0.12em;
  padding: 0.4rem 0.7rem;
  clip-path: polygon(0 0, 100% 0, 100% 65%, calc(100% - 9px) 100%, 0 100%);
}
.login-title { margin-top: 0.9rem; letter-spacing: 0.2em; }
.login-sub, .login-hint { font-size: 0.83rem; }
.login-hint { margin-bottom: 0; margin-top: 1.2rem; }

/* ---------- catalogue ---------- */

.catalog { display: grid; grid-template-columns: 17rem 1fr; gap: 1.8rem; align-items: start; }

/* The category list is longer than the window, so it scrolls on its own:
   without a scroll container of its own the wheel falls through to the page
   and moves the results instead. overscroll-behavior keeps the page still
   once the list reaches its end. */
.sidebar {
  position: sticky;
  top: 5.2rem;
  display: grid;
  gap: 1.2rem;
  grid-template-rows: auto auto minmax(0, 1fr);
  max-height: calc(100vh - 7rem);
}
.sidebar .categories {
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Room for the focus ring and the count badge against the scrollbar. */
  padding-right: 0.3rem;
}
.search { display: flex; gap: 0.5rem; }
.sidebar-title {
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  color: var(--muted);
  border-bottom: 1px solid var(--line);
  padding-bottom: 0.5rem;
}
.categories { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; }
.category {
  display: flex;
  justify-content: space-between;
  gap: 0.6rem;
  padding: 0.45rem 0.6rem;
  font-size: 0.87rem;
  border-left: 2px solid transparent;
}
.category:hover { background: rgba(255, 255, 255, 0.04); }
.category.active {
  border-left-color: var(--magenta);
  background: rgba(224, 25, 124, 0.12);
  color: #fff;
}
.category .count { font-family: var(--mono); font-size: 0.78rem; color: var(--muted); }

.subcategories {
  list-style: none;
  margin: 0.15rem 0 0.45rem 0.6rem;
  padding: 0 0 0 0.5rem;
  border-left: 1px solid var(--line-bright);
  display: grid;
  gap: 1px;
}
.subcategory {
  display: flex;
  justify-content: space-between;
  gap: 0.6rem;
  padding: 0.3rem 0.5rem;
  font-size: 0.8rem;
  color: var(--muted);
}
.subcategory:hover { background: rgba(255, 255, 255, 0.04); color: var(--text); }
.subcategory.active { color: var(--magenta-soft); }
.subcategory .count { font-family: var(--mono); font-size: 0.72rem; }

.head-sub { color: var(--magenta-soft); }

.results-head { margin-bottom: 1.1rem; }
.results-head p { margin: 0.25rem 0 0; font-size: 0.85rem; }

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15.5rem, 1fr));
  gap: 1rem;
}

.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin-top: 1.6rem;
}
.pager-state {
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

.card {
  display: flex;
  flex-direction: column;
  background: linear-gradient(180deg, var(--panel-2), var(--panel));
  border: 1px solid var(--line);
  overflow: hidden;
  clip-path: polygon(0 0, calc(100% - 11px) 0, 100% 11px, 100% 100%, 11px 100%, 0 calc(100% - 11px));
  transition: border-color 0.15s, transform 0.15s;
}
.card:hover { border-color: var(--magenta); transform: translateY(-2px); }

/* The body grows so every card in a row ends up the same height and the
   price line stays flush with the bottom edge. */
.card-body {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: 0.9rem 1rem 1rem;
  flex: 1;
}
.card-head { display: flex; justify-content: space-between; gap: 0.6rem; align-items: flex-start; }
.card-title {
  font-size: 0.95rem;
  /* Long book names must not push the badges out of the card. */
  overflow-wrap: anywhere;
  hyphens: auto;
}
.card-sub {
  margin: 0;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
}
.card-text {
  margin: 0;
  font-size: 0.84rem;
  color: var(--muted);
  flex: 1;
}
.card-foot {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
  border-top: 1px solid var(--line);
  padding-top: 0.6rem;
  margin-top: auto;
}
.card-cta {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--magenta-soft);
}

/* ---------- item pictures ---------- */

/* The rulebook data has no artwork, so most items show the placeholder.
   Both variants keep the same box so the grid stays even either way. */
.item-image {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  background: #0d0916;
  border-bottom: 1px solid var(--line);
}
.item-image-missing {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  background:
    repeating-linear-gradient(
      135deg,
      rgba(255, 255, 255, 0.022) 0 10px,
      transparent 10px 20px
    ),
    #0d0916;
  color: var(--muted);
}
.category-icon {
  width: 2.6rem;
  height: 2.6rem;
  color: var(--line-bright);
}
.item-image-note {
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: #6d6087;
}

/* Inlined once per page purely as a symbol source. */
.icon-sprite { display: none; }

.detail-figure { margin: 0 0 1.4rem; }
.detail-figure .item-image {
  aspect-ratio: 16 / 9;
  border: 1px solid var(--line);
  object-fit: contain;
}

/* ---------- htmx ---------- */

/* Only a brief dim while the swap is in flight - no layout shift, and
   nothing at all on a fast local response. */
#catalog { transition: opacity 0.12s ease; }
#catalog.htmx-request { opacity: 0.55; }

/* ---------- badges and prices ---------- */

.badges { display: flex; gap: 0.3rem; flex-shrink: 0; }
.badge {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.05em;
  padding: 0.1rem 0.38rem;
  border: 1px solid var(--line-bright);
  color: var(--muted);
  white-space: nowrap;
}
.badge-licence { border-color: var(--amber); color: var(--amber); }
.badge-illegal { border-color: var(--red); color: var(--red); }
/* The character that is in play. Cyan is what the app already uses for „this
   is your runner“ — the wallet and the balance carry it too. */
.badge-aktiv { border-color: var(--cyan); color: var(--cyan); }

.price { font-family: var(--mono); font-size: 1rem; color: var(--cyan); }
.price-unit { font-size: 0.72rem; color: var(--muted); }
.price-request { color: var(--muted); font-size: 0.88rem; }

/* ---------- item detail ---------- */

.detail { display: grid; grid-template-columns: 1fr 20rem; gap: 1.5rem; align-items: start; }
.back {
  display: inline-block;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
  margin-bottom: 1rem;
}
.back:hover { color: var(--magenta-soft); }
.detail-head {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  align-items: flex-start;
  flex-wrap: wrap;
}
.detail-head h1 { overflow-wrap: anywhere; }
.detail-sub { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.1em; margin: 0.3rem 0 1.2rem; }
.detail-text { margin: 0 0 1.4rem; }

.stats { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
.stats th, .stats td { text-align: left; padding: 0.5rem 0.7rem; border-bottom: 1px solid var(--line); }
.stats th {
  width: 40%;
  font-weight: 600;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
}
.stats td { font-family: var(--mono); color: var(--text); }

.detail-buy { position: sticky; top: 5.2rem; display: grid; gap: 1rem; }
.buy-price { display: flex; justify-content: space-between; align-items: baseline; }
.buy-price .muted { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.14em; }
.detail-buy .button-primary { width: 100%; }
.buy-balance { margin: 0; font-size: 0.8rem; border-top: 1px solid var(--line); padding-top: 0.8rem; }

/* ---------- character sheet rail ---------- */

/* The sheet scrolls on its own so a long purchase list cannot push the rail
   past the bottom of the window. */
.sheet-rail {
  position: sticky;
  top: 5.2rem;
  max-height: calc(100vh - 7rem);
  overflow-y: auto;
  padding: 1.2rem 1.3rem 1.4rem;
}

.sheet-title, .sheet-subtitle {
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  color: var(--muted);
  border-bottom: 1px solid var(--line);
  padding-bottom: 0.5rem;
}
.sheet-title { margin-bottom: 1rem; }
.sheet-subtitle { margin: 1.5rem 0 0.3rem; }

.sheet-id h3 { font-size: 1.15rem; overflow-wrap: anywhere; }
.sheet-id p { margin: 0.2rem 0 1.1rem; }

.ledger { display: grid; gap: 0.4rem; margin: 0; }
.ledger div { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; }
.ledger dt {
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted);
}
.ledger dd { margin: 0; font-family: var(--mono); font-size: 0.95rem; }
.ledger-total { border-top: 1px solid var(--line); padding-top: 0.5rem; margin-top: 0.2rem; }
.ledger-total dd { color: var(--cyan); font-size: 1.2rem; }
.ledger-total dd.over { color: var(--red); }
.sheet-rail .notice { margin: 1rem 0 0; }

.sheet-identities { list-style: none; margin: 0; padding: 0; }
.sheet-identities > li {
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--line);
  font-size: 0.85rem;
}
.sheet-identities p { margin: 0.15rem 0 0; }
.identity-name { color: var(--cyan); }
.identity-licences { list-style: none; margin: 0.15rem 0 0; padding: 0 0 0 0.9rem; }
.identity-licences li {
  color: var(--muted);
  font-size: 0.8rem;
  overflow-wrap: anywhere;
}

.sheet-purchases { list-style: none; margin: 0; padding: 0; }
.sheet-purchases li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.1rem 0.6rem;
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--line);
  font-size: 0.85rem;
}
.purchase-name { overflow-wrap: anywhere; }
.purchase-name:hover { color: var(--magenta-soft); }
.purchase-sum { font-family: var(--mono); font-size: 0.82rem; color: var(--cyan); }
.purchase-warn {
  grid-column: 1 / -1;
  margin: 0.2rem 0 0;
  font-size: 0.72rem;
  color: var(--amber);
}
.sheet-purchases form { grid-column: 2; justify-self: end; }
.sheet-purchases .linkish { font-size: 0.65rem; }

.sheet-finish { margin-top: 1rem; }
.sheet-finish .button { width: 100%; text-align: center; }
.sheet-finish p { margin: 0.5rem 0 0; }
.sheet-hint { margin-top: 0.6rem; }

.ansicht-aktionen { display: flex; gap: 0.6rem; margin-top: 1.2rem; }

.sheet-upload { border-top: 1px solid var(--line); margin-top: 1.4rem; padding-top: 1rem; }
.sheet-upload summary {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted);
}
.sheet-upload summary:hover { color: var(--text); }
.sheet-upload .stack { margin-top: 0.9rem; }
.sheet-upload .button { width: 100%; }
.sheet-upload p { margin: 0; }

/* ---------- narrow screens ---------- */

/* Below this width the sheet cannot keep its own column, so it moves under
   the page; the balance in the top bar keeps it in reach while browsing. */
@media (max-width: 75rem) {
  /* Stacked, the two are grid *rows*, and .layout stretches to the bottom of
     the window — a grid shares that leftover height out between its rows, so
     a short page opened a hole between the panel and the sheet under it. */
  .layout-sheet { grid-template-columns: 1fr; align-content: start; }
  .sheet-rail { position: static; max-height: none; overflow-y: visible; }
}

@media (max-width: 60rem) {
  .shell { width: min(1440px, 100% - 1.6rem); }
  .catalog, .detail { grid-template-columns: 1fr; }
  .sidebar, .detail-buy { position: static; }
  /* Stacked above the results, the sidebar has the whole page to grow into,
     so it must not trap the wheel in a short box of its own. */
  .sidebar { max-height: none; }
  .sidebar .categories { overflow-y: visible; }
  .topbar-inner { flex-wrap: wrap; gap: 0.8rem 1.2rem; }
  .nav { order: 3; width: 100%; margin-right: 0; }
}

.detail-figure .category-icon { width: 4rem; height: 4rem; }

/* ---------- character generator ---------- */

/* The generator owns the full width: wizard left, live sheet right. */
.layout-generator { grid-template-columns: minmax(0, 1fr); }
.generator {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(340px, 460px);
  gap: 1.5rem;
  align-items: start;
}
@media (max-width: 1180px) {
  .generator { grid-template-columns: minmax(0, 1fr); }
}
.generator-arbeit { display: flex; flex-direction: column; gap: 1.25rem; min-width: 0; }

.schritte {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  border-bottom: 1px solid var(--line);
  padding-bottom: 0.75rem;
}
.schritt {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 0.8rem;
  border: 1px solid var(--line);
  background: var(--panel);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.schritt:hover { border-color: var(--line-bright); }
.schritt.active { background: var(--magenta); border-color: var(--magenta); color: #fff; }
.schritt-nummer { font-family: var(--mono); opacity: 0.65; }

.schritt-kopf { margin-bottom: 1rem; }
.schritt-inhalt h2 {
  margin: 1.4rem 0 0.6rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--line);
  color: var(--cyan);
}
.schritt-inhalt h3 { margin: 0.9rem 0 0.5rem; }
.zaehler { color: var(--muted); font-weight: 400; letter-spacing: 0.02em; }

/* -- options ------------------------------------------------------------- */

/* Choices are peers, so they are the same size: grid stretches every card in
   a row to the height of the tallest one. Sized by their own text they were a
   comb of different lengths with holes between them, which read as broken
   rather than as a set to pick from.

   The magic list, whose cards carry a fixed amount of text, equalises across
   the whole grid (1fr rows). Everywhere a description folds open — the wizard's
   choice groups and the module catalogue — the grid equalises per row only:
   one opened card would otherwise stretch *every* row to its height, leaving a
   screen of holes below the one card that was read. */
.optionen, .modulkatalog, .magieliste {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 0.5rem;
}
.magieliste { grid-auto-rows: 1fr; }
/* 1fr equalises a row against its own tallest card, which is enough for spells
   and complex forms — their stat lines are all the same length. Adept powers
   have one entry whose cost line from the book runs eight lines ("Verbesserte
   Fertigkeit" prices combat skills apart from the rest), and that single card
   pushed its row past all the others. A fixed row height sizes every card the
   same instead; minmax keeps the text whole if a narrow window needs more. */
.kraefteliste { grid-auto-rows: minmax(14rem, auto); }

/* The two groups whose choices carry a whole book description — metatype and
   magic type. Wide columns keep the quote a paragraph instead of a narrow
   tower; at the default width one option ran to fourteen lines next to a
   two-line one. */
.optionen-breit { grid-template-columns: repeat(auto-fill, minmax(21rem, 1fr)); }

/* Wider columns than the other catalogues: a module card carries the book's
   whole effect list, and at 260px every line of it wrapped three times, which
   turned six bullets into a tower of eighteen. */
.modulkatalog {
  grid-template-columns: repeat(auto-fill, minmax(21rem, 1fr));
  max-height: 44rem;
  overflow-y: auto;
}
/* Every card the same height, across the whole catalogue and not just per row:
   the descriptions differ by several lines, and sized by their own text the
   cards were a comb. The description box takes up the slack (see below), so
   the name and both bars land on the same line on every card. */
.modulkatalog { grid-auto-rows: 1fr; }
/* The button keeps its natural height — stretching it instead would open a gap
   between the name and the bars underneath. */
.modulkatalog .option-karte .option { flex: none; }
.modulkatalog .option-karte > .option-regel:last-child {
  flex: 1;
  display: flex;
  flex-direction: column;
}
.modulkatalog .option-karte > .option-regel:last-child > .option-text { flex: 1; }
/* The card is the button plus its folded description. The button stretches to
   the card's full height so that a row of cards still ends on one line. */
/* Descendant and not child: the picking form sits between card and button as
   a display:contents box, which flattens the *layout* but not the selector. */
.option-karte { display: flex; flex-direction: column; min-width: 0; }
.option-karte .option { flex: 1; }
/* Button and fold are two boxes but one card, so the cut corner belongs to
   the card: the button keeps the top one and hands the bottom one down. */
.option-karte:has(.option-regel) .option {
  clip-path: polygon(var(--cut) 0, 100% 0, 100% 100%, 0 100%, 0 var(--cut));
}
.option-form { margin: 0; display: contents; }
.option {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  width: 100%;
  text-align: left;
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--text);
  cursor: pointer;
  font: inherit;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}
.option:hover:not(:disabled) { border-color: var(--magenta-soft); background: #221635; }
.option:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.option.aktiv { border-color: var(--magenta); background: rgba(224, 25, 124, 0.18); }
.option.gesperrt, .option:disabled { opacity: 0.45; cursor: not-allowed; }
.option-name { font-weight: 700; letter-spacing: 0.03em; }
.option-zusatz { font-family: var(--mono); font-size: 0.78rem; color: var(--cyan); }
.option-text { font-size: 0.8rem; color: var(--muted); line-height: 1.45; }
.option-sperre { font-size: 0.75rem; color: var(--red); }
/* How to undo a pick, on the picked card — the only place it can be looked
   for once picking and unpicking are the same click. */
.option-notiz { font-size: 0.72rem; color: var(--muted); }

/* What a life module grants, in the book's own words (see _schritt_module),
   behind the bar that names the kind of module. It is read while comparing
   cards, so it is set small and tight, and the label the book repeats on every
   line ("Wähle eine Option:") is greyed out rather than dropped: it belongs to
   the sentence, it just is not what tells two modules apart. */
.wirkung {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.22rem;
  margin: 0;
  padding: 0.1rem 0.7rem 0.6rem;
  font-size: 0.76rem;
  line-height: 1.4;
}
.wirkung-zeile {
  position: relative;
  padding-left: 0.7rem;
  color: var(--text);
}
.wirkung-label { color: var(--muted); }
.wirkung-zeile::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.45em;
  width: 0.22rem;
  height: 0.22rem;
  background: var(--cyan);
}
/* The sentence some entries carry after their list — a rule of the module, but
   not one of its bullets, so it is not dressed up as one. */
.wirkung-zusatz {
  margin: 0;
  padding: 0 0.7rem 0.6rem 1.4rem;
  font-size: 0.76rem;
  line-height: 1.4;
  color: var(--muted);
  font-style: italic;
}

/* The description of a single choice, folded like every other rule in the
   generator (see .buchregel). Quieter than a rule bar: it hangs under its
   card and there is one of them per choice, so it is a thin strip rather
   than a second panel. */
.option-regel {
  border: 1px solid var(--line);
  border-top: 0;
  background: var(--panel);
  font-size: 0.8rem;
  clip-path: polygon(
    0 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%
  );
}
/* A picked choice keeps its outline all the way round the card. */
.option-karte:has(.option.aktiv) .option-regel { border-color: var(--magenta); }
/* A module card carries two folds under its button — what the module does and
   what it reads like. Only the lower one ends the card, so only it gets the
   cut corner; the one above hands its bottom edge on as a plain line. */
.option-karte > .option-regel:not(:last-child) {
  clip-path: none;
  border-bottom: 0;
}
.option-regel-kopf {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.7rem;
  user-select: none;
}
.option-regel-kopf::before { color: var(--cyan); }
.option-regel-kopf:hover { background: rgba(47, 227, 213, 0.08); }
.option-regel-kopf:hover .option-regel-schalter { color: var(--text); }
.option-regel-kopf:focus-visible { outline: 2px solid var(--cyan); outline-offset: -2px; }
.option-regel-marke {
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--cyan);
  margin-right: auto;
}
/* Which kind of module it is, in the bar that opens its effects — the only
   place that still says it, so the two kinds are told apart by colour and not
   by reading the word. Must stand after .option-regel-marke: same specificity,
   so order alone decides. */
.marke-ereignis { color: var(--magenta-soft); }
.option-regel-schalter {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
  white-space: nowrap;
  transition: color 0.15s;
}
.option-regel:not([open]) .nur-auf, .option-regel[open] .nur-zu { display: none; }
.option-regel .option-text { display: block; margin: 0; padding: 0 0.7rem 0.6rem; }
/* Pushed to the bottom edge: with cards of one height the page numbers of a
   row then sit on one line instead of wherever the text happened to end. */
.option-quelle {
  margin-top: auto;
  padding-top: 0.2rem;
  font-style: normal;
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.option-tipp { font-size: 0.75rem; color: var(--amber); }

/* -- forms --------------------------------------------------------------- */

.feldreihe, .qualitaetsreihe {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 0.9rem;
}
.textfeld, .qualitaetsslot { display: flex; flex-direction: column; gap: 0.3rem; }
.textfeld label { display: flex; flex-direction: column; gap: 0.3rem; }
.textfeld label > span, .qualitaetsslot label > span {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}
.qualitaet-form, .connection-form, .wissen-form, .wildcard {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  align-items: flex-end;
  margin: 0;
}
.qualitaet-form label, .connection-form label, .wissen-form label, .wildcard label {
  display: flex; flex-direction: column; gap: 0.25rem;
}
.qualitaet-form .klein input { width: 5.5rem; }
.wachsend { flex: 1 1 12rem; }

/* -- rules from the book --------------------------------------------------

   The rule as the book words it. Quoted, so it reads as the book talking and
   not as the tool inventing a rule of its own — and therefore long: several
   quotes above one row of choices pushed the choices off the screen.

   So it is folded away, and the bar that is left has to do two things at
   once: say that there is a rule here and that clicking opens it. Hence the
   label, the page it stands on, the chevron and the word "anzeigen" — the
   whole bar is the control, and it looks like one. */
.buchregel {
  margin: -0.2rem 0 1rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--cyan);
  background: var(--panel-2);
  font-size: 0.86rem;
  line-height: 1.55;
  color: var(--text);
}

.buchregel-kopf {
  display: flex;
  align-items: center;
  /* On a phone the bar is wider than the screen. It wraps rather than
     squeezing "Regel aus dem Buch" into a one-word column, so the label and
     the word that says it opens stay legible. */
  flex-wrap: wrap;
  gap: 0.15rem 0.55rem;
  padding: 0.5rem 0.8rem;
  user-select: none;
}
/* Cyan like the accent line and the label, so the bar reads as one control. */
.buchregel-kopf::before { color: var(--cyan); }
.buchregel-kopf:hover { background: rgba(47, 227, 213, 0.08); }
.buchregel-kopf:hover .buchregel-schalter { color: var(--text); }
.buchregel-kopf:focus-visible { outline: 2px solid var(--cyan); outline-offset: -2px; }

.buchregel-marke {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--cyan);
  white-space: nowrap;
}
.buchregel-titel { font-size: 0.82rem; }
/* The page stays readable while the box is shut: which rule this is answers
   most questions without opening anything. */
.buchregel-quelle {
  font-style: normal;
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  color: var(--muted);
  margin-right: auto;
}
.buchregel-schalter {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
  white-space: nowrap;
  transition: color 0.15s;
}
.buchregel:not([open]) .nur-auf, .buchregel[open] .nur-zu { display: none; }

.buchregel-text { padding: 0.1rem 0.9rem 0.8rem; }
.buchregel-text p { margin: 0 0 0.5rem; }
.buchregel-text cite {
  display: block;
  margin-top: 0.15rem;
  font-style: normal;
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  color: var(--muted);
}
/* The second quote in the box: the limits that hold across the whole life
   path, not just this step — a line and a shade of grey apart from it. */
.buchregel-grenzen {
  color: var(--muted);
  border-top: 1px solid var(--line);
  margin-top: 0.7rem;
  padding-top: 0.7rem;
}

/* How much room is left is not something to look up, so it stays outside the
   fold — but visibly part of the same box. */
.regelblock { margin-bottom: 1rem; }
.regelblock .buchregel { margin-bottom: 0; border-bottom: 0; }
.regel-zahlen {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.2rem;
  margin: 0;
  padding: 0.45rem 0.8rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--cyan);
  background: var(--panel-2);
  font-family: var(--mono);
  font-size: 0.78rem;
  color: var(--cyan);
}
.regel-zahlen .ueber { color: var(--red); }
/* What this step still owes. Amber while it is open — this is not an error,
   it is the next thing to do; the problem list turns it red once the step is
   left behind. */
.regel-zahlen .pflicht {
  padding: 0 0.45rem;
  border: 1px solid currentColor;
  color: var(--muted);
}
.regel-zahlen .pflicht.offen { color: var(--amber); }
.regel-zahlen .pflicht.erfuellt { color: var(--green); }

/* -- quality slots -------------------------------------------------------- */

.slot-kopf { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.slot-kopf h3 { margin: 0; }
.slot-kopf form { margin: 0; }
/* What is picked, next to the name of the slot: the catalogue scrolls, and
   a slot whose pick had scrolled out of sight otherwise looked empty. */
.slot-wahl { font-size: 0.85rem; text-align: right; color: var(--muted); }

/* The fine-tuning of a picked quality, inside its own card. */
.option-karte > .qualitaet-form {
  border: 1px solid var(--magenta);
  border-top: 0;
  background: rgba(224, 25, 124, 0.1);
  padding: 0.5rem 0.7rem 0.6rem;
}
.option-karte > .qualitaet-form .fehlt { border-color: var(--red); }

/* The catalogue can be long; it scrolls inside the slot instead of pushing
   the rest of the step off the screen.

   22rem is its own height, but it grows into whatever the slot beside it is
   taller by: a picked benefit adds a panel above the left catalogue, and
   without the growth the flaw column simply ended halfway up, leaving a hole
   the size of that panel next to a scrollbar that had more to show. */
.qualitaetskatalog {
  flex: 1 1 22rem;
  min-height: 22rem;
  overflow-y: auto;
  padding-right: 0.2rem;
}
/* Sticky, because the two groups are long and the heading is the only thing
   that says whether these are benefits or flaws. */
.katalog-gruppe {
  position: sticky;
  top: 0;
  z-index: 1;
  margin: 0.6rem 0 0.4rem;
  padding: 0.25rem 0;
  background: var(--panel);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--cyan);
}
.katalog-gruppe:first-child { margin-top: 0; }
/* Sixty qualities, one under the other: a single column, because the name and
   the karma price are what you scan here. */
.qualitaetskatalog .optionen { grid-template-columns: 1fr; }

/* The search above the catalogue. Full width, because it belongs to the whole
   list below it and not to any one card in it. */
.katalogsuche { display: block; margin: 0 0 0.4rem; }
.katalogsuche input { width: 100%; }
/* The cards carry display:flex, which outranks the browser's rule for
   [hidden] — without this the search would hide nothing. */
.option-karte[hidden] { display: none; }
.katalog-leer { margin: 0.6rem 0.1rem; }

/* A "?" that explains a field the book's cost rule made necessary. */
.hilfe {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.05em;
  height: 1.05em;
  margin-left: 0.25em;
  border: 1px solid var(--line-bright);
  border-radius: 50%;
  font-size: 0.9em;
  text-decoration: none;
  cursor: help;
  color: var(--cyan);
}

input[type="text"], input[type="number"], select {
  background: var(--bg);
  border: 1px solid var(--line);
  color: var(--text);
  padding: 0.45rem 0.6rem;
  font: inherit;
  width: 100%;
}
input:focus, select:focus { outline: none; border-color: var(--cyan); }

/* -- folded section ------------------------------------------------------ */

/* A whole section of a step, folded by its own heading — for the sections that
   outgrow a screen and bury what comes after them. The bar stays the heading
   it replaces (same rule as .schritt-inhalt h2), with the chevron and the word
   that says it opens added, so it reads as a heading you can click and not as
   a new kind of control. */
.klappe { margin: 1.4rem 0 0.6rem; }
.klappe-kopf {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--line);
  color: var(--cyan);
  user-select: none;
}
/* The heading's own frame moves to the bar around it. */
.klappe-kopf > h2 { margin: 0; padding: 0; border-top: 0; }
.klappe-kopf:hover { color: var(--magenta-soft); }
.klappe-kopf:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
/* Folded, the count is all that is left of the list — so it has to keep
   answering how many modules there are, and show that adding one did. */
.klappe-zahl { font-family: var(--mono); font-size: 0.8rem; color: var(--muted); }
.klappe-schalter {
  margin-left: auto;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
  white-space: nowrap;
}
.klappe-kopf:hover .klappe-schalter { color: var(--text); }
.klappe:not([open]) .nur-auf, .klappe[open] .nur-zu { display: none; }
.klappe-inhalt { margin-top: 0.8rem; }

/* -- modules ------------------------------------------------------------- */

.modulliste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.modul { border: 1px solid var(--line); background: var(--panel-2); }
.modul.offen { border-color: var(--magenta); }
.modul-kopf { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: 0.6rem 0.8rem; }
/* The row is a fold like every other one, so it says so the same way — but it
   is a link and not a <summary> (the detail is rendered by the server, one at
   a time), so the shared chevron rule cannot reach it and it gets its own. */
.modul-name { display: flex; align-items: center; gap: 0.55rem; flex: 1; }
.modul-titel { display: flex; flex-direction: column; gap: 0.15rem; flex: 1; }
.modul-name::before {
  content: "";
  width: 0.42rem;
  height: 0.42rem;
  flex-shrink: 0;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(-45deg);
  transition: transform 0.15s ease;
  color: var(--magenta-soft);
}
.modul.offen .modul-name::before { transform: rotate(45deg); }
/* Magenta while the module still wants a decision, cyan once every one of them
   is made — the same cyan as the heading above the list, so a glance down the
   folded list says what is left to do. */
.modul.vollstaendig .modul-name::before { color: var(--cyan); }
.modul-schalter {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
  white-space: nowrap;
  transition: color 0.15s;
}
.modul-name:hover .modul-schalter { color: var(--text); }
.modul-detail { padding: 0 0.8rem 0.9rem; border-top: 1px solid var(--line); }
.modul-text { font-size: 0.86rem; line-height: 1.5; color: var(--muted); }
.auswahlgruppe { margin-top: 1rem; }
.aktionsliste { list-style: none; margin: 0.4rem 0; padding: 0; display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.85rem; }
.aktionsliste li { display: flex; gap: 0.6rem; align-items: center; }
/* One card per skill that can take a specialization. Same grid as the choice
   cards, and a fixed row height: the cards differ by one line — a skill that
   already has its specialization shows it — and sized by their own text that
   one line made a comb out of the block. */
.spezialisierungsliste {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
  grid-auto-rows: minmax(8.5rem, auto);
  gap: 0.5rem;
  margin-bottom: 1rem;
}
.spezialisierung {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--line);
  background: var(--panel-2);
}
.spezialisierung-kopf { display: flex; justify-content: space-between; gap: 0.6rem; align-items: baseline; }
.spezialisierung-name { font-weight: 600; }
.spezialisierung-wahl { margin: 0; font-size: 0.85rem; color: var(--cyan); }
/* Pushes the page reference to the bottom edge, so every card's source line
   sits on the same baseline however long the name above it is. */
.spezialisierung form { margin-top: auto; }
.spezialisierung-quelle {
  font-style: normal;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.buchungsliste { list-style: none; margin: 0.4rem 0 0.8rem; padding: 0; display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.85rem; }
.buchungsliste li {
  display: flex; gap: 0.8rem; align-items: baseline;
  padding: 0.4rem 0.6rem; border: 1px solid var(--line);
  background: var(--panel-2);
}
.buchung-name { flex: 1; }
.buchung-karma { font-family: var(--mono); font-size: 0.78rem; color: var(--cyan); }
.steigerungen { display: flex; flex-direction: column; gap: 0.4rem; margin-top: 0.6rem; }
.steigerung { display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap; }
.steigerung-name { flex: 1 1 14rem; display: flex; flex-direction: column; }

/* -- messages ------------------------------------------------------------ */

.meldungen-kopf { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; }
.karma-stand { font-family: var(--mono); color: var(--cyan); }
.meldung { margin: 0.35rem 0; padding-left: 0.8rem; border-left: 3px solid; font-size: 0.87rem; }
.meldung.problem { border-color: var(--red); color: #ffd4dc; }
.meldung.hinweis { border-color: var(--amber); color: #ffe6bd; }
.meldung.ok { border-color: var(--green); color: #c8f5e0; }

/* -- live sheet preview -------------------------------------------------- */

.vorschau {
  position: sticky;
  top: 4.5rem;
  border: 1px solid var(--line);
  background: var(--panel);
  padding: 0.9rem;
  max-height: calc(100vh - 6rem);
  overflow-y: auto;
}
/* The same width at which the preview stops being a column beside the wizard
   and moves under it. There it has the page to grow into: pinned and
   scrolling inside itself it would be a short box with a scrollbar of its own
   in the middle of a scrolling page. */
@media (max-width: 1180px) {
  .vorschau { position: static; max-height: none; overflow-y: visible; }
}
.vorschau-kopf h2 { color: var(--cyan); }
.vorschau-legende { display: flex; gap: 0.8rem; margin: 0.5rem 0 0; font-size: 0.75rem; }
.legende { display: flex; align-items: center; gap: 0.3rem; color: var(--muted); }
.legende::before { content: ""; width: 0.7rem; height: 0.7rem; border: 1px solid; }
.legende.besser::before { background: rgba(63, 209, 139, 0.35); border-color: var(--green); }
.legende.schlechter::before { background: rgba(255, 77, 109, 0.35); border-color: var(--red); }
.legende.ohne::before { background: rgba(255, 176, 32, 0.35); border-color: var(--amber); }

.vorschau-seiten { display: flex; flex-direction: column; gap: 1rem; margin-top: 0.8rem; }
.bogenseite { position: relative; margin: 0; line-height: 0; }
.bogenseite img { width: 100%; height: auto; display: block; }

/* One box per filled field, positioned in page percentages so the overlay
   follows the image at whatever width the rail happens to be. */
.bogenfeld {
  position: absolute;
  display: flex;
  align-items: center;
  overflow: hidden;
  line-height: 1;
  transition: background-color 120ms ease, box-shadow 120ms ease;
}
.bogenfeld-wert {
  font-size: clamp(4px, 0.62vw, 9px);
  font-family: var(--sans);
  color: #10131a;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  padding: 0 1px;
}
.bogenfeld.diff-besser { background: rgba(63, 209, 139, 0.45); box-shadow: 0 0 0 1px var(--green); }
.bogenfeld.diff-schlechter { background: rgba(255, 77, 109, 0.45); box-shadow: 0 0 0 1px var(--red); }
.bogenfeld.diff-ohne { background: rgba(255, 176, 32, 0.45); box-shadow: 0 0 0 1px var(--amber); }

/* -- overview and switcher ------------------------------------------------ */

.pfadliste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.pfad { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; padding: 0.7rem 0; border-bottom: 1px solid var(--line); }
.pfad-name { font-weight: 700; letter-spacing: 0.04em; flex: 1 1 12rem; }
.pfad-aktionen { display: flex; gap: 0.5rem; align-items: center; }

.switcher { position: relative; }
/* Without the chevron the character's name in the top bar looks like a label,
   and nobody finds the other characters behind it. */
.switcher summary { display: flex; align-items: center; justify-content: flex-end; gap: 0.4rem; }
.switcher summary:hover { color: var(--magenta-soft); }
.switcher-list {
  position: absolute;
  right: 0;
  z-index: 20;
  list-style: none;
  margin: 0.4rem 0 0;
  padding: 0.3rem;
  min-width: 14rem;
  background: var(--panel-2);
  border: 1px solid var(--line-bright);
}
.switcher-list button { width: 100%; text-align: left; padding: 0.35rem 0.5rem; display: flex; justify-content: space-between; gap: 0.6rem; }
.switcher-list button.active { color: var(--magenta-soft); }

.abschluss-uebersicht { margin-bottom: 1rem; }
.abschluss-aktionen { display: flex; gap: 0.7rem; align-items: center; flex-wrap: wrap; margin-top: 1rem; }

/* ---------- Kampagne ---------- */

/* Die Story-Seiten tragen das Deckblatt der Dossiers: schwarzer Grund,
   magenta schraffierte Balken, der Name in schweren schmalen Versalien über
   einem vollflächigen Bild. Nachbau von frontblatt_*.html.

   Die Farben stehen auf .deckblatt und nicht auf :root, und keine von ihnen
   heißt wie eine des Ladens: Der Shop ist violett-magenta, das Blatt ist
   schwarz, und ein hier umdefiniertes --panel oder --magenta würde in jede
   Seite durchschlagen, die zufällig darunter liegt. */
.deckblatt {
  /* Die Farben sind die des Ladens: eine Website, eine Palette. Nur Schrift,
     Schraffur und Akzent kommen vom gedruckten Deckblatt, nicht der Grund.
     Ein eigenes Schwarz hier hieße, dass die Story-Seiten aussehen, als
     gehörten sie zu einem anderen Projekt. */
  --grund: var(--panel);
  --bildgrund: var(--panel-2);
  --blatt-tinte: var(--text);
  --blatt-grau: var(--muted);
  --schraffur: var(--magenta);
  /* Je Runner inline überschrieben; ohne Angabe die Farbe des Ladens. */
  --tint: var(--magenta);
  --display: "Haettenschweiler", "Arial Narrow", "Archivo Narrow",
             "Roboto Condensed", Impact, sans-serif;

  background: var(--grund);
  color: var(--blatt-tinte);
  margin-bottom: 1.6rem;
}

/* Der schraffierte Balken: diagonale Magentastriche, wie im Buch. */
.deckblatt-schraffur {
  height: 8px;
  background: repeating-linear-gradient(
    115deg, var(--schraffur) 0 2px, transparent 2px 6px
  );
}

.deckblatt-name {
  font-family: var(--display);
  font-weight: 700;
  font-stretch: condensed;
  font-size: clamp(2.6rem, 11vw, 7rem);
  line-height: 0.9;
  letter-spacing: -0.005em;
  text-transform: uppercase;
  text-align: center;
  margin: 0.06em 0 0.05em;
  color: var(--blatt-tinte);
}

.deckblatt-rolle {
  text-align: center;
  text-transform: uppercase;
  font-weight: 700;
  font-size: clamp(0.8rem, 2.2vw, 1.3rem);
  letter-spacing: 0.12em;
  margin: 0;
  padding: 0.7rem 1rem 0.9rem;
  color: var(--tint);
}

/* -- das Blatt eines Runners --------------------------------------------- */

/* Nur die Runnerseite ist ein Blatt im Hochformat der Buchseite; die
   Story-Seite borgt sich Balken und Schrift, nicht den Papierschnitt. */
.deckblatt-blatt {
  width: min(100%, 46rem);
  margin-inline: auto;
  aspect-ratio: 1 / 1.414;
  display: grid;
  grid-template-rows: auto 1fr auto;
  overflow: hidden;
}

.deckblatt-bild {
  position: relative;
  min-height: 16rem;
  background-color: var(--bildgrund);
  background-size: cover;
  /* Der Ausschnitt sitzt hoch, damit das Gesicht auf der Mittelachse bleibt
     und unten Platz für die Zitate ist. */
  background-position: center 22%;
  overflow: hidden;
}

/* Dunkler Verlauf unter den Zitaten, damit sie auf jedem Bild lesbar sind. */
.deckblatt-bild::after {
  content: "";
  position: absolute;
  inset: 45% 0 0;
  background: linear-gradient(to bottom, transparent, rgba(20, 14, 32, 0.86));
  pointer-events: none;
}

/* Die leere Bildfläche endet dort, wo der Verlauf beginnt: darunter liegen
   die Zitate, und ohne diese Grenze schreibt der Hinweis quer durch sie
   hindurch. */
.deckblatt-platzhalter {
  position: absolute;
  inset: 0 0 45% 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  margin: 0;
  padding: clamp(1rem, 3vw, 2rem);
  color: var(--blatt-grau);
  font-size: clamp(0.72rem, 1.3vw, 0.85rem);
  line-height: 1.65;
}
.deckblatt-platzhalter strong {
  color: var(--tint);
  text-transform: uppercase;
  letter-spacing: 0.2em;
  font-size: 0.72rem;
  margin-bottom: 0.8rem;
}
.deckblatt-platzhalter code { color: var(--blatt-tinte); font-family: var(--mono); }

/* Die Zitate liegen klein und rechtsbündig auf dem Bild. */
.deckblatt-zitate {
  position: absolute;
  z-index: 1;
  right: clamp(1rem, 3.5vw, 2.4rem);
  bottom: clamp(1rem, 3.5vw, 2.2rem);
  max-width: 22rem;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  text-align: right;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.9);
}
.deckblatt-zitate p {
  margin: 0;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: clamp(0.66rem, 1.15vw, 0.84rem);
  line-height: 1.5;
  text-wrap: balance;
}
.deckblatt-zitate p:last-child { color: var(--blatt-grau); }

.deckblatt-fuss {
  text-align: center;
  padding: 0.9rem clamp(1rem, 4vw, 2.5rem) clamp(0.9rem, 2.5vw, 1.4rem);
}
.deckblatt-dossier {
  font-family: var(--display);
  font-weight: 700;
  font-stretch: condensed;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: clamp(1.2rem, 3.6vw, 2.2rem);
  margin: 0.7rem 0 0.5rem;
}
.deckblatt-essenz {
  margin: 0 auto;
  max-width: 44ch;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-size: clamp(0.68rem, 1.35vw, 0.88rem);
  line-height: 1.6;
  text-wrap: balance;
}

/* -- Persönliche Daten ---------------------------------------------------- */

.deckblatt-fakten {
  width: min(100%, 46rem);
  margin-inline: auto;
  border: 1px solid var(--line);
  padding: 1.4rem;
}
.deckblatt-fakten h2 { color: var(--tint); margin-bottom: 1rem; }
/* Eine Spalte, wie im gedruckten Dossier. Zwei nebeneinander lesen sich als
   Tabelle, in der die Zeilen einander entsprechen — tun sie aber nicht, und
   die längste Angabe („Allianz Deutscher Länder (ADL)“) reißt die eine Hälfte
   dreizeilig auf, während die andere leer danebensteht. */
.deckblatt-fakten dl { margin: 0; display: grid; gap: 0; }
.deckblatt-fakten dl > div {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.45rem 0;
  border-bottom: 1px solid var(--line);
  /* Ein Wert darf mehrzeilig sein (die Metatypen unter „Metatypen"). Dann
     steht das Label auf Höhe der ersten Zeile und nicht mittig neben dem
     Block. */
  align-items: baseline;
}
.deckblatt-fakten dt { color: var(--muted); }
.deckblatt-fakten dd { margin: 0; text-align: right; }

/* -- die Story ------------------------------------------------------------ */

/* Ohne Charakterbogen rechts, und in Lesebreite: das hier ist Fließtext und
   keine Tabelle. */
.layout-kampagne { grid-template-columns: minmax(0, 1fr); }
/* Breite statt max-width: „margin-inline: auto“ macht ein Grid-Kind
   schrumpfend statt gedehnt, und dann fällt das Blatt darin auf seine
   Textbreite zusammen. Mit fester Breite zentrieren die Ränder nur noch. */
.layout-kampagne .content { width: min(100%, 54rem); margin-inline: auto; }

/* Der Titel der Story ist vier Wörter lang und nicht ein Runnername; in der
   Größe des Blattes bricht er um. */
.deckblatt-titel .deckblatt-name { font-size: clamp(1.8rem, 6vw, 3.6rem); }

.kapitel .klappe-kopf > h2 { font-family: var(--display); font-stretch: condensed; letter-spacing: 0.04em; }
.sitzung { margin: 1.6rem 0 2.4rem; }
.sitzung-kopf {
  color: var(--magenta-soft);
  border-bottom: 1px solid var(--line);
  padding-bottom: 0.4rem;
  margin-bottom: 1rem;
}
.szene {
  margin: 1.6rem 0 0.6rem;
  color: var(--cyan);
  font-size: 0.9rem;
  letter-spacing: 0.08em;
}
.sitzung p { margin: 0 0 0.9rem; }

/* Ein verlinkter Runner im Fließtext: unterstrichen, damit er im Absatz als
   Link erkennbar ist, ohne den Text bunt zu machen. */
.deckblatt-name-link {
  color: var(--magenta-soft);
  text-decoration: underline;
  text-decoration-color: var(--line-bright);
  text-underline-offset: 0.15em;
}
.deckblatt-name-link:hover { text-decoration-color: var(--magenta-soft); }

.zurueck { margin-top: 1.4rem; }
.zurueck a { color: var(--muted); }
.zurueck a:hover { color: var(--magenta-soft); }

@media (max-width: 700px) {
  /* Im Hochformat wird das Blatt sonst höher als der Bildschirm. */
  .deckblatt-blatt { aspect-ratio: auto; }
}

/* -- die Aktennotiz ------------------------------------------------------- */

/* NSC, Orte und Firmen bekommen kein Deckblatt. Das Dossier ist das Artefakt
   der Spielerinnen und Spieler; eins für Nyx zu drucken würde behaupten, die
   Gruppe wüsste so viel über sie wie über sich selbst. Hier steht nur, was
   man sieht: Bild, Name, Tabelle. */
.akte {
  width: min(100%, 46rem);
  margin-inline: auto;
  border: 1px solid var(--line);
  padding: 1.4rem;
}
.akte-name {
  font-family: var(--display);
  font-weight: 700;
  font-stretch: condensed;
  font-size: clamp(1.8rem, 6vw, 3.4rem);
  line-height: 1;
  text-transform: uppercase;
  margin: 0;
  color: var(--tint);
}
.akte-rolle {
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 0.8rem;
  margin: 0.5rem 0 0;
  color: var(--blatt-grau);
}
/* Ohne Zuschnitt: das Bild eines NSC ist ein Bild und keine Blattfläche, an
   der oben ein Gesicht sitzen muss. */
.akte-bild {
  display: block;
  width: 100%;
  height: auto;
  margin-top: 1.1rem;
}

/* -- Text und Formular auf einer Personenseite ---------------------------- */

.personentext {
  width: min(100%, 46rem);
  margin-inline: auto;
  border: 1px solid var(--line);
  padding: 1.4rem;
}
.personentext p { margin: 0 0 0.9rem; }
.personentext p:last-child { margin-bottom: 0; }
.personentext .szene { margin: 1.2rem 0 0.6rem; }

/* Das Formular gehört dem Spieler, dem die Seite gehört. Es steht unter dem
   Blatt und zugeklappt: gelesen wird häufiger als geschrieben. */
.wikiform { max-width: 46rem; }
.wikiform p { margin: 0 0 1rem; }
.wikiform label { display: block; color: var(--muted); font-size: 0.83rem; margin-bottom: 0.3rem; }
.wikiform textarea, .wikiform input[type="text"], .wikiform input[type="number"] { width: 100%; }
.wikiform textarea {
  background: #0d0916;
  border: 1px solid var(--line-bright);
  color: var(--text);
  font: inherit;
  padding: 0.6rem 0.7rem;
  line-height: 1.6;
}

/* Sitzung hinzufügen und Kapitel bearbeiten stehen nebeneinander unter der
   letzten Sitzung — das eine ist der häufige Handgriff, das andere der
   seltene. */
.wikizeile { display: flex; align-items: baseline; gap: 1.4rem; flex-wrap: wrap; margin-top: 1.6rem; }
.wikizeile .klappe { margin-top: 0; }

/* ---------- phones ------------------------------------------------------

   The narrow-screen rules stand last: a media query adds no specificity, so
   a rule here only wins over the desktop rule it corrects if it comes after
   it in the file. Everything above is written for a window; what changes
   here is what a 390px screen cannot honour.

   Three things go wrong at that width and they are the reason for the whole
   section: the page scrolls sideways, two lists stand in front of the thing
   they belong to — the top bar in front of every page, the category list in
   front of the catalogue — and the boxes that were measured against a desktop
   window (a scrolling catalogue, a 21rem grid column, a row of three
   controls) are measured against nothing that exists on a phone.

   Both lists answer to the same move: fold, and leave the one thing out that
   is read continuously rather than looked up. */

/* The sidebar loses its own column at 60rem (see above) and lands on top of
   the results, so the fold starts there and not at the phone width. */
@media (max-width: 60rem) {
  /* Stacked, the twenty-seven categories stood between the search box and the
     first item: a full screen of scrolling before anything for sale. Folded,
     the list is one line, and it wears the sidebar's own heading style — it
     is the heading, with a chevron. */
  .filter-knopf {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.7rem 0.1rem;
    border-bottom: 1px solid var(--line);
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.18em;
    color: var(--muted);
    cursor: pointer;
    user-select: none;
  }
  .filter-knopf::before { color: var(--cyan); }
  /* Shut, the button has to say what the list is currently filtered to —
     otherwise folding it away hides the answer to "what am I looking at". */
  .filter-stand { margin-left: auto; letter-spacing: 0.08em; color: var(--text); }
  .filter-inhalt { display: none; }
  .klapp-schalter:checked ~ .filter-inhalt { display: block; }
  /* The button says "Kategorien"; the heading inside would say it twice. */
  .filter-inhalt .sidebar-title { display: none; }
  .sidebar { gap: 0.8rem; }
}

@media (max-width: 48rem) {

  /* -- the bar ----------------------------------------------------------- */

  /* Shut, the bar is one row: the mark, the balance, and the button. That is
     what lets it stay pinned — the full bar is five rows at this width, and
     pinned it would have held a third of the screen on every page.

     The balance is the one thing that stays out. It is the number you are
     against on every page of the shop, and a price is only a price next to
     it; the rest — where to go, whether there is a SIN, which runner is in
     play — is looked at when it is looked for, and that is one tap.

     .account stops being a box of its own so that the balance can sit on the
     shut row while the two identities and the name fold away with the nav;
     on a window it is untouched. */
  .topbar-inner { flex-wrap: wrap; gap: 0.45rem 0.9rem; padding: 0.5rem 0; }
  /* The four status blocks become items of the bar itself, so the balance can
     stay on the shut row while the other three fold away. Nothing else needs
     the grouping; on a window .account is untouched. */
  .account { display: contents; }
  .klapp-schalter:not(:checked) ~ .nav,
  .klapp-schalter:not(:checked) ~ .account > :not(.wallet) { display: none; }

  /* Shut: mark, balance, button. Open, in this order underneath: the four
     destinations, SIN, licences, the runner in play. */
  .brand { order: 0; }
  .brand-text { display: none; }

  .wallet {
    order: 1;
    /* Label beside value, not above it: stacked, the balance alone was two
       rows, which is the whole height the shut bar has to spend. */
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    margin-left: auto;
    text-align: left;
    padding-left: 0.7rem;
  }
  .wallet-label { font-size: 0.6rem; letter-spacing: 0.12em; }
  .wallet-value { font-size: 1rem; }

  /* This is the only way to the rest of the app on a phone, so it is dressed
     as the loudest control the app has — the same magenta fill and cut corner
     as the buy button. Grey on near-black, the way the bar's other small caps
     are set, it read as a label and was missed. */
  .menue-knopf {
    order: 2;
    display: flex;
    align-items: center;
    gap: 0.45rem;
    /* A finger's worth of button; the word alone is eleven pixels tall. */
    padding: 0.55rem 0.8rem;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    background: var(--magenta);
    color: #fff;
    clip-path: polygon(0 0, calc(100% - 9px) 0, 100% 9px, 100% 100%, 9px 100%, 0 calc(100% - 9px));
    cursor: pointer;
    user-select: none;
  }
  .klapp-schalter:checked + .menue-knopf { background: var(--magenta-soft); }

  /* Unfolded, each of these takes a row of its own: this is a menu now, read
     down, and not a bar squeezed sideways. */
  .nav, .identity, .whoami { width: 100%; text-align: left; }

  /* One destination per row, and the row is the target — as a wrapped strip
     of chips they were 26px tall, under what a finger hits, and "Story so
     far" broke across two lines besides. */
  .nav {
    order: 3;
    flex-direction: column;
    gap: 0;
    border-top: 1px solid var(--line);
  }
  .nav a {
    padding: 0.75rem 0.7rem;
    font-size: 0.82rem;
    letter-spacing: 0.08em;
    /* The underline that marks the page on a window is a hover cue on a row;
       the row takes the category list's left bar instead — the marker this
       app already uses for "this is the open one". */
    border-bottom: 0;
    border-left: 2px solid transparent;
  }
  .nav a:hover { border-bottom-color: transparent; }
  .nav a.active {
    color: var(--text);
    border-left-color: var(--magenta);
    background: rgba(224, 25, 124, 0.12);
  }

  .identity {
    order: 4;
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    padding: 0.15rem 0 0.15rem 0.7rem;
  }
  .identity-label { font-size: 0.6rem; letter-spacing: 0.12em; }
  /* The ceiling the wide bar needed is gone: the row is the screen. */
  .identity-value { max-width: none; font-size: 0.85rem; }

  .whoami {
    order: 5;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.8rem;
    border-top: 1px solid var(--line);
    padding: 0.6rem 0.7rem 0.15rem;
    margin-top: 0.2rem;
  }
  .switcher summary { justify-content: flex-start; }
  .switcher-list { right: auto; left: 0; }

  /* -- room -------------------------------------------------------------- */

  .layout { padding: 1.2rem 0 2rem; }
  .panel { padding: 1.1rem; }
  .sheet-rail { padding: 1.1rem; }
  h1 { font-size: 1.35rem; }

  /* -- the catalogue ----------------------------------------------------- */

  /* At one column a 4:3 picture is 290px tall, and since almost nothing in
     the book has artwork that is 290px of hatching per item. Both variants
     keep the same box, so the cards stay one size. */
  .item-image { aspect-ratio: 16 / 9; }

  /* Thumb-sized rows: at the desktop's 0.45rem the list is a column of
     30px targets, which is under what a finger can hit reliably. */
  .category { padding: 0.7rem 0.6rem; font-size: 0.92rem; }
  .subcategory { padding: 0.55rem 0.5rem; font-size: 0.86rem; }

  /* -- forms ------------------------------------------------------------- */

  /* Under 16px a mobile browser zooms the page when the field takes focus,
     and it does not zoom back out. */
  input[type="text"], input[type="password"], input[type="search"],
  input[type="number"], input[type="file"], select, textarea {
    font-size: 16px;
  }
  .button { padding: 0.7rem 1.1rem; }
  /* The bare-text buttons ("Abmelden", "Entfernen", "Storno") are a line of
     small caps with no box; they need the height a finger needs. */
  .linkish { min-height: 2.2rem; }

  /* -- the generator ----------------------------------------------------- */

  /* Every card catalogue drops to one column. Their minimum track is 21rem —
     wider than the panel is here, so at two decimals of a column the grid
     overflowed its own panel. */
  .optionen, .optionen-breit, .modulkatalog, .magieliste,
  .kraefteliste, .spezialisierungsliste {
    grid-template-columns: 1fr;
    grid-auto-rows: auto;
  }

  /* Both stay windows onto a long list — unfolded, the sixty qualities and
     the module catalogue make a page seventeen thousand pixels tall. What
     they cannot keep is a desktop's idea of how tall a window is: 44rem and
     22rem are both taller than the screen, so the box had no visible bottom
     edge and read as the page itself having stopped scrolling. Half a screen
     shows what it is. Scrolling still carries on into the page at the end of
     the list — no overscroll-behavior here, on purpose. */
  .modulkatalog { max-height: 55vh; }
  /* flex-basis is the height in this column, so the 22rem has to go with the
     min-height — left in, the list kept the old box and its overflow ran
     straight through the slot underneath. */
  .qualitaetskatalog { flex: none; min-height: 0; max-height: 55vh; }

  /* Name, "anzeigen" and "Entfernen" shared one line and "Entfernen" was cut
     off by the edge of the card. The chevron in front of the name already
     says the row opens, so the word saying it again is what goes: it costs a
     third of the line, and the name is what has to be readable. */
  .modul-schalter { display: none; }

  .schritt { font-size: 0.78rem; padding: 0.4rem 0.7rem; }
  .slot-kopf { flex-wrap: wrap; gap: 0.2rem 1rem; }
  .slot-wahl { text-align: left; }

  /* -- the story --------------------------------------------------------- */

  /* Heading, count and the word that opens it: three things on one line in a
     bar that is now 340px wide. */
  .klappe-kopf { flex-wrap: wrap; gap: 0.2rem 0.6rem; }
  .klappe-schalter { margin-left: 0; }
  .deckblatt-fakten, .akte, .personentext { padding: 1.1rem; }
  .deckblatt-zitate { max-width: none; left: clamp(1rem, 3.5vw, 2.4rem); }
}
