/* ==========================================================================
   Patrick Walsh — portfolio
   Single stylesheet for all page types. No build step, no dependencies.
   ========================================================================== */

/* --- Webfonts -----------------------------------------------------------
   Self-hosted, no third-party requests. DM Sans is variable and covers the
   full 100-1000 weight axis in one file, so every weight the site uses
   (300-800) is a real cut rather than a synthesized bold.
   ------------------------------------------------------------------------ */

@font-face {
  font-family: "DM Sans";
  font-style: normal;
  font-weight: 100 1000;
  font-display: swap;
  src: url("/assets/fonts/dm-sans-latin-var.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: "DM Serif Display";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/dm-serif-display-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;
}

/* --- Design tokens ------------------------------------------------------ */

:root {
  /* One sans across the whole site. Fallbacks are metric-ish neighbours so
     the swap shifts text minimally while the webfont loads. */
  --font-sans: "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI",
    Roboto, "Helvetica Neue", Arial, sans-serif;

  /* Display serif, used for case study titles only. */
  --font-display: "DM Serif Display", Georgia, "Times New Roman", serif;

  --color-pitt: #1d3a8a;
  --color-gold: #c4992a;

  --color-ink: #1a1a18;
  --color-body: #4a4a47;
  --color-page: #fff;
  --color-bar: #000;

  --radius-card: 16px;
  --radius-logo: 18px;
  --radius-pill: 99px;

  --shell-max: 1280px;
  --shell-pad: 2.25rem;
}

/* --- Reset -------------------------------------------------------------- */

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

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

body {
  font-family: var(--font-sans);
  color: var(--color-body);
  background: var(--color-page);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

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

a {
  color: inherit;
}

/* Visible focus for keyboard users, suppressed for mouse clicks. */
:focus-visible {
  outline: 3px solid #3b5be8;
  outline-offset: 3px;
  border-radius: 4px;
}

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

/* Hidden until tabbed to, then pinned to the top-left. */
.skip-link:focus {
  position: fixed;
  top: 0.5rem;
  left: 0.5rem;
  z-index: 100;
  width: auto;
  height: auto;
  clip: auto;
  clip-path: none;
  padding: 0.75rem 1.25rem;
  background: #fff;
  color: var(--color-ink);
  font-weight: 600;
  text-decoration: none;
  border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
}

/* --- Layout shell ------------------------------------------------------- */

.shell {
  max-width: var(--shell-max);
  margin-inline: auto;
  padding-inline: var(--shell-pad);
}

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

.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--color-bar);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  min-height: 144px;
}

.wordmark {
  font-size: clamp(2.75rem, 6vw, 4.25rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  color: #fff;
  text-decoration: none;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 4vw, 3rem);
}

.site-nav a {
  font-size: clamp(1.125rem, 2.2vw, 1.6rem);
  font-weight: 500;
  color: #fff;
  text-decoration: none;
  padding-block: 0.25rem;
  border-bottom: 2px solid transparent;
  transition: border-color 0.15s ease;
}

.site-nav a:hover,
.site-nav a[aria-current="page"] {
  border-bottom-color: #fff;
}

/* --- Page heading ------------------------------------------------------- */

.page-head {
  padding-block: clamp(2.5rem, 6vw, 4.5rem) clamp(2rem, 4vw, 3rem);
}

.page-head h1 {
  font-size: clamp(2.5rem, 7vw, 5rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.05;
  color: var(--color-ink);
}

.page-head p {
  margin-top: 1rem;
  max-width: 60ch;
  font-size: 1.0625rem;
}

/* Home page only — project pages keep their headings left-aligned. */
.page-head--center {
  text-align: center;
}

/* max-width alone won't centre the block, only the text inside it. */
.page-head--center p {
  margin-inline: auto;
}

/* --- Project grid ------------------------------------------------------- */

.project-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  align-items: start;
  gap: clamp(2rem, 5vw, 5.5rem) clamp(1.75rem, 4vw, 5.5rem);
  padding-bottom: clamp(3rem, 8vw, 6rem);
  list-style: none;
}

/* --- Project card ------------------------------------------------------- */

/* Each card sets --accent; everything else is shared. */
.card {
  display: block;
  text-decoration: none;
  color: inherit;
  transition: transform 0.2s ease;
}

.card:hover .card__header,
.card:focus-visible .card__header {
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.16);
}

.card:hover {
  transform: translateY(-2px);
}

