/* ==========================================================================
   Studio Max Redecker — case studies
   Shares the fonts and brand colours of css/style.css; everything else here.
   ========================================================================== */

/* Fonts: same self-hosted files as the home page, declared again so a case
   page can be opened on its own without loading style.css.
   ------------------------------------------------------------------------- */
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("../assets/fonts/figtree-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("../assets/fonts/figtree-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Yeseva One";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../assets/fonts/yeseva-one-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Tokens
   ------------------------------------------------------------------------- */
:root {
  --ink: rgb(21, 24, 46);
  --ink-soft: rgb(91, 96, 128);
  --ink-faint: rgba(21, 24, 46, 0.55);
  --paper: rgb(251, 250, 247);
  --paper-raised: rgb(255, 255, 255);
  --cream: rgb(255, 245, 200);
  --green: rgb(200, 245, 200);
  --green-strong: rgb(120, 240, 160);
  --violet: rgb(120, 90, 220);
  --amber: rgb(196, 106, 18);
  --amber-bg: rgba(255, 176, 46, 0.14);
  --line: rgba(21, 24, 46, 0.12);
  --line-soft: rgba(21, 24, 46, 0.07);
  --outline-img: rgba(0, 0, 0, 0.1);
  --pg-red: #e03127;

  --measure: 62ch;
  --gutter: 24px;
  --shell: 1240px;

  /* The one grid. It lives here rather than on .cs-page because the bar at
     the top and the line at the bottom are part of the same page and have to
     stand on the same lines as everything between them. The side padding is
     exactly one cell and the column is 17 cells, so the content spans 15
     whole cells and every edge lands on a line. */
  --c-cell: 64px;
  --c-pad-x: clamp(16px, 5vw, 64px);
  --c-col: 1088px;

  /* One easing for entrances and state changes, one for exits. */
  --ease: cubic-bezier(0.2, 0, 0, 1);
  --ease-out: cubic-bezier(0.33, 1, 0.68, 1);
}

/* Reset
   ------------------------------------------------------------------------- */
*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
}

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: "Figtree", -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif;
  font-size: 17px;
  line-height: 1.6;
  font-variant-numeric: tabular-nums;
  overflow-x: hidden;
}

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

a {
  color: inherit;
}

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

:focus-visible {
  outline: 2px solid var(--violet);
  outline-offset: 3px;
  border-radius: 4px;
}

/* Shell
   ------------------------------------------------------------------------- */
.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  padding-block: clamp(52px, 6vw, 88px);
  border-top: 1px solid var(--line-soft);
}

.section--flush {
  border-top: 0;
}

/* Type
   ------------------------------------------------------------------------- */
.display {
  font-family: "Yeseva One", Georgia, serif;
  font-weight: 400;
  line-height: 0.96;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

h1.display {
  font-size: clamp(44px, 7.5vw, 86px);
}

h2.display {
  font-size: clamp(28px, 3.6vw, 46px);
  line-height: 1.05;
}

h3 {
  font-size: clamp(21px, 2.2vw, 26px);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

.eyebrow {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.eyebrow::before {
  content: "";
  width: 28px;
  height: 1px;
  background: currentColor;
  flex: none;
}

.lede {
  max-width: var(--measure);
  font-size: clamp(18px, 1.5vw, 20px);
  line-height: 1.55;
  color: var(--ink);
}

.prose {
  max-width: var(--measure);
}

.prose p + p {
  margin-top: 1em;
}

.prose p {
  color: var(--ink-soft);
}

.prose strong {
  color: var(--ink);
  font-weight: 600;
}

.section__head {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-bottom: clamp(26px, 3vw, 40px);
}

/* Top bar
   ------------------------------------------------------------------------- */
.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid transparent;
  transition-property: border-color, background;
  transition-duration: 200ms;
  transition-timing-function: var(--ease);
}

.topbar.is-stuck {
  border-bottom-color: var(--line-soft);
}

.topbar__inner {
  max-width: var(--c-col);
  margin-inline: auto;
  padding: 14px var(--c-pad-x);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.topbar__home {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  color: var(--ink);
}

.topbar__home svg {
  width: 15px;
  height: 15px;
  transition-property: translate;
  transition-duration: 200ms;
  transition-timing-function: var(--ease);
}

@media (hover: hover) {
  .topbar__home:hover svg {
    translate: -3px 0;
  }
}

.topbar__meta {
  font-size: 13px;
  color: var(--ink-faint);
}

/* Buttons
   ------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 13px 26px;
  border: 0;
  border-radius: 50px 50px 50px 0;
  background: var(--green-strong);
  color: var(--ink);
  font: inherit;
  font-size: 16px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition-property: background, scale;
  transition-duration: 200ms;
  transition-timing-function: var(--ease);
}

.btn--ghost {
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--line);
}

@media (hover: hover) {
  .btn:hover { background: var(--cream); }
  .btn--ghost:hover { background: var(--paper-raised); }
}

.btn:active {
  scale: 0.96;
}

.btn svg {
  width: 16px;
  height: 16px;
  stroke-width: 2;
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}

/* Hero
   ------------------------------------------------------------------------- */
.hero {
  padding-block: clamp(36px, 4.5vw, 64px) clamp(28px, 3.5vw, 48px);
}

.hero__inner {
  display: flex;
  flex-direction: column;
  gap: 28px;
}

.hero__title {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 20px;
}

.hero__title em {
  font-family: "Figtree", sans-serif;
  font-size: clamp(15px, 1.2vw, 17px);
  font-style: normal;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--ink-faint);
}

.meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 1px;
  margin-top: 8px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: 14px;
  overflow: hidden;
}

.meta__item {
  padding: 16px 18px;
  background: var(--paper);
}

.meta__key {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.meta__val {
  margin-top: 3px;
  font-size: 16px;
  font-weight: 600;
}

.meta__val a {
  text-decoration: underline;
  text-decoration-color: var(--line);
  text-underline-offset: 3px;
  transition-property: color, text-decoration-color;
  transition-duration: 150ms;
}

@media (hover: hover) {
  .meta__val a:hover {
    color: var(--violet);
    text-decoration-color: currentColor;
  }
}

/* Claim strip — the answer to "does it show more than finished screens"
   ------------------------------------------------------------------------- */
.claim {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: clamp(20px, 3vw, 44px);
  padding: clamp(24px, 3vw, 36px);
  border-radius: 18px;
  background: linear-gradient(145deg, var(--cream), var(--green));
}

.claim__n {
  font-family: "Yeseva One", Georgia, serif;
  font-size: clamp(38px, 4.6vw, 58px);
  line-height: 1;
}

.claim__t {
  margin-top: 8px;
  font-size: 15px;
  line-height: 1.45;
  color: rgba(21, 24, 46, 0.72);
}

/* Flow: steps beside a sticky app window
   ------------------------------------------------------------------------- */
.flow {
  /* The guide is drawn once and used at two widths, so it is named here and
     the folded rule below reads from the same figure. */
  --pg-w: 488px;

  display: grid;
  /* Was 0.84 / 1.16, set when a step was a heading and two short notes. A step
     now opens with a job story and carries its states, and at 1440 that column
     came to 379px while its own type asks for 46ch — 471px for the job story,
     413px for a note. The guide had the slack to give: it is a narrow artefact
     that was sitting in 523px. */
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: clamp(28px, 4vw, 72px);
  align-items: start;
}

.flow__steps {
  display: flex;
  flex-direction: column;
  /* The runway the sticky guide needs. Too short and the panel flicks between
     screens while the reader is still on the first sentence; each step wants
     most of a viewport to itself. A step used to be a heading and two notes
     and the runway had to come from this gap; now it is 304 to 437px of its
     own and most of the runway is the step. */
  gap: clamp(64px, 20vh, 180px);
  padding-block: 2vh 24vh;
  counter-reset: step;
}

.step {
  --step-dim: 1;

  /* One column for everything inside a step. The job story, the states and
     the design calls are set at three different sizes, so giving each of
     them 46ch stopped each one somewhere else and the stack came out ragged
     down its right edge. This is the job story's 46ch, measured once. */
  --step-measure: 472px;
  opacity: calc(0.34 + 0.66 * var(--step-dim));
  transition-property: opacity;
  transition-duration: 450ms;
  transition-timing-function: var(--ease);
}

.step.is-active {
  --step-dim: 1;
}

.js .step:not(.is-active) {
  --step-dim: 0;
}

.step__n {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--ink);
  color: var(--paper);
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  transition-property: background, color, scale;
  transition-duration: 300ms;
  transition-timing-function: var(--ease);
}

.step:not(.is-active) .step__n {
  background: transparent;
  color: var(--ink-faint);
  box-shadow: inset 0 0 0 1px var(--line);
}

.step h3 {
  margin: 14px 0 10px;
}

/* Direct children only. When the flow folds on a narrow screen the whole
   priority guide moves inside the step, and a descendant selector here would
   put a 46ch cap on every group heading and row inside it. */
.step > p {
  color: var(--ink-soft);
  max-width: var(--step-measure);
}

/* Block, not flex: these notes carry inline <b> inside running text, and a
   flex container turns every bold run into its own narrow column. */
.step__note {
  display: block;
  margin-top: 14px;
  padding: 14px 16px;
  border-radius: 14px;
  background: var(--paper-raised);
  box-shadow: inset 0 0 0 1px var(--line-soft);
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink-soft);
  max-width: var(--step-measure);
}

.step__note b {
  color: var(--ink);
  font-weight: 600;
}

.flow__stage {
  position: sticky;
  top: 84px;
}

/* The Mac window
   ------------------------------------------------------------------------- */
.win {
  border-radius: 14px;
  background: var(--paper-raised);
  box-shadow:
    0 0 0 1px rgba(21, 24, 46, 0.08),
    0 1px 2px rgba(21, 24, 46, 0.06),
    0 12px 28px -8px rgba(21, 24, 46, 0.18),
    0 40px 80px -24px rgba(21, 24, 46, 0.22);
  overflow: hidden;
  font-size: 13px;
  user-select: none;
}

.win__bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--line-soft);
  background: linear-gradient(180deg, #fdfdfd, #f6f6f4);
}

.win__lights {
  display: flex;
  gap: 6px;
}

.win__lights i {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: #e0e0dd;
}

