/* Base styles for pages on the new shell: reset, type, the corners and the still grain.
   Colors come only from tokens.css. */

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

html {
  background-color: var(--paper);
  background-image: url("../img/grain.62709aa06b67.png");
  background-attachment: fixed; /* the top veil carries the same grain, fixed, so they line up */
  color: var(--ink);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  font-family: var(--font-reading);
  font-size: var(--reading-size);
  line-height: var(--reading-leading);
  font-optical-sizing: auto;
}

img, svg {
  display: block;
  max-width: 100%;
}

a {
  color: inherit;
}

.label {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  letter-spacing: var(--label-tracking);
  line-height: 1.4;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--muted);
}

/* Text for screen readers and search engines only, such as the name of the mark top left. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

button.label {
  background: none;
  border: 0;
  cursor: pointer;
}

/* Every interactive element answers the cursor (spec 3.4). Until the cloth arrives the answer
   is the flat fill; the ink wash replaces it when Motion is on. */
.interactive {
  position: relative;
  isolation: isolate;
  transition: color var(--fill-fade) ease;
}

.label.interactive {
  padding: .6em .8em;
  margin: -.6em -.8em;
}

.interactive::before {
  content: "";
  position: absolute;
  inset: .3em .45em;
  z-index: -1;
  background: transparent;
  transition: background-color var(--fill-fade) ease;
}

.interactive:hover,
.interactive:focus-visible,
.interactive[aria-current="page"],
.interactive[aria-current="true"],
.interactive[aria-selected="true"] {
  color: var(--ink);
}

.interactive:hover::before,
.interactive:focus-visible::before,
.interactive[aria-current="page"]::before,
.interactive[aria-current="true"]::before,
.interactive[aria-selected="true"]::before {
  background: var(--fill);
}

:focus-visible {
  outline: 1px solid var(--muted);
  outline-offset: 3px;
}

.skip-link {
  position: fixed;
  top: var(--space-3);
  left: var(--space-3);
  z-index: 10;
  padding: var(--space-2) var(--space-3);
  background: var(--paper);
  transform: translateY(-200%);
}

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

/* Each corner is a flex box, so its text sits at the corner's edge instead of inside a line box
   as tall as the body's reading line, and neighbouring corners stay level. */
.shell-corner {
  position: fixed;
  z-index: 3;
  display: flex;
}

.shell-corner--top-left { top: var(--edge-block); left: var(--edge-inline); }
.shell-corner--top-right { top: var(--edge-block); right: var(--edge-inline); }
.shell-corner--bottom-left { bottom: var(--edge-block); left: var(--edge-inline); }
.shell-corner--bottom-right { bottom: var(--edge-block); right: var(--edge-inline); }

/* Wide screens (64rem and up): the four corners stay fixed and the page runs between them, clear
   of the longest corner label (--corner-reach), so nothing ever passes under one. */
.shell-main {
  min-height: 100vh;
  padding: calc(var(--edge-block) + 3.5rem) var(--corner-reach);
}

.edge-veil {
  display: none;
}

/* Narrow screens: the page needs the full width, so the bottom corners wait at the end of the
   page (at the bottom of the window when the page is short), and along the top, where the mark and
   MENU stay, the page fades out under a veil of its own paper and grain. The veil sits at
   z-index 2, so nothing inside <main> may use a z-index above 1. */
@media (max-width: 63.99rem) {
  .js body {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
  }

  .js .shell-main {
    flex: 1 0 auto;
    min-height: 0;
    padding: calc(var(--veil-top) + var(--veil-fade)) var(--edge-inline) var(--space-5);
  }

  .js footer {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: flex-end;
    gap: var(--space-3) var(--space-4);
    padding: 0 var(--edge-inline) var(--edge-block);
  }

  .js .shell-corner--bottom-left,
  .js .shell-corner--bottom-right {
    position: static;
  }

  .js .edge-veil {
    display: block;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: calc(var(--veil-top) + var(--veil-fade));
    z-index: 2;
    pointer-events: none;
    background: url("../img/grain.62709aa06b67.png") fixed, var(--paper);
    -webkit-mask-image: linear-gradient(to bottom, var(--mask-solid) calc(100% - var(--veil-fade)), transparent);
    mask-image: linear-gradient(to bottom, var(--mask-solid) calc(100% - var(--veil-fade)), transparent);
  }
}

/* Without JavaScript (or when shell.js cannot load) the menu is always shown, so the corners sit
   in the page's flow, above and below the text, instead of floating over it. */
:root:not(.js) header,
:root:not(.js) footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--space-4);
  padding: var(--space-5) var(--edge-inline);
}