.card__header {
  background: var(--accent, #1d3a8a);
  border-radius: var(--radius-card);
  padding: 1.75rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1rem;
  transition: box-shadow 0.2s ease;
}

/* Image sits beside the title instead of above it. */
.card__header--split {
  flex-direction: row;
  align-items: center;
  gap: 1.5rem;
}

.card__logo {
  width: 88px;
  height: 88px;
  border-radius: var(--radius-logo);
  object-fit: cover;
  flex-shrink: 0;
  background: #fff;
}

/* Tall device screenshots rather than square app icons. */
.card__shot {
  width: 110px;
  height: auto;
  border-radius: 12px;
  flex-shrink: 0;
}

/* On a black card the screenshot has no edge, so give it one. */
.card--dark .card__shot {
  border: 1px solid rgba(255, 255, 255, 0.2);
}

.card__title {
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.2;
  color: #fff;
  margin-bottom: 0.5rem;
}

.tag-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  list-style: none;
}

/* Chips are light-on-dark by default; cards with a bright accent set
   --tag-bg to the dark variant so the text keeps enough contrast. */
.tag {
  font-size: 0.6875rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.9);
  background: var(--tag-bg, rgba(255, 255, 255, 0.2));
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
}

/* Each card emphasizes its lead tag, but not the same way: some swap the
   chip color, others just go bolder. Cards set whichever token applies. */
.tag--lead {
  background: var(--tag-lead-bg, var(--tag-bg, rgba(255, 255, 255, 0.2)));
  color: var(--tag-lead-ink, rgba(255, 255, 255, 0.9));
  font-weight: var(--tag-lead-weight, 500);
}

.card__body {
  padding: 1.5rem 1.75rem 0;
}

.card__description {
  font-size: 0.9375rem;
  font-weight: 300;
  line-height: 1.75;
  color: var(--color-body);
}

/* --- Responsive --------------------------------------------------------- */

@media (max-width: 960px) {
  :root {
    --shell-pad: 1.5rem;
  }

  .project-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .site-header__inner {
    min-height: 92px;
  }
}

