/*
  The look of the landing page of frei. It follows the onboarding story of the app.

  The sources are `Frei/Onboarding/OnboardingView.swift`, `Frei/Onboarding/Onboarding.swift` and
  `Frei/Style/Theme.swift`. Section 9.2 of `docs/spec.md` has the rules of the look.

  The page has two layouts.
  - The plain layout: all text shows, one part after the other. A browser with no script and a
    visitor with "Reduce Motion" get it.
  - The story layout, with the class `story-on` on the root: the text holds its place and comes in
    with the scroll, as in the app. `story.js` sets each place.
*/

:root {
  /* The darkest blue of the sky. It makes the sky darker behind white text. */
  --navy: #021a4c;
  --on-sky: #fff;
  /* The scale of a wide window: the size of each part there, as a part of its size in the first
     draft. Change this one number to make all parts of a wide window larger or smaller.
     A phone does not use it. A phone has the sizes of the app. */
  --desktop-scale: 0.7;
  /* The text size of a passage. The app has 28 points. */
  --fs: 28px;
  /* The text size of a button. The app has 17 points. */
  --ui: 17px;
  /* The text size of the links and of the scroll hint. The app has 12 and 13 points. */
  --small: 12px;
  --hint: 13px;
  /* The left and right margin of the text. */
  --margin: 28px;
  /* The left and right margin of the small word mark and of the footer. `story.js` has the same
     rule for the word mark of the start page. */
  --edge: clamp(28px, 3vw, 44px);
  /* The largest width of the text: 460 points at 28 points of text, as in the app. */
  --column: calc(var(--fs) * 16.43);
  /* The width of the word mark at the start: 32% of the width of a phone. */
  --wordmark: 32vw;
  --wordmark-height: calc(var(--wordmark) * 138 / 272);
  /* The space between the word mark and the subline, and the height of one line of the subline. */
  --subline-size: calc(var(--fs) * 0.714);
  --subline-gap: var(--subline-size);
  --subline-height: calc(var(--subline-size) * 1.3);
  /* The room at the upper and at the lower edge. `story.js` sets the two values for the story layout. */
  --safe-top: 12px;
  --safe-bottom: 12px;
}

/* A wide window. The first number of each line is the size in the first draft. The pictures, the
   subline, the text column, the button and the small word mark take their sizes from these values. */
@media (min-width: 520px) {
  :root {
    --fs: calc(40px * var(--desktop-scale));
    --ui: calc(20px * var(--desktop-scale));
    /* A text of less than 11 pixels is hard to read. */
    --small: max(11px, calc(14px * var(--desktop-scale)));
    --hint: max(11px, calc(13px * var(--desktop-scale)));
    --wordmark: calc(240px * var(--desktop-scale));
  }
}

* { box-sizing: border-box; }

