/* Stay Average: system.css
   The one source for all pages: tokens first, then base, then components.
   Pages add only layout that is specific to them (home.css, vote.css,
   member.css). No colour, font, spacing, radius, shadow, easing or duration
   value belongs anywhere else: use a token.
   Dark theme only. One type family: Archivo variable (width 62 to 125,
   weight 100 to 900). One accent: violet.
   Breakpoints (custom properties do not work inside @media, so they are
   written out): 640px, 768px, 1024px. */

/* Font (self-hosted, Latin subset of the variable font) --------------- */

@font-face {
  font-family: "Archivo";
  src: url("/fonts/archivo-variable.woff2") format("woff2");
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-style: normal;
  font-display: swap;
}

/* Tokens -------------------------------------------------------------- */

:root {
  color-scheme: dark;

  /* Colour */
  --bg: #141414;
  --fg: #efebe0;
  --accent: #b176e4;
  --card: #1e1e1e;
  --mute: #b9b5ab;
  --line: #3a3a3a;
  --line-quiet: #2b2b2b;
  --minus: #7a1f3d;
  --photo-ground: #f6f6f4;
  --scrim: rgb(0 0 0 / 0.85);

  /* Type */
  --font: "Archivo", Arial, sans-serif;
  --stretch-wide: 125%;
  --stretch-mid: 112%;
  --stretch-text: 100%;
  --w-text: 400;
  --w-strong: 600;
  --w-display: 900;
  --w-slogan: 800;

  --fs-label: 0.8125rem;
  --fs-small: 0.9375rem;
  --fs-body: 1rem;
  --fs-lead: 1.25rem;
  --fs-h3: 1.1875rem;
  --fs-h2: clamp(1.5rem, 1rem + 2vw, 2.25rem);
  --fs-title: clamp(2.25rem, 1.4rem + 3.6vw, 4.5rem);
  --fs-display: clamp(1.75rem, 1rem + 3.2vw, 3.5rem);
  --fs-slogan: clamp(2.25rem, 0.9rem + 6.4vw, 6rem);

  --lh-tight: 1.05;
  --lh-snug: 1.25;
  --lh-body: 1.5;
  --measure: 65ch;

  /* Space (brand scale 8, 16, 24, 32, 48; 4 and 12 only inside dense controls) */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s6: 24px;
  --s8: 32px;
  --s12: 48px;
  --s16: 64px;
  --s24: 96px;

  --gutter: var(--s4);
  --col-gap: var(--s4);
  --max: 1680px;
  --max-narrow: 1100px;
  --max-wide: 1320px;

  /* Controls */
  --tap: 44px;
  --field: 48px;
  --btn: 52px;
  --bw: 2px;
  --bw-thin: 1px;
  --focus: 3px;
  --focus-offset: 4px;

  /* Form: the brand has no radius, no shadow, no gradient. Tokens exist so a
     wrong value is a visible change, not a new freedom. */
  --radius: 0;
  --shadow: none;

  /* Motion */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --dur-press: 160ms;
  --dur-ui: 240ms;
  --dur-exit: 160ms;
  --dur-enter: 1000ms;
  --dur-reveal: 1100ms;
  --stagger: 120ms;
  --rise: 8px;
  --rise-lg: 32px;
  --dur-draw: 1400ms;
  --dur-leave: 700ms;
}

@media (min-width: 768px) {
  :root {
    --gutter: var(--s8);
    --col-gap: var(--s6);
  }
}

@media (min-width: 1024px) {
  :root {
    --gutter: var(--s12);
  }
}

@media (prefers-contrast: more) {
  :root {
    --line: #8a8a8a;
    --mute: #e0ddd4;
  }
}