@media (max-width: 620px) {
  .project-grid {
    grid-template-columns: 1fr;
    gap: 2.5rem;
  }

  .card__body {
    padding-inline: 1.25rem;
  }

  .card__header {
    padding: 1.25rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

/* ==========================================================================
   Case study pages
   --------------------------------------------------------------------------
   Body type is inherited from the site default (DM Sans). These pages add
   DM Serif Display for the title only.

   Accent colours come from tokens so a second case study only needs to
   override --cs-accent and --cs-rule on .case-study.
   ========================================================================== */

/* Per-study theming contract. A study sets four tokens; every rule below
   reads them, so nothing downstream hardcodes a hue.

     --cs-accent        dark panel fill -- white body text sits on it
     --cs-rule          decoration only (bullets, dots) -- never text
     --cs-ink-on-light  accent-tinted text on the white page
     --cs-ink-on-dark   accent-tinted text on the --cs-accent panel

   A project's brand colour is usually the --cs-rule, not the --cs-accent:
   both source hues below fail WCAG AA as text, so the readable variants are
   derived separately rather than reused. */
.case-study {
  --cs-accent: var(--color-pitt);

  /* The source gold (#c4992a) fails WCAG AA as text: 2.65:1 on white and
     3.90:1 on the blue panel. Kept for decoration only (rules, bullets),
     with darker/lighter variants carrying the same hue where it is text. */
  --cs-rule: var(--color-gold);
  --cs-ink-on-light: #8a6a15; /* 5.09:1 on white */
  --cs-ink-on-dark: #d9ad3a; /* 4.85:1 on --color-pitt */

  color: #1a1a1a;
}

/* Animal Network. The card green (#22c55e) is 2.28:1 on white, so it gets
   the same decoration-only treatment as the Pitt gold. */
.case-study--animal-network {
  --cs-accent: #14532d; /* white text 9.11:1 */
  --cs-rule: #22c55e;
  --cs-ink-on-light: #15803d; /* 5.02:1 on white */
  --cs-ink-on-dark: #4ade80; /* 5.23:1 on --cs-accent */
}

/* Crowd Meter. Same story a third time: the card teal (#1a9e8c) is 3.33:1 on
   white, so it stays decoration and the readable teals are derived. */
.case-study--crowd-meter {
  --cs-accent: #0f5449; /* white text 8.81:1 */
  --cs-rule: #1a9e8c;
  --cs-ink-on-light: #0f6e56; /* 6.20:1 on white */
  --cs-ink-on-dark: #6ed3b0; /* 4.87:1 on --cs-accent */
}

/* ChatGPT. The card mint (#2ee8c8) is 1.56:1 on white -- the weakest source
   hue in the project, so the same caution as Bike Shop applies: no
   .cs-findings on this study, its bullet would vanish. Use .cs-ledger.
   The mint is fine as text on the dark panel, where it does the work.

   The accent is pushed deliberately darker than Crowd Meter's #0f5449 so the
   two teal studies do not read as the same page. */
.case-study--chatgpt {
  --cs-accent: #07332e; /* white text 13.80:1 */
  --cs-rule: #2ee8c8;
  --cs-ink-on-light: #0f7a63; /* 5.27:1 on white */
  --cs-ink-on-dark: #2ee8c8; /* 8.87:1 on --cs-accent */
}

/* Nintendo Switch. The first source hue that passes AA as text on white, so
   --cs-ink-on-light is the brand red itself rather than a derived variant --
   and --cs-rule doubles it, which means this study can use .cs-findings where
   Bike Shop could not. */
.case-study--nintendo-switch {
  --cs-accent: #7a1f18; /* white text 10.31:1 */
  --cs-rule: #c0362c; /* 5.52:1 on white -- readable, unlike the others */
  --cs-ink-on-light: #c0362c; /* 5.52:1 on white */
  --cs-ink-on-dark: #f2a196; /* 5.06:1 on --cs-accent */
}

/* Bike Shop. The brand is black and yellow, which inverts the usual problem:
   the accent is the black, and the yellow is the only source hue so far that
   is genuinely readable as text -- but only on the dark panel, never on white.

   CAUTION: at 1.53:1 the yellow is too weak to read even as decoration on
   white, so this study must not use .cs-findings -- its bullet is a 5px
   --cs-rule dot that would effectively vanish. Use .cs-ledger instead: its
   marks are glyphs inked with --cs-ink-on-light. */
.case-study--bike-shop {
  --cs-accent: #1a1a1a; /* white text 17.40:1 */
  --cs-rule: #facc15;
  --cs-ink-on-light: #7a5c0a; /* 6.24:1 on white */
  --cs-ink-on-dark: #facc15; /* 11.36:1 on --cs-accent */
}

/* Scoped to main, not every .shell on the page. The site header's inner
   container is also a .shell, so an unscoped rule narrowed the wordmark and
   nav to the 820px reading column and the top bar visibly shrank relative to
   the home page. Only the reading column should be narrow; the header keeps
   --shell-max so it sits in the same place site-wide. */
.case-study main .shell {
  max-width: 820px;
}

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

.cs-head {
  padding-block: clamp(2rem, 5vw, 3rem) 0;
}

/* The Wix embed had no way back to the project list; this adds one. */
.cs-breadcrumb {
  margin-bottom: 1.25rem;
  font-size: 0.8125rem;
}

.cs-breadcrumb a {
  color: #555;
  text-decoration: none;
}

.cs-breadcrumb a::before {
  content: "\2190";
  margin-right: 0.4rem;
}

.cs-breadcrumb a:hover {
  color: var(--cs-accent);
  text-decoration: underline;
}

.cs-eyebrow {
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--cs-ink-on-light);
  margin-bottom: 0.5rem;
}

.cs-title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.8rem, 5vw, 2.4rem);
  line-height: 1.15;
  color: #111;
  margin-bottom: 0.75rem;
}

/* --- Summary ------------------------------------------------------------ */

.cs-summary {
  background: var(--cs-accent);
  border-radius: 14px;
  padding: clamp(1.25rem, 4vw, 1.75rem) clamp(1.25rem, 4vw, 2rem);
  margin-block: 1.5rem 3rem;
  color: #fff;
}

.cs-summary h2 {
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 400;
  margin-bottom: 0.75rem;
  color: var(--cs-ink-on-dark);
}

.cs-summary p {
  font-size: 0.9375rem;
  line-height: 1.8;
  color: rgba(255, 255, 255, 0.88);
}

.cs-taglist {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 1.25rem;
  list-style: none;
}

.cs-taglist li {
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 4px 12px;
  border-radius: 20px;
  /* Derived from the token rather than a literal rgba(), so the chips
     re-tint with the study instead of staying gold. */
  background: color-mix(in srgb, var(--cs-ink-on-dark) 18%, transparent);
  color: var(--cs-ink-on-dark);
  border: 1px solid color-mix(in srgb, var(--cs-ink-on-dark) 45%, transparent);
}

/* --- Sections ----------------------------------------------------------- */

.cs-section {
  margin-bottom: 3rem;
}

.cs-section > h2 {
  font-size: 0.65625rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #767676;
  margin-bottom: 1.1rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid #e8e8e8;
}

/* Running prose. The first case study was built entirely from lists and
   cards, so nothing here styled a bare paragraph -- and the reset zeroes
   margins, so consecutive paragraphs would otherwise close up solid. */
.cs-section > p {
  font-size: 0.9375rem;
  line-height: 1.8;
  max-width: 68ch;
  color: #333;
}

.cs-section > p + p {
  margin-top: 0.9rem;
}