html {
  background: #00357f;
  color-scheme: dark;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  color: var(--on-sky);
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Text for a screen reader only. */
.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- The sky ---------- */

/* A still sky of gradients. `sky.js` draws the real sky on top of it. */
.sky {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  background-color: #00357f;
  background-image:
    radial-gradient(ellipse 60% 34% at 33% 104%, rgba(242, 100, 76, 0.9) 0%, rgba(214, 108, 112, 0.45) 42%, rgba(200, 112, 124, 0) 100%),
    radial-gradient(ellipse 56% 42% at 104% 66%, #00b4ea 0%, rgba(0, 152, 226, 0.55) 45%, rgba(0, 102, 204, 0) 100%),
    radial-gradient(ellipse 52% 34% at 36% 30%, #001a48 0%, rgba(0, 36, 96, 0.6) 50%, rgba(0, 36, 96, 0) 100%),
    linear-gradient(#003078, #003a88 60%, #003c8c);
}

.sky-mesh,
.sky-specks,
.sky-grain {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.sky-specks { mix-blend-mode: screen; }

@supports (mix-blend-mode: plus-lighter) {
  .sky-specks { mix-blend-mode: plus-lighter; }
}

.sky-grain { background-repeat: repeat; }

/* ---------- The start ---------- */

.stage {
  position: relative;
  z-index: 1;
}

.hero {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  min-height: 100svh;
  padding: 0 var(--margin);
}

.wordmark {
  width: var(--wordmark);
  margin: 0;
  line-height: 0;
}

.wordmark img {
  display: block;
  width: 100%;
  height: auto;
}

.subline {
  margin: var(--subline-gap) 0 0;
  font-size: var(--subline-size);
  font-weight: 500;
  line-height: 1.3;
  text-align: center;
  text-shadow: 0 0 20px rgba(2, 26, 76, 0.35);
}

.subline span,
.hint span { display: block; }

/* The hint that the page scrolls. */
.hint {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 30px;
  margin: 0;
  color: rgba(255, 255, 255, 0.78);
  font-size: var(--hint);
  font-weight: 500;
  line-height: 1.385;
  letter-spacing: 0.03em;
  text-align: center;
}

.hint svg {
  display: block;
  width: calc(var(--hint) * 1.69);
  height: calc(var(--hint) * 0.615);
  margin: calc(var(--hint) * 0.6) auto 0;
}

/* The word mark comes in: it fades in and grows a little. Then the subline and the hint fade in. */
@keyframes wordmark-in {
  from { opacity: 0; transform: scale(0.92); }
  to { opacity: 1; transform: none; }
}

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

.js .wordmark img { animation: wordmark-in 0.6s ease-out both; }

.js .subline span,
.js .hint span { animation: fade-in 0.7s ease-out 0.65s both; }

/* `?at=`: the page jumps to a place of the story for a screenshot. Nothing comes in then. */
.no-intro .wordmark img,
.no-intro .subline span,
.no-intro .hint span { animation: none; }

.no-intro .field { transition: none; }

/* ---------- The passages ---------- */

.passages { padding: 0 var(--margin); }

/* `--block` is the width of the longest line of a passage. `story.js` sets it. The passage is then
   as wide as its text, and the text is in the centre of the window. */
.passage {
  max-width: var(--block, var(--column));
  margin: 0 auto;
  padding: 16vh 0;
  font-size: var(--fs);
  font-weight: 600;
  line-height: 1.393;
  letter-spacing: -0.0107em;
  /* Lines of about the same length, where the browser can do it. `story.js` does the same for
     each browser with a script. */
  text-wrap: balance;
  /* The soft shadow of the text and of its pictures. */
  filter: drop-shadow(0 1px 12px rgba(2, 26, 76, 0.3));
}

/* No line break between a picture and the words on its two sides. */
.nb { white-space: nowrap; }

/* A picture in a line of a passage. Its place in the line has the height of a capital letter, so the
   picture goes a little over the lines above and below, and the line keeps its height. */
.art {
  width: 1.643em;
  height: 1.643em;
  margin: -0.4645em -0.0495em;
  vertical-align: baseline;
}

/* One character of a passage. `story.js` makes these and sets how far each one shows. */
.c { position: relative; }

/* ---------- The end of the start page: the button ---------- */

.end {
  position: relative;
  isolation: isolate;
  padding: 28px 24px calc(var(--safe-bottom) + 4px);
}

/* A layer of the darkest blue of the sky behind the button. */
.end::before {
  content: "";
  position: absolute;
  inset: -60px 0 0;
  z-index: -1;
  background: linear-gradient(to bottom, rgba(2, 26, 76, 0) 0%, rgba(2, 26, 76, 0.5) 35%, rgba(2, 26, 76, 0.58) 100%);
  pointer-events: none;
}

.end-inner {
  max-width: calc(var(--column) + 8px);
  margin: 0 auto;
}

/* The plain layout: the button is directly under the last passage, one line below its last line. */
.story .passage:last-child { padding-bottom: 0; }

.story .end {
  padding-top: calc(var(--fs) * 1.393);
  padding-bottom: 16vh;
}

/* The button and the field are in the centre, one above the other. They have the same width: the
   width of the text of the last passage (`--button`, from `story.js`), with a maximum. */
.waitlist {
  --control: min(100%, var(--button, 100%), calc(var(--ui) * 24));
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* A field that a person does not see and leaves empty. A program fills it: lib/signup.ts. */
.trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* The main button: glass, with a white label.
   This rule is the glass of the style sheet: a blur of the sky, a light gradient and a thin bright
   edge. `glass.js` draws a better glass with a shader. It then sets the class `has-shader`. */
.primary {
  position: relative;
  display: block;
  width: var(--control);
  min-width: min(100%, calc(var(--ui) * 11.5));
  min-height: calc(var(--ui) * 3.18);
  padding: 0 calc(var(--ui) * 1.2);
  border: 0;
  border-radius: 999px;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0.24), rgba(255, 255, 255, 0.09));
  -webkit-backdrop-filter: blur(16px) saturate(1.5);
  backdrop-filter: blur(16px) saturate(1.5);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.2),
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 -1px 0 rgba(255, 255, 255, 0.22);
  color: var(--on-sky);
  font: inherit;
  font-size: var(--ui);
  font-weight: 600;
  cursor: pointer;
  transition: transform 0.18s ease, filter 0.18s ease;
  -webkit-tap-highlight-color: transparent;
}

/* The pointer is on the button: the glass gets a little brighter. */
.primary:hover { filter: brightness(1.12); }

/* A press: the button gets a little smaller, as glass of the app under a finger. */
.primary:active { transform: scale(0.97); }

/* The shader draws the glass and its light, so the style sheet draws none. */
.has-shader .primary,
.has-shader .primary:hover {
  background: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: none;
  filter: none;
}

/* The canvas of the shader. It has the size of the button. */
.glass {
  display: none;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.has-shader .glass { display: block; }

.label {
  position: relative;
  text-shadow: 0 1px 8px rgba(2, 26, 76, 0.4);
}

/* The field for the email address. It has the form of the second button of the app: dark glass.
   It is as wide as the button, so that nothing moves to the side when it opens. */
.field {
  width: var(--control);
  min-width: min(100%, calc(var(--ui) * 11.5));
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  visibility: hidden;
  transition: grid-template-rows 0.3s ease, opacity 0.3s ease, visibility 0s linear 0.3s;
}

.field > div {
  min-height: 0;
  overflow: hidden;
}

.is-open .field,
.no-js .field {
  grid-template-rows: 1fr;
  opacity: 1;
  visibility: visible;
  transition-delay: 0s;
}

/* The request runs: the button waits. */
.is-busy .primary {
  opacity: 0.6;
  cursor: progress;
}

/* The line of a failure, under the button. */
.note {
  max-width: calc(var(--ui) * 24);
  margin: calc(var(--ui) * 0.7) 0 0;
  color: rgba(255, 255, 255, 0.84);
  font-size: var(--small);
  font-weight: 500;
  line-height: 1.35;
  text-align: center;
}

.note[hidden] { display: none; }

.field input {
  display: block;
  width: 100%;
  height: calc(var(--ui) * 3.18);
  margin: 0 0 12px;
  padding: 0 calc(var(--ui) * 1.4);
  border: 1px solid rgba(132, 174, 255, 0.22);
  border-radius: 999px;
  background: rgba(2, 26, 76, 0.62);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  backdrop-filter: blur(18px) saturate(1.4);
  color: var(--on-sky);
  font: inherit;
  font-size: var(--ui);
  font-weight: 600;
  text-align: center;
  -webkit-appearance: none;
  appearance: none;
}

.field input:focus {
  /* The field is in a box that cuts an outline. The line of the field itself gets bright. */
  border-color: rgba(255, 255, 255, 0.72);
  outline: none;
}

.field input::placeholder {
  color: rgba(255, 255, 255, 0.6);
  opacity: 1;
}

.thanks {
  display: none;
  align-items: center;
  justify-content: center;
  max-width: calc(var(--ui) * 28);
  min-height: calc(var(--ui) * 3.18);
  margin: 0;
  font-size: var(--ui);
  font-weight: 500;
  line-height: 1.35;
  text-align: center;
  outline: none;
}

.is-done .field,
.is-done .primary { display: none; }

.is-done .thanks { display: flex; }

/* ---------- The footer: the links and the language menu ---------- */

/* Each page has one footer. It is the last part of the page.
   - A phone: the links are in the centre, and the language menu is in the centre under them.
   - A wide window: the links are at the left and the language menu is at the right. The side
     margin is the margin of the small word mark, so the links start under the word mark.
   On the start page with the story layout, the footer is at the lower edge of the window: see
   "The story layout". On each other page it is at the end of the page, and it is not fixed. */
.foot {
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  /* The room under the footer grows with the height of the window, as the room of `story.js`
     does. A phone adds its safe area: the bar of the home indicator, and a round corner. */
  padding: 20px max(var(--edge), env(safe-area-inset-right, 0px)) calc(clamp(12px, 3vh, 32px) + env(safe-area-inset-bottom, 0px)) max(var(--edge), env(safe-area-inset-left, 0px));
  font-size: var(--small);
  line-height: 1.35;
}

/* A layer of the darkest blue of the sky behind the footer of a text page. */
.foot::before {
  content: "";
  position: absolute;
  inset: -60px 0 0;
  z-index: -1;
  background: linear-gradient(to bottom, rgba(2, 26, 76, 0) 0%, rgba(2, 26, 76, 0.5) 35%, rgba(2, 26, 76, 0.58) 100%);
  pointer-events: none;
}

/* The plain layout of the start page: the layer of the end goes on behind the footer. */
.stage .foot::before {
  inset: 0;
  background: rgba(2, 26, 76, 0.58);
}

/* The row has four links, in two pairs. When the row is too wide for a phone, the second pair
   goes to a second line: two links in each line. No link breaks in its own text. */
.links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 18px;
  min-width: 0;
}

.links .pair {
  display: flex;
  gap: 18px;
}

.links a {
  padding: 8px 4px;
  white-space: nowrap;
  color: rgba(255, 255, 255, 0.62);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.links a:hover { color: rgba(255, 255, 255, 0.84); }

.langs { flex: none; }

/* The language menu: a `<details>` element. Its summary is a small button of glass with the
   language of the page and a mark. Its list opens upward, because the footer is at the lower edge.
   The menu works with no script. `menu.js` closes it after a press outside and after Escape. */
.menu { position: relative; }

.menu summary {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 8px 12px 8px 14px;
  border-radius: 999px;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.05));
  -webkit-backdrop-filter: blur(16px) saturate(1.5);
  backdrop-filter: blur(16px) saturate(1.5);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.16),
    inset 0 1px 0 rgba(255, 255, 255, 0.42),
    inset 0 -1px 0 rgba(255, 255, 255, 0.16);
  color: rgba(255, 255, 255, 0.84);
  font-weight: 500;
  white-space: nowrap;
  list-style: none;
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

/* No triangle of the browser: the summary has a mark of its own. */
.menu summary::-webkit-details-marker { display: none; }

.menu summary:hover { filter: brightness(1.12); }

/* The mark points up: the list opens upward. It turns when the list is open. */
.menu summary svg {
  flex: none;
  width: 9px;
  height: 5.25px;
  transition: transform 0.18s ease;
}

.menu[open] summary svg { transform: rotate(180deg); }

/* The list, above the summary. It is dark glass, and it lets little through: on a phone it is
   above the links, and a link must not show through its text. */
.menu ul {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  min-width: 100%;
  margin: 0;
  padding: 5px;
  transform: translateX(-50%);
  border-radius: 15px;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.04)), rgba(4, 30, 84, 0.93);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  backdrop-filter: blur(18px) saturate(1.4);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.16),
    inset 0 1px 0 rgba(255, 255, 255, 0.36),
    0 8px 24px rgba(2, 26, 76, 0.35);
  list-style: none;
}