.win__lights i:nth-child(1) { background: #ff5f57; }
.win__lights i:nth-child(2) { background: #febc2e; }
.win__lights i:nth-child(3) { background: #28c840; }

.win__title {
  flex: 1;
  text-align: center;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink-soft);
  margin-right: 45px;
}

.win__toolbar {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 9px 12px;
  border-bottom: 1px solid var(--line-soft);
  background: #fafaf8;
  flex-wrap: wrap;
}

.ctl {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 9px;
  border-radius: 7px;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(21, 24, 46, 0.1), 0 1px 1px rgba(21, 24, 46, 0.04);
  font-size: 12px;
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
}

.ctl span {
  color: var(--ink-faint);
}

.ctl svg {
  width: 9px;
  height: 9px;
  opacity: 0.45;
}

.ctl--accent {
  background: var(--ink);
  color: #fff;
  box-shadow: none;
}

.ctl--accent span { color: rgba(255, 255, 255, 0.6); }
.ctl--accent svg { opacity: 0.7; }

.win__spacer { flex: 1; }

/* Window body: one stage at a time */
.win__body {
  position: relative;
  min-height: 322px;
}

.stage {
  padding: 0;
  display: none;
}

html:not(.js) .stage:first-of-type {
  display: block;
}

.stage.is-on {
  display: block;
}

/* Empty state */
.dropzone {
  min-height: 322px;
  margin: 12px;
  border-radius: 12px;
  border: 1.5px dashed var(--line);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  text-align: center;
  padding: 24px;
  transition-property: border-color, background, scale;
  transition-duration: 300ms;
  transition-timing-function: var(--ease);
}

.is-dropping .dropzone {
  border-color: var(--green-strong);
  background: rgba(120, 240, 160, 0.09);
  scale: 0.99;
}

.dropzone__mark {
  width: 42px;
  height: 42px;
  opacity: 0.9;
}

.dropzone__t {
  font-size: 14px;
  font-weight: 600;
}

.dropzone__s {
  font-size: 12.5px;
  color: var(--ink-faint);
  max-width: 34ch;
}

/* Table */
.tbl {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

.tbl th {
  padding: 8px 12px;
  text-align: left;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  border-bottom: 1px solid var(--line-soft);
  background: #fcfcfa;
  white-space: nowrap;
}

.tbl th:nth-child(2),
.tbl th:nth-child(3),
.tbl td:nth-child(2),
.tbl td:nth-child(3) {
  text-align: right;
}

.tbl td {
  padding: 9px 12px;
  border-bottom: 1px solid var(--line-soft);
  vertical-align: middle;
}

.tbl tr:last-child td { border-bottom: 0; }

/* Rows animate in, staggered by --i */
.js .row {
  opacity: 0;
  translate: 0 6px;
  transition-property: opacity, translate;
  transition-duration: 420ms;
  transition-timing-function: var(--ease);
  transition-delay: calc(var(--i, 0) * 70ms);
}

.is-on .row {
  opacity: 1;
  translate: 0 0;
}

.file {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}

.file__thumb {
  width: 24px;
  height: 24px;
  border-radius: 5px;
  flex: none;
  outline: 1px solid var(--outline-img);
  outline-offset: -1px;
  background: linear-gradient(135deg, #cfd8e8, #e8e2d2);
}

.file__thumb--2 { background: linear-gradient(135deg, #f0d6c2, #d8c7e8); }
.file__thumb--3 { background: linear-gradient(135deg, #cfe8d8, #e8e8c2); }
.file__thumb--4 { background: linear-gradient(135deg, #e8cfd4, #cfd4e8); }
.file__thumb--pdf { background: linear-gradient(135deg, #e8dcdc, #f4efe9); }
.file__thumb--gif { background: linear-gradient(135deg, #d6e8f0, #f0e2d6); }

.file__name {
  font-size: 12.5px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.num {
  font-size: 12.5px;
  color: var(--ink-soft);
}

.saved {
  font-size: 12.5px;
  font-weight: 600;
  color: #1a7f45;
}

.saved--none { color: var(--ink-faint); font-weight: 500; }

/* Status pill: the heart of the case. Colour only where a real problem is. */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px;
  border-radius: 20px;
  background: rgba(21, 24, 46, 0.055);
  font-size: 11.5px;
  font-weight: 600;
  white-space: nowrap;
  transition-property: background, color;
  transition-duration: 250ms;
  transition-timing-function: var(--ease);
}

.pill--problem {
  background: var(--amber-bg);
  color: var(--amber);
}

.pill--shield::before {
  content: "";
  width: 11px;
  height: 11px;
  flex: none;
  background: currentColor;
  -webkit-mask: var(--shield) center / contain no-repeat;
  mask: var(--shield) center / contain no-repeat;
}

.info {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  margin-left: 5px;
  border-radius: 50%;
  background: rgba(21, 24, 46, 0.08);
  color: var(--ink-soft);
  font-size: 10px;
  font-weight: 700;
  font-style: normal;
  vertical-align: 1px;
  cursor: help;
}

/* Progress state */
.bar {
  height: 4px;
  border-radius: 4px;
  background: rgba(21, 24, 46, 0.09);
  overflow: hidden;
  min-width: 68px;
}

.bar i {
  display: block;
  height: 100%;
  border-radius: 4px;
  background: var(--green-strong);
  width: var(--p, 0%);
  transition-property: width;
  transition-duration: 700ms;
  transition-timing-function: var(--ease);
}

/* Window footer: the batch summary */
.win__foot {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 13px;
  border-top: 1px solid var(--line-soft);
  background: #fcfcfa;
  font-size: 12px;
  color: var(--ink-soft);
}

.win__foot b {
  color: var(--ink);
  font-weight: 600;
}

.win__foot .sep { opacity: 0.4; }

/* Sheet: the one-time confirmation */
.sheet-wrap {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  background: rgba(21, 24, 46, 0.14);
  -webkit-backdrop-filter: blur(1.5px);
  backdrop-filter: blur(1.5px);
  opacity: 0;
  pointer-events: none;
  transition-property: opacity;
  transition-duration: 260ms;
  transition-timing-function: var(--ease);
}

.stage.is-on .sheet-wrap {
  opacity: 1;
}

.sheet {
  width: min(330px, 86%);
  margin-top: 0;
  padding: 18px;
  border-radius: 0 0 12px 12px;
  background: #fbfbf9;
  box-shadow: 0 18px 40px -12px rgba(21, 24, 46, 0.45);
  text-align: center;
  translate: 0 -14px;
  transition-property: translate;
  transition-duration: 320ms;
  transition-timing-function: var(--ease);
}

.stage.is-on .sheet {
  translate: 0 0;
}

.sheet__t {
  font-size: 13.5px;
  font-weight: 700;
}

.sheet__s {
  margin-top: 7px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink-soft);
}

.sheet__row {
  display: flex;
  gap: 8px;
  margin-top: 15px;
}

.sheet__btn {
  flex: 1;
  padding: 6px 10px;
  border-radius: 7px;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(21, 24, 46, 0.12);
  font-size: 12px;
  font-weight: 600;
}

.sheet__btn--go {
  background: var(--ink);
  color: #fff;
  box-shadow: none;
}

.sheet__check {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  margin-top: 11px;
  font-size: 11.5px;
  color: var(--ink-faint);
}

.sheet__check i {
  width: 12px;
  height: 12px;
  border-radius: 3px;
  box-shadow: inset 0 0 0 1px var(--line);
  background: #fff;
}

/* Flow rail (mobile): horizontal step dots */
.flow__rail {
  display: none;
}

/* Decision tree
   ------------------------------------------------------------------------- */
.tree {
  padding: clamp(20px, 3vw, 32px);
  border-radius: 18px;
  background: var(--paper-raised);
  box-shadow: inset 0 0 0 1px var(--line-soft);
  overflow-x: auto;
}

.tree svg {
  min-width: 720px;
  width: 100%;
  height: auto;
}

.tree text {
  font-family: "Figtree", sans-serif;
  fill: var(--ink);
}

/* State catalogue
   ------------------------------------------------------------------------- */
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 28px;
}

.chip {
  padding: 8px 15px;
  border: 0;
  border-radius: 50px;
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--line);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-soft);
  cursor: pointer;
  transition-property: background, color, box-shadow, scale;
  transition-duration: 150ms;
  transition-timing-function: var(--ease);
}

@media (hover: hover) {
  .chip:hover { background: var(--paper-raised); color: var(--ink); }
}

.chip:active { scale: 0.96; }

.chip[aria-pressed="true"] {
  background: var(--ink);
  box-shadow: none;
  color: var(--paper);
}

.chip__n {
  margin-left: 7px;
  opacity: 0.55;
  font-weight: 500;
}

.states {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  gap: 14px;
}

.state {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 17px;
  border-radius: 16px;
  background: var(--paper-raised);
  box-shadow: inset 0 0 0 1px var(--line-soft);
  transition-property: box-shadow, translate, opacity, scale;
  transition-duration: 260ms;
  transition-timing-function: var(--ease);
}

@media (hover: hover) {
  .state:hover {
    box-shadow: inset 0 0 0 1px var(--line), 0 10px 26px -14px rgba(21, 24, 46, 0.3);
    translate: 0 -2px;
  }
}

.state[hidden] { display: none; }

.state__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.state__kind {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.state__row {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.state__detail {
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink-soft);
}

.state__why {
  margin-top: 2px;
  padding-top: 11px;
  border-top: 1px solid var(--line-soft);
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink-faint);
}

.state__why b {
  color: var(--ink-soft);
  font-weight: 600;
}

.state--problem {
  background: linear-gradient(180deg, var(--amber-bg), var(--paper-raised) 60%);
}

/* Rules
   ------------------------------------------------------------------------- */
.rules {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: 18px;
  overflow: hidden;
}

.rule {
  padding: clamp(20px, 2.4vw, 28px);
  background: var(--paper);
}

.rule__n {
  font-family: "Yeseva One", Georgia, serif;
  font-size: 15px;
  color: var(--ink-faint);
}

.rule h3 {
  margin: 10px 0 8px;
  font-size: 19px;
}

.rule p {
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-soft);
}

.rule code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9em;
  padding: 1px 5px;
  border-radius: 4px;
  background: rgba(21, 24, 46, 0.06);
}

/* Outcome
   ------------------------------------------------------------------------- */
.outcome {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: clamp(18px, 3vw, 40px);
}

.outcome__n {
  font-family: "Yeseva One", Georgia, serif;
  font-size: clamp(34px, 4vw, 48px);
  line-height: 1;
}

.outcome__t {
  margin-top: 8px;
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink-soft);
}

/* Next / footer
   ------------------------------------------------------------------------- */
.next {
  display: block;
  padding: clamp(28px, 4vw, 48px);
  border-radius: 20px;
  background: linear-gradient(145deg, var(--cream), var(--green));
  text-decoration: none;
  transition-property: scale;
  transition-duration: 300ms;
  transition-timing-function: var(--ease);
}

@media (hover: hover) {
  .next:hover { scale: 1.006; }
}

.next__k {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(21, 24, 46, 0.6);
}

.next__t {
  margin-top: 10px;
  font-family: "Yeseva One", Georgia, serif;
  font-size: clamp(24px, 2.8vw, 34px);
  line-height: 1.1;
}

.next__s {
  margin-top: 10px;
  max-width: 54ch;
  color: rgba(21, 24, 46, 0.72);
}

.sitefoot {
  /* The rule is the page's last line, so it ends where the sections end
     rather than somewhere of its own. */
  max-width: var(--c-col);
  padding-block: 48px 64px;
  padding-inline: 0;
  border-top: 1px solid var(--line-soft);
}

.sitefoot__inner {
  max-width: var(--c-col);
  margin-inline: auto;
  padding-inline: var(--c-pad-x);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  font-size: 15px;
}

.sitefoot a {
  text-decoration: underline;
  text-decoration-color: var(--line);
  text-underline-offset: 3px;
}

@media (hover: hover) {
  .sitefoot a:hover { color: var(--violet); }
}

.sitefoot__links {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
}

/* Reveal on scroll — staggered chunks, runs once
   -------------------------------------------------------------------------
   Keyed on a class the script sets itself, not on .js from the head. The
   stylesheet blocks the first paint and the script does not, so hiding these
   up front means the page can be painted with a hole in it — the reader gets
   the opening screen and then an empty stretch where a section will be, for
   as long as the script takes to arrive. Nothing is hidden until the thing
   that shows it again is already running. */
.reveal-ready .reveal > * {
  opacity: 0;
  translate: 0 14px;
}

.reveal-ready .reveal.is-in > * {
  animation: rise 620ms var(--ease) both;
}

.reveal-ready .reveal.is-in > *:nth-child(1) { animation-delay: 0ms; }
.reveal-ready .reveal.is-in > *:nth-child(2) { animation-delay: 100ms; }
.reveal-ready .reveal.is-in > *:nth-child(3) { animation-delay: 200ms; }
.reveal-ready .reveal.is-in > *:nth-child(4) { animation-delay: 300ms; }
.reveal-ready .reveal.is-in > *:nth-child(5) { animation-delay: 400ms; }
.reveal-ready .reveal.is-in > *:nth-child(6) { animation-delay: 500ms; }

/* Already on screen when the script started. There is no entrance to play:
   the reader has been looking at it since the page was painted. */
.reveal.is-now > * {
  opacity: 1;
  translate: none;
  animation: none;
}

@keyframes rise {
  from { opacity: 0; translate: 0 14px; }
  to   { opacity: 1; translate: 0 0; }
}

/* Responsive
   ------------------------------------------------------------------------- */
@media (max-width: 1000px) {
  /* Flex, not grid: a sticky grid item only travels inside its own row, so
     in one column the window would scroll away after the first step. As a
     flex item it sticks for the whole height of the flow instead. */
  .flow {
    display: flex;
    flex-direction: column;
    gap: 0;
  }

  /* Window on top, steps below it: the window stays in view while reading. */
  .flow__stage {
    order: -1;
    position: sticky;
    top: 56px;
    z-index: 20;
    padding-bottom: 14px;
    margin-bottom: 8px;
    background: linear-gradient(180deg, var(--paper) 88%, transparent);
  }

  .flow__steps {
    padding-block: 8px 24vh;
    gap: 34vh;
  }

  .win__body { min-height: 268px; }
  .dropzone { min-height: 268px; }
}

@media (max-width: 680px) {
  body { font-size: 16px; }

  .win { font-size: 12px; }
  .win__toolbar { gap: 6px; padding: 8px 10px; }
  .ctl { padding: 4px 7px; font-size: 11px; }
  .tbl th:nth-child(3),
  .tbl td:nth-child(3) { display: none; }
  .tbl th, .tbl td { padding-inline: 9px; }
  .win__body { min-height: 240px; }
  .dropzone { min-height: 240px; margin: 9px; }

  .meta { grid-template-columns: repeat(2, 1fr); }
  .states { grid-template-columns: 1fr; }
  .topbar__meta { display: none; }
}

@media (max-width: 420px) {
  .tbl th:nth-child(2),
  .tbl td:nth-child(2) { display: none; }
}

/* Reduced motion: no travel, no staging — every state simply there.
   ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
  }

    .reveal > *,
  .row {
    opacity: 1 !important;
    translate: none !important;
  }

  .step { opacity: 1; }
  .sheet { translate: none; }
}

/* Shield glyph used by the privacy pill (data URI keeps it one request).
   ------------------------------------------------------------------------- */
:root {
  --shield: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2 4 5v6c0 5 3.4 9.4 8 11 4.6-1.6 8-6 8-11V5l-8-3Z'/%3E%3C/svg%3E");
}

/* ==========================================================================
   Work index
   ========================================================================== */
.cases {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.case-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr);
  gap: clamp(20px, 3vw, 44px);
  align-items: center;
  padding: clamp(24px, 3.4vw, 44px);
  border-radius: 20px;
  background: var(--paper-raised);
  box-shadow: inset 0 0 0 1px var(--line-soft);
  text-decoration: none;
  transition-property: box-shadow, translate;
  transition-duration: 300ms;
  transition-timing-function: var(--ease);
}

@media (hover: hover) {
  .case-card:hover {
    box-shadow: inset 0 0 0 1px var(--line), 0 20px 50px -24px rgba(21, 24, 46, 0.4);
    translate: 0 -3px;
  }
}

.case-card__k {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 14px;
}

.tag {
  padding: 4px 11px;
  border-radius: 50px;
  background: rgba(21, 24, 46, 0.055);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
}

.tag--live {
  background: var(--green);
  color: #15402a;
}

.case-card__t {
  font-family: "Yeseva One", Georgia, serif;
  font-size: clamp(28px, 3.6vw, 44px);
  line-height: 1.04;
  letter-spacing: -0.02em;
}

.case-card__s {
  margin-top: 12px;
  max-width: 48ch;
  color: var(--ink-soft);
}

.case-card__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  margin-top: 20px;
}

.case-card__fact b {
  display: block;
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.case-card__fact span {
  font-size: 12.5px;
  color: var(--ink-faint);
}

.case-card__go {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 22px;
  font-size: 15px;
  font-weight: 600;
  color: var(--violet);
}

.case-card__go svg {
  width: 15px;
  height: 15px;
  stroke-width: 2;
  transition-property: translate;
  transition-duration: 200ms;
  transition-timing-function: var(--ease);
}

@media (hover: hover) {
  .case-card:hover .case-card__go svg { translate: 3px 0; }
}

/* Small preview of the case's own interface */
.case-card__art {
  border-radius: 14px;
  padding: 18px;
  background: linear-gradient(145deg, var(--cream), var(--green));
  overflow: hidden;
}
  .case-card__art .win,
.case-card__art .win {
  box-shadow: 0 0 0 1px rgba(21, 24, 46, 0.08), 0 14px 32px -12px rgba(21, 24, 46, 0.4);
}
.case-card__art .win__body { min-height: 0; }

/* Approach */
.approach {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: clamp(20px, 3vw, 44px);
}

.approach h3 {
  margin-bottom: 9px;
  font-size: 20px;
}

.approach p {
  color: var(--ink-soft);
  font-size: 15.5px;
  line-height: 1.5;
}

.approach__n {
  font-family: "Yeseva One", Georgia, serif;
  font-size: 15px;
  color: var(--ink-faint);
  margin-bottom: 8px;
}

/* Straight answers */
.qa {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: 18px;
  overflow: hidden;
}

.qa__item {
  padding: clamp(20px, 2.4vw, 28px);
  background: var(--paper);
}

.qa__q {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-faint);
  margin-bottom: 8px;
}

.qa__a {
  font-size: 16.5px;
  line-height: 1.45;
}

.qa__a b { font-weight: 700; }

.qa__a a {
  color: var(--violet);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Industries */
.inds {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.ind {
  padding: 10px 18px;
  border-radius: 50px;
  box-shadow: inset 0 0 0 1px var(--line);
  font-size: 15px;
  font-weight: 600;
}

.ind span {
  color: var(--ink-faint);
  font-weight: 500;
}

@media (max-width: 860px) {
  .case-card {
    grid-template-columns: 1fr;
  }
  .case-card__art { order: -1; }
}

/* ==========================================================================
   Orientation: what / why / where — read before anything else on the page
   ========================================================================== */
.www {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: 20px;
  overflow: hidden;
}

.www__cell {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: clamp(22px, 2.8vw, 32px);
  background: var(--paper);
}

.www__k {
  display: flex;
  align-items: baseline;
  gap: 9px;
  font-family: "Yeseva One", Georgia, serif;
  font-size: 21px;
  line-height: 1;
  color: var(--ink);
}

.www__k span {
  font-family: "Figtree", sans-serif;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.www__t {
  font-size: 16px;
  line-height: 1.5;
  color: var(--ink-soft);
}

.www__t b {
  color: var(--ink);
  font-weight: 600;
}

/* A line of narration between two sections, so the page reads as one piece
   instead of a stack of blocks. */
.bridge {
  max-width: 34ch;
  margin-inline: auto;
  padding-block: clamp(44px, 6vw, 76px);
  text-align: center;
  font-family: "Yeseva One", Georgia, serif;
  font-size: clamp(21px, 2.6vw, 29px);
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-wrap: balance;
}

.bridge em {
  font-style: normal;
  color: var(--ink-faint);
}

.bridge::before {
  content: "";
  display: block;
  width: 34px;
  height: 1px;
  margin: 0 auto clamp(22px, 3vw, 32px);
  background: var(--line);
}

/* The thread on the index: one sentence that connects the cases. */
.thread {
  max-width: 46ch;
  font-size: clamp(18px, 1.9vw, 21px);
  line-height: 1.5;
  color: var(--ink-soft);
}

.thread b { color: var(--ink); font-weight: 600; }

/* Four cards go 4-across or 2x2 — never 3 and a lonely one, which auto-fit
   would otherwise do at common desktop widths. */
.rules--quad {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 1181px) {
  .rules--quad {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .rules--quad {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Four numbers go 4-across or 2x2 — never 3 and a lonely one. */
@media (max-width: 1180px) {
  .claim,
  .outcome {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .claim,
  .outcome {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 680px) {
  .www__k { font-size: 23px; }
  .bridge { max-width: 26ch; }
}

/* ==========================================================================
   Photographs — the real place, next to the rebuilt screens
   ========================================================================== */
.shot {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.shot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 14px;
  /* A hairline keeps a light photo from bleeding into a light page. */
  outline: 1px solid var(--outline-img);
  outline-offset: -1px;
  background: var(--line-soft);
}

/* A caption is bounded by its own figure, not by a reading measure: under a
   wide photograph a 54ch limit broke a single sentence across two lines for
   no reason. In a pair the column is narrow enough on its own. */
.shot__cap {
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink-faint);
}

.shot__cap b {
  color: var(--ink-soft);
  font-weight: 600;
}

.shots {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
  gap: clamp(16px, 2.2vw, 26px);
  align-items: start;
}

/* Photographs are never cropped to tidy up a row. A screenshot has to stay
   readable, and a cropped photograph loses the context it was there for, so
   an uneven pair is simply an uneven pair. */
.shots {
  align-items: start;
}

/* ==========================================================================
   The app family around one aircraft
   ========================================================================== */
.apps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: 18px;
  overflow: hidden;
}

.app {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: clamp(18px, 2.2vw, 24px);
  background: var(--paper);
}

.app__r {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.app__n {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.app__t {
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink-soft);
}

/* The one this case is about: spans the row, so the fifth card never ends up
   stranded on its own beside three empty columns. */
.app--here {
  grid-column: 1 / -1;
  background: linear-gradient(160deg, var(--cream), var(--green));
}

@media (min-width: 681px) {
  .app--here {
    flex-direction: row;
    align-items: baseline;
    gap: 16px;
  }

  .app--here .app__r { flex: none; }
  .app--here .app__n { flex: none; }
  .app--here .app__t { flex: 1; }
}

.app--here .app__r,
.app--here .app__t {
  color: rgba(21, 24, 46, 0.68);
}

/* The icon strip is dark artwork: give it its own bed. */
.strip {
  padding: clamp(18px, 2.6vw, 34px);
  border-radius: 18px;
  background: #06303f;
}

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

/* ==========================================================================
   Long read — one column of narrative, with artefacts breaking out of it
   ==========================================================================
   The case stopped reading as a story when every part arrived as its own
   section with its own heading. Here there is one column; photographs, the
   interactive flow and the state cards break out of it and the text resumes.
   ------------------------------------------------------------------------- */
.read {
  display: grid;
  grid-template-columns:
    [full-start] minmax(var(--gutter), 1fr)
    [wide-start] minmax(0, 170px)
    [text-start] min(68ch, 100% - (2 * var(--gutter)))
    [text-end] minmax(0, 170px)
    [wide-end] minmax(var(--gutter), 1fr)
    [full-end];
}

.read > * {
  grid-column: text-start / text-end;
}

.read > .wide {
  grid-column: wide-start / wide-end;
}

.read > .full {
  grid-column: full-start / full-end;
}

.read > p:not([class]),
.read > p.soft {
  margin-bottom: 1.15em;
  font-size: clamp(17px, 1.2vw, 19px);
  line-height: 1.65;
}

.read > p:last-child { margin-bottom: 0; }

.read > p.soft { color: var(--ink-soft); }

.read strong { font-weight: 600; }

.read em { font-style: italic; }

/* Opening paragraph, a touch larger so the piece has a way in. */
.read .opening {
  font-size: clamp(19px, 1.6vw, 23px);
  line-height: 1.5;
}

/* A chapter marker that does not reset the page: a hairline and a label. */
.read .ch,
.ch {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: clamp(44px, 5vw, 68px);
  margin-bottom: clamp(14px, 1.6vw, 20px);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.ch::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line-soft);
}

.ch b {
  font-family: "Yeseva One", Georgia, serif;
  font-weight: 400;
  font-size: 15px;
  letter-spacing: 0;
  color: var(--ink);
}

/* The emotional beats. Left aligned, in the column: a big centred pull-quote
   stops the reader, this carries them. */
.read .beat,
.beat {
  margin-block: clamp(26px, 3vw, 38px);
  font-family: "Yeseva One", Georgia, serif;
  font-size: clamp(23px, 2.5vw, 31px);
  line-height: 1.2;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

/* A quotation gets the marks and a rule, so it reads as someone speaking
   rather than as another heading. */
.read .beat--quote,
.beat--quote {
  padding-left: clamp(16px, 2vw, 24px);
  border-left: 2px solid var(--ink);
}

.beat--quote::before {
  content: "“";
}

.beat--quote::after {
  content: "”";
}

/* Every block that interrupts the prose keeps the same rhythm. The icon
   strip is a div rather than a figure, and was the one that had none. */
.read figure,
.read .shots,
.read .strip {
  margin-block: clamp(24px, 2.6vw, 36px);
}

/* The flow and the catalogue sit inside the read, at wide or full width. */
.read .flow {
  margin-block: clamp(26px, 3vw, 40px) 0;
}

.read .filters {
  margin-top: clamp(22px, 3vw, 32px);
}

/* Numbers, at the end where they belong in a story rather than the top. */
.tally {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: clamp(20px, 3vw, 40px);
  margin-block: clamp(30px, 4vw, 48px);
  padding: clamp(24px, 3vw, 36px);
  border-radius: 18px;
  background: linear-gradient(145deg, var(--cream), var(--green));
}

.tally__n {
  font-family: "Yeseva One", Georgia, serif;
  font-size: clamp(30px, 3.4vw, 42px);
  line-height: 1;
}

.tally__t {
  margin-top: 8px;
  font-size: 14px;
  line-height: 1.45;
  color: rgba(21, 24, 46, 0.72);
}

@media (max-width: 1100px) {
  .tally { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 520px) {
  .tally { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   Priority guides — the notation I actually used on this project
   ==========================================================================
   Built from the Priority Guide library in the project's own Sketch file:
   a guide title, nested groups marked with bars, content rows in priority
   order, three weights of call to action, and annotations in red. No layout,
   no chrome, no pretend screenshot — content and intent only.
   ------------------------------------------------------------------------- */
.pg {
  --pg-line: #1a1a1a;
  --pg-rule: #d5d5d5;
  --pg-fill: #ebebeb;

  background: #fff;
  border: 1px solid var(--pg-line);
  font-size: 13px;
  line-height: 1.35;
  color: var(--pg-line);
  user-select: none;
}

.pg__title {
  padding: 13px 14px;
  background: var(--pg-fill);
  border-bottom: 1px solid var(--pg-line);
}

.pg__title b {
  display: block;
  font-size: 14px;
  font-weight: 700;
}

.pg__title span {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: #6d6d6d;
}

.pg__row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--pg-rule);
}

.pg__row:last-child { border-bottom: 0; }

/* Nesting is containment, not decoration. In Sketch these were stacked
   groups, so a group is drawn as the box it actually was — and the hierarchy
   is readable because the boxes sit inside each other. */
.pg__group {
  margin: 10px 12px;
  border: 1px solid var(--pg-line);
}

.pg__group > .pg__gt {
  padding: 8px 11px;
  background: #f4f4f4;
  border-bottom: 1px solid var(--pg-line);
  font-size: 12.5px;
  font-weight: 700;
}

.pg__group > .pg__gt span {
  display: block;
  margin-top: 1px;
  font-size: 11.5px;
  font-weight: 400;
  color: #6d6d6d;
}

.pg__group > .pg__row {
  padding-inline: 11px;
}

.pg__group > .pg__row:last-child {
  border-bottom: 0;
}

/* One level in, the box tightens so the depth reads at a glance. */
.pg__group .pg__group {
  margin: 8px 9px;
}

.pg__t { flex: 1; min-width: 0; }

.pg__t b { font-weight: 700; }

/* The sub-line under a row — but not the action link, which is also a span
   and has to stay the size of the row it belongs to. */
.pg__t > span:not(.pg__action) {
  display: block;
  margin-top: 1px;
  font-size: 12.5px;
  color: #6d6d6d;
}

/* An action is a link: underlined, nothing more. */
.pg__action {
  font-size: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Three weights of call to action, as in the library. */
.pg__cta {
  display: block;
  margin: 4px 0;
  padding: 9px 12px;
  border: 1px solid var(--pg-line);
  text-align: center;
  font-size: 12.5px;
  font-weight: 700;
}

/* A call to action keeps its own row, with the annotation beside it. */
.pg__row > .pg__cta {
  flex: 1;
  margin: 0;
}

.pg__cta--2 { border-style: dashed; }
.pg__cta--3 { border-style: dashed; color: #767676; border-color: #9a9a9a; }

/* Small type markers (image, input, checkbox …). */
.pg__ico {
  width: 15px;
  height: 15px;
  flex: none;
  stroke: var(--pg-line);
  fill: none;
  stroke-width: 1.4;
}

.pg__rule {
  height: 1px;
  margin: 2px 14px;
  background: var(--pg-rule);
}

/* A row that opens another screen. An action carries an underline and a call
   to action carries a box, so both already say what they are; this is for the
   rows that read as content and are targets anyway — a task in a list, a guest
   waiting for a seat. Used sparingly on purpose: mark every row and the guide
   stops being a priority guide and becomes a wireframe. */
.pg__go {
  flex: none;
  margin-left: 2px;
  color: #9a9a9a;
  font-size: 15px;
  line-height: 1;
}

/* Annotations — red, numbered, and explained under the guide. */
.pg__n {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  flex: none;
  border-radius: 50%;
  background: var(--pg-red);
  color: #fff;
  font-size: 11.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.pg__row--flag {
  box-shadow: inset 3px 0 0 var(--pg-red);
}

/* The annotation, explained next to the step it belongs to — so it is there
   at every width rather than hidden when the column stacks. */
.step__note--flag {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  max-width: var(--step-measure);
}

.step__note--flag .pg__n { margin-top: 1px; }

/* The epic, sliced
   ---------------------------------------------------------------------------
   The guides below are drawn per step, and a column of them loses the shape of
   the journey: both of these cases fork and come back, and a vertical list can
   only show a line. This is that shape, once, above the detail — the spine
   solid, the returns dashed and named, and the step being read lit as the
   reader moves. It is a map, not a decoration, so it carries only what the
   stack underneath cannot. */
.slice {
  margin-bottom: clamp(28px, 4vw, 48px);
}

/* The drawing scrolls on its own, so the note under it stays put. The padding
   is there because a scroll container clips what overflows it, and a focus
   ring on a shape at the edge would be the thing it clipped. */
.slice__scroll {
  overflow-x: auto;
  padding: 6px 0;
  margin: -6px 0;
}

.slice svg { display: block; width: 100%; height: auto; overflow: visible; }

/* Everything quiet by default. The step in view is the only thing at full
   strength, so the map reads as position rather than as another diagram
   competing with the guide beside it. */
.slice .col.is-on .nd rect { stroke: var(--ink); }
.slice .col.is-on .nd text { fill: var(--ink); }
.slice .col.is-on .nd circle { fill: var(--ink); stroke: var(--ink); }
.slice .col.is-on .nd .nd__n { fill: var(--paper); }

.slice .nd rect {
  fill: var(--paper-raised);
  stroke: var(--ink-soft);
  stroke-width: 1;
  transition: stroke 300ms var(--ease), fill 300ms var(--ease),
    stroke-width 300ms var(--ease);
}

.slice .nd text { fill: var(--ink-soft); transition: fill 300ms var(--ease); }
.slice .nd .nd__n { fill: var(--ink-faint); font-weight: 700; }
.slice .nd circle { fill: none; stroke: var(--line); transition: all 300ms var(--ease); }

.slice .nd.is-on rect { stroke: var(--ink); }
.slice .nd.is-on text { fill: var(--ink); }
.slice .nd.is-on circle { fill: var(--ink); stroke: var(--ink); }
.slice .nd.is-on .nd__n { fill: var(--paper); }

/* Three weights, so the eye has somewhere to start. The happy path is the
   heaviest line in the drawing; a branch to a state is lighter; a return is
   lighter still and dashed. */
.slice .main { stroke: var(--ink-soft); stroke-width: 1.4; fill: none; }
.slice .spine { stroke: var(--line); stroke-width: 1; fill: none; }

/* Arrowheads are painted here rather than inheriting the line they sit on:
   context-stroke is not honoured everywhere, and an arrowhead that does not
   paint leaves a flow with no direction in it. Darker than the wire, so the
   direction is the thing you see first. */
.slice .ah-main { stroke: var(--ink-soft); }
.slice .ah-sub { stroke: var(--ink-faint); }
.slice .tm rect { fill: var(--ink); stroke: none; }
.slice .tm text { fill: var(--paper); }

.slice .dc path { fill: var(--paper); stroke: var(--line); stroke-width: 1; }
.slice .el { fill: var(--ink-faint); }
.slice .q { fill: var(--ink-faint); }

/* A state is a branch of the question above it. The ones the design had to
   answer carry the flag colour, the same red the chips and the guides use, so
   one glance across the map counts them. */
/* Painted the colour of the page, not left transparent and not none. Two
   reasons, and they stack. An SVG shape with fill:none has no interior to
   hit, so the box would only answer to the pointer on its one-pixel border
   or on a letter, which reads as a target that works sometimes. And the page
   under this map carries a pattern, which ran straight through a transparent
   box while the steps and the decisions beside it blocked it — so the same
   drawing had some boxes sitting on the page and others cut out of it.
   Paper fills the shape without adding any weight to it. */
.slice .pl rect {
  fill: var(--paper);
  stroke: var(--line-soft);
  stroke-width: 1;
  transition: stroke 300ms var(--ease), fill 300ms var(--ease),
    stroke-width 300ms var(--ease);
}

.slice .pl,
.slice .col { pointer-events: all; }

.slice .pl text { fill: var(--ink-faint); transition: fill 300ms var(--ease); }
.slice .pl.is-flag rect { stroke: rgba(224, 49, 39, 0.35); }
.slice .pl.is-flag text { fill: #a3281f; }

.slice .col.is-on .dia { stroke: var(--ink); }
.slice .col.is-on .q { fill: var(--ink-soft); }
.slice .col.is-on .pl rect { stroke: var(--line); }
.slice .col.is-on .pl text { fill: var(--ink-soft); }
.slice .col.is-on .pl.is-flag rect { stroke: rgba(224, 49, 39, 0.6); }
.slice .col.is-on .pl.is-flag text { fill: var(--pg-red); }

@media (hover: hover) {
  .slice .pl { cursor: pointer; }
  /* Mixed into the paper rather than laid over it as ink at low alpha, which
     would have let the pattern back through on hover — the one state where
     the reader is looking straight at the box.

     Four per cent was a tint you had to go hunting for on a box whose border
     is a hairline to begin with, so a state you can open read the same as a
     decision you cannot. Three things move together instead: the fill, the
     border at a stroke and a half so the box lifts off the wire it hangs
     from, and the label up to full ink. One shape answering, not a corner
     of it. */
  .slice .pl:hover rect {
    fill: color-mix(in srgb, var(--ink) 7%, var(--paper));
    stroke: var(--ink-soft);
    stroke-width: 1.5;
  }
  .slice .pl:hover text { fill: var(--ink); }

  /* A flagged state hovers in its own colour, so the red that marks a design
     call in the chips and the guides is the red that answers the pointer. */
  .slice .pl.is-flag:hover rect {
    fill: color-mix(in srgb, var(--pg-red) 8%, var(--paper));
    stroke: var(--pg-red);
  }
  .slice .pl.is-flag:hover text { fill: var(--pg-red); }
}
.slice .sub { stroke: rgba(21, 24, 46, 0.28); stroke-width: 1; fill: none; stroke-dasharray: 4 4; }
.slice .sub-t { fill: var(--ink-faint); font-style: italic; }

@media (hover: hover) {
  .slice .nd { cursor: pointer; }
  /* A step box has to hover as "press me" without hovering as "you are
     here": the filled counter is what marks the step being read, and a hover
     that borrowed it would make the map lie about position every time the
     pointer crossed it. So the counter is left alone and the box does the
     work — a tint in the fill, the border at a stroke and a half, the label
     at full ink. That reads as a target on the five quiet boxes and still
     registers on the one already lit, which the old border-only hover did
     not: on the active node it changed nothing at all. */
  .slice .nd:hover rect {
    fill: color-mix(in srgb, var(--ink) 7%, var(--paper));
    stroke: var(--ink);
    stroke-width: 1.5;
  }
  .slice .nd:hover text { fill: var(--ink); }
}

/* Said under the drawing, because it is a caveat and not a caption: what is
   on the page is a reading of a working diagram, not the working diagram. */
.slice__note {
  margin: 14px 0 0;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--ink-faint);
}

/* Folded, the drawing keeps its size and the column scrolls under it. Scaled
   to fit a phone it would be whole and unreadable — the labels come out around
   five pixels — and a diagram nobody can read is not a diagram. Nine hundred
   is the width at which the type still holds. */
@media (max-width: 1000px) {
  .slice__scroll svg { min-width: 900px; }
}

/* The job the step exists to do, in the words of the person doing it. One
   sentence: a step that needs two of them is two steps. */
/* A step is three things in a row — the job story, the states you can switch
   between, and the design calls — and they have to look like one kit.

   So all three are the same material: white on the page's off-white, inside
   the same hairline, cornered the same way. What separates them is weight,
   which follows what they are. The job story is the premise and carries a
   whisper of lift. The calls are annotations on the guide and sit flat. The
   states are controls, so they stay pills, because a pill is what a thing
   you press looks like here.

   The deck's own padding and full shadow stay on ERIKS, where three cards
   stand alone on an open page and can afford them. Inside a step that made
   the premise heavier than the evidence and left the calls beneath it
   looking like a different component from a different site. */
.step__job {
  margin: 14px 0 0;
  padding: 16px 18px;
  border-radius: 14px;
  background: var(--paper-raised);
  box-shadow:
    inset 0 0 0 1px var(--line-soft),
    0 8px 20px -16px rgba(21, 24, 46, 0.26);
  font-size: 16px;
  line-height: 1.55;
  color: var(--ink);
  max-width: var(--step-measure);
}

/* The states this step has to survive, as a set you can count. Naming them
   is the claim; the guide beside them is the evidence, which is why every
   chip draws a screen rather than only labelling one. */
.step__states {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 14px;
  max-width: var(--step-measure);
}

.schip {
  padding: 5px 11px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  font: inherit;
  font-size: 12.5px;
  line-height: 1.2;
  color: var(--ink-soft);
  cursor: pointer;
  transition-property: background, color, border-color, box-shadow;
  transition-duration: 200ms;
  transition-timing-function: var(--ease);
}

.schip[aria-pressed="true"] {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}

/* A state that is one of the design calls carries the flag colour, so the
   red in the chip row and the red in the guide are the same claim. */
.schip--flag { border-color: rgba(224, 49, 39, 0.4); color: #a3281f; }
.schip--flag[aria-pressed="true"] { background: var(--pg-red); border-color: var(--pg-red); color: #fff; }

/* A border going from twelve per cent ink to full is a change you only catch
   if you already know where to look, and a row of four pills is exactly where
   you don't. A fill is what makes a pill look pressable here, so hover puts
   one in — a tint of the colour the pill turns when it is chosen, which makes
   the hover a preview of the press rather than a second idea. */
@media (hover: hover) {
  .schip:hover {
    background: color-mix(in srgb, var(--ink) 8%, var(--paper));
    border-color: var(--ink);
    color: var(--ink);
  }
  .schip--flag:hover {
    background: color-mix(in srgb, var(--pg-red) 9%, var(--paper));
    border-color: var(--pg-red);
    color: var(--pg-red);
  }

  /* The chosen chip is already filled, so a fill cannot answer for it, and
     the old rule re-stated the colour it already had — a hover that did
     nothing. A ring outside the pill answers the pointer without the pill
     looking like it changed state.

     Its own fill is set again here because the two rules weigh the same and
     the hover above comes later: left to the cascade, a chosen chip would
     drop to the tint and take its white label with it, so hovering the one
     chip you had already picked would rub it out. */
  .schip[aria-pressed="true"]:hover {
    background: var(--ink);
    border-color: var(--ink);
    color: var(--paper);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--ink) 14%, transparent);
  }
  .schip--flag[aria-pressed="true"]:hover {
    background: var(--pg-red);
    border-color: var(--pg-red);
    color: #fff;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--pg-red) 22%, transparent);
  }
}

/* One state at a time, once the chips are there to switch them. Without
   script every state is simply drawn, stacked — longer, but complete. */
.pgv + .pgv { margin-top: 14px; }
.js .pgv { display: none; }
.js .pgv.is-on { display: block; }
.js .pgv + .pgv { margin-top: 0; }

/* The claim scans, the reasoning rewards. Each annotation leads with what
   was decided and keeps why it beat the obvious alternative behind a word, so
   a column of six of these stays readable and still has the argument in it.
   Folded open by default without script, which is longer but loses nothing. */
.note__rest { display: none; }
.step__note.is-open .note__rest { display: inline; }

.note__more {
  display: inline;
  margin-left: 4px;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--ink-faint);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}

@media (hover: hover) {
  .note__more:hover { color: var(--ink); }
}

/* The guide sits where the device mock used to, and stays put while the
   steps beside it scroll. */
.pg-stage { position: sticky; top: 84px; }

.pg-cap {
  margin-top: 12px;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--ink-faint);
}

@media (max-width: 1000px) {
  .pg-stage {
    position: sticky;
    top: 56px;
    z-index: 20;
    padding-bottom: 12px;
    background: linear-gradient(180deg, var(--paper) 88%, transparent);
  }
}

/* ==========================================================================
   How I work — phases and the deliverables that belong to them
   ========================================================================== */
.phases {
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--line-soft);
}

.phase {
  display: grid;
  grid-template-columns: minmax(0, 150px) minmax(0, 1fr);
  gap: clamp(14px, 2.4vw, 32px);
  align-items: baseline;
  padding-block: clamp(16px, 1.8vw, 22px);
  border-bottom: 1px solid var(--line-soft);
}

.phase__k {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.phase__d {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 10px;
  font-size: 15.5px;
  line-height: 1.5;
  color: var(--ink-soft);
}

/* A visible separator: multi-word deliverables run together without one. */
.phase__d span::after {
  content: " ·";
  color: rgba(21, 24, 46, 0.32);
}

.phase__d span:last-child::after { content: ""; }

/* The one this portfolio shows in use. */
.phase__d b {
  font-weight: 600;
  color: var(--ink);
  box-shadow: inset 0 -0.5em 0 rgba(120, 240, 160, 0.4);
}

@media (max-width: 620px) {
  .phase {
    grid-template-columns: minmax(0, 1fr);
    gap: 6px;
  }
}

/* Used by the Maxeda case for the note under its panel. */
.stage-note {
  display: block;
  margin-top: 14px;
  padding: 12px 14px;
  border-radius: 12px;
  background: var(--paper-raised);
  box-shadow: inset 0 0 0 1px var(--line-soft);
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--ink-soft);
}

.stage-note b { color: var(--ink); font-weight: 600; }

/* ==========================================================================
   Maxeda — the operations panel
   A process has no screens. So instead of an interface, the window shows the
   artefact that exists at each stage: the backlog, the scoring, the written
   hypothesis, the split, the result, the rollout. Same flow machinery as the
   other two cases — only the stage visuals are new.
   ========================================================================== */

/* Panel chrome: a web tool, so no traffic lights. */
.ops__bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--line-soft);
  background: #fcfcfa;
}

.ops__mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 5px;
  background: var(--ink);
  color: var(--paper);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.02em;
}

.ops__crumb {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-faint);
}

.ops__crumb b {
  color: var(--ink);
  font-weight: 600;
}

.ops__id {
  margin-left: auto;
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

/* The six-stage rail. Which one is lit comes from [data-state] on the panel,
   which the flow script already sets — so the rail needs no JS of its own,
   and without JS it simply shows stage one. */
.lane {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 9px 12px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--paper-raised);
}

.lane__i {
  display: flex;
  align-items: center;
  gap: 5px;
  flex: 1;
  min-width: 0;
  padding: 5px 7px;
  border-radius: 7px;
  font-size: 10.5px;
  font-weight: 600;
  line-height: 1;
  color: var(--ink-faint);
  transition-property: background, color;
  transition-duration: 300ms;
  transition-timing-function: var(--ease);
}

.lane__i b {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px var(--line);
  font-size: 9px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.lane__i span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.lane__i.is-on,
.win:not([data-state]) .lane__i--signal,
.win[data-state="signal"]    .lane__i--signal,
.win[data-state="priority"]  .lane__i--priority,
.win[data-state="hypothesis"] .lane__i--hypothesis,
.win[data-state="build"]     .lane__i--build,
.win[data-state="validate"]  .lane__i--validate,
.win[data-state="rollout"]   .lane__i--rollout {
  background: var(--ink);
  color: var(--paper);
}

.win:not([data-state]) .lane__i--signal b,
.win[data-state="signal"]    .lane__i--signal b,
.win[data-state="priority"]  .lane__i--priority b,
.win[data-state="hypothesis"] .lane__i--hypothesis b,
.win[data-state="build"]     .lane__i--build b,
.win[data-state="validate"]  .lane__i--validate b,
.win[data-state="rollout"]   .lane__i--rollout b {
  background: rgba(255, 255, 255, 0.18);
  box-shadow: none;
}

/* A row that the process sent back, rather than one that failed. */
.tbl tr.row--back td { background: rgba(255, 176, 46, 0.06); }

.pill--back {
  background: var(--amber-bg);
  color: var(--amber);
  box-shadow: inset 0 0 0 1px rgba(196, 106, 18, 0.22);
}

.pill--go {
  background: rgba(120, 240, 160, 0.22);
  color: #166534;
  box-shadow: inset 0 0 0 1px rgba(22, 101, 52, 0.18);
}

.src {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink-faint);
}

/* The written hypothesis, with the fields that are fixed before it runs. */
.hyp { padding: 14px; }

.hyp__q {
  margin: 0;
  padding: 13px 15px;
  border-radius: 11px;
  background: var(--cream);
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink);
}

.hyp__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  margin-top: 12px;
  border-radius: 11px;
  overflow: hidden;
  background: var(--line-soft);
}

.hyp__f {
  padding: 10px 12px;
  background: var(--paper-raised);
}

.hyp__k {
  margin: 0 0 4px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.hyp__v {
  margin: 0;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.3;
}

.hyp__lock {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 12px 0 0;
  font-size: 12px;
  font-weight: 600;
  color: var(--amber);
}

.hyp__lock svg {
  flex: none;
  width: 13px;
  height: 13px;
  stroke-width: 2.2;
}

/* The split: control against variant. */
.ab {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  padding: 14px;
}

.ab__col { min-width: 0; }

.ab__k {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 0 0 8px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.ab__n {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

/* A product page, small enough to read as one. */
.mini {
  position: relative;
  border-radius: 9px;
  overflow: hidden;
  background: #fff;
  box-shadow: inset 0 0 0 1px var(--line);
}

.mini__bar {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 6px 8px;
  background: #ffdd14;
}

.mini__logo {
  font-size: 9px;
  font-weight: 800;
  color: #1a1a1a;
  letter-spacing: -0.01em;
}

.mini__search {
  flex: 1;
  height: 8px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.85);
}

.mini__body { padding: 9px; }

.mini__img {
  height: 46px;
  border-radius: 6px;
  background: linear-gradient(135deg, #dfe4e2, #cdd6d2);
}

.mini__ln {
  height: 5px;
  margin-top: 7px;
  border-radius: 3px;
  background: rgba(21, 24, 46, 0.12);
}

.mini__ln--s { width: 52%; }

.mini__price {
  margin: 8px 0 0;
  font-size: 12px;
  font-weight: 800;
  color: #d61f26;
}

.mini__cta {
  margin-top: 8px;
  padding: 5px 0;
  border-radius: 4px;
  background: #d61f26;
  color: #fff;
  font-size: 8.5px;
  font-weight: 700;
  text-align: center;
  letter-spacing: 0.02em;
}

.mini__fold {
  margin: 9px -9px -9px;
  padding: 5px 9px;
  border-top: 1px dashed var(--line);
  font-size: 8.5px;
  font-weight: 600;
  color: var(--ink-faint);
  text-align: center;
}

/* The variant's whole point: it survives the fold. */
.mini__sticky {
  position: absolute;
  inset: auto 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 7px 8px;
  background: #fff;
  box-shadow: 0 -6px 14px -6px rgba(21, 24, 46, 0.25);
  border-top: 1px solid var(--line-soft);
  font-size: 8.5px;
  font-weight: 700;
  color: #1a1a1a;
}

.mini__sticky i {
  width: 9px;
  height: 9px;
  border-radius: 2px;
  background: #ffdd14;
  flex: none;
}

/* The verdict, stated once, in the shape the report states it. */
.verdict {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  margin: 14px 14px 0;
  border-radius: 11px;
  overflow: hidden;
  background: var(--line-soft);
}

.verdict__i {
  padding: 11px 12px;
  background: var(--paper-raised);
}

.verdict__i--win { background: rgba(120, 240, 160, 0.16); }

.verdict__k {
  margin: 0 0 3px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.verdict__v {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}

.verdict__i--win .verdict__v { color: #166534; }

@media (max-width: 680px) {
  .lane { gap: 2px; padding: 8px; }
  .lane__i { padding: 5px; gap: 4px; }
  .lane__i span { display: none; }
  .lane__i.is-on span,
  .win:not([data-state]) .lane__i--signal span,
  .win[data-state="signal"]     .lane__i--signal span,
  .win[data-state="priority"]   .lane__i--priority span,
  .win[data-state="hypothesis"] .lane__i--hypothesis span,
  .win[data-state="build"]      .lane__i--build span,
  .win[data-state="validate"]   .lane__i--validate span,
  .win[data-state="rollout"]    .lane__i--rollout span { display: block; }

  .lane__i { flex: none; }
  .lane__i.is-on,
  .win:not([data-state]) .lane__i--signal,
  .win[data-state="signal"]     .lane__i--signal,
  .win[data-state="priority"]   .lane__i--priority,
  .win[data-state="hypothesis"] .lane__i--hypothesis,
  .win[data-state="build"]      .lane__i--build,
  .win[data-state="validate"]   .lane__i--validate,
  .win[data-state="rollout"]    .lane__i--rollout { flex: 1; }

  .hyp__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .verdict { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ab { gap: 8px; padding: 10px; }
  .hyp { padding: 10px; }
  .verdict { margin: 10px 10px 0; }
  .ops__id { display: none; }
}

/* ==========================================================================
   Orientation: what / why / where — read before anything else on the page
   ========================================================================== */
.www {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: 20px;
  overflow: hidden;
}

.www__cell {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: clamp(22px, 2.8vw, 32px);
  background: var(--paper);
}

.www__k {
  display: flex;
  align-items: baseline;
  gap: 9px;
  font-family: "Yeseva One", Georgia, serif;
  font-size: 26px;
  line-height: 1;
  color: var(--ink);
}

.www__k span {
  font-family: "Figtree", sans-serif;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.www__t {
  font-size: 16px;
  line-height: 1.5;
  color: var(--ink-soft);
}

.www__t b {
  color: var(--ink);
  font-weight: 600;
}

/* A line of narration between two sections, so the page reads as one piece
   instead of a stack of blocks. */
.bridge {
  max-width: 34ch;
  margin-inline: auto;
  padding-block: clamp(44px, 6vw, 76px);
  text-align: center;
  font-family: "Yeseva One", Georgia, serif;
  font-size: clamp(21px, 2.6vw, 29px);
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-wrap: balance;
}

.bridge em {
  font-style: normal;
  color: var(--ink-faint);
}

.bridge::before {
  content: "";
  display: block;
  width: 34px;
  height: 1px;
  margin: 0 auto clamp(22px, 3vw, 32px);
  background: var(--line);
}

/* The thread on the index: one sentence that connects the cases. */
.thread {
  max-width: 46ch;
  font-size: clamp(18px, 1.9vw, 21px);
  line-height: 1.5;
  color: var(--ink-soft);
}

.thread b { color: var(--ink); font-weight: 600; }

/* Four cards go 4-across or 2x2 — never 3 and a lonely one, which auto-fit
   would otherwise do at common desktop widths. */
.rules--quad {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 1181px) {
  .rules--quad {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .rules--quad {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Four numbers go 4-across or 2x2 — never 3 and a lonely one. */
@media (max-width: 1180px) {
  .claim,
  .outcome {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .claim,
  .outcome {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 680px) {
  .www__k { font-size: 23px; }
  .bridge { max-width: 26ch; }
}

/* ==========================================================================
   Photographs — the real place, next to the rebuilt screens
   ========================================================================== */
.shot {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.shot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 14px;
  /* A hairline keeps a light photo from bleeding into a light page. */
  outline: 1px solid var(--outline-img);
  outline-offset: -1px;
  background: var(--line-soft);
}

.shot__cap {
  max-width: 54ch;
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink-faint);
}

.shot__cap b {
  color: var(--ink-soft);
  font-weight: 600;
}

.shots {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
  gap: clamp(16px, 2.2vw, 26px);
  align-items: start;
}

/* NOTE: .shots is declared twice in this file and the later copy above is the
   one that applies, so this modifier has to come after it or auto-fit wins.
   Four phone screenshots that are a sequence, or four states of one component
   being compared, only work side by side: keep one row where there is room
   rather than auto-fitting into an orphaned fourth. */
.shots--4 {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

@media (max-width: 860px) {
  .shots--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 460px) {
  .shots--4 { grid-template-columns: minmax(0, 1fr); }
}

/* Edge to edge: used once, to put you in the hangar before anything is said. */
.bleed {
  width: 100%;
  margin-block: clamp(8px, 2vw, 24px) 0;
}

.bleed img {
  display: block;
  width: 100%;
  height: auto;
  background: var(--line-soft);
}

.bleed .shot__cap {
  max-width: var(--shell);
  margin: 14px auto 0;
  padding-inline: var(--gutter);
}

/* ==========================================================================
   The app family around one aircraft
   ========================================================================== */
.apps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1px;
  background: var(--line-soft);
  border: 1px solid var(--line-soft);
  border-radius: 18px;
  overflow: hidden;
}

.app {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: clamp(18px, 2.2vw, 24px);
  background: var(--paper);
}

.app__r {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.app__n {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.app__t {
  font-size: 14.5px;
  line-height: 1.45;
  color: var(--ink-soft);
}

/* The one this case is about: spans the row, so the fifth card never ends up
   stranded on its own beside three empty columns. */
.app--here {
  grid-column: 1 / -1;
  background: linear-gradient(160deg, var(--cream), var(--green));
}

@media (min-width: 681px) {
  .app--here {
    flex-direction: row;
    align-items: baseline;
    gap: 16px;
  }

  .app--here .app__r { flex: none; }
  .app--here .app__n { flex: none; }
  .app--here .app__t { flex: 1; }
}

.app--here .app__r,
.app--here .app__t {
  color: rgba(21, 24, 46, 0.68);
}

/* The icon strip is dark artwork: give it its own bed. */
.strip {
  padding: clamp(18px, 2.6vw, 34px);
  border-radius: 18px;
  background: #06303f;
}

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

/* ==========================================================================
   Long read — one column of narrative, with artefacts breaking out of it
   ==========================================================================
   The case stopped reading as a story when every part arrived as its own
   section with its own heading. Here there is one column; photographs, the
   interactive flow and the state cards break out of it and the text resumes.
   ------------------------------------------------------------------------- */
.read {
  display: grid;
  grid-template-columns:
    [full-start] minmax(var(--gutter), 1fr)
    [wide-start] minmax(0, 170px)
    [text-start] min(68ch, 100% - (2 * var(--gutter)))
    [text-end] minmax(0, 170px)
    [wide-end] minmax(var(--gutter), 1fr)
    [full-end];
}

.read > * {
  grid-column: text-start / text-end;
}

.read > .wide {
  grid-column: wide-start / wide-end;
}

.read > .full {
  grid-column: full-start / full-end;
}

.read p {
  margin-bottom: 1.15em;
  font-size: clamp(17px, 1.2vw, 19px);
  line-height: 1.65;
}

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

.read p.soft { color: var(--ink-soft); }

.read strong { font-weight: 600; }

.read em { font-style: italic; }

/* Opening paragraph, a touch larger so the piece has a way in. */
.read .opening {
  font-size: clamp(19px, 1.6vw, 23px);
  line-height: 1.5;
}

/* A chapter marker that does not reset the page: a hairline and a label. */
.ch {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: clamp(56px, 7vw, 100px);
  margin-bottom: clamp(20px, 2.4vw, 30px);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.ch::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line-soft);
}

.ch b {
  font-family: "Yeseva One", Georgia, serif;
  font-weight: 400;
  font-size: 15px;
  letter-spacing: 0;
  color: var(--ink);
}

/* The emotional beats. Left aligned, in the column: a big centred pull-quote
   stops the reader, this carries them. */
.beat {
  margin-block: clamp(32px, 4vw, 52px);
  font-family: "Yeseva One", Georgia, serif;
  font-size: clamp(28px, 4vw, 46px);
  line-height: 1.12;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

.beat--quote::before {
  content: "“";
}

.beat--quote::after {
  content: "”";
}

.read figure {
  margin-block: clamp(30px, 4vw, 54px);
}

.read .shots {
  margin-block: clamp(30px, 4vw, 54px);
}

.read > .full.bleed {
  margin-block: clamp(30px, 4vw, 54px);
}

/* The flow and the catalogue sit inside the read, at wide or full width. */
.read .flow {
  margin-block: clamp(26px, 3vw, 40px) 0;
}

.read .filters {
  margin-top: clamp(22px, 3vw, 32px);
}

/* Numbers, at the end where they belong in a story rather than the top. */
.tally {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: clamp(20px, 3vw, 40px);
  margin-block: clamp(30px, 4vw, 48px);
  padding: clamp(24px, 3vw, 36px);
  border-radius: 18px;
  background: linear-gradient(145deg, var(--cream), var(--green));
}

.tally__n {
  font-family: "Yeseva One", Georgia, serif;
  font-size: clamp(30px, 3.4vw, 42px);
  line-height: 1;
}

.tally__t {
  margin-top: 8px;
  font-size: 14.5px;
  line-height: 1.45;
  color: rgba(21, 24, 46, 0.72);
}

@media (max-width: 1100px) {
  .tally { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 520px) {
  .tally { grid-template-columns: minmax(0, 1fr); }
}


/* ==========================================================================
   Case system
   ==========================================================================
   One palette, one display face in one role, one vertical rhythm. What the
   good Behance showcases have in common is not more devices — it is that
   every section is built the same way, so the images carry the page and
   nothing competes with them.

   Grounds:   paper · white · ink. Nothing else.
   Type:      Yeseva for headlines only. Figtree for everything else.
   Accent:    one green, for the mark, the chips and the label rule.
   Rhythm:    every section has identical padding and the same
              label → headline → body → visual order.
   ------------------------------------------------------------------------- */
.cs-page {
  --c-paper: #fcfbf7;
  --c-ink: #1b2136;
  --c-mute: #747a90;
  --c-accent: #78f0a0;
  --c-head: #2f6047;
  --c-hair: rgba(21, 24, 46, 0.08);
  --c-grid: rgba(21, 24, 46, 0.03);
  --c-radius: 18px;

  --c-pad-y: clamp(44px, 6vw, 86px);

  /* One ground for the whole case. The continuity comes from this never
     changing: sections carry no background of their own, media are objects
     placed on top of it. */
  position: relative;
  background-color: var(--c-paper);
}

/* The grid runs across the whole window, but its origin is the content edge
   of the centred column, so every line still falls where the layout puts one.
   Column 1088 ÷ 2 = 544, minus one cell of padding, puts the content edge at
   50% − 480px. */
.cs-page::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--c-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--c-grid) 1px, transparent 1px);
  background-size: var(--c-cell) var(--c-cell);
  background-position:
    calc(50% - (var(--c-col) / 2) + var(--c-pad-x)) var(--c-pad-y);
  pointer-events: none;
  z-index: 1;
}

/* Soft washes of the brand colours, drifting across the whole window behind
   the grid. They are what keeps the page from reading as hard. */
.cs-page::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(44rem 30rem at 86% 4%,  rgba(200, 245, 200, 0.5), transparent 68%),
    radial-gradient(40rem 28rem at 2% 24%,  rgba(255, 245, 200, 0.55), transparent 68%),
    radial-gradient(46rem 32rem at 96% 52%, rgba(200, 245, 200, 0.42), transparent 68%),
    radial-gradient(40rem 28rem at -4% 76%, rgba(255, 245, 200, 0.5), transparent 68%);
}

.cs-page > * { z-index: 2; }

/* Content sits above the grid. */
.cs-page > * { position: relative; }

/* Above the design width the padding snaps to the cell, so the alignment is
   exact rather than nearly right. */
@media (min-width: 1200px) {
  :root { --c-pad-x: var(--c-cell); }
}

/* The ground fills the window; the content does not. Everything sits in one
   column, because a line of text running the width of a desktop is no fun to
   read however nice the ground behind it is. */
.cs,
.cs--ink,
.cs--media {
  max-width: var(--c-col);
  margin-inline: auto;
}

/* Sections carry rhythm, not a ground. */
.cs {
  padding: var(--c-pad-y) var(--c-pad-x);
  background: transparent;
}

/* The one dark moment is an object on the ground, not a band across it. */
.cs--ink {
  max-width: calc(var(--c-col) - 2 * var(--c-pad-x));
  /* Inset by exactly one cell, so the words inside stand on a line of the
     same grid as the text above and below the block rather than at whatever
     a percentage of the window happens to give. */
  padding: clamp(40px, 5.5vw, 76px) max(28px, var(--c-pad-x));
  border-radius: calc(var(--c-radius) + 6px);
  background: var(--c-ink);
  color: #fff;
  box-shadow: 0 24px 60px -34px rgba(21, 24, 46, 0.5);
}

/* A photograph is an object too: it sits on the ground with air around it. */
.cs--media {
  padding: clamp(18px, 2.5vw, 36px) var(--c-pad-x);
  background: transparent;
  line-height: 0;
}

.cs--media img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--c-radius);
  box-shadow: 0 18px 44px -26px rgba(21, 24, 46, 0.42);
}

/* A drawing with a transparent ground is not a photograph lying on the page,
   it is drawn on it. The shadow and the rounded corner both describe an edge
   that is not there, and the shadow traces the image box rather than the
   artwork, which gives the whole thing away. */
.cs--art img {
  border-radius: 0;
  box-shadow: none;
}

/* A picture on its own paper rather than a photograph. The other cases carry a
   shadow under their photographs, and it disappears into a dark picture; under
   a light one it reads as a grey smudge. Same corner, no shadow. */
.cs--flat img { box-shadow: none; }

/* The one repeated unit: label, headline, body ----------------------------- */
.cs__label {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--c-mute);
}

.cs__label::before {
  content: "";
  width: 22px;
  height: 2px;
  background: var(--c-accent);
  flex: none;
}

.cs--ink .cs__label { color: rgba(255, 255, 255, 0.55); }

.cs__h {
  margin-top: 18px;
  max-width: 17ch;
  font-family: "Yeseva One", Georgia, serif;
  font-weight: 400;
  font-size: clamp(32px, 5vw, 64px);
  line-height: 1.06;
  letter-spacing: -0.02em;
  color: var(--c-head);
  text-wrap: balance;
}

.cs--ink .cs__h { color: #fff; }

.cs__b {
  margin-top: 20px;
  max-width: 52ch;
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--c-mute);
}

.cs__b + .cs__b { margin-top: 14px; }

/* A .beside carries a top margin to hold itself off the prose above it. Put
   one straight after a headline and that margin takes over, which is why one
   section sat 46px under its title while every other sat 20. Following a
   headline it is the first paragraph, and spaces like one. */
.cs__h + .beside { margin-top: 20px; }

.cs__b b {
  color: var(--ink);
  font-weight: 600;
}

.cs--ink .cs__b { color: rgba(255, 255, 255, 0.7); }
.cs--ink .cs__b b { color: #fff; }

/* Centred variant, for the two moments that deserve it. */
.cs--mid { text-align: center; }
.cs--mid .cs__label { justify-content: center; }
.cs--mid .cs__h,
.cs--mid .cs__b { margin-inline: auto; }

/* The accent, used in exactly one way in running text. */
.cs mark {
  background: linear-gradient(transparent 56%, var(--c-accent) 56%);
  color: inherit;
  padding-inline: 1px;
}

/* Media inside a section -------------------------------------------------- */
.cs__media { margin-top: clamp(32px, 4vw, 56px); }

.cs__media img,
.cs__pair img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--c-radius);
  box-shadow: 0 14px 36px -24px rgba(21, 24, 46, 0.38);
}

.cs__pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: clamp(14px, 1.8vw, 24px);
  align-items: start;
  margin-top: clamp(32px, 4vw, 56px);
}

.cs__cap {
  margin-top: 12px;
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--c-mute);
}

.cs__cap b { color: var(--ink); font-weight: 600; }
.cs--ink .cs__cap { color: rgba(255, 255, 255, 0.55); }

/* A statement beside its evidence ----------------------------------------- */
.cs__split {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: clamp(28px, 4vw, 64px);
  align-items: center;
}

.cs__split .cs__h { max-width: 15ch; }
.cs__split .cs__media { margin-top: 0; }

/* Lists of short items ---------------------------------------------------- */
.cs__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: clamp(20px, 2.6vw, 36px);
  margin-top: clamp(32px, 4vw, 56px);
}


.cs__item-n {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--c-accent);
  font-size: 12px;
  font-weight: 700;
  color: var(--c-ink);
}

.cs__item-t {
  margin-top: 14px;
  font-size: 15.5px;
  line-height: 1.5;
  color: var(--c-mute);
}

.cs__item-t b { color: var(--ink); font-weight: 600; }
.cs--ink .cs__item-t { color: rgba(255, 255, 255, 0.7); }
.cs--ink .cs__item-t b { color: #fff; }

/* Figures ----------------------------------------------------------------- */
.cs__n {
  font-size: clamp(30px, 3.4vw, 44px);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}

/* Tags -------------------------------------------------------------------- */
.cs__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 28px;
}

.cs__tag {
  padding: 7px 15px;
  border-radius: 50px;
  /* Solid, so the grid does not run through the chip. */
  background: var(--c-paper);
  box-shadow: inset 0 0 0 1px var(--c-hair);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--c-mute);
}

/* Title ------------------------------------------------------------------- */
.cs__title {
  /* The same step the label takes above every section headline. Without it
     the page title was the one heading sitting flush against its label. */
  margin-top: 18px;
  font-family: "Yeseva One", Georgia, serif;
  font-weight: 400;
  font-size: clamp(38px, 6vw, 76px);
  line-height: 1.04;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.cs__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 26px;
  margin-top: 30px;
  padding-top: 22px;
  border-top: 1px solid var(--c-hair);
  font-size: 13.5px;
  color: var(--c-mute);
}

.cs__meta b {
  color: var(--ink);
  font-weight: 600;
}

/* Closing ----------------------------------------------------------------- */
.cs__close {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 28px;
}

.cs__btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 28px;
  border-radius: 50px;
  background: var(--c-accent);
  color: var(--c-ink);
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  transition-property: scale;
  transition-duration: 200ms;
  transition-timing-function: var(--ease);
}

.cs__btn:active { scale: 0.96; }

.cs__btn svg { width: 16px; height: 16px; stroke-width: 2; }

/* The five apps, placed as individual icons rather than one flat strip.
   ------------------------------------------------------------------------- */
.apps-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
  gap: clamp(18px, 2.4vw, 34px);
  margin-top: clamp(34px, 4vw, 54px);
}

.app-i {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  text-align: center;
}

.app-i img {
  width: clamp(56px, 6vw, 74px);
  height: auto;
  border-radius: 16px;
}

.app-i__n {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.app-i__r {
  font-size: 11.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
}

/* The one this case is about. */
.app-i--here .app-i__n { color: var(--c-accent); }

.app-i--here img {
  box-shadow: 0 0 0 3px var(--c-accent);
}

/* A curved transition between two sections, running the full window width.
   It belongs to neither section, which is the point: it carries the eye over
   the join instead of stopping it.
   ------------------------------------------------------------------------- */
.cs-turn {
  display: block;
  width: 100%;
  height: clamp(48px, 7vw, 104px);
  margin-block: clamp(-14px, -1vw, -6px);
  overflow: hidden;
  line-height: 0;
  pointer-events: none;
}

.cs-turn svg {
  display: block;
  width: 100%;
  height: 100%;
}

.cs-turn path {
  fill: none;
  stroke: rgba(47, 96, 71, 0.22);
  stroke-width: 1.5;
}

.cs-turn circle {
  fill: var(--c-accent);
}

/* Playing with the margin: a few images break the column, lean a little, or
   sit lower than their neighbour. Used sparingly — if everything breaks out,
   nothing does.
   ------------------------------------------------------------------------- */
.cs-page { overflow-x: clip; }

/* Break past the column edge into the white space beside it. */
.out-r { margin-right: calc(-1 * (var(--c-pad-x) + var(--c-cell))); }
.out-l { margin-left: calc(-1 * (var(--c-pad-x) + var(--c-cell))); }

/* A small lean, so a photograph reads as a thing that was put down rather
   than a slot that was filled. */
.lean-l { rotate: -1.4deg; }
.lean-r { rotate: 1.2deg; }

.lean-l img,
.lean-r img {
  box-shadow: 0 22px 50px -26px rgba(21, 24, 46, 0.45);
}

/* ==========================================================================
   A hand of job stories
   ==========================================================================
   These were written on cards, so they are cards. The tilt and the shadow are
   the ones the leaning figures already use, which keeps the deck inside the
   same world rather than introducing a second idea of paper. Two columns so a
   role's pair sits on one row; rotation comes off below 860px, where the
   figures lose theirs too.
   ------------------------------------------------------------------------- */
.deck {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(20px, 2.4vw, 34px);
  margin-top: clamp(34px, 4vw, 60px);
}

.deck__card {
  position: relative;
  padding: clamp(22px, 2.3vw, 30px);
  border-radius: 14px;
  background: var(--paper-raised);
  box-shadow:
    0 22px 50px -30px rgba(21, 24, 46, 0.45),
    0 1px 2px rgba(21, 24, 46, 0.05);
  transition-property: rotate, translate, box-shadow;
  transition-duration: 260ms;
  transition-timing-function: cubic-bezier(0.2, 0, 0, 1);
}

/* Dealt, not laid out. Three angles cycling so no two neighbours match. */
.deck__card:nth-child(3n + 1) { rotate: -1.1deg; }
.deck__card:nth-child(3n + 2) { rotate: 1.3deg; }
.deck__card:nth-child(3n + 3) { rotate: -0.5deg; }

.deck__card:hover {
  rotate: 0deg;
  translate: 0 -4px;
  box-shadow:
    0 32px 62px -30px rgba(21, 24, 46, 0.5),
    0 1px 2px rgba(21, 24, 46, 0.05);
}

/* Whose card this is, as a tab rather than a heading. */
.deck__who {
  display: inline-block;
  margin: 0 0 14px;
  padding: 5px 11px;
  border-radius: 999px;
  background: rgba(120, 240, 160, 0.2);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink);
}

.deck__story {
  margin: 0;
  font-size: clamp(15.5px, 1.25vw, 17px);
  line-height: 1.55;
  color: var(--ink);
}

/* The three joints of a job story, picked out so the shape repeats visibly
   down the deck. Six cards, one grammar — and the same grammar inside a step
   on the other cases, so a reader who has met one job story recognises the
   next one on sight. */
.deck__k,
.step__k {
  font-weight: 700;
  color: rgb(21, 110, 70);
}

@media (max-width: 1000px) {
  .deck { grid-template-columns: minmax(0, 1fr); }

  /* Has to match the specificity of the nth-child rules above, or they win:
     a media query adds none of its own. The leaning figures drop their tilt
     at this width too. */
  .deck__card:nth-child(3n + 1),
  .deck__card:nth-child(3n + 2),
  .deck__card:nth-child(3n + 3) { rotate: none; }

  .deck__card:hover { rotate: none; translate: none; }
}

@media (prefers-reduced-motion: reduce) {
  .deck__card { transition: none; }
  .deck__card:hover { rotate: none; translate: none; }
}

/* ==========================================================================
   A drawing that is not drawn yet
   ==========================================================================
   Max illustrates; this holds the spot and says what goes in it. Deliberately
   unfinished-looking — a dashed box on the page is a reminder, a tidy grey box
   is something you stop noticing. NOTHING WITH ONE OF THESE ON IT GOES LIVE.
   ------------------------------------------------------------------------- */
.ph {
  position: relative;
  /* Only the top margin: a shorthand here would zero the negative side
     margins that .out-l and .out-r use to step out of the column, because
     this block sits after them in the file. */
  margin-block: clamp(30px, 4vw, 52px) 0;
  padding: clamp(22px, 2.8vw, 36px);
  border: 2px dashed rgba(21, 24, 46, 0.26);
  border-radius: 18px;
  background: rgba(255, 245, 200, 0.26);
}

.ph__tag {
  margin: 0 0 12px;
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--amber);
}

.ph__title {
  margin: 0 0 12px;
  font-size: clamp(19px, 1.9vw, 24px);
  font-weight: 700;
  line-height: 1.25;
  color: var(--ink);
}

.ph__brief {
  margin: 0;
  max-width: 62ch;
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--ink-soft);
}

.ph__brief + .ph__brief { margin-top: 10px; }

.ph__spec {
  margin: 16px 0 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-faint);
}

.ph__spec code {
  padding: 2px 7px;
  border-radius: 6px;
  background: rgba(21, 24, 46, 0.06);
  font-size: 12.5px;
}

/* The scenario only: what is in the frame and how it is arranged. Max has the
   style captured elsewhere, so repeating it here would be noise he has to
   delete every time. Selectable and monospaced so it lifts straight out. */
.ph__prompt {
  margin: 16px 0 0;
  padding: 14px 16px;
  border-radius: 10px;
  background: rgba(21, 24, 46, 0.045);
  box-shadow: inset 0 0 0 1px rgba(21, 24, 46, 0.07);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--ink-soft);
  user-select: all;
}

.ph__prompt b {
  display: block;
  margin-bottom: 7px;
  font-family: "Figtree", sans-serif;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-faint);
  user-select: none;
}

/* A placeholder is allowed out of the column too, so the composition can be
   judged now rather than after the drawing lands. Below 1000px it comes back
   in: there is no room to step out of a single-column page. */
@media (max-width: 1000px) {
  .ph.out-l, .ph.out-r { margin-inline: 0; }
  .ph.lean-l, .ph.lean-r { rotate: none; }
}

/* ==========================================================================
   Reference, not subject
   ==========================================================================
   The research artefacts are what this case is about and they step out of the
   column. The Gateway screenshots are evidence that the direction had a shape,
   which is a smaller job, so they stay inside the measure with the prose. The
   case also says the visuals are a vision study to be taken with a grain of
   salt — showing them at hero size argues the opposite.
   ------------------------------------------------------------------------- */
.ref {
  max-width: var(--measure);
  margin-inline: 0;
}

.ref img {
  border-radius: 10px;
  outline: 1px solid var(--outline-img);
  outline-offset: -1px;
}

.ref .cs__cap { max-width: var(--measure); }

/* ==========================================================================
   A picture beside the thing it explains
   ==========================================================================
   Stacking every figure above its own paragraph is what turned this case into
   eleven thousand pixels of scroll. A drawing and the rows it illustrates
   belong on one screen, side by side, so the reader compares them instead of
   remembering one while scrolling to the other.
   ------------------------------------------------------------------------- */
.beside {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  /* Wider than a gap between two columns of text would be. On one side of
     this one there is artwork, and a drawing needs air around it before the
     paragraphs start or the two read as one crowded block. */
  gap: clamp(32px, 5.4vw, 86px);
  /* Top, not centre. A portrait drawing is far taller than the few paragraphs
     beside it, and centring floats those paragraphs in the middle of the
     column with air above and below, which reads as a mistake. Aligned to the
     top they start on the same line as the drawing does. */
  align-items: start;
  margin-top: clamp(28px, 3.4vw, 46px);
}

.beside > figure { margin: 0; max-width: none; }

.beside > figure img {
  display: block;
  width: 100%;
  height: auto;
}

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

/* Mirror of the default split, for a pair whose figure sits on the right.
   Both drawings are portrait, so both want the narrower half. */
.beside--fig-r { grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr); }

