:root {
  --bg: #f9f7f3;
  --bg-raised: #fdfcfa;
  --ink: #152238;
  --muted: #5a6573;
  --line: #d5cfc6;
  --line-hover: #c4bdb4;
  --accent: #1a3f72;
  --accent-hover: #122f56;
  /* "Go" green: availability lights and not-yet-taken actions. --go and
     --go-hover are used for text and clear AA on both --bg and --bg-raised
     (5.7:1 and 6.1:1). --go-lit is brighter for the indicator dot only, which
     is not text and should read as a lit lamp. */
  --go: #146b3f;
  --go-hover: #0f5330;
  --go-lit: #1e9553;
  --chip: #ebe7df;
  /* The ground the paper sits on. Deeper than --bg so the pane reads as a
     sheet laid on a desk rather than a page with the same colour all the way
     to the edge of the window. */
  --ground: #f0ede7;
  --shadow: 0 18px 50px rgba(21, 34, 56, 0.08);
  --sans: "Source Sans 3", "Segoe UI", system-ui, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, Menlo, monospace;
  --max: 68rem;
  --gutter: clamp(1.25rem, 4vw, 2.5rem);
  --portrait-slot: clamp(13rem, 26vw, 22rem);
}

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

html {
  height: 100%;
}

body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.6;
  text-rendering: optimizeLegibility;
}

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

a {
  color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}

a:hover {
  color: var(--accent-hover);
}

.skip {
  position: absolute;
  left: 1rem;
  top: -4rem;
  background: var(--ink);
  color: var(--bg);
  padding: 0.6rem 0.9rem;
  z-index: 20;
}

.skip:focus {
  top: 1rem;
}

.document {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  height: 100%;
  width: min(var(--max), calc(100% - var(--portrait-slot)));
  max-width: var(--max);
  margin-left: max(
    0px,
    calc(
      (
          100% - min(var(--max), calc(100% - var(--portrait-slot))) -
            var(--portrait-slot)
        ) /
        2
    )
  );
  margin-right: var(--portrait-slot);
}

.tab-bar {
  flex-shrink: 0;
  overflow: hidden;
  padding: 0.9rem var(--gutter) 0;
  background: linear-gradient(
    90deg,
    color-mix(in srgb, #efb3b8 13%, var(--bg)),
    color-mix(in srgb, #ecd48a 12%, var(--bg)),
    color-mix(in srgb, #c5e0a8 11%, var(--bg)),
    color-mix(in srgb, #9fd4c8 12%, var(--bg)),
    color-mix(in srgb, #b7c8ea 12%, var(--bg))
  );
  border-bottom: 1px solid var(--line);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35);
}

.tabs {
  display: flex;
  align-items: flex-end;
  gap: 0;
}

.tabs [role="tab"] {
  --tab-tint: #d4d0c8;
  appearance: none;
  position: relative;
  z-index: 0;
  flex: 0 0 auto;
  margin: 0 0 -1px -0.45rem;
  padding: 0.62rem 1.05rem 0.55rem;
  border: 1px solid var(--line);
  border-bottom: none;
  border-radius: 8px 8px 0 0;
  background: color-mix(in srgb, var(--tab-tint) 18%, var(--bg));
  color: var(--muted);
  font-family: var(--sans);
  font-size: 0.88rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  white-space: nowrap;
  cursor: pointer;
  box-shadow:
    inset 0 3px 0 color-mix(in srgb, var(--tab-tint) 42%, #fff),
    inset 0 1px 0 rgba(255, 255, 255, 0.45);
  transition: background-color 160ms ease, color 160ms ease, padding 160ms ease, transform 160ms ease;
}

.tabs [role="tab"]:nth-child(1) {
  --tab-tint: #efb3b8;
}

.tabs [role="tab"]:nth-child(2) {
  --tab-tint: #ecd48a;
}

.tabs [role="tab"]:nth-child(3) {
  --tab-tint: #9fd4c8;
}

.tabs [role="tab"]:nth-child(4) {
  --tab-tint: #b7c8ea;
}

.tabs [role="tab"]:nth-child(5) {
  --tab-tint: #d4b8e0;
}

.tabs [role="tab"]:first-child {
  margin-left: 0;
}

.tab-short {
  display: none;
}

.tabs [role="tab"]:hover {
  color: var(--ink);
  transform: translateY(-1px);
}

.tabs [role="tab"][aria-selected="true"]:hover {
  transform: none;
}

.tabs [role="tab"][aria-selected="true"] {
  z-index: 2;
  background: var(--bg);
  color: var(--ink);
  font-weight: 600;
  padding-top: 0.78rem;
  box-shadow:
    inset 0 3px 0 color-mix(in srgb, var(--tab-tint) 58%, #fff),
    3px 0 8px -4px rgba(20, 18, 15, 0.08),
    -3px 0 8px -4px rgba(20, 18, 15, 0.08);
}

.tabs [role="tab"][aria-selected="true"]::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 3px;
  background: var(--bg);
}

.shell {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(14.5rem, 16.25rem) minmax(0, 1fr);
  overflow: hidden;
  background: var(--bg);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    0 18px 40px rgba(20, 18, 15, 0.08),
    18px 0 44px -22px rgba(20, 18, 15, 0.28);
}

.rail {
  align-self: stretch;
  overflow: auto;
  padding: var(--gutter);
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 2rem;
  background: color-mix(in srgb, var(--ink) 3%, var(--bg));
}

.pages {
  min-height: 0;
  overflow: auto;
  overscroll-behavior: contain;
  background: var(--bg);
  box-shadow: inset 8px 0 16px -16px rgba(20, 18, 15, 0.18);
}

@supports not selector(::-webkit-scrollbar) {
  .pages {
    scrollbar-width: thin;
    scrollbar-color: color-mix(in srgb, var(--ink) 32%, transparent) transparent;
  }
}

.pages::-webkit-scrollbar {
  width: 6px;
}

.pages::-webkit-scrollbar-track {
  background: transparent;
}

.pages::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--ink) 28%, transparent);
  border-radius: 999px;
}

.pages::-webkit-scrollbar-thumb:hover {
  background: color-mix(in srgb, var(--ink) 42%, transparent);
}

.page {
  min-height: 100%;
  padding: clamp(1.6rem, 4vw, 3rem) var(--gutter) 3.5rem;
}

html:not(.reduced-motion) .page.is-active {
  animation: page-in 280ms ease;
}

@keyframes page-in {
  from {
    opacity: 0.35;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.page-end {
  margin: 2.5rem 0 0;
  padding-top: 1rem;
  border-top: 1px dashed var(--line);
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.portrait {
  position: fixed;
  top: 0;
  right: 0;
  width: calc(var(--portrait-slot) + 5.5rem);
  height: 100%;
  pointer-events: none;
  z-index: 0;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to left, #000 58%, transparent 100%);
  mask-image: linear-gradient(to left, #000 58%, transparent 100%);
}

.portrait img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 22% 6%;
  filter: contrast(1.06) saturate(1.12) brightness(1.02);
  opacity: 0.72;
}

.portrait::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    to top,
    color-mix(in srgb, var(--accent) 34%, transparent),
    transparent 40%
  );
}

/* Mark and name share a line; the role runs beneath both. The rail's inner
   width is about 180px at the desktop gutter, which is what sets the name's
   size -- at 2rem it filled the rail on its own. */
.identity {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  column-gap: 0.6rem;
}

.identity .mark {
  display: block;
  width: 30px;
  height: 30px;
  margin: 0;
  border-radius: 7px;
  box-shadow: 0 2px 8px rgba(21, 34, 56, 0.2);
}

.identity h1 {
  font-family: var(--sans);
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -0.028em;
  line-height: 1.1;
  margin: 0;
  white-space: nowrap;
  color: var(--ink);
}

.identity .role {
  grid-column: 1 / -1;
  margin-top: 0.7rem;
}

.identity .role {
  margin: 0;
  color: var(--muted);
  max-width: none;
}

.status {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  width: 100%;
  max-width: none;
}

.status-tile {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0;
  padding: 0.58rem 0.75rem;
  border-radius: 6px;
  font-family: var(--mono);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, var(--bg-raised));
  border: 1px solid color-mix(in srgb, var(--accent) 42%, var(--line));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.45),
    0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent);
}