.menu li a,
.menu li span {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 8px 11px;
  border-radius: 10px;
  white-space: nowrap;
}

.menu li a {
  color: rgba(255, 255, 255, 0.78);
  text-decoration: none;
}

.menu li a:hover {
  background: rgba(255, 255, 255, 0.12);
  color: var(--on-sky);
}

/* The language of the page: brighter, with a check mark. */
.menu li span {
  color: var(--on-sky);
  font-weight: 600;
}

.menu li span::after {
  content: "";
  width: 4px;
  height: 8px;
  margin: -2px 3px 0 0;
  border: solid currentColor;
  border-width: 0 1.6px 1.6px 0;
  transform: rotate(45deg);
}

@media (min-width: 520px) {
  .foot {
    flex-direction: row;
    justify-content: space-between;
    gap: 16px;
  }

  /* A link has a padding of 4 pixels. The text of the first link starts at the margin. */
  .foot .links {
    justify-content: flex-start;
    margin-left: -4px;
  }

  /* The right edge of the list is the right edge of the summary. */
  .menu ul {
    left: auto;
    right: 0;
    transform: none;
  }
}

.primary:focus-visible,
.links a:focus-visible,
.menu summary:focus-visible,
.menu a:focus-visible,
.text a:focus-visible,
.home:focus-visible {
  outline: 2px solid var(--on-sky);
  outline-offset: 3px;
}

