/*
  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 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: the button and the links ---------- */

.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 and the links. */
.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 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;
  margin-top: 8px;
  font-size: var(--small);
  line-height: 1.35;
}

.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,
.langs a:hover { color: rgba(255, 255, 255, 0.84); }

/* The end of the start page: the links, and the language links under them. The box has the height
   of one line of links, and what is under that line is outside the flow of the end. So the text and
   the button have the places that they had with three links in one line: a second line of links
   and the language links move nothing above them. `story.js` reads the height of the end. */
.foot {
  height: calc(var(--small) * 1.35 + 16px);
  margin-top: 8px;
}

.foot .links { margin-top: 0; }

/* The language links: a small, quiet row under the links. */
.langs {
  display: flex;
  justify-content: center;
  gap: 14px;
  margin-top: 2px;
  color: rgba(255, 255, 255, 0.62);
  font-size: var(--small);
  line-height: 1.35;
}

.langs a,
.langs span { padding: 8px 4px; }

.langs a {
  color: rgba(255, 255, 255, 0.46);
  text-decoration: none;
}

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

/* ---------- 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 and the links are directly under the last passage. `story.js` sets the place. */
.story-on .end {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  padding: 0 var(--margin);
  opacity: 0;
  pointer-events: none;
}

/* The soft dark layer of the last passage is behind the button and the links. */
.story-on .end::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 clamp(28px, 3vw, 44px);
  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 { 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,
  .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;
  }
}