/* This pair opens its section: the label and headline sit in the body, so the
   drawing starts at the very top and its chimney stands level with the title
   rather than beginning somewhere below the prose. */
.beside--lede { margin-top: 0; }

/* Hang the drawing from the last line of prose rather than the first. Where
   the text is the taller of the two, aligning tops leaves the drawing
   stopping short in mid-air; aligning the feet gives both columns the same
   baseline to stand on. */
.beside--foot { align-items: end; }

/* The drawing starts half behind the headline. Its top corner is empty sky,
   so the words can cross it without a single line running through a letter --
   which is why the headline spills right over the figure rather than the
   figure sliding left under the prose, where it would meet the factory wall.
   Text over artwork, never the other way round. */
.beside--lede > .beside__body { position: relative; z-index: 1; }
.beside--lede > figure { position: relative; z-index: 0; }

/* Set on two lines, not three. The lines get long enough to carry the
   headline out over the drawing on their own, so the chimney ends up behind
   the words without the drawing moving an inch and without the paragraphs
   giving up any width. */
.beside--lede .cs__h {
  max-width: none;
  width: calc(100% + clamp(0px, 36vw, 490px));
}

@media (max-width: 1000px) {
  .beside { grid-template-columns: minmax(0, 1fr); }
  /* 520px of a portrait drawing is over 700px tall once stacked, which is a
     whole tablet screen of one illustration. Cap it nearer 400. */
  .beside > figure { max-width: 400px; margin-inline: auto; }
  .beside--lede .cs__h { width: 100%; }
}