.menu a:focus-visible { outline-offset: -2px; }

/* ---------- The story layout ---------- */

/* The page is empty space with the length of the story. The stage does not scroll: it fills the
   window, and each part takes its place and its opacity from the scroll position. */
.story-on .story {
  height: calc(100vh + var(--total, 1200px));
  height: calc(100lvh + var(--total, 1200px));
}

.story-on .stage {
  position: fixed;
  inset: 0;
  overflow: hidden;
}

.story-on .hero,
.story-on .passages { display: contents; }

/* The word mark and the subline are one group in the centre of the window. */
.story-on .wordmark {
  position: absolute;
  left: calc(50% - var(--wordmark) / 2);
  top: calc(50% - (var(--wordmark-height) + var(--subline-gap) + var(--subline-height)) / 2);
  transform-origin: 50% 50%;
  will-change: transform;
}

.story-on .subline {
  position: absolute;
  left: var(--margin);
  right: var(--margin);
  top: calc(50% + (var(--wordmark-height) + var(--subline-gap) - var(--subline-height)) / 2);
  margin: 0;
}

.story-on .hint {
  top: calc(100% - var(--safe-bottom) - 62px);
  bottom: auto;
}

/* `story.js` puts each passage in the centre of the window, with the width of its longest line. */
.story-on .passage {
  position: absolute;
  left: 0;
  top: 0;
  width: min(var(--block, var(--column)), calc(100% - 2 * var(--margin)));
  max-width: none;
  margin: 0;
  padding: 0;
  opacity: 0;
  will-change: transform, opacity;
}

