@layer components {
  .skip-link {
    position: absolute;
    inset-inline-start: var(--s-4);
    inset-block-start: -100%;
    z-index: 100;
    padding: var(--s-3) var(--s-5);
    background: var(--accent);
    color: var(--on-accent);
    font-size: var(--t--1);
    font-weight: 600;
    text-decoration: none;
    border-radius: var(--radius-sm);
  }
  .skip-link:focus { inset-block-start: var(--s-3); }

  /* ---------- header ---------- */

  .header {
    position: sticky;
    inset-block-start: 0;
    z-index: 50;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s-4) var(--s-5);
    min-height: var(--header-h);
    padding: var(--s-3) var(--gutter);
    border-block-end: 1px solid var(--rule);
    background: color-mix(in srgb, var(--bg) 88%, transparent);
    backdrop-filter: blur(8px);
  }

  /*
   * The two words are set as a grid so the tracking can differ per line. The
   * looser, lighter second line optically matches the width of the first.
   */
  .wordmark {
    display: grid;
    font-size: 0.95rem;
    line-height: 1.18;
    text-transform: uppercase;
    color: var(--text);
    /* Inert on the home page, where this is a <span>; on every other page the
       wordmark is the link home and must not pick up default underlining. */
    text-decoration: none;
  }
  .wordmark__line { font-weight: 600; letter-spacing: var(--track-wide); }
  .wordmark__line--wide {
    font-weight: 400;
    letter-spacing: var(--track-wordmark);
    /* Claw back the trailing gap the last letter's tracking leaves behind. */
    margin-inline-end: calc(-1 * var(--track-wordmark));
    color: var(--text-dim);
  }

  .nav { margin-inline-start: auto; }
  .nav__list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-2) var(--s-5);
    font-size: var(--t--1);
  }
  /*
   * Rendered as spans, not anchors. An <a> with no href is not a link and is not
   * focusable, which is exactly right here: there is nowhere to go yet, so the
   * item should never enter the tab order or offer a dead target.
   */
  .nav__item {
    color: var(--text-dim);
    cursor: default;
    letter-spacing: 0.01em;
  }

  /* ---------- hero ---------- */

  .hero {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--s-5);
    padding: var(--s-8) var(--gutter);
    text-align: center;
    flex: 1 0 auto;
  }

  /*
   * The graticule: two repeating gradients, no image and no SVG. Masked with a
   * radial fade so it never runs up against the text it sits behind.
   */
  .hero::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -2;
    opacity: var(--grid-opacity);
    background:
      repeating-linear-gradient(0deg, var(--grid-line) 0 1px, transparent 1px 64px),
      repeating-linear-gradient(90deg, var(--grid-line) 0 1px, transparent 1px 64px);
    -webkit-mask-image: radial-gradient(ellipse 70% 60% at 50% 45%, transparent 10%, #000 85%);
    mask-image: radial-gradient(ellipse 70% 60% at 50% 45%, transparent 10%, #000 85%);
  }

  /*
   * A single band of light crosses the grid once on load, then stops. One pass,
   * not a loop; a looping background reads as decoration competing with copy.
   */
  .hero__sweep {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    z-index: -1;
    width: 45%;
    pointer-events: none;
    background: linear-gradient(105deg, transparent, var(--sweep), transparent);
    transform: translate3d(-120%, 0, 0);
    animation: sweep var(--dur-slow) var(--ease) 200ms 1 forwards;
  }
  @keyframes sweep {
    from { transform: translate3d(-120%, 0, 0); }
    to   { transform: translate3d(340%, 0, 0); opacity: 0; }
  }
  /* The zeroed --dur-slow would still fire this in 1ms; suppress it outright. */
  @media (prefers-reduced-motion: reduce) {
    .hero__sweep { animation: none; opacity: 0; }
  }

  .hero__kicker {
    font-family: var(--font-mono);
    font-size: var(--t--1);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--accent);
    filter: drop-shadow(0 0 6px var(--glow));
  }

  .hero__title { font-size: var(--t-5); max-width: 16ch; }

  .motto {
    font-family: var(--font-display);
    font-size: var(--t-2);
    font-style: italic;
    line-height: var(--leading-snug);
    color: var(--text);
    max-width: 24ch;
  }
  /* The line breaks are a typographic choice, so they only apply where they fit. */
  .motto br { display: none; }
  @media (min-width: 40rem) {
    .motto { max-width: none; }
    .motto br { display: inline; }
  }

  .hero__note {
    max-width: var(--measure);
    color: var(--text-dim);
  }

  /* ---------- what's ahead ---------- */

  .ahead {
    padding: var(--s-7) var(--gutter) var(--s-8);
    border-block-start: 1px solid var(--rule);
    background: var(--surface-sunk);
  }
  .ahead__inner { max-width: var(--width-page); margin-inline: auto; }

  .ahead__title {
    font-family: var(--font-mono);
    font-size: var(--t--1);
    font-weight: 400;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--text-dim);
    text-align: center;
    margin-block-end: var(--s-6);
  }

  .cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: var(--s-4);
  }

  .card {
    padding: var(--s-5);
    border: 1px solid var(--rule);
    border-radius: var(--radius-md);
    background: var(--surface);
    box-shadow: var(--shadow-sm);
  }
  .card__label {
    display: inline-block;
    margin-block-end: var(--s-2);
    font-size: var(--t--1);
    font-weight: 600;
    letter-spacing: var(--track-wide);
    text-transform: uppercase;
    color: var(--tint);
    filter: drop-shadow(0 0 6px var(--glow));
  }
  .card--journal { --tint: var(--journal); }
  .card--tools { --tint: var(--tools); }
  .card--reference { --tint: var(--reference); }

  .card__text { color: var(--text-dim); font-size: var(--t--1); }

  .card__soon {
    display: inline-block;
    margin-block-start: var(--s-4);
    padding: var(--s-1) var(--s-3);
    border: 1px solid var(--rule);
    border-radius: var(--radius-pill);
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-dim);
  }

  /* ---------- theme toggle ---------- */

  /*
   * Hidden until the inline head script adds `.js` to <html>. Without scripting
   * the control would be present and dead, which is worse than absent; the page
   * still themes correctly from prefers-color-scheme alone.
   */
  .toggle { display: none; }
  .js .toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--s-2);
    min-height: 44px;
    padding: var(--s-2) var(--s-4);
    border: 1px solid var(--rule);
    border-radius: var(--radius-pill);
    background: var(--surface);
    color: var(--text-dim);
    font: inherit;
    font-size: var(--t--1);
    cursor: pointer;
    transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
  }
  /*
   * The header right-aligns its last item via .nav's auto margin. On a page with
   * no nav the toggle has to do it itself; giving BOTH an auto margin would split
   * the free space between them and strand the nav mid-header, so it is a
   * modifier rather than a rule on .toggle.
   */
  .toggle--end { margin-inline-start: auto; }

  .toggle:hover { color: var(--text); border-color: var(--edge); }
  .toggle svg { width: 1em; height: 1em; }

  /* ---------- footer ---------- */

  .footer {
    padding: var(--s-6) var(--gutter);
    border-block-start: 1px solid var(--rule);
    background: var(--bg);
    color: var(--text-dim);
    font-size: var(--t--1);
    text-align: center;
  }
  .footer__inner {
    max-width: var(--width-page);
    margin-inline: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--s-3);
  }
  .footer__tagline { color: var(--text); }
  .footer__legal {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--s-2) var(--s-4);
  }
  .footer__legal span { color: var(--text-dim); cursor: default; }

  /* ---------- one-shot entrance ---------- */

  .rise {
    animation: rise var(--dur) var(--ease) both;
    animation-delay: calc(var(--i, 0) * var(--stagger));
  }
  @keyframes rise {
    from { opacity: 0; transform: translate3d(0, 8px, 0); }
    to   { opacity: 1; transform: none; }
  }

  /* ---------- 404 ---------- */

  /*
   * The one real link on the site so far, so it is styled as a control rather
   * than as body text: it reuses the toggle's pill geometry, including the 44px
   * minimum target, and does not depend on .js being present the way .toggle does.
   */
  .backlink {
    display: inline-flex;
    align-items: center;
    gap: var(--s-2);
    min-height: 44px;
    padding: var(--s-2) var(--s-5);
    border: 1px solid var(--edge);
    border-radius: var(--radius-pill);
    background: var(--surface);
    color: var(--text);
    font-size: var(--t--1);
    font-weight: 600;
    text-decoration: none;
    transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
  }
  .backlink:hover { color: var(--accent); border-color: var(--accent); }

  /*
   * Print: animations do not run, so `animation-fill-mode: both` could otherwise
   * leave the backwards-filled state (opacity 0) on the page. This is the only
   * path by which content could ever print blank.
   */
  @media print {
    .rise { opacity: 1 !important; transform: none !important; animation: none !important; }
    .hero::before, .hero__sweep, .toggle, .skip-link { display: none !important; }
    .header, .ahead, .footer { border-color: #ccc; background: #fff; }
    body { background: #fff; color: #000; }
    .card { border-color: #ccc; box-shadow: none; }
  }
}
