/* polok.no
   Tokens come from the Polok IT Consulting design system (tokens.json).
   Additions that exist only on the site are marked "site:". */

/* ---------- Fonts: IBM Plex Sans, variable weight (OFL, see ../fonts/OFL.txt) ---------- */

@font-face {
  font-family: "IBM Plex Sans";
  src: url("../fonts/ibm-plex-sans-latin-wght-normal.woff2") format("woff2");
  font-weight: 100 700;
  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: "IBM Plex Sans";
  src: url("../fonts/ibm-plex-sans-latin-ext-wght-normal.woff2") format("woff2");
  font-weight: 100 700;
  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;
}

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

:root {
  /* Design system: colour */
  --paper: #f7f6f1;
  --paper-2: #efede5;
  --paper-edge: #d8d4c5;
  --ink: #1a2e2a;
  --ink-2: #2d4a44;
  --ink-3: #4d6661;
  --ink-4: #7a8a86;
  --ink-5: #9faaa6;
  --brass: #c9a96e;
  --brass-deep: #a88845;
  --brass-ink: #87692f; /* site: brass as type on paper, dark enough to read */
  --brass-soft: #e8d8b4;
  --ink-paper: #f4f1e8;
  --ink-paper-2: #c8c4b6;

  /* Design system: type and motion */
  --font-sans: "IBM Plex Sans", ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --ease: cubic-bezier(0.2, 0.6, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: 120ms;
  --dur: 200ms;
  --dur-slow: 360ms;
  --dur-reveal: 700ms; /* site: entrance reveals */

  /* Roles, light */
  --bg: var(--paper);
  --surface: var(--paper-2);
  --text: var(--ink);
  --text-2: var(--ink-3);
  --text-3: var(--ink-4);
  --line: var(--paper-edge);
  --accent: var(--brass);
  --accent-text: var(--brass-ink); /* site: the sentence's ending */
  --focus: var(--brass-deep);
  --btn-bg: var(--ink);
  --btn-bg-hover: var(--ink-2);
  --btn-text: var(--ink-paper);
  --tile-bg: var(--brass-soft); /* site: icon tiles */
  --tile-ink: var(--ink-2);
  --card-bg: var(--ink); /* site: the business card is printed on ink in both themes */
  --card-shadow: 0 1px 2px rgba(26, 46, 42, 0.12), 0 18px 36px -14px rgba(26, 46, 42, 0.34), 0 48px 96px -32px rgba(26, 46, 42, 0.36);
  --glare: rgba(255, 255, 255, 0.55); /* site: the shine on a card under the pointer */
  --lift-shadow: 0 22px 44px -26px rgba(26, 46, 42, 0.4);
  --toggle-on: rgba(26, 46, 42, 0.09); /* site: the chosen theme and language in the header */
  --flag-edge: rgba(26, 46, 42, 0.14);

  /* Layout */
  --max-w: 1200px;
  --gutter: clamp(20px, 5vw, 40px);
  --gap: 32px;
  --header-h: 72px;
  --edge: clamp(20px, 2.6vw, 44px); /* site: the screen's edge, for the header and the sidebar */
  --side-w: 196px; /* site: the sidebar, with room for the name of the part on show */
  --side-gap: clamp(28px, 3.6vw, 64px);
  --radius: 12px; /* site: surfaces (the cells in How I work, the card); controls keep the design system's 2px */

  color-scheme: light;
}

/* site: dark mode, from the design system's inverted pair (ink ground, ink-paper type) */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: var(--ink);
    --surface: rgba(244, 241, 232, 0.05);
    --text: var(--ink-paper);
    --text-2: var(--ink-paper-2);
    --text-3: var(--ink-5);
    --line: rgba(244, 241, 232, 0.14);
    --accent-text: var(--brass);
    --focus: var(--brass);
    --btn-bg: var(--ink-paper);
    --btn-bg-hover: var(--ink-paper-2);
    --btn-text: var(--ink);
    --tile-bg: rgba(201, 169, 110, 0.16);
    --tile-ink: var(--brass);
    --card-bg: var(--ink-2);
    --card-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 20px 44px -16px rgba(0, 0, 0, 0.5), 0 56px 112px -40px rgba(0, 0, 0, 0.55);
    --glare: rgba(244, 241, 232, 0.07);
    --lift-shadow: 0 22px 44px -24px rgba(0, 0, 0, 0.6);
    --toggle-on: rgba(244, 241, 232, 0.14);
    --flag-edge: rgba(244, 241, 232, 0.2);
    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --bg: var(--ink);
  --surface: rgba(244, 241, 232, 0.05);
  --text: var(--ink-paper);
  --text-2: var(--ink-paper-2);
  --text-3: var(--ink-5);
  --line: rgba(244, 241, 232, 0.14);
  --accent-text: var(--brass);
  --focus: var(--brass);
  --btn-bg: var(--ink-paper);
  --btn-bg-hover: var(--ink-paper-2);
  --btn-text: var(--ink);
  --tile-bg: rgba(201, 169, 110, 0.16);
  --tile-ink: var(--brass);
  --card-bg: var(--ink-2);
  --card-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 20px 44px -16px rgba(0, 0, 0, 0.5), 0 56px 112px -40px rgba(0, 0, 0, 0.55);
  --glare: rgba(244, 241, 232, 0.07);
  --lift-shadow: 0 22px 44px -24px rgba(0, 0, 0, 0.6);
  --toggle-on: rgba(244, 241, 232, 0.14);
  --flag-edge: rgba(244, 241, 232, 0.2);
  color-scheme: dark;
}

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

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: 17px;
  font-weight: 400;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

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

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

h1,
h2,
h3 {
  color: var(--text);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.02em;
}

a {
  color: inherit;
}

svg {
  display: block;
}

::selection {
  background: var(--brass-soft);
  color: var(--ink);
}

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

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip {
  position: absolute;
  top: 12px;
  left: var(--gutter);
  z-index: 10;
  padding: 10px 16px;
  border-radius: 999px;
  background: var(--btn-bg);
  color: var(--btn-text);
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
  transform: translateY(-200%);
}

.skip:focus-visible {
  transform: none;
}

.wrap {
  width: 100%;
  max-width: var(--max-w);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* The brass full stop from the wordmark ends every headline. */
.dot {
  color: var(--accent);
}

.icon {
  width: 18px;
  height: 18px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

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

.header__inner {
  display: flex;
  align-items: center;
  gap: var(--gap);
  height: var(--header-h);
}

.brand {
  display: inline-flex;
  align-items: center;
  height: 44px;
  margin-left: -4px;
  padding-inline: 4px;
  color: var(--text);
}

.brand svg {
  width: auto;
  height: 26px;
}

.brand .wordmark__dot {
  fill: var(--accent);
}

.nav {
  display: flex;
  gap: 28px;
  margin-left: auto;
}

.nav a {
  position: relative;
  padding-block: 6px;
  color: var(--text);
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
}

.nav a::after,
.email::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur) var(--ease);
}

.nav a::after {
  bottom: 2px;
}

.nav a:hover::after {
  transform: scaleX(1);
}

.lang {
  display: inline-flex;
  flex: none;
  padding: 2px;
  border: 1px solid var(--line);
  border-radius: 999px;
}

.lang a,
.lang span {
  padding: 7px 11px;
  border-radius: 999px;
  color: var(--text-2);
  font-size: 12px;
  font-weight: 500;
  line-height: 1;
  text-decoration: none;
  transition: color var(--dur) var(--ease);
}

.lang a:hover {
  color: var(--text);
}

.lang [aria-current] {
  background: var(--text);
  color: var(--bg);
}

/* site: the header runs to the screen's edges, so the brand stands over the sidebar. */
.header__inner--wide {
  width: 100%;
  padding-inline: var(--edge);
}

/* site: the theme switch and the language flags sit together, in matching pills. */
.header__tools {
  display: flex;
  flex: none;
  align-items: center;
  gap: 8px;
}

/* The theme toggle: "Classic" from toggles.dev by Alfie Jones (MIT licence), in a pill that matches the flags.
   Switched on (dark), the sun's rays fold away and a bite slides in to make it a moon. */