.story-on .passage .c,
.story-on .passage .art { opacity: 0; }

/* The soft dark layer behind a passage, where the sky is bright. It has no edge. */
.passage-scrim {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  opacity: 0;
  background: linear-gradient(to bottom, rgba(2, 26, 76, 0) 0%, var(--navy) 30%, var(--navy) 70%, rgba(2, 26, 76, 0) 100%);
  pointer-events: none;
}

/* The button is directly under the last passage. `story.js` sets the place.
   The room under the button is the room of the row of links that was there until 2026-10-13: 8
   pixels and one line of links. The last passage, the button and this room are one group, and
   `story.js` puts the group in its place. So the text and the button have the places of the look
   that the owner approved. */
.story-on .end {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  padding: 0 var(--margin) calc(var(--small) * 1.35 + 24px);
  opacity: 0;
  pointer-events: none;
}

/* The soft dark layer of the last passage is behind the button. */
.story-on .end::before { display: none; }

/* The footer is at the lower edge of the window. It belongs to the last frame: it comes in with the
   button, and `story.js` sets its opacity. The side margin is a part of the width of the stage, as
   the margin of the word mark in `story.js`. */
.story-on .stage .foot {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding-top: 0;
  padding-right: max(clamp(28px, 3%, 44px), env(safe-area-inset-right, 0px));
  padding-left: max(clamp(28px, 3%, 44px), env(safe-area-inset-left, 0px));
  opacity: 0;
  pointer-events: none;
}