/* Sub-heading for an iteration round: a step below the uppercase section
   label, clearly above body copy. */
.cs-section > h3 {
  font-size: 1.0625rem;
  font-weight: 600;
  color: #111;
  margin-top: 2.25rem;
  margin-bottom: 0.5rem;
}

/* A paragraph introducing a round sits tight under its heading. */
.cs-section > h3 + p {
  margin-top: 0;
}

/* h4 as well as h3: where a column sits under its own <h3> round heading,
   the column head has to drop a level to keep the outline in order. */
.cs-columns h3,
.cs-columns h4 {
  font-size: 0.8125rem;
  font-weight: 600;
  color: #111;
  margin-bottom: 0.55rem;
}

/* --- Card grids --------------------------------------------------------- */

/* min(Npx, 100%) rather than a bare Npx floor: a bare minimum is a hard
   width, so on a viewport narrower than the floor the track stops shrinking
   and pushes the page sideways. Wrapping it in min() caps the floor at the
   container, which changes nothing at normal widths and makes narrow ones
   impossible to break. Applied to every auto-fit grid below. */
.cs-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr));
  gap: 14px;
  list-style: none;
}

.cs-grid--tight {
  grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
  gap: 12px;
}

.cs-card {
  background: #f8f8f6;
  border-radius: 12px;
  border: 1px solid #ebebeb;
  padding: 1.15rem 1.3rem;
}

.cs-card h3,
.cs-card h4 {
  font-size: 0.875rem;
  font-weight: 500;
  margin-bottom: 6px;
  color: #111;
}

.cs-card p {
  font-size: 0.8125rem;
  line-height: 1.65;
  color: #555;
}

/* A sub-heading part-way down a card needs air above it; the first child
   never does. */
.cs-card > * + h4 {
  margin-top: 0.9rem;
}

.cs-card__icon {
  width: 34px;
  height: 34px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 10px;
  background: var(--icon-bg, #e6f1fb);
}

.cs-card__why {
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--cs-ink-on-light);
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid #e8e8e8;
}

/* --- Stat tiles ----------------------------------------------------------
   A research-led study has no device shots to lead with, so the headline
   numbers do that job: this is the hero row where an app study puts screens.
   ------------------------------------------------------------------------ */

.cs-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(158px, 100%), 1fr));
  gap: 14px;
  margin-block: 1.5rem;
  list-style: none;
}

.cs-stat {
  background: #f8f8f6;
  border: 1px solid #ebebeb;
  border-radius: 12px;
  padding: 1.15rem 1.3rem;
}

/* The figure carries the study hue; the label underneath stays neutral so
   the number is what the eye lands on. */
.cs-stat b {
  display: block;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.55rem, 4vw, 1.95rem);
  line-height: 1.1;
  color: var(--cs-ink-on-light);
  margin-bottom: 6px;
}

.cs-stat span {
  display: block;
  font-size: 0.8125rem;
  line-height: 1.55;
  color: #555;
}

/* Price heading a revenue tier, sitting above the usual .cs-card h3. */
.cs-price {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.5rem;
  line-height: 1.1;
  color: var(--cs-ink-on-light);
  margin-bottom: 4px;
}

.cs-price span {
  font-family: var(--font-sans);
  font-size: 0.8125rem;
  color: #767676;
}

/* --- Full-width card stack -----------------------------------------------
   .cs-grid packs cards into columns, which is wrong when each card holds its
   own two-column body -- three platform teardowns side by side leave the
   pros and cons about 100px wide. This stacks them instead.
   ------------------------------------------------------------------------ */

.cs-stack {
  display: grid;
  gap: 14px;
  margin-block: 1.5rem;
  list-style: none;
}

/* --- Comparison table ----------------------------------------------------
   The first real table on the site. It scrolls inside its own box rather
   than reflowing: dropping columns from a four-way comparison destroys the
   comparison, and the page itself must never scroll sideways.
   ------------------------------------------------------------------------ */

.cs-table-wrap {
  overflow-x: auto;
  border: 1px solid #ebebeb;
  border-radius: 12px;
  margin-block: 1.5rem;
}

.cs-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.84375rem;
  /* Below this the columns are too narrow to read; scroll instead. */
  min-width: 540px;
}

/* Column headers only. The row headers in <tbody> are labels, not chrome,
   and are styled with the body cells below. */
.cs-table thead th {
  text-align: left;
  padding: 10px 14px;
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #767676;
  background: #f8f8f6;
  border-bottom: 1px solid #ebebeb;
  white-space: nowrap;
}

.cs-table thead th:first-child {
  width: 30%;
}

