:root {
  --bg: #F2F2F7;
  --ink: #1C1C1E;
  --ink-60: rgba(28, 28, 30, 0.58);
  --ink-45: rgba(28, 28, 30, 0.45);
  --gutter: 5vw;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
}

body {
  font-family: 'Archivo', system-ui, -apple-system, sans-serif;
  font-weight: 400;
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}

section {
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding: 6vh var(--gutter);
}

.col {
  width: 50%;
}

.lede {
  margin: 0;
  font-size: 1rem;
  line-height: 1.35;
  text-wrap: pretty;
}


a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  transition: text-decoration-color 0.3s ease;
}

a:hover {
  text-decoration-color: rgba(28, 28, 30, 0.35);
}

/* Mark floating in the corner, its rotation driven by scroll position. */
/* The mascot is always a link: back to top on the homepage, home elsewhere.
   The 88px box is the hit area, so the transparent parts of the drawing are
   clickable too. */
.home {
  position: fixed;
  /* The drawing is inscribed in its canvas so rotating it cannot push the ink
     outside this box -- that overflow was what made the mascot look like it
     drifted. The canvas is 1.23x the drawing, so the box is 10px larger a side
     than the 88px drawing; top/right pull back by the same 10px to leave the
     drawing itself sitting on the 6vh / gutter line. */
  top: calc(6vh - 10px);
  right: calc(var(--gutter) - 10px);
  width: 108px;
  height: 108px;
  z-index: 10;
  cursor: pointer;
}

.spinner {
  display: block;
  width: 100%;
  height: 100%;
}

/* Hands the rotation over to the unwind animation on the way home. */
.spinner.unwinding { animation: none; }

@keyframes spin {
  to { transform: rotate(720deg); }
}

@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: scroll()) {
    .spinner {
      animation: spin linear both;
      animation-timeline: scroll(root block);
    }
  }
}

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

/* Vita ------------------------------------------------------------------ */

.vita {
  /* Size to content: the space above the footer stops being leftover slack. */
  min-height: 0;
  align-items: flex-start;
}

.vita .col {
  width: 100%;
}

/* Columns stretch to the tallest, then each list spreads its rows so all
   three bottom out at the same line. */
.groups {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  align-items: stretch;
  gap: 4rem;
}

.group {
  display: flex;
  flex-direction: column;
}

.group h2 {
  margin: 0 0 1.75rem;
  font-size: 0.8125rem;
  font-weight: 500;
}

.entries {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 1.875rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.dates {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--ink-45);
  font-variant-numeric: tabular-nums;
}

.group h3 {
  margin: 0.15rem 0 0;
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.3;
}

.sub {
  margin: 0.15rem 0 0;
  font-size: 0.8125rem;
  color: var(--ink-60);
}

/* A company is named once, with its roles on a line of continuity below. */
.run {
  display: flex;
  flex-direction: column;
}

.run:has(.roles li + li) {
  flex: 1;
}

.org {
  margin: 0 0 0.75rem;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--ink-60);
}