/* Base ---------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  -webkit-tap-highlight-color: transparent;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-weight: var(--w-text);
  font-stretch: var(--stretch-text);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1,
h2,
h3,
p,
ul,
ol,
dl,
dd,
figure {
  margin: 0;
}

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

img {
  display: block;
  max-width: 100%;
  height: auto;
}

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

button {
  cursor: pointer;
  touch-action: manipulation;
}

a {
  color: inherit;
}

::selection {
  background: var(--accent);
  color: var(--bg);
}

:focus-visible {
  outline: var(--focus) solid var(--accent);
  outline-offset: var(--focus-offset);
}

[hidden] {
  display: none !important;
}

/* Layout -------------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--max);
  margin-inline: auto;
  padding-inline: max(var(--gutter), env(safe-area-inset-left));
}

.wrap--narrow {
  max-width: var(--max-narrow);
}

.wrap--wide {
  max-width: var(--max-wide);
}

.grid-12 {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--col-gap);
}

.skip-link {
  position: absolute;
  top: var(--s2);
  left: var(--s2);
  z-index: 100;
  padding: var(--s3) var(--s4);
  background: var(--fg);
  color: var(--bg);
  font-weight: var(--w-strong);
  transform: translateY(-200%);
}

.skip-link:focus {
  transform: translateY(0);
}

/* Type ---------------------------------------------------------------- */

h1 {
  font-weight: var(--w-display);
  font-stretch: var(--stretch-wide);
  font-size: var(--fs-title);
  line-height: var(--lh-tight);
  letter-spacing: -0.02em;
  /* Long words (German pages) break at the line end instead of running off the screen. */
  overflow-wrap: break-word;
  hyphens: auto;
}

h2 {
  font-weight: var(--w-display);
  font-stretch: var(--stretch-wide);
  font-size: var(--fs-h2);
  line-height: 1.1;
  letter-spacing: -0.015em;
  padding-right: var(--s8); /* room for the arrow in the corner */
  overflow-wrap: anywhere;
  hyphens: auto;
}

h3 {
  font-weight: var(--w-strong);
  font-stretch: var(--stretch-mid);
  font-size: var(--fs-h3);
  line-height: 1.3;
}

.label {
  font-weight: var(--w-strong);
  font-stretch: var(--stretch-text);
  font-size: var(--fs-label);
  line-height: 1.25rem;
  letter-spacing: 0.01em;
}

.lead {
  max-width: var(--measure);
  font-weight: 500;
  font-stretch: var(--stretch-wide);
  font-size: var(--fs-lead);
  line-height: 1.4;
}

.muted {
  color: var(--mute);
  font-size: var(--fs-small);
}

/* Link ---------------------------------------------------------------- */

.link,
.prose a:not(.btn),
.site-footer a {
  text-decoration: underline;
  text-decoration-thickness: var(--bw-thin);
  text-underline-offset: 3px;
  transition: color var(--dur-press) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .link:hover,
  .prose a:not(.btn):hover,
  .site-footer a:hover {
    color: var(--accent);
    text-decoration-thickness: var(--bw);
  }
}

/* Button: link or button element. The fill runs in from the left. ------- */

.btn {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s6);
  min-height: var(--btn);
  padding: var(--s2) var(--s6);
  border: var(--bw) solid var(--fg);
  border-radius: var(--radius);
  background: transparent;
  color: var(--fg);
  font-weight: var(--w-strong);
  font-stretch: var(--stretch-mid);
  line-height: 1.4;
  text-decoration: none;
  transition: color var(--dur-ui) var(--ease-out), transform var(--dur-press) var(--ease-out);
}

.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-ui) var(--ease-out);
}

.btn--primary {
  background: var(--fg);
  color: var(--bg);
}

.btn--small {
  min-height: var(--tap);
  padding: var(--s1) var(--s3);
  font-stretch: var(--stretch-text);
  font-size: var(--fs-small);
}

.btn--danger {
  border-color: var(--minus);
}

/* Link button with the arrow icon (Phosphor, bold). */
.btn--arrow {
  display: flex;
  justify-content: space-between;
}

.btn__icon {
  flex: none;
  width: 1.25em;
  height: 1.25em;
  background-color: currentColor;
  -webkit-mask: url("/img/icons/arrow-up-right.svg") center / contain no-repeat;
  mask: url("/img/icons/arrow-up-right.svg") center / contain no-repeat;
  transition: transform var(--dur-ui) var(--ease-out);
}

.btn__icon--download {
  -webkit-mask-image: url("/img/icons/download-simple.svg");
  mask-image: url("/img/icons/download-simple.svg");
}