.theme-toggle {
  --theme-toggle__classic--duration: 500ms;
  display: grid;
  flex: none;
  place-items: center;
  width: 44px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: none;
  color: var(--text);
  font-size: 18px;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease);
}

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

.theme-toggle:hover {
  background: var(--toggle-on);
}

.theme-toggle__classic {
  width: 1em;
  height: 1em;
}

.theme-toggle__classic path {
  transition-timing-function: cubic-bezier(0, 0, 0.15, 1.25);
  transform-origin: center;
  transition-duration: calc(var(--theme-toggle__classic--duration) * 0.8);
}

.theme-toggle__rays path {
  transition-property: opacity, transform;
  transition-delay: calc(var(--theme-toggle__classic--duration) * 0.2);
}

.theme-toggle__cutout {
  transition-property: transform, d;
}

.theme-toggle[aria-checked="true"] .theme-toggle__rays path {
  transform: scale(0.5) rotate(45deg);
  opacity: 0;
  transition-delay: 0s;
}

.theme-toggle[aria-checked="true"] .theme-toggle__cutout {
  d: path("M-12 5h30a1 1 0 0 0 9 13v24h-39Z");
  transition-delay: calc(var(--theme-toggle__classic--duration) * 0.2);
}

@supports not (d: path("")) {
  .theme-toggle[aria-checked="true"] .theme-toggle__cutout {
    transform: translate3d(-12px, 10px, 0);
  }
}

.lang--flags a {
  display: grid;
  place-items: center;
  width: 36px;
  height: 28px;
  padding: 0;
  border-radius: 999px;
  transition: background-color var(--dur) var(--ease);
}

.lang--flags [aria-current] {
  background: var(--toggle-on);
}

/* The text version of the language switch pads its spans; the flag version must not. */
.lang--flags span {
  padding: 0;
}

.lang--flags .flag {
  display: block;
  width: 20px;
  height: 14px;
  overflow: hidden;
  border-radius: 3px;
  box-shadow: 0 0 0 1px var(--flag-edge);
  transition: filter var(--dur) var(--ease), opacity var(--dur) var(--ease);
}

.flag svg {
  width: 100%;
  height: 100%;
}

/* The other language's flag is quieter until the pointer is on it. */
.lang--flags a:not([aria-current]) .flag {
  filter: saturate(0.35);
  opacity: 0.75;
}

.lang--flags a:not([aria-current]):hover .flag {
  filter: none;
  opacity: 1;
}

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 24px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--btn-bg);
  color: var(--btn-text);
  font: inherit;
  font-size: 15px;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
}

.btn:hover {
  background: var(--btn-bg-hover);
}

.btn:active {
  transform: translateY(1px);
}

.btn .icon {
  transition: transform var(--dur) var(--ease);
}

.btn:hover .icon {
  transform: translate(2px, -2px);
}

/* site: the landing's one button, big enough to be the obvious next step. */
.btn--go {
  gap: 16px;
  padding: 22px 32px;
  font-size: clamp(17px, min(1.45vw, 2.6svh), 21px);
}

.btn--go .icon {
  width: 20px;
  height: 20px;
}

.btn--go:hover .icon {
  transform: translateY(3px);
}


/* ---------- The site: one pinned screen ---------- */

/* site: scrolling always comes to rest on a whole step, and a quick swipe never skips one. */
.snap {
  scroll-snap-type: y mandatory;
}

.story {
  --title-size: clamp(34px, min((min(100vw, var(--max-w)) - 2 * var(--gutter)) * 0.113, 10svh), 96px);
  --scene-size: calc(var(--title-size) * 0.64);
  --top-pad: clamp(12px, 4svh, 48px);
  position: relative;
}

/* One invisible step per screen of scrolling: the landing, the four services, how I work, about, and the card. */
.story__mark {
  display: none;
}

/* The column everything is read in. When the screen is pinned it also keeps clear of the sidebar. */
.story__main {
  padding-inline: max(var(--gutter), (100% - var(--max-w)) / 2 + var(--gutter));
  padding-bottom: clamp(24px, 4svh, 48px);
}

.story__wrap {
  padding-top: clamp(24px, 6svh, 72px);
}

/* "En ekstra hånd med" is 8.6em wide and must stay on one line. */
.story__title {
  font-size: var(--title-size);
  line-height: 1.05;
  letter-spacing: -0.025em;
}

/* One line of a headline, masked so its text can rise into place. */
.line {
  display: block;
  overflow: hidden;
  overflow: clip;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}

.line__inner {
  display: block;
}

/* The ending of the sentence: every variant sits in one grid cell and rolls in or out. */
.phrase {
  display: grid;
}

/* The endings roll like a counter: the one giving way slides up out of the line's clip, the next slides up into it. */
.phrase__item {
  grid-area: 1 / 1;
  color: var(--accent-text);
  white-space: nowrap;
  transition: transform 700ms var(--ease-out);
}

.phrase__item[data-pos="above"] {
  transform: translateY(-112%);
}

.phrase__item[data-pos="below"] {
  transform: translateY(112%);
}

.phrase__item.is-instant {
  transition: none;
}

.story__lead {
  max-width: 34ch;
  color: var(--text-2);
  font-size: clamp(18px, min(1.9vw, 3.3svh), 26px);
  line-height: 1.45;
  text-wrap: pretty;
}

.panel__go {
  margin-top: clamp(24px, 4.6svh, 52px);
}

/* ---------- The services: the part under the sentence. Without JavaScript every part is simply listed. ---------- */

.panel {
  display: grid;
  gap: clamp(56px, 8vw, 96px);
  margin-top: clamp(20px, 3.6svh, 44px);
}

.panel__item {
  position: relative;
  transition: opacity 360ms var(--ease-out), transform 560ms var(--ease-out);
}

.panel__head {
  display: flex;
  align-items: center;
  gap: clamp(12px, 1.4vw, 18px);
}

/* Icons sit on a soft brass tile. */
.panel__icon {
  display: grid;
  flex: none;
  place-items: center;
  width: var(--tile, clamp(40px, 5.8svh, 52px));
  height: var(--tile, clamp(40px, 5.8svh, 52px));
  border-radius: 14px;
  background: var(--tile-bg);
  color: var(--tile-ink);
}

.panel__icon .icon {
  width: 50%;
  height: 50%;
}

