/* jonasmueller.net stylesheet. Plain CSS, custom properties, no framework. */

@font-face {
  font-family: "Inter";
  src: url("../fonts/InterVariable.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* Alegreya (SIL OFL, licence beside the font files) sets the reading text:
   a serif with a calligraphic rhythm that suits the brush headings. Inter
   stays for the header and the hero until those are redesigned. */
@font-face {
  font-family: "Alegreya";
  src: url("../fonts/Alegreya-normal-latin.woff2") format("woff2");
  font-weight: 400 900;
  font-style: normal;
  font-display: swap;
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Alegreya";
  src: url("../fonts/Alegreya-normal-latin-ext.woff2") format("woff2");
  font-weight: 400 900;
  font-style: normal;
  font-display: swap;
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Alegreya";
  src: url("../fonts/Alegreya-italic-latin.woff2") format("woff2");
  font-weight: 400 900;
  font-style: italic;
  font-display: swap;
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Alegreya";
  src: url("../fonts/Alegreya-italic-latin-ext.woff2") format("woff2");
  font-weight: 400 900;
  font-style: italic;
  font-display: swap;
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* Typography scale, major third (1.250). */
  --font-size-base: 1.25rem;
  --font-size-lg: 1.563rem;
  --font-size-xl: 1.953rem;
  --font-size-hero: 2.067em;
  --font-weight-regular: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --letter-spacing-tight: -0.02em;

  /* Spacing scale, major third. */
  --space-2xs: 0.5rem;
  --space-xs: 0.75rem;
  --space-s: 1rem;
  --space-m: 1.25rem;
  --space-l: 1.563rem;
  --space-xl: 1.953rem;
  --space-2xl: 2.441rem;
  --space-3xl: 3.052rem;

  /* Colours. */
  --color-paper: #faf9f5;
  --color-text: rgb(0 0 0 / 87%);
  --color-link: #2c5aa0;
  --color-link-hover: #1e3d6f;
  --color-dark: #222;
  --color-on-dark: rgb(255 255 255 / 90%);

  /* Strength of the decorative ink, below the headings and the text: the
     motifs and dividers are painted fainter than they were drawn so they
     accompany the content rather than compete with it. */
  --ink-motif-opacity: 0.6;
  --ink-divider-opacity: 0.6;

  /* Layout. */
  --header-height: 3.5rem;
  --column-width: 36rem;
  --menu-breakpoint: 62em;

  /* The content is one sheet of paper sliding over the hero; only its top
     edge casts a shadow onto the video. The negative spread cancels the
     blur below the sheet, where it would draw a line across the page. */
  --shadow-paper: 0 -10px 20px -10px rgb(0 0 0 / 25%);
}

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

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

html {
  scroll-behavior: smooth;
  scroll-padding-top: var(--header-height);
  /* The canvas shows when a browser overscrolls past either end of the
     page; dark matches the hero at the top and the footer at the bottom. */
  background-color: var(--color-dark);
}

body {
  margin: 0;
  color: var(--color-text);
  background-color: var(--color-paper);
  font-family: "Alegreya", Georgia, serif;
  font-weight: var(--font-weight-regular);
  font-size: var(--font-size-base);
  /* Alegreya's lowercase is small for its size; matching the x-height to
     half the font size keeps the reading size of the previous sans. */
  font-size-adjust: 0.5;
  line-height: 1.6;
  /* Lining figures: Alegreya's default old-style 1 and 0 are too easily
     read as l and o in dates. */
  font-feature-settings: "kern" 1, "liga" 1, "lnum" 1;
  text-rendering: optimizelegibility;
}

.site-header,
.hero {
  font-family: "Inter", system-ui, sans-serif;
  font-size-adjust: none;
  font-feature-settings: "kern" 1, "liga" 1, "calt" 1, "cv05" 1;
}

body.menu-open {
  overflow: hidden;
}

p,
ul {
  max-width: 35em;
  margin: 0 auto var(--space-m);
  text-wrap: pretty;
}

ul {
  padding-left: var(--space-m);
}

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

a {
  color: var(--color-link);
  text-decoration: underline;
  text-decoration-color: rgb(44 90 160 / 40%);
  text-decoration-skip-ink: auto;
  text-underline-offset: 0.2em;
  transition: color 0.2s ease, text-decoration-color 0.2s ease;
}

a:hover {
  color: var(--color-link-hover);
  text-decoration-color: currentcolor;
  text-decoration-thickness: 0.125em;
}

a:focus-visible {
  outline: 2px solid var(--color-link);
  outline-offset: 2px;
  border-radius: 2px;
}

.icon {
  width: 1em;
  height: 1em;
  vertical-align: middle;
}

.skip-link {
  position: absolute;
  top: -100%;
  left: var(--space-s);
  z-index: 200;
  padding: var(--space-2xs) var(--space-s);
  background: var(--color-paper);
  color: var(--color-link);
  border-radius: 4px;
}

.skip-link:focus {
  top: var(--space-s);
}

.wrap {
  width: min(100% - 2 * var(--space-m), var(--column-width));
  margin-inline: auto;
}

/* ------------------------------------------------------------------ */
/* Headings                                                            */
/* ------------------------------------------------------------------ */

h1 {
  margin: 0;
}

/* Section headings are ink lettering painted over a pale wash, one image
   per heading. Every image shares one canvas, so equal widths give equal
   letter sizes. The images are black with alpha, so they sit on any paper. */
.ink-heading {
  margin: var(--space-l) auto var(--space-xl);
}

.ink-heading img {
  display: block;
  width: min(100%, 30rem);
  height: auto;
  margin-inline: auto;
}

h3 {
  margin: var(--space-2xl) auto var(--space-s);
  font-weight: var(--font-weight-semibold);
  font-size: var(--font-size-lg);
  letter-spacing: var(--letter-spacing-tight);
  text-align: center;
  text-wrap: balance;
}

/* ------------------------------------------------------------------ */
/* Header and navigation                                               */
/* ------------------------------------------------------------------ */

.site-header {
  position: fixed;
  inset: 0 0 auto;
  z-index: 100;
  height: var(--header-height);
  transition: background-color 0.3s ease, box-shadow 0.3s ease;
}

.site-header nav {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
}

/* Three states, set by the client: transparent at the top of the hero,
   frosted glass once the hero scrolls under the header, opaque over the
   paper sections. The glass lives on a pseudo-element because a
   backdrop-filter on the header itself would make it the containing block
   of the fixed-position mobile drawer inside it. */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgb(255 255 255 / 8%);
  border-bottom: 1px solid rgb(255 255 255 / 15%);
  box-shadow: 0 2px 20px rgb(0 0 0 / 10%);
  opacity: 0;
  transition: opacity 0.3s ease;
}

body.is-glass .site-header::before {
  opacity: 1;
  backdrop-filter: blur(15px) brightness(110%) saturate(120%);
}

@supports not (backdrop-filter: blur(15px)) {
  body.is-glass .site-header::before {
    background: rgb(255 255 255 / 25%);
  }
}

body.is-scrolled .site-header {
  background-color: rgb(255 255 255 / 95%);
  box-shadow: 0 1px 0 rgb(0 0 0 / 10%);
}

.nav-list {
  display: flex;
  gap: var(--space-l);
  max-width: none;
  margin: 0;
  padding: 0;
  list-style: none;
}

.nav-list a {
  position: relative;
  display: inline-block;
  padding: 0.25em 0;
  color: var(--color-on-dark);
  font-size: 0.75em;
  letter-spacing: 0.125em;
  text-transform: uppercase;
  text-decoration: none;
  transition: color 0.3s ease;
}

.nav-list a::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 2px;
  background-color: currentcolor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.3s ease;
}