/* Three screens shown small on purpose: evidence that the direction had a
   shape, not something to read. The label under each carries the point. */
.strip3 {
  display: grid;
  /* Not three equal columns. The three screens are 1.60, 0.93 and 0.80 wide
     for every one tall, so equal widths give three different heights and a
     ragged bottom edge. Weighting each column by its own ratio renders them
     at one height, flush, with nothing cropped. */
  grid-template-columns: 1.6fr 0.93fr 0.8fr;
  gap: clamp(14px, 1.8vw, 24px);
  margin-top: clamp(28px, 3.4vw, 44px);
  align-items: start;
}

.strip3 figure { margin: 0; }

.strip3 img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 8px;
  outline: 1px solid var(--outline-img);
  outline-offset: -1px;
}

.strip3 figcaption {
  margin-top: 9px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink-faint);
}

.strip3 figcaption b { color: var(--ink); font-weight: 700; }

@media (max-width: 720px) {
  .strip3 { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .strip3 figure { max-width: 420px; }
}

/* Drop one of a pair, so the two do not sit on the same line. */
.drop { margin-top: clamp(22px, 4vw, 64px); }

/* Let a dropped image overlap its neighbour a touch. */
.lift { position: relative; z-index: 2; }

@media (max-width: 860px) {
  .out-r, .out-l { margin-inline: 0; }
  .lean-l, .lean-r { rotate: none; }
  .drop { margin-top: 0; }
}


/* A statement given the room to land, on the open ground rather than inside
   a block. Two heavy blocks in a row is one too many, and the case only
   needs one dark moment for it to mean anything.
   ------------------------------------------------------------------------- */
.cs--say {
  padding-block: clamp(64px, 9vw, 132px);
}

.cs--say .cs__h {
  max-width: 20ch;
  font-size: clamp(34px, 5.6vw, 72px);
  color: var(--c-ink);
}

.cs--say .cs__b {
  margin-top: 26px;
  font-size: 16.5px;
}

/* An award, dropped on the page rather than slotted into the grid.
   ------------------------------------------------------------------------- */
.cs__award {
  position: absolute;
  top: clamp(42px, 6vw, 92px);
  right: calc(-1 * var(--c-cell));
  width: clamp(112px, 12vw, 164px);
  rotate: 9deg;
  text-align: center;
  pointer-events: none;
}

.cs__award img {
  width: 100%;
  height: auto;
  filter: drop-shadow(0 14px 26px rgba(21, 24, 46, 0.22));
}

.cs__award-t {
  margin-top: 10px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 1.35;
  color: var(--c-mute);
}

/* No margin to float in on a phone, so the stamp cannot sit in one. Tilting
   a block that is now in the flow only tips its four lines of capitals over
   with it. It becomes a line instead: the medal kept small and still tilted,
   because it is a thing, with the words upright beside it. */
@media (max-width: 900px) {
  .cs__award {
    position: static;
    display: flex;
    align-items: center;
    gap: 14px;
    width: auto;
    margin: 30px 0 0;
    rotate: none;
    text-align: left;
  }

  .cs__award img {
    flex: none;
    width: 68px;
    rotate: 4deg;
  }

  .cs__award-t { margin-top: 0; }
}


/* ==========================================================================
   The landing page
   ==========================================================================
   One link to share, so the landing page is the portfolio, not a door to it.
   Same ground as the cases (.cs-page) — opening a case should not feel like
   arriving somewhere else.

   The idea is layers on one sheet of paper. The name is set big enough to
   step out of the column; the photograph lies over the rule under it; every
   case carries its number as a watermark behind the type, and its evidence
   leans out into the margin. Nothing is boxed, nothing alternates
   background, and the page closes with a signature rather than a slogan.
   ------------------------------------------------------------------------- */

/* Hero --------------------------------------------------------------------- */
.idx-hero {
  /* The photograph's column, named once: the rule underneath has to keep
     exactly this much room clear, or the text runs under the picture. */
  --idx-photo: clamp(170px, 23vw, 330px);
  --idx-gap: clamp(22px, 3vw, 44px);

  padding-top: clamp(40px, 8vw, 104px);
  padding-bottom: clamp(20px, 3vw, 40px);
}

/* The photograph lies behind the name, in the air the short first line
   leaves at the top right. Stacked, so on a phone it is simply an object
   under the words. */
.idx-head {
  position: relative;
}

.idx-eyebrow,
.idx-name {
  position: relative;
  z-index: 2;
}

.idx-eyebrow {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--c-mute);
}