.status-tile-dot {
  flex-shrink: 0;
  width: 0.48rem;
  height: 0.48rem;
  border-radius: 50%;
  background: var(--go-lit);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--go-lit) 35%, transparent),
    0 0 7px 1px color-mix(in srgb, var(--go-lit) 55%, transparent);
}

html:not(.reduced-motion) .status-tile {
  animation: status-tile-breathe 3.2s ease-in-out infinite;
}

html:not(.reduced-motion) .status-tile:nth-child(2) {
  animation-delay: 0.55s;
}

html:not(.reduced-motion) .status-tile-dot {
  animation: status-dot-pulse 2.4s ease-in-out infinite;
}

html:not(.reduced-motion) .status-tile:nth-child(2) .status-tile-dot {
  animation-delay: 0.55s;
}

@keyframes status-tile-breathe {
  0%,
  100% {
    background: color-mix(in srgb, var(--accent) 12%, var(--bg-raised));
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.45),
      0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent);
  }
  50% {
    background: color-mix(in srgb, var(--accent) 20%, var(--bg-raised));
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.5),
      0 0 16px color-mix(in srgb, var(--accent) 24%, transparent);
  }
}

@keyframes status-dot-pulse {
  0%,
  100% {
    box-shadow:
      0 0 0 1px color-mix(in srgb, var(--go-lit) 35%, transparent),
      0 0 7px 1px color-mix(in srgb, var(--go-lit) 55%, transparent);
  }
  50% {
    box-shadow:
      0 0 0 1px color-mix(in srgb, var(--go-lit) 20%, transparent),
      0 0 13px 3px color-mix(in srgb, var(--go-lit) 30%, transparent);
  }
}