.nav-list a:hover::after,
.nav-list a:focus-visible::after,
.nav-list a[aria-current]::after {
  transform: scaleX(1);
}

.nav-list a:hover,
.nav-list a[aria-current] {
  color: #fff;
}

.nav-list a:focus-visible {
  outline: 2px solid currentcolor;
  outline-offset: 4px;
}

body.is-glass .nav-inline a {
  color: rgb(255 255 255 / 95%);
  text-shadow: 0 1px 3px rgb(0 0 0 / 30%);
}

body.is-glass .nav-inline a:hover,
body.is-glass .nav-inline a[aria-current] {
  color: #fff;
  text-shadow: 0 1px 4px rgb(0 0 0 / 40%);
}

body.is-scrolled .nav-inline a {
  color: var(--color-dark);
}

body.is-scrolled .nav-inline a:hover,
body.is-scrolled .nav-inline a[aria-current] {
  color: var(--color-link);
}

/* Mobile menu: a native disclosure, styled as a drawer. */
.menu {
  display: none;
  position: absolute;
  top: 0;
  left: var(--space-s);
  height: var(--header-height);
}

.menu summary {
  display: flex;
  align-items: center;
  height: 100%;
  padding: 0 var(--space-2xs);
  cursor: pointer;
  list-style: none;
  position: relative;
  z-index: 2;
}