.cs-table td,
.cs-table tbody th {
  padding: 11px 14px;
  border-bottom: 1px solid #f0f0f0;
  color: #555;
  vertical-align: top;
  line-height: 1.5;
  text-align: left;
  font-weight: 400;
}

.cs-table tr:last-child td,
.cs-table tr:last-child th {
  border-bottom: none;
}

.cs-table tbody th b {
  display: block;
  font-weight: 500;
  color: #111;
}

.cs-table tbody th small {
  font-size: 0.75rem;
  color: #767676;
}

/* Verdicts carry a glyph as well as a colour. Colour alone would be the only
   thing distinguishing a win from a loss otherwise -- the same reasoning as
   the ledger marks above. */
.cs-verdict::before {
  content: var(--mark);
  color: var(--mark-ink);
  font-weight: 700;
  margin-right: 6px;
}

.cs-verdict--win {
  --mark: "\2713";
  --mark-ink: #3b6d11; /* 6.21:1 on white */
}

.cs-verdict--mid {
  --mark: "\2022";
  --mark-ink: #767676; /* 4.54:1 on white */
}

.cs-verdict--low {
  --mark: "\2715";
  --mark-ink: #993c1d; /* 6.96:1 on white */
}

/* --- Persona -------------------------------------------------------------
   No photography exists for these and none should be invented: a stock face
   would imply a research participant who was never photographed. The card
   leads with the name, role and their own words instead.
   ------------------------------------------------------------------------ */

.cs-persona {
  background: #f8f8f6;
  border: 1px solid #ebebeb;
  border-radius: 12px;
  padding: 1.25rem 1.4rem;
}

.cs-persona__name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.35rem;
  line-height: 1.15;
  color: #111;
}

.cs-persona__role {
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--cs-ink-on-light);
  margin-bottom: 0.9rem;
}

.cs-persona dl {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 7px 14px;
  font-size: 0.8125rem;
}

.cs-persona dt {
  font-weight: 500;
  color: #111;
}

.cs-persona dd {
  color: #555;
  line-height: 1.55;
}

.cs-persona blockquote {
  margin-top: 1rem;
  padding-top: 0.9rem;
  border-top: 1px solid #e4e4e0;
}

.cs-persona blockquote p {
  font-size: 0.875rem;
  font-style: italic;
  line-height: 1.65;
  color: #444;
}

/* --- Scenario stages -----------------------------------------------------
   The deck laid each scenario out as a labelled row of stages. Kept as a
   grid rather than folded into .cs-timeline so each question heading stays
   attached to its own answer.
   ------------------------------------------------------------------------ */

.cs-stages {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
  gap: 14px;
  margin-block: 1.25rem;
  list-style: none;
  counter-reset: stage;
}

.cs-stages > li {
  background: #fff;
  border: 1px solid #ebebeb;
  border-radius: 12px;
  padding: 1rem 1.15rem;
  counter-increment: stage;
}

.cs-stages > li::before {
  content: counter(stage);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  margin-bottom: 0.7rem;
  font-size: 0.6875rem;
  font-weight: 600;
  background: color-mix(in srgb, var(--cs-rule) 16%, #fff);
  color: var(--cs-ink-on-light);
}

.cs-stages h4 {
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--cs-ink-on-light);
  margin-bottom: 0.4rem;
}

.cs-stages p {
  font-size: 0.8125rem;
  line-height: 1.6;
  color: #555;
}

/* --- Timeline ----------------------------------------------------------- */

.cs-timeline {
  position: relative;
  padding-left: 1.6rem;
  list-style: none;
}

.cs-timeline::before {
  content: "";
  position: absolute;
  left: 5px;
  top: 6px;
  bottom: 6px;
  width: 1px;
  background: #ddd;
}

.cs-timeline > li {
  position: relative;
  margin-bottom: 1.5rem;
}

.cs-timeline > li::before {
  content: "";
  position: absolute;
  left: -1.6rem;
  top: 5px;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--cs-accent);
  border: 2px solid #fff;
  box-shadow: 0 0 0 1px var(--cs-accent);
}

.cs-timeline h3 {
  font-size: 0.875rem;
  font-weight: 500;
  color: #111;
  margin-bottom: 4px;
}

.cs-timeline p {
  font-size: 0.8125rem;
  line-height: 1.65;
  color: #555;
}

.cs-chip {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 500;
  padding: 3px 10px;
  border-radius: 20px;
  margin: 3px 3px 3px 0;
  background: #e6f1fb;
  color: #185fa5;
}

/* The base chip is a fixed blue the Pitt study depends on. This variant
   re-tints with the study like the rest of the case study rules. */
.cs-chip--themed {
  background: color-mix(in srgb, var(--cs-rule) 14%, #fff);
  color: var(--cs-ink-on-light);
}

/* --- Findings ----------------------------------------------------------- */

.cs-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin-bottom: 1rem;
}