.panel__title {
  font-size: clamp(20px, min(1.9vw, 3.4svh), 28px);
  line-height: 1.15;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.panel__lead {
  max-width: 34ch;
  margin-top: clamp(12px, 2.2svh, 24px);
  color: var(--text);
  font-size: clamp(18px, min(1.9vw, 3.3svh), 26px);
  line-height: 1.42;
  text-wrap: pretty;
}

.panel__list {
  display: grid;
  margin-top: clamp(10px, 2svh, 20px);
  color: var(--text-2);
  font-size: clamp(15px, min(1.2vw, 2.2svh), 17px);
  line-height: 1.4;
}

.panel__list li {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding-block: clamp(5px, 0.9svh, 8px);
  border-top: 1px solid var(--line);
}

.panel__list .icon {
  width: 1.15em;
  height: 1.15em;
  margin-top: 0.12em;
  color: var(--text);
}

/* The services page: four services in a list, and beside them a mock-up of an admin page, drawn with the site's own
   parts (bars for text, an icon for each service). The mock-up arrives in a mess and a moment later its parts slide into
   place and the shields and ticks appear (the pinned screen, further down). Nothing in it is smaller than 12px type or
   a 16px icon. */
.services {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  column-gap: clamp(28px, 4vw, 72px);
  align-items: center;
}

.offer {
  display: grid;
  gap: clamp(12px, 2.4svh, 24px);
}

.offer__item {
  display: flex;
  align-items: flex-start;
  gap: clamp(12px, 1.2vw, 16px);
}

.offer__icon {
  display: grid;
  flex: none;
  place-items: center;
  width: clamp(38px, 5svh, 46px);
  height: clamp(38px, 5svh, 46px);
  border-radius: 12px;
  background: var(--tile-bg);
  color: var(--tile-ink);
}

.offer__icon .icon {
  width: 50%;
  height: 50%;
}

.offer__title {
  font-size: clamp(17px, min(1.5vw, 2.7svh), 21px);
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.offer p {
  max-width: 40ch;
  margin-top: 3px;
  color: var(--text-2);
  font-size: clamp(14px, min(1.15vw, 2.2svh), 16px);
  line-height: 1.45;
  text-wrap: pretty;
}

/* The window: a bar with three dots and an address, then a side menu and four tiles. */
.mock {
  position: relative;
  height: clamp(220px, 36svh, 380px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  container-type: size;
}

.mock__bar {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 34px;
  padding: 0 14px;
  border-bottom: 1px solid var(--line);
}

.mock__bar > i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--line);
}

.mock__url {
  width: 34%;
  height: 12px;
  margin-left: 10px;
  border-radius: 999px;
  background: var(--line);
}

/* The parts are measured in the window's own size, and never fall under 12px. */
.mock__body {
  position: absolute;
  inset: 34px 0 0;
  display: grid;
  grid-template-columns: 22% repeat(2, minmax(0, 1fr));
  grid-template-rows: repeat(2, minmax(0, 1fr));
  gap: 1em;
  padding: 1em;
  font-size: clamp(12px, 1.7cqw, 14px);
}

.mock__part {
  min-width: 0;
  min-height: 0;
}

.mock__side {
  display: grid;
  grid-row: 1 / 3;
  align-content: start;
  gap: 0.9em;
  padding: 0.9em 0.8em 0.9em 0;
  border-right: 1px solid var(--line);
}

.mock__side > span {
  height: 0.7em;
  border-radius: 999px;
  background: var(--line);
}

.mock__side > span:nth-child(1) {
  width: 62%;
  background: var(--tile-bg);
}

.mock__side > span:nth-child(2) {
  width: 84%;
}

.mock__side > span:nth-child(3) {
  width: 70%;
}

.mock__side > span:nth-child(4) {
  width: 78%;
}

.mock__tile {
  position: relative;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  gap: 0.8em;
  padding: 1em;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg);
}

.mock__icon {
  display: grid;
  place-items: center;
  width: 2.3em;
  height: 2.3em;
  border-radius: 8px;
  background: var(--tile-bg);
  color: var(--tile-ink);
}

.mock__icon .icon,
.mock__avatar > .icon,
.mock__mark .icon {
  width: 1.35em;
  height: 1.35em;
}

.mock__lines {
  display: grid;
  align-content: end;
  gap: 0.55em;
}

.mock__lines > span {
  height: 0.6em;
  border-radius: 999px;
  background: var(--line);
}

.mock__lines > span:nth-child(2) {
  width: 68%;
}

.mock__lines > span:nth-child(3) {
  width: 44%;
}

/* People in the Microsoft 365 tile, each with a shield once everything is in place. */
.mock__people {
  display: flex;
  gap: 1em;
}

.mock__avatar {
  position: relative;
  display: grid;
  place-items: center;
  width: 3.1em;
  height: 3.1em;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-2);
}

/* The marks that appear once everything is in place: shields on the people, a tick on the other tiles. */
.mock__mark {
  position: absolute;
  display: grid;
  place-items: center;
  width: 2.1em;
  height: 2.1em;
  border-radius: 50%;
  background: var(--accent);
  color: var(--ink);
}

.mock__avatar .mock__mark {
  top: -0.55em;
  right: -0.7em;
  width: 1.75em;
  height: 1.75em;
  box-shadow: 0 0 0 2px var(--bg);
}

.mock__tile > .mock__mark {
  top: 1em;
  right: 1em;
}

/* A short window loses the bars of text; a narrow one the side menu. */
@container (max-height: 250px) {
  .mock__lines {
    display: none;
  }

  .mock__tile {
    grid-template-rows: auto;
    align-content: center;
  }
}