.nav {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.nav a {
  color: var(--muted);
  text-decoration: none;
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.35rem 0;
  border-left: 2px solid transparent;
  padding-left: 0.7rem;
}

.nav a:hover,
.nav a[aria-current="true"] {
  color: var(--ink);
  border-left-color: var(--accent);
}

.rail-meta {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.reveal {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  cursor: pointer;
  text-align: left;
  color: var(--go);
}

.reveal:hover {
  color: var(--go-hover);
}

.rail-meta a,
.rail-meta span,
.rail-meta .reveal {
  font-family: var(--mono);
  font-size: 0.78rem;
  text-decoration: none;
}

/* The action links match the Contact pills' setting; the location line above
   them is a label, not an action, and stays as it is. */
.rail-meta a,
.rail-meta .reveal {
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.rail-meta span {
  color: var(--muted);
}

.rail-meta a {
  color: var(--accent);
}

.rail-meta a:hover {
  color: var(--accent-hover);
}

.hero-kicker {
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 1rem;
}

.lede {
  font-family: var(--sans);
  font-size: clamp(1.85rem, 3.2vw, 2.55rem);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.028em;
  margin: 0 0 1.4rem;
  max-width: 30rem;
  color: var(--ink);
  text-wrap: balance;
}

.lede-body {
  max-width: 38rem;
  color: var(--muted);
  margin: 0;
}

section h2,
.page h2 {
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 2.4rem 0 1.2rem;
  font-weight: 500;
}

.page > h2:first-child {
  margin-top: 0;
}

.page-intro {
  max-width: 38rem;
  color: var(--muted);
  margin: 0 0 1.6rem;
}

.jobs {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.job {
  position: relative;
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 1.25rem;
  padding: 1.4rem 0;
  border-top: 1px solid var(--line);
}

.job::before {
  content: "";
  position: absolute;
  top: -4px;
  left: 0;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
}

.job:last-child {
  border-bottom: 1px solid var(--line);
}

.when {
  font-family: var(--mono);
  font-size: 0.78rem;
  color: var(--muted);
  padding-top: 0.35rem;
}

.when-part {
  white-space: nowrap;
}

.job h3 {
  font-family: var(--sans);
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0 0 0.2rem;
  color: var(--accent);
}

.job .org {
  margin: 0 0 0.7rem;
  color: var(--muted);
}

.job ul {
  margin: 0;
  padding-left: 1.1rem;
  color: var(--ink);
}

.job li + li {
  margin-top: 0.35rem;
}

.earlier {
  margin-top: 1.5rem;
  color: var(--muted);
  max-width: 40rem;
}

.projects {
  display: grid;
  gap: 1.1rem;
}

.project-desk {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  min-height: 0;
}

.subtabs {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0;
  padding: 0;
}

.subtabs [role="tab"] {
  --tab-tint: #d4d0c8;
  appearance: none;
  position: relative;
  z-index: 0;
  text-align: center;
  border: 1px solid var(--line);
  border-bottom: none;
  border-radius: 10px 10px 0 0;
  margin: 0 0 -1px -1px;
  padding: 0.58rem 1.15rem 0.5rem;
  background: color-mix(in srgb, var(--tab-tint) 22%, var(--bg));
  color: var(--muted);
  font-family: var(--sans);
  font-size: 0.92rem;
  font-weight: 500;
  cursor: pointer;
  box-shadow: inset 0 3px 0 color-mix(in srgb, var(--tab-tint) 55%, #fff);
}

.subtabs [role="tab"]:first-child {
  margin-left: 0;
}

.subtabs [role="tab"]:nth-child(1) {
  --tab-tint: #efb3b8;
}

.subtabs [role="tab"]:nth-child(2) {
  --tab-tint: #ecd48a;
}

.subtabs [role="tab"]:nth-child(3) {
  --tab-tint: #9fd4c8;
}

.subtabs [role="tab"]:hover,
.subtabs [role="tab"][aria-selected="true"] {
  color: var(--ink);
}

.subtabs [role="tab"][aria-selected="true"] {
  z-index: 1;
  background: var(--bg-raised);
  font-weight: 600;
  box-shadow:
    inset 0 3px 0 color-mix(in srgb, var(--tab-tint) 70%, #fff),
    3px 0 8px -4px rgba(20, 18, 15, 0.08),
    -3px 0 8px -4px rgba(20, 18, 15, 0.08);
}

.subtabs [role="tab"][aria-selected="true"]::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 3px;
  background: var(--bg-raised);
}

.project-stage {
  border: 1px solid var(--line);
  background: var(--bg-raised);
  min-height: 100%;
}

.project-sheet {
  padding: 1.4rem 1.5rem 1.8rem;
  display: grid;
  gap: 1.2rem;
}

.project-sheet[hidden] {
  display: none;
}

.project-sheet .idx {
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
}

.project-sheet h3 {
  font-size: 1.35rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0;
  color: var(--accent);
}

.detail h4 {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 0.4rem;
  font-weight: 500;
}

.detail p,
.detail li {
  margin: 0;
  color: var(--muted);
}

.detail p + p {
  margin-top: 0.75rem;
}

/* Selected numbers under the About lede. The figures are all in the prose
   already; this pulls them where a skim-reader looks first, and gives the
   About sheet an anchor instead of ending in empty paper.

   Markup order is dt (label) then dd (value) for correct <dl> semantics;
   column-reverse puts the value on top visually without reordering the DOM. */
.stats {
  margin: 1.7rem 0 0;
  padding-top: 1.15rem;
  border-top: 1px solid var(--line);
  display: grid;
  /* auto-fit rather than a fixed count: five across on the desktop pane,
     folding to four then two as it narrows, with no extra breakpoints. The
     min track is wide enough that a label wraps to two or three short lines
     instead of running up against the next column. */
  grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
  gap: 1.4rem 1rem;
}

.stat {
  margin: 0;
  /* Named rows rather than column-reverse: the reversed flex axis packs from
     the bottom, so a cell with a one-line label pushed its figure lower than
     the rest. Explicit rows keep every figure on the same line whatever the
     label wraps to, while the DOM order stays dt-then-dd for <dl> semantics. */
  display: grid;
  grid-template-areas:
    "value"
    "label";
  align-content: start;
  justify-items: center;
  text-align: center;
  gap: 0.35rem;
}

.stat dd {
  grid-area: value;
}

.stat dt {
  grid-area: label;
}

.stat dd {
  margin: 0;
  font-size: clamp(1.9rem, 3vw, 2.5rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.stat dt {
  font-family: var(--mono);
  font-size: 0.62rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: 1.4;
  color: var(--muted);
  /* Hold the label narrower than its column so it wraps under the figure
     rather than reaching for the neighbouring cell. */
  max-width: 8rem;
}

/* Labelled spec list for Technology / tools. No bullets: the mono label is the
   marker. Deliberately darker and smaller than the navy .detail h4 above it so
   the two levels do not compete. */
.spec {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 0.7rem;
}

/* The section heading and the first spec label are both uppercase mono, so the
   default h4 spacing reads as one cramped block. Give the list its own air. */
.detail h4 + .spec {
  margin-top: 0.7rem;
}

.spec strong {
  display: block;
  font-family: var(--mono);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  margin-bottom: 0.15rem;
}

.spec + .tags {
  margin-top: 1rem;
}

.detail p.placeholder,
.shot-placeholder {
  color: var(--muted);
  font-style: italic;
}

.shot-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem;
  align-items: start;
}

.shot {
  margin: 0;
  border: 1px solid var(--line);
  background: var(--bg-raised);
  overflow: hidden;
  border-radius: 6px;
}

.shot img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 5px 5px 0 0;
}

.shot figcaption {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--muted);
  background: var(--bg-raised);
  padding: 0.45rem 0.6rem 0.55rem;
}

.shot--wide {
  grid-column: 1 / -1;
}

#project-whereistay .shot-grid,
#project-zonepal .shot-grid,
#project-blueprint .shot-grid {
  align-items: stretch;
}

#project-whereistay .shot img,
#project-zonepal .shot img,
#project-blueprint .shot img {
  aspect-ratio: 1024 / 644;
  object-fit: cover;
  object-position: top center;
}

.shot-placeholder {
  margin: 0;
  min-height: 9.5rem;
  border: 1px dashed var(--line);
  background:
    repeating-linear-gradient(
      -45deg,
      color-mix(in srgb, var(--ink) 3%, var(--bg-raised)),
      color-mix(in srgb, var(--ink) 3%, var(--bg-raised)) 8px,
      var(--bg-raised) 8px,
      var(--bg-raised) 16px
    );
  display: grid;
  place-items: center;
  text-align: center;
  padding: 1rem;
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  font-style: normal;
}

.card {
  background: var(--bg-raised);
  border: 1px solid var(--line);
  padding: 1.4rem 1.4rem 1.25rem;
  box-shadow: var(--shadow);
  display: grid;
  gap: 0.65rem;
  transition: transform 160ms ease, border-color 160ms ease;
}

.card:hover {
  transform: translateY(-2px);
  border-color: var(--line-hover);
}

.card .idx {
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
}

.card h3 {
  font-family: var(--sans);
  font-size: 1.2rem;
  margin: 0;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--accent);
}

.card p {
  margin: 0;
  color: var(--muted);
}

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.3rem;
}