.menu summary::-webkit-details-marker {
  display: none;
}

.menu summary:focus-visible {
  outline: 2px solid var(--color-on-dark);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Over the opaque header the light ring would vanish; open, the icon sits
   on the dark backdrop again. */
body.is-scrolled .menu:not([open]) summary:focus-visible {
  outline-color: var(--color-dark);
}

.hamburger {
  position: relative;
  display: block;
  width: 24px;
  height: 18px;
}

.hamburger span {
  position: absolute;
  left: 0;
  width: 100%;
  height: 2px;
  border-radius: 1px;
  background: var(--color-on-dark);
  transition: transform 0.25s ease, opacity 0.25s ease, top 0.25s ease;
}

.hamburger span:nth-child(1) {
  top: 0;
}

.hamburger span:nth-child(2) {
  top: 8px;
}

.hamburger span:nth-child(3) {
  top: 16px;
}

body.is-glass .hamburger span {
  background: rgb(255 255 255 / 95%);
  box-shadow: 0 1px 2px rgb(0 0 0 / 20%);
}

body.is-scrolled .hamburger span {
  background: var(--color-dark);
}

/* Open, the icon sits on the dark backdrop, not on the panel. */
.menu[open] .hamburger span {
  background: #fff;
}

.menu[open] .hamburger span:nth-child(1) {
  top: 8px;
  transform: rotate(135deg);
}

.menu[open] .hamburger span:nth-child(2) {
  opacity: 0;
}

.menu[open] .hamburger span:nth-child(3) {
  top: 8px;
  transform: rotate(-135deg);
}

.menu[open]::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 1;
  background: rgb(0 0 0 / 50%);
}

.nav-panel {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 0;
  width: min(280px, 85vw);
  height: 100%;
  padding: calc(var(--header-height) + var(--space-l)) var(--space-l);
  /* Short or zoomed viewports: the page behind is locked, so the panel
     itself must scroll to reach its last links. */
  overflow-y: auto;
  background: rgb(255 255 255 / 96%);
  backdrop-filter: blur(20px);
  box-shadow: -8px 0 32px rgb(0 0 0 / 15%);
  transition: transform 0.3s ease;
}

@starting-style {
  .menu[open] .nav-panel {
    transform: translateX(100%);
  }
}

.nav-panel a {
  display: block;
  padding: var(--space-xs) 0;
  color: var(--color-dark);
  font-size: 0.9em;
}

.nav-panel a:hover,
.nav-panel a[aria-current] {
  color: var(--color-link);
}

@media (max-width: 61.99em) {
  .nav-inline {
    display: none;
  }

  .menu {
    display: block;
  }
}

/* ------------------------------------------------------------------ */
/* Hero                                                                */
/* ------------------------------------------------------------------ */

.hero {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  height: 100svh;
  min-height: 25em;
  /* Confine the fixed video to the hero's box. Without this it paints
     wherever the page does not cover the viewport, such as the strip a
     browser reveals when it overscrolls past the footer. */
  clip-path: inset(0);
}

/* The video is fixed in the viewport and clipped to the hero, so the paper
   sections scroll over it, which used to need a scroll-driven transform. */
.hero-video {
  position: fixed;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background-color: var(--color-dark);
}

.hero-overlay {
  position: absolute;
  inset: 0;
  background: radial-gradient(
    ellipse at center,
    rgb(0 0 0 / 75%) 0%,
    rgb(44 62 80 / 50%) 40%,
    rgb(0 0 0 / 30%) 100%
  );
}

.hero-text {
  position: relative;
  width: 100%;
  margin-top: -10vh;
  padding: var(--space-xl) var(--space-m);
  text-align: center;
  background: rgb(255 255 255 / 8%);
  backdrop-filter: blur(20px);
  border-top: 1px solid rgb(255 255 255 / 15%);
  border-bottom: 1px solid rgb(255 255 255 / 15%);
}

@supports not (backdrop-filter: blur(20px)) {
  .hero-text {
    background: rgb(0 0 0 / 25%);
  }
}