.idx-eyebrow::before {
  content: "";
  width: 22px;
  height: 2px;
  flex: none;
  background: var(--c-accent);
}

/* The one piece of type that is allowed to be louder than a case headline.
   It is a name, so it can carry the page on its own. */
/* The name is the picture. It has the column to itself and is set to fill
   it, so the opening screen is carried by one piece of type rather than by
   a photograph of a face trying to hold half a page on its own. */
.idx-name {
  margin-top: clamp(14px, 2vw, 24px);
  font-family: "Yeseva One", Georgia, serif;
  font-weight: 400;
  font-size: clamp(52px, 12.4vw, 180px);
  line-height: 0.86;
  letter-spacing: -0.04em;
  color: var(--c-head);
}

.idx-role {
  margin-top: clamp(22px, 2.6vw, 34px);
  max-width: 44ch;
  font-size: clamp(16px, 1.4vw, 19px);
  line-height: 1.55;
  color: var(--c-mute);
}

.idx-role b {
  color: var(--ink);
  font-weight: 600;
}

/* The photograph as a placed asset: crop marks around it, the way artwork
   sits in a layout before it is trimmed. It is what makes a square of a man
   at less than full strength read as a decision instead of an accident, and
   it is the right register for a page about design work. */
.idx-shot {
  /* How far the marks stand off the picture, and how far short of it they
     stop. Both shrink with the page: on a phone the gutter is 16px, and a
     mark standing 26px off would be cut in half by the window. */
  --mark-out: clamp(14px, 4vw, 26px);
  --mark-gap: clamp(6px, 1.5vw, 10px);
  --mark-ink: rgba(21, 24, 46, 0.3);

  position: relative;
  width: clamp(142px, 38vw, 178px);
  /* Room under it for the marks, which stand outside the picture and would
     otherwise cross the line that follows. */
  margin: 0 0 clamp(20px, 6vw, 34px);
  rotate: 2.2deg;
}

