/* ==========================================================================
   mullatan.com
   Single fixed viewport. Four panels. Nothing scrolls.

   Every size below is expressed in --u, where 1u = 1% of the width of the
   original Figma frame (1400 x 1024). That keeps the proportions of the
   design intact at any viewport size, because --u is capped by BOTH the
   viewport width and the viewport height: the layout scales to whichever
   dimension is the tighter constraint, so it can never overflow either way.
   ========================================================================== */

:root {
  --bg:  #FFF6DC;
  --ink: #C2AA68;

  /* Design unit. 14px at the 1400x1024 reference frame. */
  --u: min(calc(0.594vw + 5.68px), 1.3672vh, 18px);

  /* Type scale, measured off the frames (multiples of --u) */
  --fs-masthead: calc(var(--u) * 2.573);
  --fs-tab:      calc(var(--u) * 1.503);
  --fs-tab-on:   calc(var(--u) * 2.085);
  --fs-timer:    calc(var(--u) * 5.900);
  --fs-about:    calc(var(--u) * 1.643);
  --fs-link:     calc(var(--u) * 1.571);
  --fs-colophon: calc(var(--u) * 1.429);

  /* Geometry, measured off the frames */
  --margin:      calc(var(--u) * 2.93);   /* left / right page margin      */
  --masthead-y:  calc(var(--u) * 4.32);   /* top of the wordmark's box     */
  --masthead-x:  calc(var(--u) * 2.65);   /* optically aligned to the tabs */
  --colophon-y:  calc(var(--u) * 3.29);   /* bottom of the colophon's box  */
  --tab-pitch:   calc(var(--u) * 4.876);  /* row-to-row distance           */
  --tabs-centre: 49.0%;                   /* vertical centre of the stack  */
  --about-width: min(calc(var(--u) * 49.2), 86vw);

  --fade: 450ms;
  --morph: 360ms;
  --ease: cubic-bezier(0.4, 0.0, 0.2, 1);
}

/* Every element this page uses, listed rather than reached with a
   universal selector, which some editors flag. */
html, body,
.masthead, .tabs, .tab, .tab::before, .tab > span,
.stage, .panel, .timer, .about, .link, .colophon {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
}

body {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100dvh;
  background: var(--bg);
  color: var(--ink);
  font-family: Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
  font-optical-sizing: auto;
  text-rendering: optimizeLegibility;
  /* Blocks panning but still allows the viewer to pinch-zoom. */
  touch-action: pinch-zoom;
}

/* Fallback for browsers without dvh support */
@supports not (height: 100dvh) {
  body { height: 100vh; }
}

/* --------------------------------------------------------------- wordmark */

.masthead {
  position: fixed;
  top: var(--masthead-y);
  left: var(--masthead-x);
  margin: 0;
  font-size: var(--fs-masthead);
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0;
  white-space: nowrap;
  user-select: none;
}

/* ------------------------------------------------------------------- tabs */

.tabs {
  position: fixed;
  top: var(--tabs-centre);
  left: var(--margin);
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  z-index: 2;
}

.tab {
  /* Two things keep the stack dead still while the type morphs. The row is
     a fixed height, so a growing label cannot push the ones below it. And
     ::before holds an invisible copy of the label at its bold size in the
     same grid cell, so every tab is already as wide as it will ever be. */
  height: var(--tab-pitch);
  display: grid;
  grid-template-areas: "label";
  align-items: center;
  justify-items: start;
  padding: 0;
  margin: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-size: var(--fs-tab);
  font-weight: 400;
  font-variation-settings: "wght" 400;
  line-height: 1;
  white-space: nowrap;
  text-align: left;
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition:
    font-size var(--morph) var(--ease),
    font-variation-settings var(--morph) var(--ease);
}

.tab::before,
.tab > span {
  grid-area: label;
}

.tab::before {
  content: attr(data-label);
  font-size: var(--fs-tab-on);
  font-weight: 700;
  font-variation-settings: "wght" 700;
  visibility: hidden;
  pointer-events: none;
}

.tab[aria-selected="true"] {
  font-size: var(--fs-tab-on);
  font-weight: 700;
  font-variation-settings: "wght" 700;
}

.tab:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: calc(var(--u) * 0.4);
}

/* ------------------------------------------------------------- the stage */

.stage {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  z-index: 1;
}

.panel {
  /* All four panels occupy the same cell, so each one is centred on the
     true centre of the viewport and they cross-fade in place. */
  grid-area: 1 / 1;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--fade) var(--ease), visibility 0s linear var(--fade);
}

.panel.is-active {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity var(--fade) var(--ease), visibility 0s linear 0s;
}

/* ------------------------------------------------------------ panel: timer */

.timer {
  margin: 0;
  font-size: var(--fs-timer);
  font-weight: 400;
  font-variation-settings: "wght" 400;
  line-height: 1;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  user-select: none;
}

/* ------------------------------------------------------------ panel: about */

.about {
  width: var(--about-width);
  margin: 0;
  font-size: max(var(--fs-about), 14px);
  font-weight: 400;
  line-height: 1.5;
  text-align: left;
  text-wrap: pretty;
  hyphens: none;
}

/* ------------------------------------------------- panels: the book, and X */

.link {
  display: inline-block;
  max-width: 86vw;
  font-size: max(var(--fs-link), 15px);
  font-weight: 400;
  line-height: 1.4;
  text-align: center;
  text-decoration: none;
  color: inherit;
  /* The frames show no rule under these, so the underline is held back
     until the pointer or keyboard is actually on the link. */
  border-bottom: 1px solid transparent;
  padding-bottom: calc(var(--u) * 0.2);
  transition: opacity 200ms var(--ease), border-color 200ms var(--ease);
}

a.link:hover {
  opacity: 0.66;
  border-bottom-color: currentColor;
}

a.link:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: calc(var(--u) * 0.5);
}

.link.is-pending {
  cursor: default;
  opacity: 0.55;
}

/* --------------------------------------------------------------- colophon */

.colophon {
  position: fixed;
  right: var(--margin);
  bottom: var(--colophon-y);
  font-size: var(--fs-colophon);
  font-weight: 400;
  line-height: 1;
  white-space: nowrap;
  user-select: none;
}

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

@media (prefers-reduced-motion: reduce) {
  .tab   { transition: none; }
  .panel { transition: opacity 1ms linear, visibility 0s linear 1ms; }
  .panel.is-active { transition: opacity 1ms linear, visibility 0s linear 0s; }
}


/* --------------------------------------------------------------- narrow
   Below roughly 820px the left rail and a centred block of content start
   to overlap, so the rail lies down: same four labels in the same order,
   same bold-and-larger treatment, same scroll behaviour, turned through
   ninety degrees and parked under the wordmark. The stage is then inset
   top and bottom so nothing can run into the nav or the colophon.
   -------------------------------------------------------------------- */

@media (max-width: 820px) {
  .tabs {
    top: calc(var(--u) * 9);
    transform: none;
    flex-direction: row;
    align-items: center;
    gap: calc(var(--u) * 2.4);
    right: var(--margin);
  }

  /* Laid out in a row, each label is centred inside the width its bold
     twin reserves, so the gaps between them stay even. */
  .tab { justify-items: center; }

  .stage {
    padding: calc(var(--u) * 15) var(--margin) calc(var(--u) * 7);
  }

  .about {
    width: 100%;
  }
}