.cs-findings {
  list-style: none;
}

.cs-findings li {
  font-size: 0.84375rem;
  line-height: 1.7;
  color: #555;
  padding: 8px 0 8px 1.1rem;
  border-bottom: 1px solid #f0f0f0;
  position: relative;
}

.cs-findings li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 16px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--cs-rule);
}

.cs-findings li:last-child {
  border-bottom: none;
}

/* Lead-in for a finding that states its conclusion before explaining it. */
.cs-findings b {
  font-weight: 600;
  color: #111;
}

.cs-quote {
  background: #f8f8f6;
  border-left: 3px solid var(--cs-accent);
  border-radius: 0 10px 10px 0;
  padding: 1rem 1.25rem;
  /* Block, not just top: a quote can now be followed by more prose. */
  margin-block: 1rem;
}

.cs-quote p {
  font-size: 0.875rem;
  font-style: italic;
  line-height: 1.7;
  color: #444;
}

.cs-quote cite {
  font-size: 0.75rem;
  font-style: normal;
  color: #767676;
  display: block;
  margin-top: 6px;
}

/* --- Recommendations ---------------------------------------------------- */

.cs-recs > li + li {
  margin-top: 1.4rem;
  padding-top: 1.4rem;
  border-top: 1px solid #ebebeb;
}

.cs-recs {
  list-style: none;
}

.cs-badge {
  display: inline-block;
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 4px 14px;
  border-radius: 20px;
  margin-bottom: 0.85rem;
  background: var(--badge-bg);
  color: var(--badge-ink);
  border: 1px solid var(--badge-edge);
}

.cs-badge--high {
  --badge-bg: #fcebeb;
  --badge-ink: #a32d2d;
  --badge-edge: #f09595;
}

.cs-badge--med {
  --badge-bg: #faeeda;
  --badge-ink: #854f0b;
  --badge-edge: #fac775;
}

.cs-badge--low {
  --badge-bg: #eaf3de;
  --badge-ink: #3b6d11;
  --badge-edge: #c0dd97;
}

/* Heuristic ratings. Same palette as the priority badges but named for what
   they mean, so a rating is never mistaken for a priority in the markup.
   The word carries the meaning; the colour only reinforces it. */
.cs-badge--strong {
  --badge-bg: #eaf3de;
  --badge-ink: #3b6d11; /* 5.43:1 on its own background */
  --badge-edge: #c0dd97;
}

.cs-badge--adequate {
  --badge-bg: #faeeda;
  --badge-ink: #854f0b; /* 5.87:1 on its own background */
  --badge-edge: #fac775;
}

/* --- Report link -------------------------------------------------------- */

.cs-cta {
  text-align: center;
  padding-block: 1rem 2rem;
}

.cs-cta a {
  display: inline-block;
  background: var(--cs-accent);
  color: #fff;
  font-size: 0.875rem;
  font-weight: 500;
  padding: 14px 32px;
  border-radius: 8px;
  text-decoration: none;
  letter-spacing: 0.02em;
}

/* Derived, not literal. This was #162f70 -- a hardcoded dark Pitt blue that
   would have hovered blue on every other study. Mixing the accent toward
   black lands within a shade of that value for Pitt, so its button is
   unchanged, and every other study now darkens its own hue. */
.cs-cta a:hover {
  background: color-mix(in srgb, var(--cs-accent) 82%, #000);
}

.cs-cta small {
  display: block;
  margin-top: 0.6rem;
  font-size: 0.75rem;
  color: #767676;
}

@media (max-width: 540px) {
  .cs-columns {
    grid-template-columns: 1fr;
  }
}

/* --- Case study figures --------------------------------------------------
   Scoped to .cs-figure rather than bare <figure>, because .cs-quote is
   already a figure and must not pick these up.
   ------------------------------------------------------------------------ */

.cs-figure {
  margin-block: 1.5rem;
}

.cs-figure img {
  width: 100%;
  height: auto;
  border-radius: 12px;
  border: 1px solid #ebebeb;
  background: #f8f8f6;
}

/* Screenshots of light UIs blend into the page; a defined edge stops the
   image dissolving into the background. Set .cs-figure--flush to drop it
   for artwork that already has its own edge. */
.cs-figure--flush img {
  border: 0;
  background: none;
}

.cs-figure figcaption {
  margin-top: 0.6rem;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: #555;
}

.cs-figure figcaption b {
  font-weight: 500;
  color: #111;
}

/* Breaks out past the 820px reading column for hero shots and wide
   artifacts like empathy maps, without exceeding the viewport. */
.cs-figure--wide {
  width: min(1120px, calc(100vw - 2 * var(--shell-pad)));
  position: relative;
  left: 50%;
  transform: translateX(-50%);
}

/* Two images side by side — before/after, or a pair of screens. */
.cs-figure-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin-block: 1.5rem;
  list-style: none;
}