.hero-name {
  margin: 0 0 var(--space-l);
  color: rgb(255 255 255 / 85%);
  font-weight: var(--font-weight-regular);
  font-size: var(--font-size-base);
}

.hero-focus {
  max-width: none;
  margin: 0.125em 0 0;
  color: #fff;
  font-weight: 800;
  font-size: var(--font-size-hero);
  letter-spacing: 0.125em;
  line-height: 1.4;
  text-transform: uppercase;
  text-wrap: balance;
}

.scroll-down {
  position: absolute;
  bottom: 2.5em;
  left: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5em;
  height: 2.5em;
  margin-left: -1.25em;
  color: #fff;
  border: 0.125em solid #fff;
  border-radius: 50%;
  text-decoration: none;
}

.scroll-down .icon {
  width: 1.6em;
  height: 1.6em;
  animation: drop 1.5s linear infinite;
}

.scroll-down:focus-visible {
  outline: 2px solid rgb(255 255 255 / 80%);
  outline-offset: 2px;
}

@keyframes drop {
  0% {
    transform: translateY(-0.4em);
    opacity: 0;
  }

  30% {
    transform: translateY(0);
    opacity: 1;
  }

  100% {
    transform: translateY(0.6em);
    opacity: 0;
  }
}

.video-toggle {
  position: absolute;
  right: var(--space-m);
  bottom: var(--space-m);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5em;
  height: 2.5em;
  padding: 0;
  color: #fff;
  background: rgb(0 0 0 / 35%);
  border: 1px solid rgb(255 255 255 / 40%);
  border-radius: 50%;
  cursor: pointer;
  font-size: 0.8em;
}

.video-toggle[hidden] {
  display: none;
}

.video-toggle:hover {
  background: rgb(0 0 0 / 55%);
}

.video-toggle:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

.video-toggle .icon {
  width: 1.2em;
  height: 1.2em;
}

.video-toggle .icon + .icon,
.video-toggle.is-paused .icon:first-child {
  display: none;
}

.video-toggle.is-paused .icon + .icon {
  display: block;
}

/* ------------------------------------------------------------------ */
/* Paper sections                                                      */
/* ------------------------------------------------------------------ */

.paper {
  /* With very large text a long word can outgrow a narrow column; let it
     break rather than push the page sideways. Normal sizes are unaffected. */
  overflow-wrap: anywhere;
  position: relative;
  padding: var(--space-3xl) 0;
  background: var(--color-paper);
  text-align: left;
}

.paper .wrap {
  text-align: center;
}

.paper p,
.paper ul {
  text-align: left;
}

/* A section list shrinks to its longest item, so a list of short entries
   sits centred under the heading instead of hugging the column's left
   edge. Lists of long items still fill the column. */
.section-content > ul {
  width: fit-content;
}

/* The sections form one continuous sheet: the layout already separates
   them, so only the first casts a shadow, upwards onto the hero. */
main > .paper:nth-of-type(2) {
  z-index: 2;
  box-shadow: var(--shadow-paper);
}

.paper-last {
  z-index: 1;
}

.portrait,
.rat {
  width: 11em;
  margin: var(--space-l) auto;
}

.rat {
  width: 10em;
  margin: var(--space-xl) auto;
}

/* ------------------------------------------------------------------ */
/* Social links, footer, back to top                                   */
/* ------------------------------------------------------------------ */