.btn:focus-visible {
  color: var(--bg);
}

.btn:focus-visible::before {
  transform: scaleX(1);
}

@media (hover: hover) and (pointer: fine) {
  .btn:hover:not([disabled]) {
    color: var(--bg);
  }

  .btn:hover:not([disabled])::before {
    transform: scaleX(1);
  }

  .btn:hover .btn__icon {
    transform: translate(3px, -3px);
  }

  .btn:hover .btn__icon--download {
    transform: translateY(3px);
  }
}

/* Press: fills at once (also on touch, where hover does not exist) and
   shrinks a little. */
.btn:active:not([disabled]) {
  color: var(--bg);
  transform: scale(0.97);
}

.btn:active:not([disabled])::before {
  transform: scaleX(1);
  transition-duration: 0ms;
}

.btn[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}

@media (min-width: 1024px) {
  .btn--arrow {
    min-height: calc(var(--btn) + var(--s2));
    padding-inline: var(--s6);
    font-size: var(--fs-h3);
  }
}

/* Header -------------------------------------------------------------- */

.site-header {
  padding-block: var(--s6) var(--s2);
}

.site-header__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2) var(--s8);
}

.site-header__logo {
  display: block;
  width: min(280px, 100%);
  line-height: 0;
}

.site-header__nav {
  display: flex;
  gap: var(--s6);
}

.site-header__nav a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-weight: var(--w-strong);
  font-stretch: var(--stretch-mid);
  text-decoration: none;
  transition: color var(--dur-press) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .site-header__nav a:hover {
    color: var(--accent);
  }
}

@media (min-width: 768px) {
  .site-header {
    padding-block: var(--s8) var(--s4);
  }
}

/* Footer -------------------------------------------------------------- */

.site-footer {
  margin-top: var(--s24);
  border-top: var(--bw-thin) solid var(--line-quiet);
  padding-block: var(--s12);
  font-size: var(--fs-small);
  line-height: var(--lh-body);
}

.site-footer__inner {
  row-gap: var(--s8);
  align-items: end;
}

.site-footer__disclosure,
.site-footer__nav,
.site-footer__badge {
  grid-column: 1 / -1;
}

.site-footer__disclosure .label {
  margin-bottom: var(--s2);
}

.site-footer__disclosure p:last-child {
  max-width: 46ch;
}

.site-footer__nav ul {
  display: flex;
  flex-wrap: wrap;
  column-gap: var(--s6);
}

/* 44px tap targets without making the links look bigger. */
.site-footer__nav a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
}

.site-footer__badge {
  width: 64px;
  height: 64px;
}

@media (min-width: 768px) {
  .site-footer__disclosure {
    grid-column: 1 / span 6;
  }

  .site-footer__nav {
    grid-column: 7 / span 4;
  }

  .site-footer__badge {
    grid-column: 12 / -1;
    justify-self: end;
  }
}

/* Prose page (imprint, privacy, 404) ----------------------------------- */

.prose {
  max-width: var(--measure);
  padding-block: var(--s8) 0;
}

.prose h1 {
  margin-bottom: var(--s8);
}

.prose h2 {
  margin-top: var(--s12);
  margin-bottom: var(--s2);
  font-weight: var(--w-strong);
  font-stretch: var(--stretch-mid);
  font-size: var(--fs-h3);
  line-height: 1.4;
  letter-spacing: 0;
}

.prose p + p,
.prose p + ul,
.prose ul + p {
  margin-top: var(--s4);
}

.prose .btn {
  margin-top: var(--s8);
}

.prose .updated {
  margin-top: var(--s12);
}

/* Card ---------------------------------------------------------------- */