.roles {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Only a run of two or more roles needs the line. */
.roles:has(li + li) {
  padding-left: 0.875rem;
  border-left: 1px solid rgba(28, 28, 30, 0.16);
}

/* Footer --------------------------------------------------------------- */

footer {
  margin-top: clamp(6rem, 18vh, 12rem);
  display: flex;
  align-items: center;
  gap: 2.5rem;
  padding: 0 var(--gutter) 8vh;
  font-size: 0.8125rem;
}

/* Reset the button back to text so it reads like the site's links. */
.copy {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

/* Quieter than the links in the prose: down here the glyph already marks each
   item as something you can act on, so the rule only shows on approach. */
footer a,
footer .copy {
  text-decoration: none;
}

footer a:hover,
footer a:focus-visible,
footer .copy:hover,
footer .copy:focus-visible {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}

.cv,
.out {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

/* All three are persistent rather than revealed on hover: the glyph is what
   says whether an item copies, opens away or hands you a file, and that is
   worth knowing before you point at it. */
.glyph {
  width: 0.9em;
  height: 0.9em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.55;
}

.done-glyph { display: none; }

.copy[data-copied] .copy-glyph { display: none; }
.copy[data-copied] .done-glyph { display: block; }

/* Case study ------------------------------------------------------------ */

/* Prose needs a measure: 50% of a wide viewport runs ~95 characters. */
.study {
  --col-gap: 4rem;
  /* Exactly one of the two equal columns, so prose and pair text share both
     edges without repeating a number. */
  --col: calc((100% - var(--col-gap)) / 2);

  max-width: 1280px;
  margin-inline: auto;
  padding: 18vh var(--gutter) 0;
}

/* Prose keeps to the left column; the right side stays open for visuals. */
.study > h1,
.study > .live,
.study .body > h2,
.study .body > p,
.study .body > dl,
.study .body > ol {
  max-width: var(--col);
}

.study h1 {
  margin: 0;
  font-size: 1.5rem;
  font-weight: 500;
  letter-spacing: -0.015em;
}

.study .meta {
  margin: 0.5rem 0 0;
  font-size: 0.8125rem;
  color: var(--ink-60);
}

.study .live {
  margin: 1.5rem 0 0;
  font-size: 0.8125rem;
}

.study .body {
  /* flow-root so the floated figures below are contained and cannot
     overlap the pager. */
  display: flow-root;
  margin-top: 3.5rem;
  font-size: 1rem;
  line-height: 1.5;
}

.study .body h2 {
  margin: 2.5rem 0 0.75rem;
  font-size: 0.8125rem;
  font-weight: 500;
}

.study .body h2:first-child { margin-top: 0; }

.study .body p {
  margin: 0 0 1rem;
  text-wrap: pretty;
}

.study .body p:last-child { margin-bottom: 0; }

/* Case study body elements ---------------------------------------------- */

/* Role / Focus / Timeline / Team / Status. Label column echoes the vita. */
.details {
  display: grid;
  grid-template-columns: 7rem 1fr;
  gap: 0.5rem 1.5rem;
  margin: 0 0 3rem;
  font-size: 0.8125rem;
}

.details dt {
  color: var(--ink-45);
}

.details dd {
  margin: 0;
}

/* The lead sentence of a section, a step above body copy but not a heading. */
.study .body .statement {
  margin: 0 0 1rem;
  font-size: 1rem;
  font-weight: 500;
  text-wrap: pretty;
}

/* A text block and the visual it points to, tops aligned. */
.pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 var(--col-gap);
  align-items: start;
  margin-top: 5rem;
}

/* Any number of figures stay right rather than wrapping into column one. */
.pair > figure { grid-column: 2; }
.pair > .shot { margin-top: 0; }

/* Figures drop into the open right-hand column while the prose keeps flowing
   past them -- the text is already capped at var(--col) above, so no line ever
   has to wrap around one. clear stacks each figure under the last; without it
   two half-width floats sit side by side and the second lands on the prose. */
.study .body > figure.shot {
  float: right;
  clear: right;
  /* Narrower than the prose column on purpose. A float cannot rise above the
     text it follows, so once the stack of figures is taller than the prose
     beside it they queue up, stop tracking what they illustrate, and the last
     one hangs below the final paragraph. 0.90 is what makes the current six fit. */
  width: calc(var(--col) * 0.90);
  margin: 0 0 2rem;
}

.step-no {
  margin: 0 0 0.5rem;
  font-size: 0.8125rem;
  color: var(--ink-45);
  font-variant-numeric: tabular-nums;
}

/* Image slot. Swap the div for an <img> when the real asset lands. */
.shot {
  margin: 1.5rem 0 0;
}

.shot .placeholder {
  aspect-ratio: 16 / 10;
  background: rgba(28, 28, 30, 0.04);
  border: 1px solid rgba(28, 28, 30, 0.08);
}

.shot img {
  display: block;
  width: 100%;
  height: auto;
}

.shot figcaption {
  margin-top: 0.625rem;
  font-size: 0.75rem;
  line-height: 1.4;
  color: var(--ink-45);
  text-wrap: pretty;
}

.outcome {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: outcome;
}

.outcome li {
  counter-increment: outcome;
  display: grid;
  grid-template-columns: 2.5rem 1fr;
  gap: 1rem;
  margin-bottom: 1rem;
}

.outcome li::before {
  content: counter(outcome, decimal-leading-zero);
  color: var(--ink-45);
  font-variant-numeric: tabular-nums;
}

/* Pager ----------------------------------------------------------------- */

.pager {
  display: flex;
  gap: 2.5rem;
  padding: 10vh var(--gutter) 0;
  font-size: 0.8125rem;
}

/* Keeps Next on the right even when there is no Previous. */
.pager .next {
  margin-left: auto;
  text-align: right;
}

.pager a { text-decoration: none; }
.pager a:hover .title { text-decoration: underline; }

.pager span {
  display: block;
  color: var(--ink-45);
  margin-bottom: 0.25rem;
}

/* The pager already separates content from the footer, so the footer's own
   large margin would double up here. */
.pager + footer {
  margin-top: clamp(3rem, 8vh, 5rem);
}

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

@media (max-width: 1000px) {
  .groups { grid-template-columns: repeat(2, 1fr); gap: 3.5rem; }
}

@media (max-width: 900px) {
  .pair { grid-template-columns: 1fr; gap: 1.5rem; }
  /* Without this the explicit column 2 spawns an implicit track and the
     single-column collapse never happens. */
  .pair > figure { grid-column: auto; }
  .study > h1,
  .study > .live,
  .study .body > h2,
  .study .body > p,
  .study .body > dl,
  .study .body > ol { max-width: none; }
  .study .body > figure.shot {
    float: none;
    width: auto;
    margin: 1.5rem 0 2.5rem;
  }
}

@media (max-width: 700px) {
  .col { width: 100%; }
  .groups { grid-template-columns: 1fr; gap: 3rem; align-items: start; }
  .study { padding-top: 22vh; }
  .home {
    top: calc(6vh - 8px);
    right: calc(var(--gutter) - 8px);
    width: 84px;
    height: 84px;
  }
  .run:has(.roles li + li) { flex: 0; }
}

@media print {
  .home { display: none; }
  body { background: #fff; color: #000; }
  section { min-height: 0; display: block; padding: 0 0 1.5rem; }
  .col, .vita .col { width: 100%; }
  .groups { grid-template-columns: repeat(3, 1fr); gap: 1.5rem; }
  .entries { justify-content: flex-start; }
  .run:has(.roles li + li) { flex: 0; }
  footer { margin-top: 2rem; padding: 0; }
  .pager { display: none; }
}