@container (max-width: 480px) {
  .mock__side {
    display: none;
  }

  .mock__body {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .mock__people {
    gap: 0.7em;
  }

  .mock__avatar {
    width: 2.6em;
    height: 2.6em;
  }
}

/* ---------- The sidebar: an icon and a name for every part, the one on show marked. Only on the pinned screen. ---------- */

.sidebar {
  display: none;
}

.sidebar__stops {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* A stop is a pill like the ones in the header: its icon and its name; the one on show gets the pill's ground. */
.sidebar__stop {
  display: flex;
  align-items: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 11px;
  border-radius: 999px;
  color: var(--text-2);
  font-size: 14px;
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.01em;
  text-decoration: none;
  transition: color var(--dur) var(--ease), background-color var(--dur) var(--ease);
}

.sidebar__stop .icon {
  width: 22px;
  height: 22px;
}

.sidebar__stop:hover,
.sidebar__stop:focus-visible {
  color: var(--text);
}

.sidebar__stop[aria-current] {
  color: var(--text);
  background: var(--toggle-on);
}

.sidebar__name {
  display: block;
  white-space: nowrap;
}

.sidebar__name > span {
  display: inline-block;
  padding: 0 5px 0 10px;
}

/* ---------- The other parts: how I work, about, and the card. Each has its own layout. ---------- */

.scene,
.finale {
  margin-top: clamp(88px, 12vw, 152px);
}

.scene__title {
  font-size: var(--scene-size);
  line-height: 1.05;
  letter-spacing: -0.025em;
  text-wrap: balance;
}

/* How I work: three cells, the first one twice the height and in brass. */
.how {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  grid-template-rows: repeat(2, minmax(0, 1fr));
  gap: clamp(10px, 1.4vw, 18px);
  margin-top: clamp(20px, 4svh, 48px);
}

.how__cell {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: clamp(12px, 2svh, 24px);
  min-height: 0;
  padding: clamp(18px, min(2.4vw, 3.6svh), 36px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.how__cell--main {
  grid-row: 1 / span 2;
  border-color: transparent;
  background: var(--tile-bg);
  color: var(--text);
}

.how__icon {
  display: grid;
  flex: none;
  place-items: center;
  width: clamp(38px, 6svh, 52px);
  height: clamp(38px, 6svh, 52px);
  border-radius: 12px;
  background: var(--tile-bg);
  color: var(--tile-ink);
}

.how__icon .icon {
  width: 50%;
  height: 50%;
}

/* The brass cell is the tile: its icon stands alone, larger. */
.how__cell--main .how__icon {
  width: auto;
  height: auto;
  place-items: start;
  background: none;
}

.how__cell--main .how__icon .icon {
  width: clamp(36px, 6.4svh, 56px);
  height: clamp(36px, 6.4svh, 56px);
  stroke-width: 1.25;
}

.how__body {
  margin-top: auto;
}

.how__title {
  font-size: clamp(18px, min(1.7vw, 3svh), 25px);
  line-height: 1.25;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

.how__body p {
  max-width: 42ch;
  margin-top: 6px;
  font-size: clamp(15px, min(1.3vw, 2.4svh), 18px);
  line-height: 1.45;
  text-wrap: pretty;
}

.how__cell--main .how__title {
  font-size: clamp(24px, min(2.7vw, 4.6svh), 40px);
  line-height: 1.12;
  letter-spacing: -0.02em;
}

.how__cell--main .how__body p {
  max-width: 24ch;
  margin-top: clamp(8px, 1.6svh, 16px);
  color: var(--text);
  font-size: clamp(17px, min(1.7vw, 3svh), 23px);
  line-height: 1.4;
}

/* About: the words on the left, the portrait on the right, rising from the foot of the screen. */
.scene--about {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: clamp(24px, 4vw, 72px);
  align-items: end;
}

.about__text {
  align-self: start;
}

.about__lead {
  max-width: 38ch;
  margin-top: clamp(12px, 2.4svh, 26px);
  color: var(--text);
  font-size: clamp(17px, min(1.7vw, 2.9svh), 23px);
  line-height: 1.45;
  text-wrap: pretty;
}

/* Three things I care about, each with its icon on a brass tile. */
.about__points {
  display: grid;
  gap: clamp(14px, 3svh, 32px);
  margin-top: clamp(18px, 3.6svh, 38px);
}

.about__points li {
  display: flex;
  align-items: flex-start;
  gap: clamp(12px, 1.2vw, 16px);
}

.about__icon {
  display: grid;
  flex: none;
  place-items: center;
  width: clamp(34px, 5svh, 42px);
  height: clamp(34px, 5svh, 42px);
  border-radius: 11px;
  background: var(--tile-bg);
  color: var(--tile-ink);
}

.about__icon .icon {
  width: 50%;
  height: 50%;
}

.about__point {
  font-size: clamp(16px, min(1.5vw, 2.6svh), 20px);
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.about__points p {
  max-width: 46ch;
  margin-top: 3px;
  font-size: clamp(14.5px, min(1.25vw, 2.3svh), 17px);
  line-height: 1.45;
  text-wrap: pretty;
}

/* Certifications, and where else to find me: a label and a row of chips each, under a hairline. */
.about__meta {
  display: grid;
  gap: 10px;
  margin: clamp(18px, 3.4svh, 36px) 0 0;
  padding-top: clamp(14px, 2.6svh, 24px);
  border-top: 1px solid var(--line);
}

.about__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
}

.about__row dt {
  min-width: 9em;
  color: var(--text-2);
  font-size: 14px;
  font-weight: 500;
}

.about__row dd {
  margin: 0;
}

.about__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 14px 7px 11px;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--text);
  font-size: 14.5px;
  line-height: 1.2;
  text-decoration: none;
  transition: border-color var(--dur) var(--ease), background-color var(--dur) var(--ease);
}

a.chip:hover {
  border-color: var(--text-3);
  background: var(--toggle-on);
}

.chip .icon {
  width: 16px;
  height: 16px;
}

/* The empty place for the certifications still to come. */
.chip--soon {
  padding-inline: 14px;
  border-style: dashed;
  color: var(--text-2);
}

.about__photo {
  margin: 0;
}

/* The bright portrait on paper, the dark one on ink; the theme decides, and the hidden one is never loaded. */
.about__photo .about__img--dark {
  display: none;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .about__photo .about__img--light {
    display: none;
  }

  :root:not([data-theme="light"]) .about__photo .about__img--dark {
    display: block;
  }
}

:root[data-theme="dark"] .about__photo .about__img--light {
  display: none;
}

:root[data-theme="dark"] .about__photo .about__img--dark {
  display: block;
}

/* Both portraits fade out at the foot, so they meet the page softly. */
.about__photo img {
  display: block;
  width: auto;
  height: min(560px, 64svh);
  -webkit-mask-image: linear-gradient(to top, transparent, rgba(0, 0, 0, 0.45) 13%, #000 30%);
  mask-image: linear-gradient(to top, transparent, rgba(0, 0, 0, 0.45) 13%, #000 30%);
  clip-path: inset(0 0 0 0);
  transform-origin: 50% 100%;
}

/* The shine under the pointer, on the cells, the mock-up window and the card. site.js moves it and fades it in. */
.how__cell::after,
.mock::after,
.bcard::after {
  content: "";
  position: absolute;
  inset: -1px;
  z-index: 2;
  border-radius: inherit;
  background: radial-gradient(circle at var(--mx, 50%) var(--my, 50%), var(--glare), transparent 55%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 500ms var(--ease-out);
}

/* ---------- Kontakt: a heading, then a business card ---------- */

.finale {
  --base-h: 56px;
  display: flex;
  flex-direction: column;
}

/* The heading and its line stand over the card, in the middle: the site's one centred page, the last one. */
.finale__head {
  max-width: 40ch;
  margin-inline: auto;
  text-align: center;
}

.finale__lead {
  margin-top: clamp(10px, 2svh, 18px);
  color: var(--text-2);
  font-size: clamp(16px, min(1.5vw, 2.6svh), 20px);
  line-height: 1.45;
  text-wrap: pretty;
}

.finale__place {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-block: clamp(24px, 4svh, 48px);
  container-type: inline-size;
}

/* The card: ID-1 proportions (85.6 x 54 mm), printed on ink, the size of a card in the hand rather than a page. The
   wordmark and the four services at the top, the name and the email at the foot. Its type is measured in the card's
   own width, so it reads the same at every size. */
.bcard {
  --card-w: min(100cqw, 640px);
  --text: var(--ink-paper);
  --text-2: var(--ink-paper-2);
  --text-3: var(--ink-5);
  --line: rgba(244, 241, 232, 0.2);
  --accent: var(--brass);
  --focus: var(--brass);
  --glare: rgba(244, 241, 232, 0.14);
  position: relative;
  isolation: isolate;
  display: grid;
  flex: none;
  grid-template-areas:
    "mark services"
    "who services"
    "reach reach";
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: auto minmax(0, 1fr) auto;
  column-gap: calc(var(--card-w) * 0.06);
  width: var(--card-w);
  aspect-ratio: 1.586;
  padding: calc(var(--card-w) * 0.07);
  border-radius: var(--radius);
  color: var(--text-2);
  container-type: inline-size;
}

/* The card itself, with a hairline on its edge for the dark theme, where card and page are both ink. It is a layer
   of its own, so it can form first and let everything else fall into it. */
.bcard::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: var(--card-bg);
  box-shadow: inset 0 0 0 1px rgba(244, 241, 232, 0.07), var(--card-shadow);
}

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

.bcard__mark {
  grid-area: mark;
  width: auto;
  height: clamp(22px, 5.2cqw, 34px);
  margin-left: -0.3cqw;
  color: var(--text);
}

.bcard__mark .wordmark__dot {
  fill: var(--accent);
}

/* The four services, as headings with their icons on brass tiles, two by two. */
.bcard__services {
  grid-area: services;
  display: grid;
  grid-template-columns: repeat(2, max-content);
  gap: clamp(12px, 3.6cqw, 20px) clamp(14px, 4.4cqw, 24px);
  align-self: start;
}

.bcard__services li {
  display: flex;
  align-items: center;
  gap: clamp(8px, 2cqw, 11px);
  color: var(--text);
  font-size: clamp(13px, 3cqw, 16.5px);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.bcard__icon {
  display: grid;
  flex: none;
  place-items: center;
  width: clamp(28px, 7cqw, 38px);
  height: clamp(28px, 7cqw, 38px);
  border-radius: 10px;
  background: rgba(201, 169, 110, 0.16);
  color: var(--brass);
}

.bcard__icon .icon {
  width: max(16px, 52%);
  height: max(16px, 52%);
}

.bcard__who {
  grid-area: who;
  align-self: end;
}

.bcard__name {
  color: var(--text);
  font-size: clamp(22px, 5cqw, 32px);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: -0.025em;
}

.bcard__role {
  margin-top: clamp(4px, 1cqw, 6px);
  font-size: clamp(13px, 2.3cqw, 15px);
  line-height: 1.35;
}

.bcard__reach {
  grid-area: reach;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  margin-top: clamp(14px, 3.4cqw, 24px);
  padding-top: clamp(14px, 3.4cqw, 24px);
  border-top: 1px solid var(--line);
}

/* The whole card is the email link: the address's underline pseudo-element spreads over the card (the link is static, so
   the card is what holds it), and only the copy button stands above it. Under a pointer the address underlines. */
.bcard {
  cursor: pointer;
}

.bcard .email {
  position: static;
  font-size: clamp(16px, 3cqw, 20px);
  letter-spacing: -0.02em;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.16em;
  transition: text-decoration-color var(--dur) var(--ease);
}

/* Every row is positioned (it stands over the card's face); this one must not be, or it would hold the link's spread. */
.bcard__reach {
  position: static;
}

.bcard .email::after {
  inset: 0;
  z-index: 1;
  height: auto;
  border-radius: var(--radius);
  background: none;
  transform: none;
}

.bcard:hover .email {
  text-decoration-color: var(--accent);
}

.bcard .email:focus-visible {
  outline: none;
}

.bcard:has(.email:focus-visible) {
  outline: 2px solid var(--focus);
  outline-offset: 6px;
}

.bcard .copy {
  position: relative;
  z-index: 2;
  padding: 8px 14px;
  font-size: 13px;
}

.bcard .phone {
  font-size: clamp(14px, 2.2cqw, 18px);
}

/* A small card: the services sit closer. */
@container (max-width: 480px) {
  .bcard__services {
    gap: 8px 12px;
  }

  .bcard__services li {
    gap: 7px;
    font-size: 13px;
  }

  .bcard__icon {
    width: 26px;
    height: 26px;
    border-radius: 8px;
  }
}

.finale__base {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0 24px;
  min-height: var(--base-h);
  font-size: 14px;
}
/* ---------- Contact parts (shared with the concept prototypes) ---------- */

.section {
  padding-block: clamp(72px, 9vw, 120px) clamp(80px, 10vw, 136px);
  /* The divider is a hairline on the text column, not across the whole screen. */
  background: linear-gradient(var(--line), var(--line)) center top / min(calc(100% - 2 * var(--gutter)), calc(var(--max-w) - 2 * var(--gutter))) 1px no-repeat;
}

.section__title {
  font-size: clamp(30px, min(4.6vw, 7svh), 60px);
  line-height: 1.05;
  letter-spacing: -0.025em;
  text-wrap: balance;
}

.contact {
  padding-bottom: clamp(64px, 8vw, 104px);
}

.contact__lead {
  max-width: 44ch;
  margin-top: 16px;
  font-size: 19px;
}

.contact__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 28px;
  margin-top: clamp(40px, 6vw, 72px);
}

.email {
  position: relative;
  color: var(--text);
  font-size: clamp(34px, 8vw, 104px);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.035em;
  white-space: nowrap;
  text-decoration: none;
}

.email::after {
  bottom: 0.02em;
  height: 2px;
  transition-duration: var(--dur-slow);
}

.email:hover::after {
  transform: scaleX(1);
}

.copy {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 11px 16px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
}

.copy[hidden] {
  display: none;
}

.copy:hover {
  border-color: var(--text-3);
}

.copy:active {
  transform: translateY(1px);
}

.copy .icon {
  width: 16px;
  height: 16px;
}

.copy .icon--check,
.copy.is-done .icon--copy {
  display: none;
}

.copy.is-done .icon--check {
  display: block;
}

/* Optional phone link (commented out in the HTML until there is a number). */
.phone {
  color: var(--text);
  font-size: 20px;
  font-weight: 500;
  text-underline-offset: 4px;
  text-decoration-color: var(--line);
}

.phone:hover {
  text-decoration-color: var(--accent);
}

.footer {
  border-top: 1px solid var(--line);
  font-size: 14px;
}

.footer__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 32px;
  padding-block: 28px 36px;
}

.footer a,
.finale__base a {
  text-underline-offset: 3px;
}

.footer a:hover,
.finale__base a:hover {
  text-decoration-color: var(--accent);
}

/* ---------- Pinned: JavaScript on and the screen tall enough (phones need a little more height) ---------- */

@media (min-width: 900px) and (min-height: 521px), (max-width: 899px) and (min-height: 641px) {
  .js .story {
    height: 500vh;
    height: 500svh;
  }

  .js .story__mark {
    position: absolute;
    top: calc(var(--k) * 100vh);
    top: calc(var(--k) * 100svh);
    left: 0;
    display: block;
    width: 1px;
    height: 100vh;
    height: 100svh;
    scroll-snap-align: start;
    scroll-snap-stop: always;
  }

  .js .story__stage {
    position: sticky;
    top: 0;
    height: 100vh;
    height: 100svh;
    overflow: hidden;
    overflow: clip;
  }

  .js .sidebar {
    position: absolute;
    z-index: 2;
    display: flex;
  }

  /* Every part lies in the same place under the header, and only the one on show takes part. */
  .js .story__main {
    position: absolute;
    inset: var(--header-h) 0 0;
    display: grid;
    grid-template: minmax(0, 1fr) / minmax(0, 1fr);
    padding-bottom: 0;
  }

  .js .story__wrap,
  .js .scene,
  .js .finale {
    grid-area: 1 / 1;
    min-height: 0;
    margin: 0;
    padding-top: var(--top-pad);
  }

  .js .story__wrap {
    align-self: start;
  }

  /* The sentence and what stands under it sit a little above the middle of the screen; site.js measures how far down. */
  .js .story__wrap {
    translate: 0 var(--drop-services, 0px);
  }

  .js .story[data-step="0"] .story__wrap {
    translate: 0 var(--drop, 0px);
  }

  /* The sentence is big on the landing only. From the services on it is the size of the other pages' headings, and
     it shrinks as the landing gives way (site.js keeps to the same ratio when it measures). */
  .js .story:not([data-step="0"]) .story__title {
    font-size: var(--scene-size);
  }

  .js .panel {
    gap: 0;
  }

  .js .panel__item {
    grid-area: 1 / 1;
    align-self: start;
  }

  /* Parts not on show stay readable for screen readers; site.js moves to one when it takes keyboard focus. */
  .js [data-from][data-pos="above"],
  .js [data-from][data-pos="below"] {
    opacity: 0;
    pointer-events: none;
  }

  .js .sidebar[data-pos="below"],
  .js .nav[data-pos="above"] {
    visibility: hidden;
  }

  .js .panel__item[data-pos="above"] {
    transform: translateY(-32px);
  }

  .js .panel__item[data-pos="below"] {
    transform: translateY(32px);
  }

  .js .story__wrap[data-pos="above"],
  .js .scene[data-pos="above"],
  .js .finale[data-pos="above"] {
    transform: translateY(-40px);
  }

  .js .scene[data-pos="below"],
  .js .finale[data-pos="below"] {
    transform: translateY(40px);
  }

  .js [data-from].is-instant {
    transition: none;
  }

  /* The mock-up beside the services lies in a mess when the page arrives, and site.js sorts it a moment later. */
  .js .panel__item[data-sorted="false"] .mock__part {
    translate: calc(var(--dx) * 1cqw) calc(var(--dy) * 1cqh);
    rotate: calc(var(--r) * 1deg);
  }

  .js .panel__item[data-sorted="false"] .mock__mark {
    opacity: 0;
    scale: 0.5;
  }

  /* Coming back to the services from further on, the picture is set tidy without a show (site.js holds the class for
     a frame). */
  .js .panel__item.is-jump :is(.mock__part, .mock__mark) {
    transition: none !important;
  }

  /* What each part does while it waits: the cells and tags wait below, and the portraits wait under their own foot. */
  .js .scene--how:not([data-pos="current"]) .how__cell {
    opacity: 0;
    translate: 0 24px;
  }

  .js .scene--about:not([data-pos="current"]) .about__points li,
  .js .scene--about:not([data-pos="current"]) .about__row {
    opacity: 0;
    transform: translateY(12px);
  }

  .js .scene--about:not([data-pos="current"]) .about__photo img {
    opacity: 0;
    clip-path: inset(100% 0 0 0);
    translate: 0 40px;
    scale: 1.04;
  }

  /* The card: before its step it is not there yet, and everything it holds waits above the screen. */
  .js .finale:not([data-pos="current"]) .bcard::before {
    opacity: 0;
    scale: 0.97;
  }

  .js .finale:not([data-pos="current"]) .bcard__row {
    translate: 0 -100vh;
    translate: 0 -100svh;
  }

  /* The email and its button are the card's only controls. They drop a short way only, so tabbing to them never
     has to scroll the page up to find them. */
  .js .finale:not([data-pos="current"]) .bcard__reach {
    opacity: 0;
    translate: 0 -40px;
  }

  /* How I work and the card sit a little above the middle of the height, like the sentence: about a quarter of the room
     above them, three quarters below. (About does the same, further down.) */
  .js .scene--how {
    display: grid;
    grid-template-rows: minmax(0, 0.24fr) auto auto minmax(0, 0.76fr);
  }

  .js .scene--how .scene__title {
    grid-row: 2;
  }

  .js .scene--how .how {
    grid-row: 3;
  }

  /* The card's room is as big as the screen allows, up to a 960px card; when the screen is shorter, the card shrinks. */
  .js .finale {
    --place-m: clamp(12px, 2.4svh, 32px);
    --place-h: calc(640px / 1.586 + 2 * var(--place-m));
    display: grid;
    grid-template-rows: minmax(0, 0.24fr) auto minmax(0, var(--place-h)) minmax(0, 0.76fr) auto;
  }

  .js .finale__head {
    grid-row: 2;
    margin-bottom: clamp(12px, 2.4svh, 32px);
  }

  .js .finale__place {
    grid-row: 3;
    height: 100%;
    min-height: 0;
    margin: 0;
    padding-block: var(--place-m);
    container-type: size;
  }

  .js .finale__base {
    grid-row: 5;
  }
}

/* Desktop, pinned: the sidebar at the screen's left edge, and the parts beside it. */
@media (min-width: 900px) and (min-height: 521px) {
  .js .story {
    --main-wv: calc(100vw - max(var(--edge) + var(--side-w) + var(--side-gap), (100vw - var(--max-w)) / 2 + var(--gutter)) - max(var(--gutter), (100vw - var(--max-w)) / 2 + var(--gutter)));
    --title-size: clamp(40px, min(var(--main-wv) * 0.112, 10.5svh), 104px);
  }

  .js .story__main {
    padding-left: max(var(--edge) + var(--side-w) + var(--side-gap), (100% - var(--max-w)) / 2 + var(--gutter));
    padding-right: max(var(--gutter), (100% - var(--max-w)) / 2 + var(--gutter));
  }

  /* Centred on the whole screen, so it sits level with the middle of each part. */
  .js .sidebar {
    top: var(--header-h);
    bottom: 0;
    left: var(--edge);
    flex-direction: column;
    justify-content: center;
    width: var(--side-w);
    padding-bottom: var(--header-h);
  }

  .js .sidebar[data-pos="below"] {
    transform: translateX(-16px);
  }

  .js .how {
    height: clamp(260px, 100svh - 228px, 560px);
    min-height: 0;
  }

  /* About: a quarter of the room above, three quarters below; the words and the portrait share one line through it, the
     face level with the greeting. */
  .js .scene--about {
    grid-template-rows: minmax(0, 0.24fr) auto minmax(0, 0.76fr);
    align-items: center;
  }

  .js .about__text,
  .js .about__photo {
    grid-row: 2;
    align-self: center;
  }

  .js .about__photo {
    margin-top: 6svh;
  }

  .js .about__photo img {
    height: min(62svh, var(--main-wv) * 0.56, 620px);
  }

  .js .bcard {
    --card-w: min(100cqw, 100cqh * 1.586, 640px);
  }
}

/* A short desktop window: the list sits tighter, and the window is lower. */
@media (min-width: 900px) and (min-height: 521px) and (max-height: 640px) {
  .js .offer {
    gap: 8px;
  }

  .js .offer__icon {
    width: 36px;
    height: 36px;
    border-radius: 10px;
  }

  .js .offer__title {
    font-size: 16px;
  }

  .js .offer p {
    font-size: 14px;
    line-height: 1.4;
  }

  .js .mock {
    height: clamp(200px, 40svh, 260px);
  }

  .js .scene--about .scene__title,
  .js .finale__head .scene__title {
    font-size: calc(var(--scene-size) * 0.84);
  }

  .js .finale__lead {
    margin-top: 6px;
    font-size: 15px;
  }
}

/* A short desktop window: in the two small cells the icon moves beside the words, and they get more of the width. */
@media (min-width: 900px) and (min-height: 521px) and (max-height: 700px) {
  .js .how {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
  }

  .js .how__cell:not(.how__cell--main) {
    flex-direction: row;
    align-items: flex-start;
  }

  .js .how__cell:not(.how__cell--main) .how__title {
    font-size: 16.5px;
  }

  .js .how__cell:not(.how__cell--main) .how__body p {
    font-size: 14px;
  }

  .js .how__cell:not(.how__cell--main) .how__body {
    margin-top: 0;
  }
}

/* ---------- Small screens ---------- */

@media (max-width: 899px) {
  :root {
    --header-h: 64px;
  }

  .nav {
    display: none;
  }

  .lang,
  .header__tools {
    margin-left: auto;
  }

  .panel__go .btn {
    justify-content: center;
    width: 100%;
    max-width: 440px;
  }

  .panel__icon {
    --tile: clamp(32px, 4.6svh, 40px);
    border-radius: 11px;
  }

  .panel__title {
    font-size: clamp(19px, 3.4svh, 24px);
  }

  .panel__lead {
    max-width: none;
    margin-top: clamp(8px, 1.6svh, 14px);
    font-size: clamp(16px, 2.7svh, 19px);
  }

  .panel__list {
    grid-template-columns: minmax(0, 1fr);
    margin-top: clamp(6px, 1.2svh, 12px);
    font-size: clamp(14px, 2.3svh, 16px);
  }

  .panel__list li {
    gap: 8px;
    padding-block: clamp(2px, 0.4svh, 5px);
    border-top: 0;
  }

  /* The list, and the window under it, as tall as the room allows, cut off at the screen's edge. */
  .services {
    grid-template-columns: minmax(0, 1fr);
    row-gap: clamp(14px, 2.4svh, 24px);
  }

  .offer {
    gap: clamp(8px, 1.4svh, 14px);
  }

  .offer__icon {
    width: 34px;
    height: 34px;
    border-radius: 10px;
  }

  .offer__title {
    font-size: 17px;
  }

  .offer p {
    font-size: 14px;
  }

  .mock {
    height: clamp(170px, 100svh - 620px, 300px);
  }

  /* How I work: the cells stack, each with its icon beside the words. */
  .how {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: none;
    gap: clamp(8px, 1.4svh, 10px);
    margin-top: clamp(14px, 2.6svh, 24px);
  }

  .how__cell,
  .how__cell--main {
    grid-row: auto;
    flex-direction: row;
    align-items: flex-start;
    gap: 14px;
    padding: clamp(12px, 2.4svh, 16px) clamp(14px, 4.4vw, 18px);
  }

  .how__body {
    margin-top: 0;
  }

  .how__icon {
    width: 36px;
    height: 36px;
    border-radius: 10px;
  }

  .how__cell--main .how__icon .icon {
    width: 32px;
    height: 32px;
  }

  .how__title,
  .how__cell--main .how__title {
    font-size: clamp(17px, 2.8svh, 20px);
    line-height: 1.25;
  }

  .how__body p,
  .how__cell--main .how__body p {
    max-width: none;
    margin-top: 3px;
    font-size: clamp(14px, 2.3svh, 16px);
    line-height: 1.45;
  }

  /* About on a phone: a round portrait beside the greeting, the lead full width under them, the three points spread
     over the room that is left, and the rows of chips at the foot. */
  .scene--about {
    grid-template-areas: "title photo" "lead lead" "points points" "meta meta";
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto auto minmax(auto, 1fr) auto;
    column-gap: 16px;
    align-items: start;
  }

  .about__text {
    display: contents;
  }

  .scene--about .scene__title {
    grid-area: title;
    align-self: center;
  }

  .about__lead {
    grid-area: lead;
    max-width: none;
    margin-top: clamp(8px, 1.4svh, 12px);
    font-size: clamp(15.5px, 2.3svh, 18px);
  }

  .about__points {
    grid-area: points;
    align-self: stretch;
    align-content: space-evenly;
    gap: clamp(10px, 1.8svh, 18px);
    margin-top: clamp(12px, 2.2svh, 20px);
  }

  .about__icon {
    width: 30px;
    height: 30px;
    border-radius: 9px;
  }

  .about__point {
    font-size: clamp(15px, 2.3svh, 17px);
  }

  .about__points p {
    max-width: none;
    font-size: clamp(13.5px, 2.1svh, 15px);
    line-height: 1.4;
  }

  .about__meta {
    grid-area: meta;
    gap: 6px;
    margin-top: clamp(10px, 1.8svh, 18px);
    padding-top: clamp(8px, 1.5svh, 14px);
  }

  .about__row dt {
    min-width: 7.4em;
    font-size: 13px;
  }

  .chip {
    padding: 6px 12px 6px 10px;
    font-size: 13.5px;
  }

  .about__photo {
    --avatar: clamp(60px, 9svh, 84px);
    grid-area: photo;
    align-self: center;
    justify-self: end;
    width: var(--avatar);
    height: var(--avatar);
    overflow: hidden;
    border-radius: 50%;
  }

  .about__photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 50% 0;
    -webkit-mask-image: none;
    mask-image: none;
  }

  /* The card on a phone: as wide as the screen and as tall as what it holds; the wordmark, the four services two by
     two, then the name and the email. */
  .bcard {
    --card-w: min(100cqw, 400px);
    grid-template-areas:
      "mark"
      "services"
      "who"
      "reach";
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto auto auto;
    padding: calc(var(--card-w) * 0.075);
  }

  .bcard__mark {
    height: clamp(18px, 7.6cqw, 30px);
  }

  .bcard__services {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: clamp(8px, 3cqw, 14px) clamp(8px, 3cqw, 14px);
    margin-top: clamp(14px, 5cqw, 22px);
  }

  .bcard__services li {
    gap: clamp(6px, 2.6cqw, 10px);
    font-size: clamp(13px, 4.6cqw, 16px);
  }

  .bcard__icon {
    width: clamp(28px, 9.6cqw, 36px);
    height: clamp(28px, 9.6cqw, 36px);
    border-radius: 8px;
  }

  .bcard__who {
    margin-top: clamp(16px, 6cqw, 28px);
  }

  .bcard__name {
    font-size: clamp(20px, 7.6cqw, 30px);
  }

  .bcard__role {
    margin-top: clamp(3px, 1.2cqw, 6px);
    font-size: clamp(13px, 3.9cqw, 16px);
  }

  .bcard__reach {
    margin-top: clamp(10px, 3.6cqw, 16px);
    padding-top: clamp(10px, 3.6cqw, 16px);
  }

  .bcard .email {
    font-size: clamp(15px, 5cqw, 20px);
  }

  .finale {
    --base-h: 48px;
  }
}

/* Short screens: the three points in About keep their titles; the lines under them are kept for screen readers. */
@media (min-width: 900px) and (min-height: 521px) and (max-height: 640px), (max-width: 899px) and (min-height: 641px) and (max-height: 760px) {
  .js .about__points p {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .js .about__points li {
    align-items: center;
  }
}

/* A narrower desktop window (an iPad on its side, say): the portrait takes less of the width, so each row of chips under
   the hairline keeps to one line. */
@media (min-width: 900px) and (max-width: 1279px) and (min-height: 521px) {
  .js .about__photo img {
    height: min(62svh, var(--main-wv) * 0.44, 620px);
  }

  .js .chip {
    gap: 7px;
    padding: 6px 12px 6px 10px;
    font-size: 14px;
  }
}

/* A short desktop window: the lead in About is a little smaller, the rows under the hairline sit closer, and the empty
   chip for the certifications to come steps out. */
@media (min-width: 900px) and (min-height: 521px) and (max-height: 640px) {
  .js .about__lead {
    font-size: 15.5px;
  }

  .js .chip--soon {
    display: none;
  }

  .js .about__meta {
    margin-top: 12px;
    padding-top: 10px;
    gap: 6px;
  }

  .js .chip {
    padding-block: 5px;
  }
}

/* The narrowest phones: the points a little smaller, and the cells in How I work give their icons' room to the words. */
@media (max-width: 359px) {
  .panel__list {
    font-size: 13px;
  }

  .how__icon {
    display: none;
  }

  .how__cell,
  .how__cell--main {
    padding: 11px 14px;
  }

  .how__body p,
  .how__cell--main .how__body p {
    font-size: 14px;
  }
}

/* A tablet has the width for the list and the window side by side. */
@media (min-width: 600px) and (max-width: 899px) {
  .services {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  }
}

/* A short phone has no room for the window; the list says the same. */
@media (max-width: 899px) and (max-height: 759px) {
  .js .mock {
    display: none;
  }
}

/* Phones, pinned: the sidebar becomes a bar along the foot of the screen, under the thumb. */
@media (max-width: 899px) and (min-height: 641px) {
  .js .sidebar {
    right: 0;
    bottom: 0;
    left: 0;
    padding: 6px var(--gutter) max(8px, env(safe-area-inset-bottom));
    border-top: 1px solid var(--line);
    background: var(--bg);
  }

  .js .sidebar[data-pos="below"] {
    transform: translateY(16px);
  }

  /* A tab bar: every stop its icon with its name under it, sharing the width. */
  .js .sidebar__stops {
    flex-direction: row;
    justify-content: space-between;
    gap: 2px;
    width: 100%;
  }

  .js .sidebar__stop {
    flex-direction: column;
    gap: 3px;
    min-width: 0;
    min-height: 0;
    padding: 5px 7px;
    border-radius: 10px;
    font-size: 12px;
    line-height: 1.15;
  }

  .js .sidebar__stop .icon {
    width: 20px;
    height: 20px;
  }

  .js .sidebar__name > span {
    padding: 0;
  }

  /* Room at the foot for the bar; site.js measures it. */
  .js .scene,
  .js .finale {
    padding-bottom: calc(var(--bar-h, 96px) + 12px);
  }

  .js .scene--about {
    align-content: start;
  }

  /* Kontakt: the heading and the card sit together in the middle of the room, and the foot line stands over the bar. */
  .js .finale {
    grid-template-rows: minmax(0, 1fr) auto auto minmax(0, 1fr) auto;
  }

  .js .finale__place {
    height: auto;
    padding-top: 0;
    container-type: inline-size;
  }

  .js .bcard {
    --card-w: min(100cqw, 400px);
  }
}

/* A tall phone: in How I work the brass cell grows to fill the screen, its icon at the top and its words at the foot,
   like the tile on a desktop. */
@media (max-width: 899px) and (min-height: 761px) {
  .js .scene--how {
    grid-template-rows: 0 auto minmax(0, 1fr) 0;
  }

  .js .how {
    grid-template-rows: minmax(auto, 1fr) auto auto;
    min-height: 0;
  }

  .js .how__cell--main {
    flex-direction: column;
    align-items: stretch;
    gap: 16px;
    padding: 20px;
  }

  .js .how__cell--main .how__icon {
    display: grid;
  }

  .js .how__cell--main .how__icon .icon {
    width: 40px;
    height: 40px;
  }

  .js .how__cell--main .how__body {
    margin-top: auto;
  }

  .js .how__cell--main .how__title {
    font-size: clamp(22px, 3.2svh, 28px);
    line-height: 1.15;
  }

  .js .how__cell--main .how__body p {
    max-width: 30ch;
    margin-top: 8px;
    font-size: clamp(16px, 2.3svh, 18px);
  }
}

/* Too short for one screen per step (a phone on its side): an ordinary scrolling page. */
@media (max-height: 520px) {
  .snap {
    scroll-snap-type: none;
  }
}

/* ---------- Changing theme: the new one opens out from the toggle in a circle (site.js), with no crossfade ---------- */

::view-transition-old(root),
::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
}

/* ---------- Cards that lean towards the pointer: a mouse or trackpad, and motion allowed ---------- */

@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .js [data-tilt] {
    transform: perspective(1000px) rotateX(calc(var(--rx, 0) * 1deg)) rotateY(calc(var(--ry, 0) * 1deg));
    transition: transform 700ms var(--ease-out), box-shadow 400ms var(--ease-out);
  }

  .js .bcard[data-tilt] {
    transform: perspective(1600px) rotateX(calc(var(--rx, 0) * 1deg)) rotateY(calc(var(--ry, 0) * 1deg));
  }

  /* While the pointer moves the card follows it closely; on leaving it settles back slowly. */
  .js [data-tilt].is-tilting {
    transition: transform 160ms var(--ease-out), box-shadow 400ms var(--ease-out);
  }

  .js .how__cell.is-tilting,
  .js .mock.is-tilting {
    box-shadow: var(--lift-shadow);
  }

  .js [data-tilt].is-tilting::after {
    opacity: 1;
  }
}

/* ---------- Motion (only when the visitor has not asked for less) ---------- */

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }

  /* Entrance: header, headline lines, then the lead and the button. Waits for the brand font. */
  .js [data-hero] {
    opacity: 0;
    transform: translateY(12px);
  }

  .js .line__inner {
    transform: translateY(105%);
  }

  .js .line .dot {
    display: inline-block;
    transform: scale(0);
    transform-origin: 50% 85%;
  }

  .js.is-ready [data-hero] {
    opacity: 1;
    transform: none;
    transition: opacity var(--dur-reveal) var(--ease-out), transform var(--dur-reveal) var(--ease-out);
    transition-delay: calc(var(--i, 0) * 110ms + 200ms);
  }

  .js.is-ready .story .line__inner {
    transform: none;
    transition: transform 1000ms var(--ease-out);
    transition-delay: calc(var(--i, 0) * 120ms + 60ms);
  }

  .js.is-ready .story .line .dot {
    transform: none;
    transition: transform 500ms var(--ease-out) 900ms;
  }
}