.idx-shot::before {
  --len: calc(var(--mark-out) - var(--mark-gap));

  content: "";
  position: absolute;
  inset: calc(-1 * var(--mark-out));
  pointer-events: none;
  background:
    linear-gradient(var(--mark-ink), var(--mark-ink)) left 0 top var(--mark-out) /
      var(--len) 1px no-repeat,
    linear-gradient(var(--mark-ink), var(--mark-ink)) left var(--mark-out) top 0 /
      1px var(--len) no-repeat,
    linear-gradient(var(--mark-ink), var(--mark-ink)) right 0 top var(--mark-out) /
      var(--len) 1px no-repeat,
    linear-gradient(var(--mark-ink), var(--mark-ink)) right var(--mark-out) top 0 /
      1px var(--len) no-repeat,
    linear-gradient(var(--mark-ink), var(--mark-ink)) left 0 bottom var(--mark-out) /
      var(--len) 1px no-repeat,
    linear-gradient(var(--mark-ink), var(--mark-ink)) left var(--mark-out) bottom 0 /
      1px var(--len) no-repeat,
    linear-gradient(var(--mark-ink), var(--mark-ink)) right 0 bottom var(--mark-out) /
      var(--len) 1px no-repeat,
    linear-gradient(var(--mark-ink), var(--mark-ink)) right var(--mark-out) bottom 0 /
      1px var(--len) no-repeat;
}

.idx-portrait {
  width: 100%;
  height: auto;
  border-radius: var(--c-radius);
  box-shadow: 0 22px 50px -26px rgba(21, 24, 46, 0.5);
}

/* The practical facts, on a rule the photograph lies across. */
.idx-meta {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: clamp(5px, 1vw, 8px) clamp(16px, 2vw, 24px);
  /* Full width on purpose: the rule has to run on under the photograph,
     or the two layers never actually meet. */
  margin-top: clamp(26px, 3.4vw, 44px);
  padding-top: 20px;
  border-top: 1px solid var(--c-hair);
  font-size: 13.5px;
  color: var(--c-mute);
}

/* Nothing in this row is emphasised except the one thing you can click.
   Weight inside it only fought the gaps that already separate the facts. */
.idx-meta a {
  color: var(--ink);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--c-hair);
  text-underline-offset: 3px;
}

@media (hover: hover) {
  .idx-meta a:hover { text-decoration-color: var(--c-accent); }
}

@media (min-width: 760px) {
  /* In the air the short first line of the name leaves at the top right.
     Small enough to sit in that gap rather than under the second line, so
     it can be the photograph itself and not a wash behind the words. */
  .idx-shot {
    --mark-out: clamp(20px, 2.2vw, 30px);
    --mark-gap: clamp(8px, 0.9vw, 12px);

    position: absolute;
    z-index: 1;
    /* Dropped far enough that the tail of the second line falls across its
       bottom corner — the words in front, the picture behind. */
    top: clamp(-6px, 0.8vw, 16px);
    right: 0;
    width: var(--idx-photo);
    margin: 0;
  }
}

/* And out into the margin at the width where every other picture does. */
@media (min-width: 1240px) {
  .idx-shot { right: calc(-1 * var(--c-pad-x)); }
}

/* The four cases -----------------------------------------------------------
   Two are written up and link; two are not and say so. The written ones get
   a wide row and their own evidence; the other two are a quiet pair at the
   end — which is the difference between them, shown rather than explained. */
.idx-list {
  margin-top: clamp(40px, 5.5vw, 78px);
}

.idx-case {
  display: block;
  color: inherit;
  text-decoration: none;
}

.idx-case + .idx-case {
  margin-top: clamp(56px, 7.5vw, 112px);
}

.idx-case__text {
  position: relative;
}

/* The picture belongs to the block, not above it: one object beside the
   words, at roughly the weight of the words. */
.idx-case__art {
  margin-top: clamp(24px, 3vw, 36px);
  line-height: 0;
}

/* One shape for both, so the two rows weigh the same. Left to themselves a
   2.35:1 hangar and a 1.84:1 apron differ by sixty pixels of height, which
   on a page this strict reads as a mistake. Two to one also lands the
   picture at about the height of the words beside it. */
.idx-case__art img {
  width: 100%;
  height: auto;
  aspect-ratio: 2 / 1;
  object-fit: cover;
  border-radius: var(--c-radius);
  box-shadow: 0 18px 44px -28px rgba(21, 24, 46, 0.4);
}

/* The number as a watermark behind the type, not a label in front of it. */
.idx-case__big {
  position: absolute;
  z-index: -1;
  top: -0.08em;
  left: -0.06em;
  font-family: "Yeseva One", Georgia, serif;
  font-weight: 400;
  font-size: clamp(92px, 13vw, 176px);
  line-height: 1;
  letter-spacing: -0.05em;
  color: rgba(21, 24, 46, 0.06);
  pointer-events: none;
  user-select: none;
}

.idx-case__t {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--c-mute);
}

.idx-case__s {
  margin-top: 12px;
  max-width: 15ch;
  font-family: "Yeseva One", Georgia, serif;
  font-weight: 400;
  font-size: clamp(27px, 3.4vw, 42px);
  line-height: 1.08;
  letter-spacing: -0.02em;
  color: var(--c-head);
  text-wrap: balance;
  transition-property: color;
  transition-duration: 200ms;
  transition-timing-function: var(--ease);
}

.idx-case__side {
  margin-top: 20px;
}

.idx-case__m {
  max-width: 42ch;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--c-mute);
}

.idx-case__m b {
  color: var(--ink);
  font-weight: 600;
}

.idx-case__go {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 20px;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--ink);
}

.idx-case__go span {
  box-shadow: inset 0 -2px 0 var(--c-accent);
}

.idx-case__go svg {
  width: 16px;
  height: 16px;
  stroke-width: 2;
  transition-property: translate;
  transition-duration: 200ms;
  transition-timing-function: var(--ease);
}

@media (min-width: 720px) {
  /* Two equal halves with one cell between them: seven cells of words, a
     cell of air, seven cells of picture. Fractions of the window put the
     split at whatever the window happened to be. */
  .idx-case {
    display: grid;
    grid-template-columns: 6fr 8fr;
    gap: max(30px, var(--c-pad-x));
    align-items: center;
  }

  /* The second case turns around. Two rows built the same way read as one
     thing said twice; mirrored, the page has a rhythm and each picture gets
     the margin on its own side to lean into. */
  .idx-case:nth-child(even) {
    grid-template-columns: 8fr 6fr;
  }

  .idx-case:nth-child(even) .idx-case__art {
    grid-column: 1;
    grid-row: 1;
  }

  .idx-case:nth-child(even) .idx-case__text {
    grid-column: 2;
    grid-row: 1;
  }

  .idx-case__art { margin-top: 0; }
}

/* Both pictures lean one cell past the right edge of the column, where
   there is margin to lean into. */
@media (min-width: 1240px) {
  .idx-case__art { margin-right: calc(-1 * var(--c-pad-x)); }

  .idx-case:nth-child(even) .idx-case__art {
    margin-right: 0;
    margin-left: calc(-1 * var(--c-pad-x));
  }
}

/* Hovering lifts the picture: the only thing on this page that moves, and it
   moves because you asked. */