.detail p + .tags {
  margin-top: 0.7rem;
}

.tags span {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  background: var(--chip);
  padding: 0.22rem 0.5rem;
}

.card-link {
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--accent);
  width: fit-content;
  border-bottom: 1px solid var(--accent);
  padding-bottom: 0.1rem;
}

.card-link:hover {
  color: var(--accent-hover);
  border-bottom-color: var(--accent-hover);
}

.skill-group {
  margin-bottom: 1.5rem;
}

.skill-group h3 {
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin: 0 0 0.75rem;
  color: var(--accent);
}

.skills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
}

.skills li {
  list-style: none;
  font-family: var(--sans);
  font-size: 0.92rem;
  font-weight: 500;
  padding: 0.36rem 0.72rem;
  border-radius: 4px;
  background: var(--chip);
  color: var(--ink);
  transition: background-color 140ms ease;
}

.skills li:hover {
  background: color-mix(in srgb, var(--accent) 12%, var(--chip));
}

#contact > p,
.contact-block p {
  max-width: 36rem;
  margin: 0 0 1rem;
  color: var(--muted);
}

/* "What I am looking for" sits below the contact links so anyone who only
   wants the address gets it first. The rule separates it without needing a
   second heading weight. */
.contact-block {
  margin-top: 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}

.contact-block h3 {
  margin: 0 0 0.75rem;
  font-size: 1rem;
  color: var(--accent);
}

.contact-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 0.7rem;
}

/* Pills rather than underlined mono, so the four do not read as a shell
   prompt. Colour carries state: green while the action is untaken, navy once
   revealed (the button is replaced by a plain <a>, which takes the base rule). */
.contact-links a,
.contact-links .reveal {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.8rem;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line));
  border-radius: 6px;
  background: color-mix(in srgb, var(--accent) 6%, var(--bg-raised));
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--accent);
  transition: background-color 140ms ease, border-color 140ms ease;
}

.contact-links a:hover {
  color: var(--accent-hover);
  border-color: color-mix(in srgb, var(--accent) 65%, var(--line));
  background: color-mix(in srgb, var(--accent) 11%, var(--bg-raised));
}

.contact-links .reveal {
  color: var(--go);
  border-color: color-mix(in srgb, var(--go) 45%, var(--line));
  background: color-mix(in srgb, var(--go) 7%, var(--bg-raised));
}

.contact-links .reveal:hover {
  color: var(--go-hover);
  border-color: color-mix(in srgb, var(--go) 70%, var(--line));
  background: color-mix(in srgb, var(--go) 12%, var(--bg-raised));
}

.edu {
  display: grid;
  gap: 0.35rem;
}

.edu strong {
  font-family: var(--sans);
  font-size: 1.05rem;
  font-weight: 600;
}

.edu span {
  color: var(--muted);
}

.footnote {
  margin-top: 4rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--muted);
}

.menu-toggle {
  display: none;
}