/* Motion between the steps: the part on show leaves quickly, the next one arrives a moment later. */
@media (prefers-reduced-motion: no-preference) and (min-width: 900px) and (min-height: 521px), (prefers-reduced-motion: no-preference) and (max-width: 899px) and (min-height: 641px) {
  /* Coming back from the card, every part waits this much longer, so the card has emptied first. */
  .js .story[data-prev="4"] {
    --enter: 420ms;
  }

  .js .scene,
  .js .finale {
    transition: opacity 460ms var(--ease-out) calc(220ms + var(--enter, 0ms)), transform 700ms var(--ease-out) calc(220ms + var(--enter, 0ms));
  }

  .js .story__wrap {
    transition: translate 900ms var(--ease-out), opacity 460ms var(--ease-out) calc(220ms + var(--enter, 0ms)), transform 700ms var(--ease-out) calc(220ms + var(--enter, 0ms));
  }

  .js .story__title {
    transition: font-size 800ms var(--ease-out);
  }

  .js .scene:not([data-pos="current"]) {
    transition: opacity 260ms var(--ease), transform 420ms var(--ease);
  }

  /* Leaving the card, its rows fly back up first; only then does the rest of the step fade. */
  .js .finale:not([data-pos="current"]) {
    transition: opacity 280ms var(--ease) 480ms, transform 420ms var(--ease) 480ms;
  }

  .js .story__wrap:not([data-pos="current"]) {
    transition: translate 900ms var(--ease-out), opacity 260ms var(--ease), transform 420ms var(--ease);
  }

  /* One service hands over to the next: the old one is nearly gone before the new one rises. */
  .js .panel__item {
    transition: opacity 420ms var(--ease-out) calc(170ms + var(--enter, 0ms)), transform 640ms var(--ease-out) calc(170ms + var(--enter, 0ms));
  }

  .js .panel__item:not([data-pos="current"]) {
    transition: opacity 200ms var(--ease), transform 320ms var(--ease);
  }

  /* The parts of the window slide into place one after another, unhurried, then the shields and ticks appear.
     Scattering again is quicker. */
  .js .mock__part {
    transition: translate 1400ms cubic-bezier(0.2, 0.75, 0.25, 1) calc(var(--i, 0) * 160ms), rotate 1400ms cubic-bezier(0.2, 0.75, 0.25, 1) calc(var(--i, 0) * 160ms);
  }

  .js .panel__item[data-sorted="false"] .mock__part {
    transition: translate 500ms var(--ease) calc(var(--i, 0) * 30ms), rotate 500ms var(--ease) calc(var(--i, 0) * 30ms);
  }

  .js .mock__mark {
    transition: opacity 360ms var(--ease-out) calc(var(--i, 0) * 160ms + var(--j, 0) * 120ms + 1300ms), scale 500ms cubic-bezier(0.2, 0.75, 0.25, 1) calc(var(--i, 0) * 160ms + var(--j, 0) * 120ms + 1300ms);
  }

  .js .panel__item[data-sorted="false"] .mock__mark {
    transition: opacity 200ms var(--ease), scale 200ms var(--ease);
  }

  /* The sidebar slides in once the landing gives way, and the menu in the header hands over to it. */
  .js .sidebar {
    transition: opacity 460ms var(--ease-out) calc(160ms + var(--enter, 0ms)), transform 640ms var(--ease-out) calc(160ms + var(--enter, 0ms)), visibility 0s;
  }

  .js .sidebar[data-pos="below"],
  .js .story[data-step="4"] .sidebar {
    transition: opacity 240ms var(--ease), transform 320ms var(--ease), visibility 0s linear 320ms;
  }

  .js .nav {
    transition: opacity 320ms var(--ease-out) 120ms, visibility 0s;
  }

  .js .nav[data-pos="above"] {
    transition: opacity 200ms var(--ease), visibility 0s linear 200ms;
  }

  .js .how__cell {
    transition:
      opacity 520ms var(--ease-out) calc(var(--i, 0) * 90ms + 300ms + var(--enter, 0ms)),
      translate 760ms var(--ease-out) calc(var(--i, 0) * 90ms + 300ms + var(--enter, 0ms)),
      transform 700ms var(--ease-out),
      box-shadow 400ms var(--ease-out);
  }

  .js .about__points li,
  .js .about__row {
    transition: opacity 420ms var(--ease-out), transform 600ms var(--ease-out);
    transition-delay: calc(var(--i, 0) * 80ms + 380ms + var(--enter, 0ms));
  }

  .js .scene--about:not([data-pos="current"]) .about__points li,
  .js .scene--about:not([data-pos="current"]) .about__row {
    transition: opacity 200ms var(--ease), transform 300ms var(--ease);
  }

  .js .scene--how:not([data-pos="current"]) .how__cell {
    transition: opacity 200ms var(--ease), translate 300ms var(--ease), transform 700ms var(--ease-out), box-shadow 400ms var(--ease-out);
  }

  /* The portrait rises from its faded foot, and sinks away again when its part leaves. */
  .js .about__photo img {
    transition: opacity 240ms var(--ease), clip-path 360ms var(--ease), translate 360ms var(--ease), scale 360ms var(--ease);
  }

  .js .scene--about[data-pos="current"] .about__photo img {
    --after: calc(260ms + var(--enter, 0ms));
    transition: opacity 500ms var(--ease-out) var(--after), clip-path 1100ms var(--ease-out) var(--after), translate 1100ms var(--ease-out) var(--after), scale 1100ms var(--ease-out) var(--after);
  }

  /* The card forms, then everything it holds falls into it from above, lowest first. Scrolling back up sends it all
     up again, top first, and the card goes after it. */
  .js .bcard::before {
    transition: opacity 300ms var(--ease) 280ms, scale 400ms var(--ease) 280ms;
  }

  .js .finale[data-pos="current"] .bcard::before {
    transition: opacity 420ms var(--ease-out) 120ms, scale 600ms var(--ease-out) 120ms;
  }

  .js .bcard__row {
    transition: translate 420ms cubic-bezier(0.55, 0, 0.8, 0.2) calc((6 - var(--i, 0)) * 30ms);
  }

  .js .finale[data-pos="current"] .bcard__row {
    transition: translate 860ms cubic-bezier(0.2, 0.75, 0.25, 1) calc(var(--i, 0) * 75ms + 200ms);
  }

  .js .bcard__reach.bcard__row {
    transition: translate 300ms var(--ease), opacity 200ms var(--ease);
  }

  .js .finale[data-pos="current"] .bcard__reach.bcard__row {
    transition: translate 700ms cubic-bezier(0.2, 0.75, 0.25, 1) 280ms, opacity 420ms var(--ease-out) 280ms;
  }
}

/* Asked for less motion: state changes stay, movement goes. */
@media (prefers-reduced-motion: reduce) {
  .theme-toggle__classic path,
  .phrase__item,
  .panel__item,
  .story__wrap,
  .story__title,
  .scene,
  .finale,
  .sidebar,
  .nav,
  .mock__part,
  .mock__mark,
  .how__cell,
  .about__points li,
  .about__row,
  .about__photo img,
  .bcard,
  .bcard::before,
  .bcard__row {
    transition: none;
  }
}