:root:not(.js) .shell-corner {
  position: static;
}

:root:not(.js) .shell-main {
  min-height: 0;
  padding: var(--space-4) var(--edge-inline);
}

/* Motion off (the switch, or a system asking for reduced motion with nothing saved) stops every
   transition and animation. Without JavaScript the boot script never sets data-motion, so the
   system setting decides. */
[data-motion="off"] *,
[data-motion="off"] *::before,
[data-motion="off"] *::after {
  transition: none !important;
  animation: none !important;
}

@media (prefers-reduced-motion: reduce) {
  :root:not([data-motion]) *,
  :root:not([data-motion]) *::before,
  :root:not([data-motion]) *::after {
    transition: none !important;
    animation: none !important;
  }
}

/* Chapters (spec 4.3) and the threshold (4.2): one block, centred both ways in the space the page
   has (between the corners from 64rem up); a long chapter grows and the page scrolls. */
.layout-chapter .shell-main {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  place-items: center;
}

.chapter {
  width: 100%;
  max-width: var(--chapter-measure);
  font-variant-numeric: lining-nums;
}

.chapter__title {
  margin: 0 0 var(--space-4);
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 300;
  font-size: var(--title-size);
  line-height: 1.15;
  text-wrap: balance;
}

.chapter > p {
  margin: 0 0 var(--space-3);
}

.chapter__heading {
  margin: var(--space-5) 0 var(--space-3);
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  font-size: 1.45em;
  line-height: 1.2;
}

.chapter__label {
  margin: var(--space-4) 0 var(--space-2);
  font-weight: 400;
}

.chapter__steps {
  margin: 0;
}

.chapter__steps dt {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  font-size: 1.25em;
}

.chapter__steps dd {
  margin: 0 0 var(--space-4);
}

/* Inline links in prose: a dotted underline that gives way to the flat fill (spec 3.4). A labelled
   link (.interactive) is not one: it answers the cursor with its own inset fill, above. */
.chapter :is(p, dd) a:not(.interactive) {
  text-decoration: underline dotted var(--muted);
  text-decoration-thickness: 1px;
  text-underline-offset: .22em;
  transition: background-color var(--fill-fade) ease, text-decoration-color var(--fill-fade) ease;
}

.chapter :is(p, dd) a:not(.interactive):is(:hover, :focus-visible) {
  background-color: var(--fill);
  text-decoration-color: transparent;
}

.chapter code {
  font-family: var(--font-mono);
  font-size: .8em;
}

.chapter pre {
  margin: 0 0 var(--space-3);
  padding: var(--space-3);
  overflow-x: auto;
  border: 1px solid var(--hair);
  background: var(--box);
}

.chapter pre code {
  font-size: .75em;
  line-height: 1.7;
}

.plans {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 10.5rem), 1fr));
  gap: var(--space-5);
  margin: var(--space-4) 0 var(--space-5);
}

/* The threshold (spec 4.2): the line and COME IN, then the install line alone in their place. Changes
   are fades only, made while the content is invisible, so nothing ever moves in view. */
.threshold {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  gap: var(--space-5);
  text-align: center;
}

.threshold > * {
  transition: opacity var(--fade) ease;
}

.threshold .is-faded {
  opacity: 0;
  pointer-events: none;
}

.threshold__line {
  max-width: 30ch;
  margin: 0;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 300;
  font-size: var(--display-size);
  line-height: 1.22;
  text-wrap: balance;
}

.threshold__break {
  display: none;
}

/* On wide screens the line breaks after "moment," (spec 3.6). That first line is about 16em long, so
   there the threshold takes the page's whole width and the type shrinks before the line would wrap. */
@media (min-width: 56.25rem) {
  .chapter:has(> .threshold) {
    max-width: none;
    container-type: inline-size;
  }

  .threshold__line {
    max-width: none;
    font-size: min(var(--display-size), 100cqi / 16.5);
  }

  .threshold__break {
    display: inline;
  }
}

.label.threshold__enter {
  padding: 1em 1.6em;
  margin: 0;
  letter-spacing: .28em;
  /* Both: the rule for .threshold > * above would otherwise leave only the fade, and the colour would snap. */
  transition: color var(--fill-fade) ease, opacity var(--fade) ease;
}

.threshold__install {
  max-width: 100%;
}

/* In-place chapter changes (shell.js, spec 4.5): the content fades out and back in; nothing slides. */
.shell-main {
  transition: opacity var(--fade) ease;
}

.shell-main.is-leaving {
  opacity: 0;
}