@media (max-width: 840px) {
  .tab-bar {
    padding: 0.65rem 0.9rem 0;
  }

  .tabs [role="tab"] {
    flex: 0 0 auto;
    font-size: 0.82rem;
    padding: 0.5rem 0.85rem 0.45rem;
  }

  .tab-full {
    display: none;
  }

  .tab-short {
    display: inline;
  }

  .shell {
    grid-template-columns: 1fr;
    grid-template-rows: auto 1fr;
  }

  .rail {
    overflow: visible;
    padding: 0.85rem var(--gutter);
    gap: 0.6rem;
    border-right: 0;
    border-bottom: 1px solid var(--line);
    background: color-mix(in srgb, var(--bg) 92%, transparent);
    backdrop-filter: blur(10px);
  }

  .identity h1 {
    font-size: 1.2rem;
    margin: 0;
  }

  .identity .role,
  .status,
  .rail-meta {
    display: none;
  }

  .page {
    padding-top: 1.4rem;
    padding-bottom: 4.5rem;
  }

  :root {
    --portrait-slot: 0rem;
  }

  .document {
    width: 100%;
    margin: 0;
  }

  .portrait {
    width: min(78vw, 24rem);
    -webkit-mask-image: linear-gradient(to top left, #000 8%, transparent 72%);
    mask-image: linear-gradient(to top left, #000 8%, transparent 72%);
  }

  .portrait img {
    object-position: 62% 6%;
    opacity: 0.58;
  }

  .lede,
  .lede-body {
    max-width: 40rem;
  }

  /* Five cells: auto-fit lands on four here, orphaning the fifth. Three and
     two is the tidier split at this width. */
  .stats {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }


  .job {
    grid-template-columns: 1fr;
    gap: 0.35rem;
  }

  .subtabs [role="tab"] {
    flex: 1 1 auto;
    font-size: 0.82rem;
    padding: 0.5rem 0.75rem 0.42rem;
  }

  .shot-grid {
    grid-template-columns: 1fr;
  }
}

@media print {
  html,
  body {
    height: auto;
    overflow: visible;
  }

  .rail,
  .tab-bar,
  .page-end,
  .card-link,
  .footnote a,
  .portrait {
    display: none !important;
  }

  .document,
  .shell,
  .pages {
    display: block;
    height: auto;
    overflow: visible;
    width: auto;
    max-width: none;
    margin: 0;
  }

  .page {
    display: block !important;
    padding: 0 0 2rem;
  }

  .project-desk {
    display: block;
  }

  .subtabs {
    display: none;
  }

  .project-sheet {
    display: block !important;
    border: 0;
    padding: 0 0 2rem;
  }

  .card {
    box-shadow: none;
    break-inside: avoid;
  }

  a {
    color: inherit;
    text-decoration: none;
  }
}

/* AI project sheet figures ------------------------------------------------
   Each sheet carries a small figure beside its heading: a miniature of the
   project's own screen, animated to mime what the thing IS before any prose
   is read. whereistay.co is a browser typing the address and the cream site
   loading in (it is a live address you can visit). Zonepal is its dark globe
   window with a pin clicked and the on-shift panel filling. Mac Blueprint is
   its Restore screen, Choose File clicked, the restore ticking through.

   Colours inside a figure are the depicted app's, not the site's -- the
   screenshot tiles below each sheet already carry them, and a navy-only
   Zonepal would be a picture of something else. The site palette stops at
   the figure's border.

   Each sequence runs ONCE and holds its final frame. A hidden sheet is
   display:none, which stops CSS animations and rewinds them, so switching
   projects or leaving and returning to AI Projects replays the figure with no
   JS. It plays on arrival and then sits still while the sheet is read.

   Every moving rule is gated behind html:not(.reduced-motion); the static
   rules are the finished frame, so a reduced-motion reader sees the typed
   address, the open panel and the completed restore, just without the
   journey. */
.sheet-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.5rem;
}

.sheet-head .head-text {
  display: grid;
  gap: 1.2rem;
  min-width: 0;
}

.proj-anim {
  flex: 0 0 auto;
  position: relative;
  width: 13.25rem;
  height: 8rem;
  margin: 0.1rem 0 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
  box-shadow: 0 6px 18px rgba(21, 34, 56, 0.08);
  font-family: var(--sans);
  line-height: 1;
  -webkit-user-select: none;
  user-select: none;
}

/* Below this the sheet body is narrow enough that the figure would push the
   project title onto a third line. The prose carries the meaning. */
@media (max-width: 860px) {
  .proj-anim {
    display: none;
  }
}

/* Shared cursor. Positioned by transform from the figure's top-left, so each
   sequence's keyframes read as plain (x, y) pixel coordinates. */
.proj-anim .pointer {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 5;
  width: 13px;
  height: 17px;
  opacity: 0;
  fill: var(--ink);
  stroke: var(--bg-raised);
  stroke-width: 1.2;
}

.proj-anim .pip {
  flex: 0 0 auto;
  border-radius: 50%;
}

/* macOS window furniture shared by the two dark app figures. */
.proj-anim.mac {
  background: #1d1d1f;
  border-color: #3a3a3c;
}

.mac .mac-bar {
  position: absolute;
  inset: 0 0 auto 0;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 4px;
  height: 17px;
  padding: 0 7px;
}

.mac .tl {
  width: 6px;
  height: 6px;
  border-radius: 50%;
}

.mac .tl.r { background: #ff5f57; }
.mac .tl.y { background: #febc2e; }
.mac .tl.g { background: #28c840; }

.mac .win-title {
  margin-left: 5px;
  font-size: 7px;
  font-weight: 600;
  color: #f2f2f2;
}

.mac .pointer {
  fill: #fff;
  stroke: #1d1d1f;
}

/* 01 — whereistay.co: a browser going to the address ---------------------- */
.anim-browser .chrome {
  display: flex;
  align-items: center;
  gap: 0.28rem;
  height: 23px;
  padding: 0 0.45rem;
  border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--ink) 4%, var(--bg-raised));
}

.anim-browser .dot {
  flex: 0 0 auto;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--ink) 20%, transparent);
}