.card,
.panel {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.panel {
  max-width: 560px;
  margin-bottom: var(--s6);
  padding: var(--s6);
}

.panel--wide {
  max-width: none;
}

/* Form field ---------------------------------------------------------- */

.field {
  margin-bottom: var(--s4);
}

.field label {
  display: block;
  margin-bottom: var(--s2);
  font-weight: var(--w-strong);
}

.field input[type="text"],
.field input[type="email"],
.field input[type="password"],
.field input[type="date"],
.field input[type="time"],
.field input[type="url"] {
  width: 100%;
  min-height: var(--field);
  padding: var(--s3) var(--s4);
  border: var(--bw) solid var(--fg);
  border-radius: var(--radius);
  background: var(--bg);
}

.check {
  display: flex;
  gap: var(--s3);
  align-items: flex-start;
  margin-bottom: var(--s4);
  font-size: var(--fs-small);
}

.check input {
  flex: none;
  width: var(--s6);
  height: var(--s6);
  margin: var(--s1) 0 0;
  accent-color: var(--accent);
}

.field input[type="number"] {
  width: 100%;
  min-height: var(--field);
  padding: var(--s3) var(--s4);
  border: var(--bw) solid var(--fg);
  border-radius: var(--radius);
  background: var(--bg);
  font-variant-numeric: tabular-nums;
}

.field input[aria-invalid="true"] {
  border-color: var(--minus);
}

.field .hint {
  margin-top: var(--s1);
  color: var(--mute);
  font-size: var(--fs-small);
}

/* Choice: a row of radio buttons that look like buttons. The input stays
   in the page (keyboard and screen reader work), the label shows the state. */
.choice {
  min-width: 0;
  margin: 0 0 var(--s4);
  padding: 0;
  border: 0;
}

.choice legend {
  margin-bottom: var(--s2);
  padding: 0;
  font-weight: var(--w-strong);
}

.choice__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}

.choice label {
  position: relative;
  display: block;
}

.choice input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.choice span {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  padding: var(--s2) var(--s4);
  border: var(--bw) solid var(--line);
  border-radius: var(--radius);
  font-weight: var(--w-strong);
  font-size: var(--fs-small);
}

.choice input:checked + span {
  border-color: var(--fg);
  background: var(--fg);
  color: var(--bg);
}

.choice input:focus-visible + span {
  outline: var(--focus) solid var(--accent);
  outline-offset: var(--focus-offset);
}

@media (hover: hover) and (pointer: fine) {
  .choice input:not(:checked):hover + span {
    border-color: var(--fg);
  }
}

/* Message: one line above a form. Error in plum, success in violet. */
.msg {
  margin: 0 0 var(--s4);
  padding: var(--s3) var(--s4);
  border: var(--bw) solid var(--line);
  font-weight: var(--w-strong);
}

.msg--error {
  border-color: var(--minus);
}

.msg--ok {
  border-color: var(--accent);
}

/* Table --------------------------------------------------------------- */

.tablewrap {
  overflow-x: auto;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-small);
}

th,
td {
  padding: var(--s3) var(--s2);
  border-bottom: var(--bw-thin) solid var(--line);
  text-align: left;
  vertical-align: top;
}

th {
  font-weight: var(--w-strong);
  font-stretch: var(--stretch-mid);
}

td.num,
th.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Badge --------------------------------------------------------------- */

.badge {
  display: inline-block;
  padding: var(--s1) var(--s3);
  border: var(--bw) solid var(--line);
  font-weight: var(--w-strong);
  font-size: var(--fs-label);
}

.badge--freigegeben {
  border-color: var(--accent);
  color: var(--accent);
}

.badge--gesperrt {
  border-color: var(--minus);
}

/* Account bar (members area): name, log out, links ------------------------ */

.who {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3);
  align-items: center;
  margin-top: var(--s4);
}

.who__name {
  flex: 1 1 100%;
  min-height: calc(var(--fs-body) * var(--lh-body));
  font-weight: var(--w-strong);
}

/* Link cards: a button with a title and a line of text (tools overview, members overview). */
.card-links {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
  gap: var(--s4);
  padding-block: var(--s6) 0;
}

.card-link {
  align-items: flex-start;
  min-height: 200px;
  padding: var(--s6);
  text-align: left;
}

.card-link__text {
  display: grid;
  gap: var(--s2);
}

.card-link__title {
  font-weight: var(--w-display);
  font-stretch: var(--stretch-wide);
  font-size: var(--fs-h2);
  line-height: 1.1;
  letter-spacing: -0.015em;
}

.card-link__desc {
  max-width: 36ch;
  font-weight: var(--w-text);
  font-stretch: var(--stretch-text);
  font-size: var(--fs-small);
  line-height: var(--lh-body);
}