.cs-figure-row .cs-figure {
  margin-block: 0;
}

@media (max-width: 540px) {
  .cs-figure-row {
    grid-template-columns: 1fr;
  }
}

/* Dense diagrams stay unreadable inline no matter how sharp the export,
   so they open at full size. The image alt supplies the link text. */
.cs-figure--zoom a {
  display: block;
  border-radius: 12px;
  cursor: zoom-in;
}

.cs-figure--zoom a:hover img {
  border-color: #c8c8c8;
}

.cs-figure__hint {
  color: #767676;
}

/* Kept / discarded columns in a competitive teardown. The mark is a token so
   the two lists differ by glyph as well as colour, rather than colour alone. */
.cs-ledger {
  list-style: none;
  margin-top: 0.5rem;
}

.cs-ledger li {
  position: relative;
  padding-left: 1.4rem;
  font-size: 0.875rem;
  line-height: 1.6;
  margin-bottom: 0.35rem;
}

.cs-ledger li::before {
  content: var(--mark);
  position: absolute;
  left: 0;
  font-weight: 700;
  color: var(--mark-ink);
}

.cs-ledger--took {
  --mark: "\2713";
  --mark-ink: var(--cs-ink-on-light);
}

.cs-ledger--left {
  --mark: "\2715";
  --mark-ink: #a13b32; /* 5.42:1 on white */
}

/* --- Screen galleries ----------------------------------------------------
   Phone screens are tall, narrow, and come in rounds of seven to ten. A
   fixed column count either dwarfs them or runs the page on forever, so
   they pack by available width and reflow on their own.
   ------------------------------------------------------------------------ */

.cs-screens {
  display: grid;
  /* auto-fit, not auto-fill: a three-screen hero row should stretch to fill
     the column, while a ten-screen round still packs at thumbnail size. */
  grid-template-columns: repeat(auto-fit, minmax(min(148px, 100%), 1fr));
  gap: 1.5rem 14px;
  margin-block: 1.5rem;
  list-style: none;
}

.cs-screens .cs-figure {
  margin-block: 0;
}

.cs-screens figcaption {
  margin-top: 0.5rem;
  text-align: center;
}

/* Prototype screens are exported inside a rendered device frame, which is
   already an edge. Bare wireframes are not, and keep the default border. */
.cs-screens--device img {
  border: 0;
  border-radius: 0;
  background: none;
}

/* ==========================================================================
   Resume

   The third page type. It shares the header and shell with everything else
   but none of the case study vocabulary -- a resume is a document, not an
   article, and borrowing .cs-* here would misdescribe both.
   ========================================================================== */

.resume {
  /* Reused as link and section-title colour. 10.37:1 on white. */
  --resume-accent: var(--color-pitt);

  color: #1a1a1a;
}

/* Same measure as a case study: this is continuous reading. Scoped to main
   for the same reason -- the header must not narrow with it. */
.resume main .shell {
  max-width: 820px;
}

/* --- Name and contact ---------------------------------------------------- */

.resume-head {
  text-align: center;
  padding-block: clamp(2rem, 5vw, 3rem) 0;
  margin-bottom: clamp(2rem, 5vw, 2.75rem);
}

.resume-name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2rem, 6vw, 2.75rem);
  line-height: 1.15;
  color: #111;
  margin-bottom: 0.9rem;
}

/* Contact actions sit directly under the name. Flex-wrap so the pair stacks
   rather than overflowing once there is no room for both on one line. */
.resume-contact {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.6rem 0.75rem;
  font-size: 0.875rem;
}

.resume-contact a {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 7px 16px;
  border: 1px solid #dcdcdc;
  border-radius: 20px;
  color: var(--resume-accent);
  text-decoration: none;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}

.resume-contact a:hover {
  border-color: var(--resume-accent);
  background: color-mix(in srgb, var(--resume-accent) 6%, #fff);
}

.resume-contact svg {
  flex-shrink: 0;
}

/* --- Download ------------------------------------------------------------
   One action, at the end, matching where the case studies put .cs-cta. The
   HTML page above already *is* the resume, so the PDF's only remaining job
   is to be taken away as a file -- which is why this is a download rather
   than a second way to view the same content.
   ------------------------------------------------------------------------ */

.resume-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding-block: 2rem 3rem;
  border-top: 1px solid #e0e0e0;
}

.resume-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 13px 28px;
  border-radius: 8px;
  font-size: 0.875rem;
  font-weight: 500;
  background: var(--resume-accent);
  color: #fff; /* 10.37:1 */
  text-decoration: none;
  transition: background-color 0.15s ease;
}