.anim-browser .omni {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  margin-left: 0.2rem;
  height: 15px;
  padding: 0 0.35rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--bg-raised);
  overflow: hidden;
  font-family: var(--mono);
}

.anim-browser .url {
  display: block;
  width: 17ch;
  overflow: hidden;
  white-space: nowrap;
  font-size: 0.6rem;
  color: var(--accent);
}

.anim-browser .caret {
  flex: 0 0 auto;
  width: 1px;
  height: 0.66rem;
  background: var(--accent);
  opacity: 0;
}

/* The page that loads: whereistay.co's own cream and bottle green. */
.anim-browser .site {
  position: absolute;
  inset: 23px 0 0 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 7px 8px 8px;
  background: #f7f2e8;
}

.anim-browser .site-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 14px;
}

.anim-browser .wordmark {
  position: relative;
  padding-top: 3px;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 8px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #23463a;
}

.anim-browser .wordmark::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 1px;
  background: #b7a98a;
}

.anim-browser .book {
  padding: 4px 6px;
  border-radius: 2px;
  background: #1f3f33;
  font-size: 5.5px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #f7f2e8;
}

.anim-browser .stays {
  flex: 1 1 auto;
  display: flex;
  gap: 5px;
}

.anim-browser .stay {
  position: relative;
  flex: 1 1 0;
  border-radius: 3px;
  overflow: hidden;
}

/* Three "photographs" as gradients: a sofa against a sky window, the pool
   under hedge and sky, an interior opening onto the sea. */