@media (hover: hover) {
  .idx-case__art {
    transition-property: translate;
    transition-duration: 320ms;
    transition-timing-function: var(--ease);
  }

  .idx-case:hover .idx-case__art { translate: 0 -6px; }
  .idx-case:hover .idx-case__go svg { translate: 4px 0; }
  .idx-case:hover .idx-case__s { color: var(--c-ink); }
}


/* The two own products ---------------------------------------------------- */
.idx-products {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: max(30px, var(--c-pad-x));
  margin-top: clamp(32px, 4vw, 56px);
}

.idx-product__ico {
  width: clamp(56px, 6.5vw, 72px);
  height: auto;
  border-radius: 16px;
  box-shadow: 0 14px 30px -16px rgba(21, 24, 46, 0.55);
}

.idx-products > *:nth-child(1) .idx-product__ico { rotate: -3.5deg; }
.idx-products > *:nth-child(2) .idx-product__ico { rotate: 3.5deg; }

.idx-product__n {
  margin-top: 20px;
  font-family: "Yeseva One", Georgia, serif;
  font-weight: 400;
  font-size: 27px;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--c-head);
}

.idx-product__d {
  margin-top: 10px;
  max-width: 36ch;
  font-size: 15px;
  line-height: 1.55;
  color: var(--c-mute);
}

.idx-product__l {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  margin-top: 14px;
  font-size: 13.5px;
  color: var(--c-mute);
}

.idx-product__l a {
  color: var(--ink);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--c-hair);
  text-underline-offset: 3px;
}

@media (hover: hover) {
  .idx-product__l a:hover { text-decoration-color: var(--c-accent); }
}


/* The page that is not there -----------------------------------------------
   The one error state this site can actually serve, so it gets the same
   ground, the same column and the same grid as everything else. The code is
   a watermark behind the headline, the way a case number is. */
.err {
  position: relative;
  padding-top: clamp(80px, 12vw, 168px);
}

.err__big {
  position: absolute;
  z-index: -1;
  top: clamp(40px, 7vw, 96px);
  left: -0.06em;
  font-family: "Yeseva One", Georgia, serif;
  font-weight: 400;
  font-size: clamp(110px, 17vw, 232px);
  line-height: 1;
  letter-spacing: -0.05em;
  color: rgba(21, 24, 46, 0.055);
  pointer-events: none;
  user-select: none;
}

/* Four ways out, each saying where it goes rather than just "home". */
.err__ways {
  display: grid;
  margin-top: clamp(34px, 5vw, 60px);
  border-top: 1px solid var(--c-hair);
}

.err__way {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 4px 18px;
  padding: clamp(18px, 2.4vw, 26px) 0;
  border-bottom: 1px solid var(--c-hair);
  color: inherit;
  text-decoration: none;
}

.err__way-k {
  grid-column: 1;
  font-size: clamp(17px, 1.9vw, 22px);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--c-head);
}

.err__way-t {
  grid-column: 1;
  font-size: 15px;
  line-height: 1.55;
  color: var(--c-mute);
}

.err__way svg {
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: center;
  width: 20px;
  height: 20px;
  stroke-width: 1.8;
  color: var(--c-mute);
}

@media (hover: hover) {
  .err__way {
    transition-property: background-color;
    transition-duration: 160ms;
    transition-timing-function: var(--ease);
  }

  .err__way:hover { background-color: rgba(21, 24, 46, 0.025); }
  .err__way:hover .err__way-k { color: var(--c-ink); }
  .err__way:hover svg { color: var(--c-accent); }
}

@media (min-width: 720px) {
  .err__way {
    grid-template-columns: minmax(0, 22ch) minmax(0, 1fr) auto;
    align-items: center;
    gap: 24px;
  }

  .err__way-t { grid-column: 2; }
  .err__way svg { grid-column: 3; grid-row: 1; }
}

/* Close -------------------------------------------------------------------
   Signed by hand, because the rest of the page is set by machine. */
.idx-sign {
  width: clamp(164px, 21vw, 228px);
  height: auto;
  margin-top: clamp(28px, 3.5vw, 44px);
  opacity: 0.7;
  rotate: -1.4deg;
}

/* The ink block is an object lying on the ground, so it keeps its margin at
   every width. The shared rule holds it in with a max-width of roughly one
   column, which stops insetting anything once the screen is narrower than
   that — on a phone it would run edge to edge. This lands it on the same
   side margin as the text column instead, on every page that has one. */
.cs--ink {
  width: calc(100% - 2 * var(--c-pad-x));
  margin-inline: auto;
}

/* Who the work was for. Eleven names say more than a paragraph about range,
   and cost almost no reading. */
.idx-brands {
  margin-top: clamp(24px, 3vw, 34px);
  font-size: clamp(19px, 2.2vw, 28px);
  font-weight: 400;
  line-height: 1.55;
  letter-spacing: -0.015em;
  /* The separators sit well behind the names, so eleven clients read as one
     wall rather than as a list to be counted. */
  color: rgba(255, 255, 255, 0.28);
}

.idx-brands b {
  font-weight: 600;
  color: #fff;
}

/* The landing page keeps the same measure as the cases, but marks it with
   dots instead of ruled squares: the grid is still there to line things up
   against, it just stops looking like paper from a notebook. The half-cell
   offset puts each dot exactly where two rules used to cross. */
.cs-page--dots {
  --c-dot: rgba(21, 24, 46, 0.07);
}

/* Half the layout cell, so every second dot still falls on a layout line but
   the field reads as a texture instead of as a row of marks you can count. */
.cs-page--dots::before {
  background-image: radial-gradient(circle at center, var(--c-dot) 1px, transparent 1.5px);
  background-size: calc(var(--c-cell) / 2) calc(var(--c-cell) / 2);
  background-position:
    calc(50% - (var(--c-col) / 2) + var(--c-pad-x) - (var(--c-cell) / 4))
    calc(var(--c-pad-y) - (var(--c-cell) / 4));
}

/* Case-page components restored after a merge dropped them.
   The landing page rules above are current; these are what the four case
   pages are built from and nothing on the landing page uses them.
   ------------------------------------------------------------------------- */
/* Two directions, side by side ------------------------------------------- */
.mirror {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: clamp(16px, 2.5vw, 30px);
  margin-top: 34px;
}

.mirror__p { margin: 0; }

.mirror__p svg { display: block; width: 100%; height: auto; }

.mirror .mr-f { fill: rgba(255, 255, 255, 0.04); stroke: rgba(255, 255, 255, 0.14); }

.mirror .mr-b { fill: rgba(255, 255, 255, 0.5); }

.mirror .mr-d { fill: rgba(255, 255, 255, 0.16); }

.mirror .mr-l { fill: rgba(255, 255, 255, 0.26); }

.mirror .mr-l--s { fill: rgba(255, 255, 255, 0.16); }

.mirror .mr-keep rect { fill: rgba(120, 240, 160, 0.14); stroke: rgba(120, 240, 160, 0.5); }

.mirror .mr-keep text {
  fill: var(--c-accent);
  font-size: 11px;
  font-weight: 700;
  text-anchor: middle;
  letter-spacing: 0.02em;
}

.mirror .mr-cabin .mr-hull {
  fill: none;
  stroke: rgba(120, 240, 160, 0.42);
  stroke-width: 1.2;
  stroke-linejoin: round;
}

.mirror .mr-cabin .mr-s {
  fill: rgba(120, 240, 160, 0.13);
  stroke: rgba(120, 240, 160, 0.34);
  stroke-width: 1;
}

.mirror .mr-cabin .mr-s--hi {
  fill: var(--c-accent);
  stroke: var(--c-accent);
}

.mirror .mr-cabin .mr-col,
.mirror .mr-cabin .mr-row {
  fill: rgba(120, 240, 160, 0.45);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.04em;
}

.mirror .mr-cabin .mr-col { text-anchor: middle; }

.mirror .mr-cabin .mr-row { text-anchor: end; }

.mirror .mr-cabin .mr-row--hi {
  fill: var(--c-accent);
  font-weight: 700;
}

.mirror__p figcaption {
  margin-top: 12px;
  text-align: center;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.4);
}

.mirror__k {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 10px clamp(20px, 3vw, 40px);
  margin: 22px 0 0;
  padding: 0;
  list-style: none;
  text-align: left;
}

.mirror__k li {
  position: relative;
  padding-left: 20px;
  font-size: 14.5px;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.62);
}

.mirror__k li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 7px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.26);
}

.mirror__k li:last-child::before {
  background: rgba(120, 240, 160, 0.2);
  border: 1.5px solid var(--c-accent);
}

.mirror__k b { color: #fff; font-weight: 600; }

/* A measured result, drawn rather than tabulated ------------------------- */
.res {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  gap: clamp(26px, 4vw, 54px);
  align-items: center;
  margin-top: 36px;
}

.res__row {
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr) auto;
  align-items: center;
  gap: 14px;
  margin-bottom: 14px;
}

.res__k {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
}

.res__bar {
  display: block;
  height: 14px;
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.07);
}

.res__bar i {
  display: block;
  height: 100%;
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.22);
}

.res__row--win .res__bar i { background: var(--c-accent); }

.res__row--win .res__k { color: rgba(255, 255, 255, 0.72); }

.res__row--win .res__v { color: var(--c-accent); }

.res__v {
  min-width: 68px;
  text-align: right;
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: rgba(255, 255, 255, 0.78);
}

.res__v small { font-size: 0.55em; font-weight: 600; margin-left: 1px; }

.res__note {
  margin: 16px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.4);
}

.res__split {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  padding: 22px 20px;
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.045);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.09);
}

.res__n {
  margin: 0;
  font-size: clamp(20px, 2.4vw, 27px);
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: #fff;
}

.res__n small { font-size: 0.55em; font-weight: 600; }

.res__t {
  margin: 4px 0 0;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.42);
}

@media (max-width: 760px) {
  .res { grid-template-columns: minmax(0, 1fr); }
  .res__row { grid-template-columns: 78px minmax(0, 1fr) auto; gap: 10px; }
  .res__k { font-size: 11px; }
  .res__v { font-size: 22px; min-width: 60px; }
}

/* 87 states, one of which is a problem ----------------------------------- */
.dots {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  grid-auto-rows: 1fr;
  gap: clamp(6px, 1vw, 12px);
  margin-top: 38px;
}

.dots span {
  aspect-ratio: 1;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.08);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
}

.dots .dots__o {
  background: rgba(255, 176, 46, 0.9);
  box-shadow: 0 0 0 4px rgba(255, 176, 46, 0.18), 0 0 26px rgba(255, 176, 46, 0.45);
}

@media (min-width: 861px) { .dots { grid-template-columns: repeat(29, 1fr); } }

@media (max-width: 860px) { .dots { grid-template-columns: repeat(16, 1fr); } }

@media (max-width: 480px) { .dots { grid-template-columns: repeat(12, 1fr); } }

/* Keys under a graphic, on the light ground ------------------------------- */
.keys {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 12px clamp(20px, 3vw, 44px);
  margin: 30px 0 0;
  padding: 0;
  list-style: none;
}

.keys li {
  position: relative;
  padding-left: 20px;
  font-size: 15px;
  line-height: 1.55;
  color: var(--c-mute);
}

.keys li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 8px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--c-accent);
}

.keys b { color: var(--c-ink); font-weight: 600; }

/* One page, scrolled
   The three screens in this case were never three screens — they are three
   parts of one booking page. So it is one screenshot in a phone-sized window,
   and the window scrolls it as you read past. The text steps on the left are
   what gives the scroll its distance.
   ------------------------------------------------------------------------- */
.cs--pull { margin-top: calc(-1 * clamp(30px, 5vw, 80px)); }

.pscroll {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(28px, 5vw, 80px);
  margin-top: clamp(30px, 5vw, 60px);
  align-items: start;
}

/* Room after the last step, so the shot can run out to its end. */
.pscroll__text { padding-bottom: 34vh; }

.pscroll__step {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 72vh;
  padding-block: 20px;
  max-width: 44ch;
}

.pscroll__step p {
  margin: 0;
  font-size: 15.5px;
  line-height: 1.65;
  color: var(--c-mute);
}

.pscroll__step p b { color: var(--c-ink); font-weight: 600; }

.pscroll__k {
  margin: 0 0 10px !important;
  font-size: 11px;
  font-weight: 700 !important;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--c-head) !important;
}

.pscroll__stage {
  position: sticky;
  top: 108px;
}

/* An abstract handset: a bezel, a speaker slit, two buttons. Nothing branded. */
.pscroll__device {
  position: relative;
  width: clamp(252px, 27vw, 332px);
  margin: 0;
  padding: 12px;
  border-radius: 36px;
  background: linear-gradient(168deg, #efe7d6, #d8cbb2 66%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.6),
    0 0 0 1px rgba(21, 24, 46, 0.08),
    0 30px 70px -34px rgba(21, 24, 46, 0.42);
}

.pscroll__device::before,
.pscroll__device::after {
  content: "";
  position: absolute;
  left: 100%;
  width: 2px;
  border-radius: 0 2px 2px 0;
  background: rgba(21, 24, 46, 0.14);
}

.pscroll__device::before { top: 23%; height: 36px; }

.pscroll__device::after { top: 38%; height: 56px; }

.pscroll__notch {
  position: absolute;
  top: 4px;
  left: 50%;
  translate: -50% 0;
  width: 58px;
  height: 4px;
  border-radius: 2px;
  background: rgba(21, 24, 46, 0.2);
}

.pscroll__screen {
  position: relative;
  display: block;
  aspect-ratio: 350 / 690;
  overflow: hidden;
  border-radius: 24px;
  background: #fff;
}

.pscroll__screen img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: auto;
  will-change: transform;
}

.pscroll__cap {
  margin: 14px 0 0;
  font-size: 12.5px;
  color: var(--c-mute);
}

@media (max-width: 860px) {
  .cs--pull { margin-top: 0; }

  .pscroll {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
  }

  .pscroll__stage {
    order: -1;
    top: 56px;
    z-index: 20;
    padding-bottom: 16px;
    background: linear-gradient(180deg, var(--c-paper) calc(100% - 18px), transparent);
  }

  /* Stacked, the handset and the step it explains are fighting over one
     screen, so the handset is sized from the viewport's height rather than its
     width. At 64vw it took 500px of an 812px phone and left the paragraph a
     slot it could not fit in. Two fifths of the height, on any device. */
  .pscroll__device {
    width: min(248px, 64vw, calc(20vh + 12px));
    width: min(248px, 64vw, calc(20dvh + 12px));
    margin-inline: auto;
  }

  .pscroll__cap { text-align: center; }

  /* The step stays centred in its box, because the box's middle is the point
     the script steers the shot by — move the text off it and the words and
     the screen stop agreeing. What was wrong was the box: 60vh under a frame
     that took 500px left the paragraph on the bottom lip of the screen. */
  .pscroll__step {
    min-height: 46vh;
    min-height: 46dvh;
    padding-block: 20px;
    max-width: none;
  }
}

/* Etihad's own ground
   The square grid gives way to the Facets of Abu Dhabi: the triangulated mesh
   the airline builds its backdrops from. Rebuilt here as a seamless tile on
   their construction principle — scattered points, matching edge points,
   nothing running along the seam — sized to six layout cells so it still
   answers to the same grid underneath.
   ------------------------------------------------------------------------- */
.cs-page--facets::before {
  background-image: url("../assets/images/work/etihad-facets-soft-2.svg");
  background-size: 384px 384px;
}

/* A full-column figure inside a section that is otherwise centred text. */
.cs__media--wide {
  margin-top: clamp(34px, 5vw, 64px);
  max-width: none;
  text-align: left;
}

/* Folded flow: each screen under the step it belongs to --------------------- */
.flow--inline { display: block; }

.flow--inline .flow__stage { display: none; }

.flow--inline .flow__steps {
  padding-block: 0;
  gap: clamp(46px, 10vw, 80px);
}

.flow--inline .step,
.flow--inline .step:not(.is-active) {
  opacity: 1;
  animation: none;
  translate: none;
}

/* A priority guide is a drawing of a screen, so it keeps a screen's
   proportion. Left to fill the column it reaches 900px of 13px type, and
   every row becomes a label, a void, and a red flag far to the right. The cap
   is the width the guide has beside the steps, so the artefact is the same
   size whichever way the page is folded. */
.flow--inline .stage {
  display: block;
  max-height: none;
  overflow: visible;
  margin-top: 22px;
  max-width: var(--pg-w, 488px);
}

.flow--inline .pg-cap { display: none; }

/* Every step is current when they sit one under the other. */
.flow--inline .step:not(.is-active) .step__n {
  background: var(--ink);
  color: var(--paper);
  box-shadow: none;
}


/* ==========================================================================
   Involvement across the phases
   ==========================================================================
   Two curves over one timeline, and a row of phases you can pick. Every bend
   in a curve has to mean something, so each phase carries the sentence that
   explains its own bend rather than leaving the reader to guess. Radios, not
   script: the page already refuses to hide anything behind JavaScript.
   ------------------------------------------------------------------------- */
.wave { margin-top: clamp(28px, 4vw, 44px); }

.wave > input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.wave__body {
  padding: clamp(20px, 3vw, 32px);
  border-radius: 18px;
  background: var(--paper-raised);
  box-shadow: inset 0 0 0 1px var(--line-soft);
}