.story-on .stage .foot::before { display: none; }

/* ---------- A text page: privacy, terms, imprint ---------- */

.text-page {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
}

/* The small word mark at the upper left corner. It goes to the start page. */
.home {
  display: block;
  width: calc(var(--fs) * 2.07);
  margin: calc(var(--fs) * 0.9) 0 0 var(--edge);
  line-height: 0;
}

.home img {
  display: block;
  width: 100%;
  height: auto;
}

.text {
  flex: 1;
  width: min(var(--column), calc(100% - 2 * var(--margin)));
  margin: 0 auto;
  padding: 18vh 0 10vh;
  filter: drop-shadow(0 1px 12px rgba(2, 26, 76, 0.3));
}

.text h1 {
  margin: 0;
  font-size: var(--fs);
  font-weight: 600;
  line-height: 1.393;
  letter-spacing: -0.0107em;
}

.text p {
  margin: 0.5em 0 0;
  color: rgba(255, 255, 255, 0.84);
  font-size: var(--subline-size);
  font-weight: 500;
  line-height: 1.4;
}

.text a { color: inherit; }

/* The one button of the page of a link of the email. It is the button of the start page, with the glass of the style sheet. */
.action {
  --control: min(100%, calc(var(--ui) * 20));
  margin: calc(var(--fs) * 0.9) 0 0;
}

/* ---------- The contact form ---------- */

/* The two fields and the button of the contact page, one under the other. A field has the dark
   glass of the field of the start page. The button is the button of the start page. */
.contact {
  --control: min(100%, calc(var(--ui) * 20));
  margin: calc(var(--fs) * 0.9) 0 0;
}

.contact > label {
  display: block;
  margin: 0 0 6px;
  color: rgba(255, 255, 255, 0.84);
  font-size: var(--subline-size);
  font-weight: 500;
  line-height: 1.4;
}

.contact > input,
.contact textarea {
  display: block;
  width: 100%;
  margin: 0 0 calc(var(--ui) * 1.1);
  padding: calc(var(--ui) * 0.8) calc(var(--ui) * 1.1);
  border: 1px solid rgba(132, 174, 255, 0.22);
  border-radius: calc(var(--ui) * 1.1);
  background: rgba(2, 26, 76, 0.62);
  color: var(--on-sky);
  font: inherit;
  font-size: var(--ui);
  font-weight: 500;
  line-height: 1.4;
  -webkit-appearance: none;
  appearance: none;
}

.contact textarea {
  min-height: calc(var(--ui) * 9);
  resize: vertical;
}

.contact > input:focus,
.contact textarea:focus {
  border-color: rgba(255, 255, 255, 0.72);
  outline: none;
}

/* The line about the data, under the button. It is small, and it starts at the left edge, as the text of the page. */
.contact .note {
  max-width: none;
  margin: calc(var(--ui) * 0.9) 0 0;
  color: rgba(255, 255, 255, 0.72);
  font-size: var(--small);
  font-weight: 500;
  line-height: 1.4;
  text-align: left;
}

/* ---------- A legal text: privacy, terms, imprint ---------- */

/* A calm page for a long text: the sky is darker behind it, and the column is wider than a passage. */
.text-page:has(.legal)::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background: rgba(2, 26, 76, 0.72);
  pointer-events: none;
}