.anim-browser .stay:nth-child(1) {
  background:
    linear-gradient(180deg, #9fc4e2 0 42%, #efe7d7 42% 68%, #d9cdb5 68%);
}

.anim-browser .stay:nth-child(2) {
  background:
    radial-gradient(ellipse 34% 14% at 28% 90%, #f2c531 0 70%, transparent 74%),
    linear-gradient(180deg, #3f8fdc 0 40%, #5f9346 40% 56%, #3fb2c4 56%);
}

.anim-browser .stay:nth-child(3) {
  background:
    linear-gradient(180deg, #b4d1e6 0 36%, #f3ede2 36% 64%, #c9b99f 64%);
}

.anim-browser .stay i {
  position: absolute;
  top: 4px;
  left: 4px;
  padding: 2px 3px;
  border-radius: 999px;
  background: #fff;
  font-size: 4.5px;
  font-style: normal;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #23463a;
}

html:not(.reduced-motion) .anim-browser .pointer {
  animation: browser-pointer 4.4s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

html:not(.reduced-motion) .anim-browser .omni {
  animation: omni-focus 4.4s steps(1) forwards;
}

html:not(.reduced-motion) .anim-browser .url {
  width: 0;
  animation: browser-type 1.7s steps(17) 1.15s forwards;
}

html:not(.reduced-motion) .anim-browser .caret {
  animation: caret-blink 0.65s steps(1) 1.05s 4 forwards;
}

html:not(.reduced-motion) .anim-browser .site {
  opacity: 0;
  animation: fade-in 0.35s ease-out 3.05s forwards;
}

html:not(.reduced-motion) .anim-browser .stay {
  opacity: 0;
  transform: translateY(7px);
  animation: rise-in 0.45s ease-out forwards;
}

html:not(.reduced-motion) .anim-browser .stay:nth-child(1) { animation-delay: 3.25s; }
html:not(.reduced-motion) .anim-browser .stay:nth-child(2) { animation-delay: 3.4s; }
html:not(.reduced-motion) .anim-browser .stay:nth-child(3) { animation-delay: 3.55s; }

@keyframes browser-pointer {
  0% { transform: translate(158px, 96px); opacity: 0; }
  8% { opacity: 1; }
  20% { transform: translate(74px, 14px); opacity: 1; }
  23% { transform: translate(74px, 14px) scale(0.86); }
  27% { transform: translate(74px, 14px) scale(1); }
  62% { transform: translate(74px, 14px); opacity: 1; }
  76%, 100% { transform: translate(92px, 50px); opacity: 0; }
}

@keyframes omni-focus {
  0% {
    border-color: var(--line);
    box-shadow: none;
  }
  24%, 100% {
    border-color: color-mix(in srgb, var(--accent) 50%, var(--line));
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 12%, transparent);
  }
}

@keyframes browser-type {
  from { width: 0; }
  to { width: 17ch; }
}

@keyframes caret-blink {
  0%, 49% { opacity: 1; }
  50%, 100% { opacity: 0; }
}

@keyframes fade-in {
  to { opacity: 1; }
}

@keyframes rise-in {
  to { opacity: 1; transform: none; }
}

/* 02 — Zonepal: the Timeline view, the now-line dragged --------------------
   The app's signature move is dragging the vertical line to compare local
   times, so that is what the cursor does. The chips on the line step through
   the times as it moves, and Ciaran -- offline at 2am in London when the line
   starts -- comes on shift as it reaches his block. */
.anim-zonepal {
  background:
    radial-gradient(ellipse 30% 22% at 22% 30%, rgba(180, 190, 205, 0.16), transparent 70%),
    radial-gradient(ellipse 26% 30% at 62% 26%, rgba(180, 190, 205, 0.14), transparent 70%),
    radial-gradient(ellipse 22% 16% at 84% 72%, rgba(180, 190, 205, 0.12), transparent 70%),
    #182236;
}

.anim-zonepal .tl-panel {
  position: absolute;
  inset: 17px 6px 6px 6px;
  border-radius: 5px;
  background: rgba(34, 35, 40, 0.94);
  border: 1px solid #3b3c41;
}

.anim-zonepal .tl-head {
  position: absolute;
  top: 6px;
  left: 7px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.anim-zonepal .tl-title {
  font-size: 7.5px;
  font-weight: 700;
  color: #fff;
}

.anim-zonepal .tl-sub {
  font-size: 4.6px;
  color: #9a9aa0;
}

.anim-zonepal .hours {
  position: absolute;
  top: 25px;
  left: 48px;
  right: 6px;
  display: flex;
  justify-content: space-between;
  font-size: 4.4px;
  color: #7c7c82;
}

.anim-zonepal .rows {
  position: absolute;
  top: 34px;
  left: 6px;
  right: 6px;
  bottom: 6px;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: 5px;
}

.anim-zonepal .trow {
  display: flex;
  align-items: center;
  height: 16px;
}

.anim-zonepal .nm {
  flex: 0 0 42px;
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 6px;
  font-weight: 600;
  color: #e8e8ec;
}

.anim-zonepal .you .nm {
  color: #4aa3ff;
}

.anim-zonepal .pip {
  width: 5px;
  height: 5px;
  background: #ff453a;
}

.anim-zonepal .pip.on {
  background: #30d158;
}

.anim-zonepal .track {
  position: relative;
  flex: 1 1 auto;
  height: 100%;
  border-radius: 2px;
  background:
    repeating-linear-gradient(90deg, transparent 0 24.6%, #3a3b40 24.6% 25%),
    #2c2d32;
}

/* Working-hours blocks on the 24h track: 9am–7:30pm for the two locals; for
   Ciaran, asleep until 8am then on shift from late Brisbane afternoon. */
.anim-zonepal .blk {
  position: absolute;
  top: 2px;
  bottom: 2px;
  border-radius: 2px;
}

.anim-zonepal .blk.on {
  left: 37.5%;
  width: 40.5%;
  background: rgba(48, 209, 88, 0.22);
  border: 1px solid rgba(48, 209, 88, 0.6);
}

.anim-zonepal .far .blk.off {
  left: 0;
  width: 30%;
  background: rgba(255, 69, 58, 0.22);
  border: 1px solid rgba(255, 69, 58, 0.55);
}

.anim-zonepal .far .blk.on {
  left: 68.5%;
  width: 31.5%;
}

/* The now-line. Its x is measured from the track's left edge; 67px is about
   11am on a 146px day, and the drag carries it 46px to roughly 6:30pm. */
.anim-zonepal .now {
  position: absolute;
  top: -3px;
  left: calc(42px + 67px);
  height: 62px;
  width: 1.5px;
  background: #2f8cff;
  transform: translateX(46px);
}

.anim-zonepal .now::before {
  content: "";
  position: absolute;
  top: -3px;
  left: 50%;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #2f8cff;
  transform: translateX(-50%);
  box-shadow: 0 0 0 1.5px #232328;
}

.anim-zonepal .chip {
  position: absolute;
  left: 50%;
  padding: 2px 3px;
  border-radius: 3px;
  background: #1c1d21;
  border: 1px solid #4a4b50;
  font-size: 5px;
  font-weight: 600;
  white-space: nowrap;
  color: #fff;
  transform: translate(-50%, -50%);
}

.anim-zonepal .chip.c1 { top: 11px; }
.anim-zonepal .chip.c2 { top: 32px; }
.anim-zonepal .chip.c3 { top: 53px; }

/* Each chip holds its four readings stacked; the first (widest) sets the
   chip's size and the rest sit over it. Only one shows at a time. `content`
   cannot be keyframed in Chrome, so the text is swapped by opacity instead. */
.anim-zonepal .chip i {
  display: block;
  font-style: normal;
  opacity: 0;
}

.anim-zonepal .chip i + i {
  position: absolute;
  inset: 2px 0;
  text-align: center;
}

.anim-zonepal .chip i:last-child {
  opacity: 1;
}

.anim-zonepal .far .pip {
  background: #30d158;
}

html:not(.reduced-motion) .anim-zonepal .pointer {
  animation: zonepal-pointer 4.4s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

html:not(.reduced-motion) .anim-zonepal .now {
  transform: none;
  animation: now-drag 4.4s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

html:not(.reduced-motion) .anim-zonepal .chip i {
  animation: 4.4s steps(1) forwards;
}

html:not(.reduced-motion) .anim-zonepal .chip i:nth-child(1) { animation-name: chip-1; }
html:not(.reduced-motion) .anim-zonepal .chip i:nth-child(2) { animation-name: chip-2; }
html:not(.reduced-motion) .anim-zonepal .chip i:nth-child(3) { animation-name: chip-3; }
html:not(.reduced-motion) .anim-zonepal .chip i:nth-child(4) { animation-name: chip-4; }

html:not(.reduced-motion) .anim-zonepal .far .pip {
  animation: far-on-shift 4.4s steps(1) forwards;
}

@keyframes zonepal-pointer {
  0% { transform: translate(170px, 104px); opacity: 0; }
  8% { opacity: 1; }
  20% { transform: translate(120px, 43px); opacity: 1; }
  23% { transform: translate(120px, 43px) scale(0.86); }
  27% { transform: translate(120px, 43px) scale(0.86); }
  65% { transform: translate(166px, 43px) scale(0.86); opacity: 1; }
  69% { transform: translate(166px, 43px) scale(1); }
  76% { transform: translate(166px, 43px); opacity: 1; }
  86%, 100% { transform: translate(184px, 84px); opacity: 0; }
}

@keyframes now-drag {
  0%, 27% { transform: none; }
  65%, 100% { transform: translateX(46px); }
}

@keyframes chip-1 {
  0%, 39% { opacity: 1; }
  40%, 100% { opacity: 0; }
}

@keyframes chip-2 {
  0%, 39% { opacity: 0; }
  40%, 51% { opacity: 1; }
  52%, 100% { opacity: 0; }
}

@keyframes chip-3 {
  0%, 51% { opacity: 0; }
  52%, 61% { opacity: 1; }
  62%, 100% { opacity: 0; }
}

@keyframes chip-4 {
  0%, 61% { opacity: 0; }
  62%, 100% { opacity: 1; }
}

@keyframes far-on-shift {
  0%, 55% { background: #ff453a; }
  56%, 100% { background: #30d158; }
}

/* 03 — Mac Blueprint: Restore, Choose File, the restore running ------------ */
.anim-blueprint .stage {
  position: absolute;
  inset: 17px 0 0 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 7px;
}

/* The green document-with-arrow from the Restore screen, at 16 x 20. */
.anim-blueprint .doc {
  position: relative;
  width: 16px;
  height: 20px;
  border-radius: 2px;
  background: #30d158;
  clip-path: polygon(0 0, 66% 0, 100% 26%, 100% 100%, 0 100%);
}

.anim-blueprint .doc::before {
  content: "";
  position: absolute;
  left: 7px;
  top: 6px;
  width: 2px;
  height: 7px;
  background: #1d1d1f;
}

.anim-blueprint .doc::after {
  content: "";
  position: absolute;
  left: 4.5px;
  top: 9px;
  width: 5px;
  height: 5px;
  border: solid #1d1d1f;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

.anim-blueprint .h {
  font-size: 7.5px;
  font-weight: 700;
  color: #fff;
}

.anim-blueprint .btn {
  padding: 4px 8px;
  border-radius: 999px;
  background: #0a84ff;
  font-size: 6px;
  font-weight: 600;
  color: #fff;
}

.anim-blueprint .run {
  align-items: stretch;
  justify-content: center;
  padding: 0 26px;
}

.anim-blueprint .steps {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.anim-blueprint .steps li {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 7px;
  color: #e5e5ea;
}

/* Checkmark drawn from two borders on a rotated box, so nothing loads. */
.anim-blueprint .tick {
  flex: 0 0 auto;
  width: 4px;
  height: 8px;
  margin: -2px 2px 0;
  border: solid #30d158;
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(42deg);
}

.anim-blueprint .meter {
  display: block;
  height: 3px;
  margin-top: 4px;
  border-radius: 999px;
  background: #3a3a3c;
  overflow: hidden;
}

.anim-blueprint .meter i {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: inherit;
  background: #0a84ff;
}

/* Finished frame: the Restore screen has been replaced by the running
   restore. Animation plays the swap. */
.anim-blueprint .load {
  opacity: 0;
}

html:not(.reduced-motion) .anim-blueprint .pointer {
  animation: blueprint-pointer 4.4s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

html:not(.reduced-motion) .anim-blueprint .load {
  opacity: 1;
  animation: fade-out 0.3s ease-in 1.35s forwards;
}

html:not(.reduced-motion) .anim-blueprint .btn {
  animation: btn-press 4.4s steps(1) forwards;
}

html:not(.reduced-motion) .anim-blueprint .run {
  opacity: 0;
  animation: fade-in 0.35s ease-out 1.6s forwards;
}

html:not(.reduced-motion) .anim-blueprint .tick {
  opacity: 0;
  transform: rotate(42deg) scale(0.4);
  animation: tick-in 0.32s cubic-bezier(0.34, 1.4, 0.64, 1) forwards;
}

html:not(.reduced-motion) .anim-blueprint .steps li:nth-child(1) .tick { animation-delay: 2.1s; }
html:not(.reduced-motion) .anim-blueprint .steps li:nth-child(2) .tick { animation-delay: 2.7s; }
html:not(.reduced-motion) .anim-blueprint .steps li:nth-child(3) .tick { animation-delay: 3.3s; }

html:not(.reduced-motion) .anim-blueprint .meter i {
  width: 0;
  animation: meter-fill 1.9s cubic-bezier(0.3, 0, 0.3, 1) 1.8s forwards;
}

@keyframes blueprint-pointer {
  0% { transform: translate(170px, 106px); opacity: 0; }
  8% { opacity: 1; }
  20% { transform: translate(108px, 92px); opacity: 1; }
  23% { transform: translate(108px, 92px) scale(0.86); }
  27% { transform: translate(108px, 92px) scale(1); }
  34% { transform: translate(108px, 92px); opacity: 1; }
  46%, 100% { transform: translate(150px, 112px); opacity: 0; }
}

@keyframes btn-press {
  0%, 22% { filter: none; }
  23%, 100% { filter: brightness(0.8); }
}

@keyframes fade-out {
  to { opacity: 0; }
}

@keyframes tick-in {
  to { opacity: 1; transform: rotate(42deg) scale(1); }
}

@keyframes meter-fill {
  to { width: 100%; }
}

/* Richness pass: measure and material ------------------------------------
   Prose is held to a book measure whatever the pane width; long lines on a
   wide pane were the cheapest-looking thing on the site. The grain is a
   fixed, click-through noise layer at 4% -- enough that the paper is not a
   flat fill, not enough to be seen as texture. */
.page p,
.job li,
.detail li,
.earlier {
  max-width: 42rem;
}

body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  opacity: 0.025;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.7 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