/* The drawing needs 720px before its labels are legible, so on a phone it
   scrolls. Only it: the key and the panel underneath read fine at any
   width, and dragging them off-screen to look at a curve is no good. */
.wave__scroll {
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

/* The drawing is the control. Labels sit over each phase at the fractions
   of the viewBox that phase occupies, so they stay on it at any width. */
.wave__chart {
  position: relative;
  min-width: 720px;
}

.wave svg {
  display: block;
  width: 100%;
  height: auto;
}

.wave__hit {
  position: absolute;
  top: 24.8%;
  height: 71.7%;
  border-radius: 6px;
  cursor: pointer;
  transition: background 160ms var(--ease);
}

.wave__hit:hover { background: rgba(21, 24, 46, 0.05); }

/* Two settings in one drawing: on my own, and in a multidisciplinary team.
   Same radio-and-sibling trick as the phases, on its own group. */
/* The setting and whose line to look at are both ways of narrowing the same
   drawing, so they sit in one row above it rather than one above and one
   below. Wraps to two rows on a phone. */
.wave__controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 22px;
  margin-bottom: 18px;
}

.wave__modes {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  border-radius: 999px;
  background: rgba(21, 24, 46, 0.05);
}

.wave__mode {
  padding: 7px 16px;
  border-radius: 999px;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--ink-faint);
  cursor: pointer;
  transition: background 180ms var(--ease), color 180ms var(--ease);
}

.wave__mode:hover { color: var(--ink); }

#wm0:checked ~ .wave__body .wave__mode[for="wm0"],
#wm1:checked ~ .wave__body .wave__mode[for="wm1"] {
  background: var(--paper-raised);
  color: var(--ink);
  box-shadow: 0 1px 2px rgba(21, 24, 46, 0.12);
}

#wm0:focus-visible ~ .wave__body .wave__mode[for="wm0"],
#wm1:focus-visible ~ .wave__body .wave__mode[for="wm1"] {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* Only one set of curves at a time. Without CSS both render, which is
   wrong but readable, and nothing is hidden before script runs because
   there is no script. */
#wm0:checked ~ .wave__body .set--team,
#wm1:checked ~ .wave__body .set--solo { display: none; }

#wm0:checked ~ .wave__body .mode--team,
#wm1:checked ~ .wave__body .mode--solo { display: none; }



/* The key is real markup under the drawing, not labels laid over SVG text.
   Inside the SVG it could only be clicked through an invisible overlay, and
   the overlay never quite lined up with the glyphs. */
/* Body links in a case: the same underline the meta line uses. */
.cs__b a {
  text-decoration: underline;
  text-decoration-color: var(--line);
  text-underline-offset: 3px;
  transition: text-decoration-color 150ms var(--ease);
}

.cs__b a:hover { text-decoration-color: currentColor; }

.wave__key {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  position: relative;
}

.chip__wrap {
  position: relative;
  display: inline-flex;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 13px 6px 10px;
  border-radius: 999px;
  box-shadow: inset 0 0 0 1px var(--line);
  font-size: 13.5px;
  font-weight: 700;
  color: var(--ink-soft);
  cursor: pointer;
  transition: box-shadow 160ms var(--ease), color 160ms var(--ease), background 160ms var(--ease);
}

.chip:hover { color: var(--ink); box-shadow: inset 0 0 0 1px rgba(21, 24, 46, 0.28); }

.chip__dot {
  width: 13px;
  height: 13px;
  border-radius: 50%;
  flex: none;
}

.chip--me  .chip__dot { background: rgba(120, 240, 160, 0.32); box-shadow: inset 0 0 0 2px rgb(34, 146, 92); }
.chip--ai  .chip__dot { background: rgba(255, 170, 60, 0.38); box-shadow: inset 0 0 0 2px rgba(196, 106, 18, 0.6); }
.chip--dev .chip__dot { background: rgba(140, 115, 230, 0.24); box-shadow: inset 0 0 0 2px rgba(96, 70, 190, 0.8); }

#wp1:checked ~ .wave__body .chip--me,
#wp2:checked ~ .wave__body .chip--ai,
#wm1:checked ~ #wp3:checked ~ .wave__body .chip--dev { color: var(--ink); }

#wp1:checked ~ .wave__body .chip--me {
  background: rgba(120, 240, 160, 0.18);
  box-shadow: inset 0 0 0 1.5px rgb(34, 146, 92);
}

#wp2:checked ~ .wave__body .chip--ai {
  background: rgba(255, 170, 60, 0.16);
  box-shadow: inset 0 0 0 1.5px rgba(196, 106, 18, 0.75);
}

#wm1:checked ~ #wp3:checked ~ .wave__body .chip--dev {
  background: rgba(140, 115, 230, 0.14);
  box-shadow: inset 0 0 0 1.5px rgba(96, 70, 190, 0.8);
}

#wp1:focus-visible ~ .wave__body .chip--me,
#wp2:focus-visible ~ .wave__body .chip--ai,
#wp3:focus-visible ~ .wave__body .chip--dev {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

#wm0:checked ~ .wave__body .chip__wrap--dev { display: none; }

/* Clicking the one that is already on takes it off again. */
.chip__off {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  cursor: pointer;
  pointer-events: none;
}

#wp1:checked ~ .wave__body .chip__wrap--me .chip__off,
#wp2:checked ~ .wave__body .chip__wrap--ai .chip__off,
#wm1:checked ~ #wp3:checked ~ .wave__body .chip__wrap--dev .chip__off { pointer-events: auto; }

.wave__note {
  margin: 0 0 0 auto;
  text-align: right;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-faint);
}

/* Once the chips wrap, the note lands on a line of its own, and pinned to
   the right it reads as orphaned. */
@media (max-width: 720px) {
  .wave__note { margin-left: 0; text-align: left; }
}

/* Veil, not hide: the same move as picking a phase. The others stay on the
   drawing so the picked one still has something to be compared against. */
.set path { transition: opacity 200ms var(--ease); }

#wp1:checked ~ .wave__body .ai-f, #wp1:checked ~ .wave__body .ai,
#wp1:checked ~ .wave__body .dv-f, #wp1:checked ~ .wave__body .dv,
#wp2:checked ~ .wave__body .me-f, #wp2:checked ~ .wave__body .me,
#wp2:checked ~ .wave__body .dv-f, #wp2:checked ~ .wave__body .dv,
#wm1:checked ~ #wp3:checked ~ .wave__body .me-f,
#wm1:checked ~ #wp3:checked ~ .wave__body .me,
#wm1:checked ~ #wp3:checked ~ .wave__body .ai-f,
#wm1:checked ~ #wp3:checked ~ .wave__body .ai { opacity: 0.22; }

/* A party reads the whole line at once, so no phase is singled out. */
#wp1:checked ~ .wave__body .wave__band,
#wp2:checked ~ .wave__body .wave__band,
#wm1:checked ~ #wp3:checked ~ .wave__body .wave__band,
#wp1:checked ~ .wave__body .wave__notch,
#wp2:checked ~ .wave__body .wave__notch,
#wm1:checked ~ #wp3:checked ~ .wave__body .wave__notch { opacity: 0; }

/* With a role on, no phase is the current one, so none of them may offer to
   be clicked off. Without that the last phase you had open still carries its
   click-off label and hovers as a deselect while every other phase hovers as
   a select. */
#wp1:checked ~ .wave__body .wave__off,
#wp2:checked ~ .wave__body .wave__off,
#wm1:checked ~ #wp3:checked ~ .wave__body .wave__off { pointer-events: none; }

/* Picking a phase beats having a role picked, so without the script the
   click still lands somewhere sensible: that phase, with that one line. */
#wv1:checked ~ .wave__body .wave__p,
#wv2:checked ~ .wave__body .wave__p,
#wv3:checked ~ .wave__body .wave__p,
#wv4:checked ~ .wave__body .wave__p,
#wv5:checked ~ .wave__body .wave__p { display: none; }

#wv1:checked ~ .wave__body .wave__phases,
#wv2:checked ~ .wave__body .wave__phases,
#wv3:checked ~ .wave__body .wave__phases,
#wv4:checked ~ .wave__body .wave__phases,
#wv5:checked ~ .wave__body .wave__phases { display: block; }

#wv1:checked ~ .wave__body .wave__notch,
#wv2:checked ~ .wave__body .wave__notch,
#wv3:checked ~ .wave__body .wave__notch,
#wv4:checked ~ .wave__body .wave__notch,
#wv5:checked ~ .wave__body .wave__notch { opacity: 1; }

/* The party panel replaces the phase panels while one is picked. */
.wave__p { display: none; }

#wp1:checked ~ .wave__body .wave__phases,
#wp2:checked ~ .wave__body .wave__phases,
#wm1:checked ~ #wp3:checked ~ .wave__body .wave__phases { display: none; }

#wm0:checked ~ #wp1:checked ~ .wave__body .wave__p--me.mode--solo,
#wm1:checked ~ #wp1:checked ~ .wave__body .wave__p--me.mode--team,
#wm0:checked ~ #wp2:checked ~ .wave__body .wave__p--ai.mode--solo,
#wm1:checked ~ #wp2:checked ~ .wave__body .wave__p--ai.mode--team,
#wm1:checked ~ #wp3:checked ~ .wave__body .wave__p--dev { display: block; }

/* Stacked on top of the hit area: clicking the phase that is already
   selected drops the focus and brings the overview back. Only the
   selected phase's overlay takes a click, so the others stay switchable. */
.wave__off {
  position: absolute;
  top: 24.8%;
  height: 71.7%;
  border-radius: 6px;
  cursor: pointer;
  pointer-events: none;
}

#wv1:checked ~ .wave__body .wave__off--1,
#wv2:checked ~ .wave__body .wave__off--2,
#wv3:checked ~ .wave__body .wave__off--3,
#wv4:checked ~ .wave__body .wave__off--4,
#wv5:checked ~ .wave__body .wave__off--5 { pointer-events: auto; }

/* The notch ties the phase above to the words below. */
.wave__exp {
  position: relative;
  margin-top: 14px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}

.wave__notch {
  position: absolute;
  top: -7px;
  left: 4.2778%;
  width: 13px;
  height: 13px;
  margin-left: -7px;
  border-top: 1px solid var(--line);
  border-left: 1px solid var(--line);
  background: var(--paper-raised);
  rotate: 45deg;
  transition: left 240ms var(--ease), opacity 180ms var(--ease);
}

.wave__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 10px;
}

/* A picked phase has no paragraph of its own any more, only the button to go
   back, so it takes a right-aligned row above the table's headers. */

.wave__clear {
  flex: none;
  padding: 5px 12px;
  border-radius: 999px;
  box-shadow: inset 0 0 0 1px var(--line);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--ink-faint);
  cursor: pointer;
  transition: color 160ms var(--ease), box-shadow 160ms var(--ease);
}

.wave__clear:hover {
  color: var(--ink);
  box-shadow: inset 0 0 0 1px rgba(21, 24, 46, 0.3);
}

.wave__ph {
  margin: 0;
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
}

.wave text { font-family: "Figtree", sans-serif; }

/* A spotlight rather than a tint. Every phase carries a veil, the selected
   one lifts it, and a light wash is far easier to see than a light fill. */
.wave__band {
  fill: var(--paper-raised);
  opacity: 0.6;
  transition: opacity 200ms var(--ease);
  pointer-events: none;
}

.wave__e { display: none; }

.wave__e p {
  margin: 18px 0 0;
  max-width: 70ch;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--ink-soft);
}

.wave__e b { color: var(--ink); font-weight: 600; }

/* What the phase leaves behind, for the two who get it. */
.wave__out {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px clamp(20px, 3vw, 40px);
  margin: 18px 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--line-soft);
}

.wave__out dt {
  margin-bottom: 4px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* The same key as the chart: green is me, amber is Claude Code. */
.wave__out div:nth-child(2) dt { color: rgb(34, 146, 92); }
.wave__out div:last-child dt { color: var(--amber); }

.wave__out dd {
  margin: 0;
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink-soft);
}

/* Nothing chosen: no veil anywhere, and the notch has nowhere to point. */
#wv0:checked ~ .wave__body .wave__band { opacity: 0; }
#wv0:checked ~ .wave__body .wave__notch { opacity: 0; }

#wv1:checked ~ .wave__body .wave__band--1,
#wv2:checked ~ .wave__body .wave__band--2,
#wv3:checked ~ .wave__body .wave__band--3,
#wv4:checked ~ .wave__body .wave__band--4,
#wv5:checked ~ .wave__body .wave__band--5 { opacity: 0; }

#wv1:checked ~ .wave__body .wave__notch { left: 4.2778%; }
#wv2:checked ~ .wave__body .wave__notch { left: 16.9444%; }
#wv3:checked ~ .wave__body .wave__notch { left: 34.3333%; }
#wv4:checked ~ .wave__body .wave__notch { left: 65.4444%; }
#wv5:checked ~ .wave__body .wave__notch { left: 93.7778%; }

#wv0:checked ~ .wave__body .wave__e0,
#wv1:checked ~ .wave__body .wave__e1,
#wv2:checked ~ .wave__body .wave__e2,
#wv3:checked ~ .wave__body .wave__e3,
#wv4:checked ~ .wave__body .wave__e4,
#wv5:checked ~ .wave__body .wave__e5 { display: block; }

#wv1:focus-visible ~ .wave__body .wave__hit[for="wv1"],
#wv2:focus-visible ~ .wave__body .wave__hit[for="wv2"],
#wv3:focus-visible ~ .wave__body .wave__hit[for="wv3"],
#wv4:focus-visible ~ .wave__body .wave__hit[for="wv4"],
#wv5:focus-visible ~ .wave__body .wave__hit[for="wv5"] {
  outline: 2px solid var(--violet);
  outline-offset: -2px;
}

/* The chain, drawn ---------------------------------------------------------
   Four artefacts, each one made out of the one above it. Written as four
   paragraphs this reads as a list of definitions; given a spine it reads as
   a hand-over, which is the whole point of the section. The spine is the
   same green as my line in the chart above, because the chain is the part
   I hold. */
.chain {
  list-style: none;
  margin: clamp(26px, 3vw, 38px) 0 0;
  padding: clamp(24px, 3vw, 36px) clamp(22px, 3vw, 34px);
  /* Square at the foot: the rail underneath is part of the same block, and two
     rounded corners meeting two square ones reads as a seam. */
  border-radius: 18px 18px 0 0;
  background: var(--paper-raised);
  box-shadow: inset 0 0 0 1px var(--line-soft);
}

.chain__step {
  position: relative;
  padding: 0 0 clamp(24px, 2.8vw, 34px) 38px;
}

.chain__step:last-child { padding-bottom: 0; }

/* The node itself. White centre on a green ring, so the line appears to pass
   behind it rather than stopping at it. */
.chain__step::before {
  content: "";
  position: absolute;
  left: 0;
  top: 3px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--paper-raised);
  box-shadow: inset 0 0 0 2.5px var(--green-strong);
}

/* The run between one node and the next. Not drawn under the last one: the
   chain ends at a screen, and a line trailing off below it would promise a
   step that is not there. */
.chain__step:not(:last-child)::after {
  content: "";
  position: absolute;
  left: 7px;
  top: 18px;
  bottom: 4px;
  width: 1.5px;
  background: var(--green-strong);
}

/* The end of the chain is filled in rather than open. */
.chain__step--end::before {
  background: var(--green-strong);
  box-shadow: inset 0 0 0 2.5px var(--green-strong);
}

.chain__from {
  margin: 0;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.chain__name {
  margin: 5px 0 7px;
  font-size: 19px;
}

.chain__line {
  margin: 0;
  max-width: 62ch;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--ink-soft);
}

.chain__line b { color: var(--ink); }


/* Claude Code does not sit in the chain, it runs beside it, so it gets a rail
   under the whole thing instead of a node of its own. */
.chain__rail {
  margin: 0;
  padding: clamp(16px, 1.8vw, 22px) clamp(22px, 3vw, 34px) clamp(18px, 2vw, 24px);
  border-radius: 0 0 18px 18px;
  background: rgba(255, 170, 60, 0.07);
  box-shadow: inset 0 0 0 1px var(--line-soft);
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--ink-soft);
}

.chain__rail-k {
  display: block;
  margin-bottom: 4px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(196, 106, 18, 0.9);
}

/* The two guardrails are the two lines from the chart, so they carry the same
   key. Not decoration: the reader has already learned that green is me and
   amber is Claude Code, a few hundred pixels up. */
.rule--me h3,
.rule--ai h3,
.rule--ds h3 {
  display: flex;
  align-items: center;
  gap: 9px;
}

.rule--me h3::before,
.rule--ai h3::before,
.rule--ds h3::before {
  content: "";
  width: 13px;
  height: 13px;
  border-radius: 50%;
  flex: none;
}

.rule--me h3::before {
  background: rgba(120, 240, 160, 0.32);
  box-shadow: inset 0 0 0 2px rgb(34, 146, 92);
}

/* Not one of the people on the chart, so it carries no party's colour. */
.rule--ds h3::before {
  box-shadow: inset 0 0 0 2px rgba(21, 24, 46, 0.35);
}

.rule--ai h3::before {
  background: rgba(255, 170, 60, 0.38);
  box-shadow: inset 0 0 0 2px rgba(196, 106, 18, 0.6);
}