.social-links {
  display: flex;
  justify-content: center;
  gap: 0.6em;
  max-width: none;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Bare icons with a comfortable touch target: no boxes or lift on hover,
   only a change of colour. */
.social-links a {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 2.75rem;
  min-height: 2.75rem;
  font-size: 0.7em;
  border-radius: 0.25em;
  text-decoration: none;
  transition: color 0.2s ease;
}

.social-links .icon {
  width: 1.3em;
  height: 1.3em;
}

.social-links-footer a {
  color: rgb(255 255 255 / 60%);
}

.social-links-footer a:hover {
  color: rgb(255 255 255 / 90%);
}

.social-links-footer a:focus-visible {
  outline-color: rgb(255 255 255 / 80%);
}

.site-footer {
  position: relative;
  z-index: 1;
  padding: 2em 0;
  color: #fff;
  background: var(--color-dark);
  text-align: center;
}

.site-footer p {
  margin: 0 auto 0.5em;
  font-size: 0.8em;
  text-align: center;
}

.scroll-top {
  position: fixed;
  right: 2em;
  bottom: 2em;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5em;
  height: 2.5em;
  color: #fff;
  font-size: 0.7em;
  /* Dark enough for the white chevron to reach 3:1 over the paper. */
  background-color: rgb(60 60 60 / 70%);
  border-radius: 0.25em;
  text-decoration: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0.3s ease, background-color 0.2s ease;
}

.scroll-top .icon {
  width: 1.4em;
  height: 1.4em;
}

body.is-glass .scroll-top,
body.is-scrolled .scroll-top {
  opacity: 1;
  visibility: visible;
}

.scroll-top:hover {
  color: var(--color-link);
  background-color: rgb(235 235 235 / 80%);
}

/* ------------------------------------------------------------------ */
/* Responsive                                                          */
/* ------------------------------------------------------------------ */

@media (max-width: 48em) {
  .hero-text {
    margin-top: -15vh;
    backdrop-filter: blur(15px);
  }

  .hero-focus {
    font-size: 1.6em;
  }
}

@media (max-width: 30em) {
  .hero-focus {
    font-size: 1.4em;
  }
}

/* ------------------------------------------------------------------ */
/* User preferences                                                    */
/* ------------------------------------------------------------------ */

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

  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
  }
}

@media (prefers-contrast: more) {
  body {
    color: #000;
    background-color: #fff;
  }

  .paper,
  .paper-last,
  main > .paper:nth-of-type(2) {
    background: #fff;
  }

  a {
    color: #0000ee;
    text-decoration-thickness: 0.125em;
  }

  .hero-overlay {
    background: rgb(0 0 0 / 90%);
  }

  .hero-text {
    background: rgb(0 0 0 / 80%);
  }
}

/* Forced colours repaint the paper in a system colour, often black, but
   leave images untouched, so the black ink of the headings and the portrait
   would vanish. A white plate behind each keeps it visible in any theme. */
@media (forced-colors: active) {
  .ink-heading img,
  .portrait {
    forced-color-adjust: none;
    background-color: #fff;
  }
}

/* ------------------------------------------------------------------ */
/* Section motifs                                                      */
/* ------------------------------------------------------------------ */

/* The motifs accompany the text only where there is room beside it; on
   narrow screens they would lengthen the page without adding to it. Their
   source only applies from the same breakpoint, so hidden ones are never
   downloaded. */
.motif {
  display: none;
}

/* Wide screens put content and motif side by side, alternating sides from
   section to section, up to a maximum page width. The text column keeps
   its reading width; the motif is centred in the space beside it, so the
   paper around it is even. Every motif shares one frame size so no section
   outweighs another. */
@media (min-width: 62em) {
  .motif-left .wrap,
  .motif-right .wrap {
    display: grid;
    grid-template-columns: minmax(0, 1fr) var(--column-width);
    column-gap: var(--space-3xl);
    align-items: center;
    width: min(100% - 2 * var(--space-3xl), 80rem);
  }

  .motif-right .wrap {
    grid-template-columns: var(--column-width) minmax(0, 1fr);
  }

  .motif-left .section-side,
  .motif-right .section-content {
    grid-row: 1;
    grid-column: 1;
  }

  .motif-left .section-content,
  .motif-right .section-side {
    grid-row: 1;
    grid-column: 2;
  }

  .motif {
    display: block;
    width: min(100%, 15rem);
    margin-inline: auto;
  }

  .motif img {
    display: block;
    width: 100%;
    height: auto;
    opacity: var(--ink-motif-opacity);
  }

  .portrait {
    width: min(100%, 13rem);
    margin: 0 auto;
  }
}

/* ------------------------------------------------------------------ */
/* Section dividers                                                    */
/* ------------------------------------------------------------------ */

/* A divider takes no space of its own: its horizon is centred on the edge
   where one sheet meets the next, above both. Its layer clears every sheet,
   including the stacked sheets of the shadowed design, and stays below the
   back-to-top link and the header. */
.divider {
  position: relative;
  z-index: 10;
  height: 0;
}

.divider img {
  opacity: var(--ink-divider-opacity);
  position: absolute;
  top: 0;
  left: 50%;
  width: min(100% - 2 * var(--space-m), 80rem);
  height: auto;
  transform: translate(-50%, -50%);
}