/* Toast --------------------------------------------------------------- */

.toast {
  position: fixed;
  left: 50%;
  bottom: max(var(--s6), env(safe-area-inset-bottom));
  z-index: 80;
  max-width: 90vw;
  padding: var(--s3) var(--s4);
  background: var(--fg);
  color: var(--bg);
  font-weight: var(--w-strong);
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, var(--s4));
  transition: opacity var(--dur-exit) var(--ease-out), transform var(--dur-exit) var(--ease-out);
}

.toast.on {
  opacity: 1;
  transform: translate(-50%, 0);
  transition-duration: var(--dur-ui);
}

/* Motion -------------------------------------------------------------- */
/* Only transform and opacity, plus one clip-path reveal per image. No
   transition: all. Hover effects sit inside (hover: hover) and
   (pointer: fine) above. Exit is faster than enter. */

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(var(--rise));
  }

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

@keyframes fade {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

@keyframes settle {
  from {
    transform: scale(1.08);
  }

  to {
    transform: scale(1);
  }
}

@media (prefers-reduced-motion: no-preference) {
  /* Load sequence (runs by itself, no script): add .rise and a step with
     .rise--1 ... .rise--9. One step is --stagger (120ms). --delay shifts a whole group. */
  .rise {
    animation: rise var(--dur-enter) var(--ease-out) both;
    animation-delay: calc(var(--delay, 0ms) + var(--i, 0) * var(--stagger));
  }

  .rise--1 { --i: 1; }
  .rise--2 { --i: 2; }
  .rise--3 { --i: 3; }
  .rise--4 { --i: 4; }
  .rise--5 { --i: 5; }
  .rise--6 { --i: 6; }
  .rise--7 { --i: 7; }
  .rise--8 { --i: 8; }
  .rise--9 { --i: 9; }

  /* Scroll reveals, both ways: js/main.js adds .is-in when the element is
     100px inside the viewport and takes it away again when the element sinks
     back below the bottom edge (scrolling up), so it builds up again on the
     way down. The way out is quicker (--dur-leave) and has no stagger. Only
     when scripting is on, so nothing stays hidden if the script does not
     run. */
  @media (scripting: enabled) {
    /* Block: fades in and rises. Add .reveal and, for a cascade, .rise--N. */
    .reveal {
      opacity: 0;
      transform: translateY(var(--rise-lg));
      transition: opacity var(--dur-leave) var(--ease-in-out), transform var(--dur-leave) var(--ease-in-out);
    }

    .reveal.is-in {
      opacity: 1;
      transform: translateY(0);
      transition: opacity var(--dur-reveal) var(--ease-out), transform var(--dur-reveal) var(--ease-out);
      transition-delay: calc(var(--delay, 0ms) + var(--i, 0) * var(--stagger));
    }

    /* Image: uncovered from the top. */
    [data-reveal] {
      clip-path: inset(0 0 100% 0);
      transition: clip-path var(--dur-leave) var(--ease-in-out);
    }

    [data-reveal].is-in {
      clip-path: inset(0);
      transition: clip-path var(--dur-reveal) var(--ease-in-out);
      transition-delay: var(--delay, 0ms);
    }

    /* Rule that draws itself from the left. The element needs position:
       relative and data-line. */
    [data-line]::before {
      transform: scaleX(0);
      transition: transform var(--dur-leave) var(--ease-in-out);
    }

    [data-line].is-in::before {
      transform: scaleX(1);
      transition: transform var(--dur-draw) var(--ease-in-out);
    }
  }

  /* Image settles while it enters the screen. Browsers without scroll
     timelines show the plain image. */
  @supports (animation-timeline: view()) {
    .settle {
      animation: settle linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 55%;
    }
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .rise {
    animation: fade 200ms var(--ease-out) both;
  }

  .btn,
  .toast {
    transition-property: opacity, color;
  }

  .btn:active:not([disabled]) {
    transform: none;
  }

  .btn::before {
    transition: none;
  }

  .toast,
  .toast.on {
    transform: translate(-50%, 0);
  }
}