.resume-btn:hover {
  background: color-mix(in srgb, var(--resume-accent) 82%, #000);
}

/* Its own row beneath the button rather than beside it. */
.resume-actions small {
  flex-basis: 100%;
  text-align: center;
  font-size: 0.75rem;
  color: #767676;
}

/* --- Sections ------------------------------------------------------------ */

.resume-section {
  margin-bottom: clamp(1.75rem, 4vw, 2.5rem);
}

.resume-section > h2 {
  font-size: 0.65625rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--resume-accent);
  margin-bottom: 0.9rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid #e0e0e0;
}

.resume-section > p {
  font-size: 0.9375rem;
  line-height: 1.8;
  color: #333;
  max-width: 68ch;
}

/* --- Entries (education, roles) ------------------------------------------ */

.resume-entry + .resume-entry {
  margin-top: 1.5rem;
}

/* Role and dates share a line, and fall to two lines rather than colliding
   once the date can no longer sit beside a long title. */
.resume-entry__head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: 2px 1rem;
}

.resume-entry__role {
  font-size: 0.9375rem;
  font-weight: 600;
  color: #111;
}

/* Every project named on the resume has a case study on this site, so the
   titles link through. Underlined rather than recoloured, to stay legible as
   a heading first and a link second. */
.resume-entry__role a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--resume-accent) 35%, transparent);
}

.resume-entry__role a:hover {
  color: var(--resume-accent);
  border-bottom-color: var(--resume-accent);
}

.resume-entry__date {
  font-size: 0.8125rem;
  color: #767676;
}

.resume-entry__org {
  font-size: 0.84375rem;
  color: #555;
  margin-bottom: 0.5rem;
}

.resume-entry ul {
  list-style: none;
}

.resume-entry li {
  position: relative;
  padding-left: 1.1rem;
  font-size: 0.875rem;
  line-height: 1.65;
  color: #333;
  margin-bottom: 0.28rem;
}

.resume-entry li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #c8c8c8;
}

/* --- Skills --------------------------------------------------------------- */

.resume-skills {
  display: grid;
  grid-template-columns: 170px 1fr;
  gap: 0.75rem 1.25rem;
  font-size: 0.875rem;
}

.resume-skills dt {
  font-weight: 600;
  color: #111;
}

.resume-skills dd {
  color: #555;
  line-height: 1.7;
}

/* The label column stops being worth its width before the text gets tight. */
@media (max-width: 560px) {
  .resume-skills {
    grid-template-columns: 1fr;
    gap: 0.2rem;
  }

  .resume-skills dd {
    margin-bottom: 0.85rem;
  }

  .resume-skills dd:last-child {
    margin-bottom: 0;
  }
}

/* ==========================================================================
   Site footer

   Two contact actions, identical on every page. The links are icon-only, so
   each carries its own aria-label and the SVGs are hidden from assistive
   tech -- the icon is decoration, the label is the accessible name.

   Not inside .case-study main, so it keeps --shell-max and lines up with the
   header rather than the narrower reading column.
   ========================================================================== */

/* White bar, so the separation from the page has to come from the rule --
   the page behind it is also white and a bare background would be invisible.
   The dark buttons below carry the rest of the weight. */
.site-footer {
  margin-top: clamp(3rem, 8vw, 5rem);
  border-top: 1px solid #dcdcdc;
  background: var(--color-page);
}

.site-footer__inner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  padding-block: clamp(2.25rem, 5vw, 3.25rem);
}

/* 52px targets, comfortably past the 44px AAA minimum. Solid dark plates on
   the white bar -- at 21:1 they are the only heavy mark in the footer, which
   is the point: these are its only two actions and they should not have to be
   discovered. The border matches the fill rather than adding an outline, so
   it just widens the plate and the box model stays identical on hover
   (nothing reflows). */
.site-footer a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border: 1.5px solid var(--color-bar);
  border-radius: 50%;
  background: var(--color-bar);
  color: #fff; /* 21:1 on the plate */
  transition: border-color 0.15s ease, background-color 0.15s ease,
    transform 0.15s ease;
}

/* Already at full weight at rest, so hover lightens rather than darkening,
   and the lift carries the rest of the feedback. #333 keeps the white glyph
   at 12.6:1. */
.site-footer a:hover {
  border-color: #333;
  background: #333;
  transform: translateY(-2px);
}

/* Overrides the width/height attributes on the inline SVGs, which keeps this
   change to the stylesheet -- the footer markup is byte-identical across all
   eight pages and there is no include mechanism to edit it in one place. */
.site-footer svg {
  width: 22px;
  height: 22px;
}