.text.legal {
  --read: 16px;
  width: min(680px, calc(100% - 2 * var(--margin)));
  padding: 12vh 0 8vh;
  filter: none;
  color: rgba(255, 255, 255, 0.9);
  font-size: var(--read);
  font-weight: 400;
  line-height: 1.6;
  overflow-wrap: break-word;
}

.legal h1 { color: var(--on-sky); }

.legal h2 {
  margin: 2.4em 0 0;
  color: var(--on-sky);
  font-size: calc(var(--read) * 1.3);
  font-weight: 600;
  line-height: 1.3;
}

.legal h3 {
  margin: 1.8em 0 0;
  color: var(--on-sky);
  font-size: calc(var(--read) * 1.08);
  font-weight: 600;
  line-height: 1.35;
}

.legal p,
.legal li {
  color: inherit;
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
}

.legal p { margin: 0.9em 0 0; }

.legal ul,
.legal ol {
  margin: 0.9em 0 0;
  padding-left: 1.3em;
}

.legal li { margin: 0.4em 0 0; }

.legal li > ul { margin-top: 0.2em; }

.legal strong {
  color: var(--on-sky);
  font-weight: 600;
}

/* A wide table scrolls in its own box. */
.legal .table {
  margin: 1.2em 0 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.legal table {
  width: 100%;
  min-width: 560px;
  border-collapse: collapse;
  font-size: calc(var(--read) * 0.9);
  line-height: 1.5;
}

.legal th,
.legal td {
  padding: 0.6em 0.9em 0.6em 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.18);
  text-align: left;
  vertical-align: top;
}

.legal th {
  color: var(--on-sky);
  font-weight: 600;
}

/* ---------- Reduce Motion ---------- */

@media (prefers-reduced-motion: reduce) {
  /* The word mark only fades in. */
  .js .wordmark img { animation-name: fade-in; }

  .field,
  .primary,
  .menu summary svg { transition: none; }

  .primary:active { transform: none; }
}

/* ---------- Reduce Transparency ---------- */

/* A glass control gets a solid surface and a thin line around it, as in the app. */
@media (prefers-reduced-transparency: reduce) {
  .primary,
  .primary:hover,
  .menu summary,
  .menu summary:hover,
  .menu ul,
  .field input,
  .contact > input,
  .contact textarea {
    background: #0b2f73;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.45);
    filter: none;
  }
}

/* ---------- Safari 26 on an iPhone ---------- */

/* Safari 26 draws no fixed layer behind its status bar and behind its toolbar: the sky ends at the
   two bars. Behind a bar it shows one flat colour, the background colour of the body or of the
   root, and the page content that scrolls under the bar. The colour of the root is the base colour
   of the sky. So the sky goes over into that colour at its upper and at its lower edge, and a bar
   has no hard edge. web/README.md has the tests and the sources.
   The first condition is true for a browser of iOS only. The second one is true from version 26. */
@supports (-webkit-touch-callout: none) and (anchor-name: --frei) {
  .sky::after {
    content: "";
    position: absolute;
    inset: 0;
    background:
      linear-gradient(to bottom, #00357f 0%, rgba(0, 53, 127, 0.74) 24%, rgba(0, 53, 127, 0.36) 56%, rgba(0, 53, 127, 0) 100%) top / 100% 44px no-repeat,
      linear-gradient(to top, #00357f 0%, rgba(0, 53, 127, 0.74) 24%, rgba(0, 53, 127, 0.36) 56%, rgba(0, 53, 127, 0) 100%) bottom / 100% 68px no-repeat;
  }

  /* A legal page has a dark layer on the sky. The colour of the bars is the colour of the root
     under that layer. The background colour of the body comes before the colour of the root. */
  body:has(.legal) { background-color: #01225a; }

  /* The end of a page is at the upper edge of the toolbar. A dark layer behind the footer ends
     there with a hard edge. A text page has no such layer here, and the layer of the plain start
     page ends with no colour. */
  .text-page .foot::before { display: none; }

  .stage .foot::before { background: linear-gradient(to bottom, rgba(2, 26, 76, 0.58), rgba(2, 26, 76, 0)); }
}
