/* =========================================================
   case-study-page — single entry point for all CSS a case
   study page needs. A new case study links only this file
   (plus the fonts in <head>).

   BUNDLED FILE — this is a flat concatenation (no @imports,
   which load serially and delay first render). If any source
   file below changes, regenerate by concatenating in this
   exact order:

     tokens/tokens.css
     icons/icons.css
     components/arrow-button/arrow-button.css
     components/copy-button/copy-button.css
     components/app-bar/app-bar.css
     components/tag/tag.css
     components/case-study-header/case-study-header.css
     components/case-study-details/case-study-details.css
     components/lightbox/lightbox.css
     layouts/case-study/case-study.css
   ========================================================= */

/* =========================================================
   Tokens
   Primitives (colour, spacing) → Semantics (role-based).
   Semantics always reference primitives via var(), never raw values.
   ========================================================= */

:root {
  /* ---------- Primitives: Colour ---------- */

  /* Radix Red — light, solid */
  --red-1:  #fffcfc;
  --red-2:  #fff7f7;
  --red-3:  #feebec;
  --red-4:  #ffdbdc;
  --red-5:  #ffcdce;
  --red-6:  #fdbdbe;
  --red-7:  #f4a9aa;
  --red-8:  #eb8e90;
  --red-9:  #e5484d;
  --red-10: #dc3e42;
  --red-11: #ce2c31;
  --red-12: #641723;

  /* Radix Gray — light, solid */
  --gray-1:  #fcfcfc;
  --gray-2:  #f9f9f9;
  --gray-3:  #f0f0f0;
  --gray-4:  #e8e8e8;
  --gray-5:  #e0e0e0;
  --gray-6:  #d9d9d9;
  --gray-7:  #cecece;
  --gray-8:  #bbbbbb;
  --gray-9:  #8d8d8d;
  --gray-10: #838383;
  --gray-11: #646464;
  --gray-12: #202020;

  /* Pure black — the only use is the modal scrim (see --color-overlay). Not a
     Radix step; kept separate from the gray scale, which bottoms out at #202020. */
  --black: #000000;

  /* Radix Blue — light, solid. Brought in for the keyboard focus ring. */
  --blue-1:  #fbfdff;
  --blue-2:  #f4faff;
  --blue-3:  #e6f4fe;
  --blue-4:  #d5efff;
  --blue-5:  #c2e5ff;
  --blue-6:  #acd8fc;
  --blue-7:  #8ec8f6;
  --blue-8:  #5eb1ef;
  --blue-9:  #0090ff;
  --blue-10: #0588f0;
  --blue-11: #0d74ce;
  --blue-12: #113264;

  /* ---------- Primitives: Spacing ---------- */
  /* Carbon v11 spacing scale — non-linear geometric progression. */

  --spacing-01: 0.125rem; /*   2px */
  --spacing-02: 0.25rem;  /*   4px */
  --spacing-03: 0.5rem;   /*   8px */
  --spacing-04: 0.75rem;  /*  12px */
  --spacing-05: 1rem;     /*  16px */
  --spacing-06: 1.5rem;   /*  24px */
  --spacing-07: 2rem;     /*  32px */
  --spacing-08: 2.5rem;   /*  40px */
  --spacing-09: 3rem;     /*  48px */
  --spacing-10: 4rem;     /*  64px */
  --spacing-11: 5rem;     /*  80px */
  --spacing-12: 6rem;     /*  96px */
  --spacing-13: 10rem;    /* 160px */

  /* ---------- Primitives: Typography ---------- */
  /* Families. */
  --font-family-roboto: "Roboto", system-ui, sans-serif;
  --font-family-mono:   ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace;

  /* Carbon type scale — productive + expressive (steps 01–13). */
  --type-scale-01: 0.75rem;   /*  12px */
  --type-scale-02: 0.875rem;  /*  14px */
  --type-scale-03: 1rem;      /*  16px */
  --type-scale-04: 1.125rem;  /*  18px */
  --type-scale-05: 1.25rem;   /*  20px */
  --type-scale-06: 1.5rem;    /*  24px */
  --type-scale-07: 1.75rem;   /*  28px */
  --type-scale-08: 2rem;      /*  32px */
  --type-scale-09: 2.25rem;   /*  36px */
  --type-scale-10: 2.625rem;  /*  42px */
  --type-scale-11: 3rem;      /*  48px */
  --type-scale-12: 3.375rem;  /*  54px */
  --type-scale-13: 3.75rem;   /*  60px */

  /* Font weights. */
  --font-weight-light:   300;
  --font-weight-regular: 400;
  --font-weight-medium:  500;
  --font-weight-bold:    700;

  /* Line heights — numeric modifiers (percentage as unitless). */
  --line-height-120: 1.2;
  --line-height-150: 1.5;
  --line-height-160: 1.6;
  --line-height-180: 1.8;

  /* ---------- Semantics: Colour ---------- */
  /* Naming: [object]-[base]-[modifier] — here, color-<property>-<scale>. */
  /* Every semantic references a primitive via var(), never a raw value.  */

  --color-background:  var(--gray-2);
  --color-accent:      var(--red-9);
  --color-font:        var(--gray-12);
  --color-font-light:  var(--gray-11);
  --color-border:      var(--gray-4);
  --color-border-dark: var(--gray-5);

  /* Inline text links. Blue-9 is the closest match to the reference site's
     link blue (#09f); hover steps one scale darker for a pressed-in feel. */
  --color-link:        var(--blue-9);
  --color-link-hover:  var(--blue-11);   /* two scale steps darker than rest, for a clear hover shift */

  /* Selected/active surface — e.g. the current nav tab's pill fill. Separate
     from --color-border-dark (also gray-5) to keep surface and border roles distinct. */
  --color-background-selected: var(--gray-5);

  /* Modal scrim — black at 90%, dimming the page behind the lightbox. */
  --color-overlay: color-mix(in srgb, var(--black) 90%, transparent);

  /* Inline code — subtle fill sitting one step above the page background. */
  --color-background-code: var(--gray-3);

  /* ---------- Semantics: Border Radius ---------- */
  /* No primitive layer — these four values are consumed directly by role. */

  --border-radius-none:    0;
  --border-radius-image:   0.5rem;  /* 8px — inline case-study images */
  --border-radius-card:    1rem;    /* 16px — cards, panels, modals */
  --border-radius-feature: 2.5rem;  /* 40px — feature blocks, callouts */
  --border-radius-pill:    999px;   /* buttons, tags, avatars */

  /* ---------- Semantics: Focus ---------- */
  /* Keyboard focus ring. Token setup + sizes mirror squareup.com; the colour
     resolves to Radix --blue-9 (#0090ff) — the closest match to Square's focus
     blue (#006aff). Width / style / offset / radius are fixed accessibility
     values with no primitive equivalent (same precedent as the 2px outlines
     already used per-component). */
  --accessibility-focus-outline-color:         var(--blue-9);
  --accessibility-focus-outline-width:         2px;
  --accessibility-focus-outline-style:         solid;
  --accessibility-focus-outline-offset:        2px;
  --accessibility-focus-outline-border-radius: 5px;
}

/* ---------- Base ---------- */
/* Page-level defaults so unclassed text still gets Roboto and consistent
   rendering. Smoothing is applied here (not per utility class) so it
   cascades to every text element across every page. */

/* border-box everywhere: padding and borders sit inside an element's declared
   width, so the spacing tokens compose predictably (e.g. width:100% + padding
   doesn't overflow the viewport). Foundational to every component. */
*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  font-family: var(--font-family-roboto);
  color:       var(--color-font);
  background:  var(--color-background);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

code {
  font-family: var(--font-family-mono);
  font-size:   var(--type-scale-02);   /* 14px */
  background:  var(--color-background-code);
  padding:     var(--spacing-02) var(--spacing-03);   /* 4px 8px */
  border-radius: var(--border-radius-image);
}

/* Global keyboard-focus ring, token-driven (setup mirrors squareup.com). The
   :not(:active) guard keeps the ring off elements being actively clicked, so it
   reads as a keyboard affordance. Components may override with their own outline
   (currently the red --color-accent rings) — those win on source order, since
   their CSS loads after tokens.css. See a11y/a11y.md §1. */
:focus-visible:not(:active) {
  outline: var(--accessibility-focus-outline-width)
           var(--accessibility-focus-outline-style, solid)
           var(--accessibility-focus-outline-color);
  outline-offset: var(--accessibility-focus-outline-offset);
  border-radius: var(--accessibility-focus-outline-border-radius);
}

/* Honour reduced-motion globally — see a11y/a11y.md §7. Components keep their
   own short transitions; this neutralises them when the user opts out. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration:  0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- Semantics: Typography ---------- */
/* Utility classes composed from primitives. No raw values inside. */

.heading-01 {
  font-family: var(--font-family-roboto);
  font-size:   var(--type-scale-13);
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-120);
}

.heading-02 {
  font-family: var(--font-family-roboto);
  font-size:   var(--type-scale-08);
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-120);
}

.heading-03 {
  font-family: var(--font-family-roboto);
  font-size:   var(--type-scale-06);
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-150);
}

.heading-04 {
  font-family: var(--font-family-roboto);
  font-size:   var(--type-scale-05);
  font-weight: var(--font-weight-medium);
  line-height: var(--line-height-150);
}

.heading-05 {
  font-family:    var(--font-family-roboto);
  font-size:      var(--type-scale-02);
  font-weight:    var(--font-weight-bold);
  line-height:    var(--line-height-150);
  text-transform: uppercase;
}

.body-01 {
  font-family: var(--font-family-roboto);
  font-size:   var(--type-scale-04);   /* 18px */
  font-weight: var(--font-weight-light);
  line-height: var(--line-height-150);
}

.body-02 {
  font-family: var(--font-family-roboto);
  font-size:   var(--type-scale-03);
  font-weight: var(--font-weight-regular);
  line-height: var(--line-height-180);
}

.body-03 {
  font-family: var(--font-family-roboto);
  font-size:   var(--type-scale-02);
  font-weight: var(--font-weight-regular);
  line-height: var(--line-height-160);
}
/* Heroicons outline, overridden to a 1px stroke.
   Apply .icon to any rendered Heroicons SVG. */

.icon {
  width: 1.5rem;            /* 24px — Heroicons native size */
  height: 1.5rem;
  stroke-width: 1;          /* override Heroicons' 1.5 default */
  stroke: currentColor;     /* inherits text colour */
  fill: none;               /* explicit for outline style */
  flex-shrink: 0;           /* prevents collapse inside flex containers */
}
/* =========================================================
   arrow-button — directional navigation control.
   Apply to <a> or <button>. Two usages:
     Icon only  — app-bar back link (icon provides direction)
     Icon + text — learnings nav (← Back / Next →)
   States are identical in both cases; the containing component
   handles sizing and layout.
   ========================================================= */

.arrow-button {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-03);
  background: none;
  border: none;
  padding: 0;
  font-family: var(--font-family-roboto);
  font-size: var(--type-scale-03);
  font-weight: var(--font-weight-regular);
  line-height: var(--line-height-160);
  color: var(--color-font-light);
  text-decoration: none;
  cursor: pointer;
  transition: color 120ms ease;
}

.arrow-button:hover {
  color: var(--color-font);
}

.arrow-button:active {
  color: var(--color-font-light);
}

.arrow-button:disabled {
  cursor: default;
}

.arrow-button:focus-visible {
  outline: var(--accessibility-focus-outline-width)
           var(--accessibility-focus-outline-style)
           var(--accessibility-focus-outline-color);
  outline-offset: var(--accessibility-focus-outline-offset);
  border-radius: var(--accessibility-focus-outline-border-radius);
}
/* =========================================================
   copy-button — copies a string (here, an email) to the
   clipboard and confirms. Label + Heroicon; on success it
   enters a "copied" state (toggled via [data-copied="true"]).
   The email stays visible throughout — a small tooltip pops
   below the button to confirm the copy, so layout never shifts.
   ========================================================= */

.copy-button {
  /* Positioning context for the confirmation tooltip. */
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-03);
  min-height: 1.5rem;   /* 24px hit target */
  padding: var(--spacing-02) var(--spacing-03);
  /* body-03 (14px / line-height-160) with a light-weight override. */
  font-family: var(--font-family-roboto);
  font-size: var(--type-scale-02);   /* 14px */
  font-weight: var(--font-weight-light);
  line-height: var(--line-height-160);
  color: var(--color-font-light);
  background: none;
  border: 0;
  border-radius: var(--border-radius-pill);
  cursor: pointer;
  transition: color 120ms ease;
}

.copy-button__label {
  white-space: nowrap;
}

/* Confirmation tooltip. Appears on copy ([data-copied="true"]) and replaces
   the old inline "Copied" overlay. Sits BELOW the button so it never clips
   against the viewport top when the app-bar is pinned. */
.copy-button__tooltip {
  position: absolute;
  top: calc(100% + var(--spacing-02));
  left: 50%;
  z-index: 1;
  padding: var(--spacing-02) var(--spacing-03);
  font-size: var(--type-scale-01);   /* 12px */
  font-weight: var(--font-weight-regular);
  line-height: var(--line-height-150);
  color: var(--color-background);
  white-space: nowrap;
  background: var(--color-font);
  border-radius: var(--border-radius-pill);
  opacity: 0;
  /* Start nudged up, settle into place — paired with the opacity fade. */
  transform: translate(-50%, calc(-1 * var(--spacing-01)));
  pointer-events: none;
  transition: opacity 120ms ease, transform 120ms ease;
}

/* Up-pointing arrow joining the tooltip to the button. */
.copy-button__tooltip::before {
  content: "";
  position: absolute;
  bottom: 100%;
  left: 50%;
  border: 4px solid transparent;
  border-bottom-color: var(--color-font);
  transform: translateX(-50%);
}

/* Heroicon, smaller than the 24px .icon default. Stroke inherits via currentColor. */
.copy-button__icon {
  width: 1.25rem;    /* 20px */
  height: 1.25rem;
}

/* Visually-hidden live region for the screen-reader announcement. */
.copy-button__status {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.copy-button:hover {
  color: var(--color-font);
}

.copy-button:active {
  color: var(--color-font);
}

.copy-button:focus-visible {
  outline: var(--accessibility-focus-outline-width)
           var(--accessibility-focus-outline-style, solid)
           var(--accessibility-focus-outline-color);
  outline-offset: var(--accessibility-focus-outline-offset);
  border-radius: var(--border-radius-pill);   /* keep the pill — overrides the global 5px focus default */
}

/* Copied state — set by the click handler for ~2s. Reveals the tooltip;
   the email and the button colour stay put. */
.copy-button[data-copied="true"] .copy-button__tooltip {
  opacity: 1;
  transform: translate(-50%, 0);
}
/* =========================================================
   app-bar — sticky site header that composes logo-mark, tab,
   copy-button and social-link. Translucent blurred fill;
   stays pinned to the top once scrolled. Adapts to its OWN
   width via a container query (not the viewport): at 582px
   and below it drops the tabs and the email label, leaving a
   compact logo + icons view.
   ========================================================= */

.app-bar {
  /* Sits below the hero in flow; pins to the top once the page scrolls
     past it. The frosted surface spans the full viewport width so content
     scrolling underneath is blurred edge-to-edge. */
  position: sticky;
  top: 0;
  z-index: 2;
  width: 100%;
  /* Outer gutter around the row: 16px top, 32px left/right. The fill covers
     the padding box, so the frost still spans the full viewport width while
     the bordered row sits inset from the edges. */
  padding: var(--spacing-05) var(--spacing-07) 0;
  /* 40% of the page background + blur — token-derived translucent fill. */
  background: color-mix(in srgb, var(--color-background) 40%, transparent);
  -webkit-backdrop-filter: blur(5px);
  backdrop-filter: blur(5px);
  /* The query context: the bar reacts to its own inline size. */
  container-type: inline-size;
  container-name: app-bar;
}

.app-bar__inner {
  /* Full width, capped at 2000px and centred, with a 32px gutter each side. */
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-06);
  height: 56px;                 /* component-level: no spacing primitive matches */
  max-width: 2000px;
  margin: 0 auto;
  padding: 0 var(--spacing-07);   /* 32px left / right */
  border: 1px solid var(--color-border-dark);
}

/* The two sections inside the bar — both tight 8px rows. Left: logo-mark ↔ tabs.
   Right: the email copy-button grouped with the social icons. */
.app-bar__nav,
.app-bar__contact {
  display: flex;
  align-items: center;
  gap: var(--spacing-03);   /* 8px */
}

/* At full width the copy-button shows only its email label — the duplicate
   icon is dropped. It returns in the compact view below, where the label is
   hidden and the icon alone stands in for the action. */
.app-bar .copy-button__icon { display: none; }

/* ---------- Compact view ----------
   Reacts to the bar's own width. Hidden elements use display:none
   so they also leave the tab order (see a11y.md §2). */
@container app-bar (max-width: 582px) {
  .app-bar .tab { display: none; }
  .app-bar .copy-button__label { display: none; }
  .app-bar .copy-button__icon { display: block; }
}

/* ---------- Case-study variant ----------
   Same frosted surface, fill, sticky behaviour, outer gutter and 2000px /
   56px row as the parent — but NO bordered box. The row is just a back
   control on the left and the copy-button on the right, sitting at the 32px
   gutter (the parent's padding), space-between. Everything else, including the
   582px compaction of the copy-button label, is inherited from the rules above
   because the variant still carries the base .app-bar class. */
.app-bar--case-study .app-bar__inner {
  padding: 0;     /* no inner inset — content aligns to the parent's 32px gutter */
  border: 0;      /* the case-study bar drops the bordered box */
}

/* Back control: a square hit area holding the arrow-left glyph; returns to the
   homepage's work grid. Muted at rest, darkening to the solid font colour on
   hover — the same muted→solid move as the tab, with no background fill. */
.app-bar__back {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--spacing-08);    /* 40px hit area */
  height: var(--spacing-08);
  border-radius: var(--border-radius-pill);
}

/* 20px glyph — matches the copy-button's icon so the two ends read at the same
   weight (the 24px .icon default would feel heavy as the only left element). */
.app-bar__back .icon {
  width: 1.25rem;
  height: 1.25rem;
}

/* Keep the pill radius on the focus ring (overrides the global 5px default). */
.app-bar__back:focus-visible {
  border-radius: var(--border-radius-pill);
}
/* =========================================================
   tag — a small, non-interactive pill label. Used in threes
   under the case-study header to name what a study touches on
   (e.g. "Design System", "Leadership"). A quiet grey-filled
   pill with 12px light text.
   ========================================================= */

.tag {
  display: inline-flex;
  align-items: center;
  padding: var(--spacing-02) var(--spacing-03);   /* 4px / 8px */
  /* 12px / light / line-height-150 — a caption-weight label. */
  font-family: var(--font-family-roboto);
  font-size: var(--type-scale-01);
  font-weight: var(--font-weight-light);
  line-height: var(--line-height-150);
  color: var(--color-font);
  white-space: nowrap;
  background: var(--color-background-selected);   /* grey-5 fill */
  border-radius: var(--border-radius-pill);
}
/* =========================================================
   case-study-header — the centred hero block that opens every
   case study. Three stacked rows: a muted sub-header lockup
   (a logo slot beside "Product · Company"), the heading-01
   title, and a centred row of three tags. The whole block is
   centred; the body below it returns to left-aligned reading.
   ========================================================= */

.case-study-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

/* Sub-header lockup: placeholder logo slot + product · company context line.
   body-02 supplies the size; weight is overridden to light. */
.case-study-header__subheader {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-03);   /* 8px between logo and text */
  margin: 0;
  padding: 0;
  font-weight: var(--font-weight-light);
  color: var(--color-font-light);
}

/* Logo slot — a rounded-square placeholder until a real company/product mark is
   dropped in (an <img>/<svg> goes inside the span, same box). When it holds a real
   logo the grey placeholder fill and radius drop away, leaving just the mark. */
.case-study-header__logo {
  display: inline-flex;
  flex-shrink: 0;
  width: 1.75rem;    /* 28px — matches the logo-mark svg */
  height: 1.75rem;
  background: var(--color-border);
  border-radius: var(--border-radius-card);
}

.case-study-header__logo:has(img, svg) {
  background: none;
  border-radius: 0;
}

.case-study-header__logo img,
.case-study-header__logo svg {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: inherit;
}

/* heading-01 supplies the type; the component owns the 4px gap under the
   sub-header and resets the default h1 margin. */
.case-study-header__title {
  margin: var(--spacing-01) 0 0;   /* 4px under the sub-header */
}

/* Centred, wrapping row of tags, 24px under the title. */
.case-study-header__tags {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--spacing-03);   /* 8px between tags */
  margin: var(--spacing-04) 0 0;   /* 24px under the title */
  padding: 0;
  list-style: none;
}
/* =========================================================
   case-study-details — the meta strip under the header. A
   vertical list of "Label: Description" rows (Company, Product,
   Role, Date — variable per study) bounded by a top and bottom
   rule. The label reads muted (--color-font-light) with a colon;
   the description sits inline beside it in the solid body colour.
   Both body-03.
   ========================================================= */

.case-study-details {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-03);   /* 8px between rows */
  margin: 0;
  padding: var(--spacing-07) var(--spacing-03);   /* 32px block / 8px inline, inside the rules */
  border-top: 1px solid var(--color-border-dark);
  border-bottom: 1px solid var(--color-border-dark);
}

/* One row: label on the left, description to its right, on a single line. */
.case-study-details__item {
  display: flex;
  gap: var(--spacing-02);   /* 4px — between "Label:" and the value */
}

/* Label: the muted term, with a trailing colon. Doesn't shrink or wrap. */
.case-study-details__title {
  flex: none;
  margin: 0;
  color: var(--color-font-light);
  white-space: nowrap;
}

.case-study-details__title::after {
  content: ":";
}

/* Description: the value, inline beside the label, in the solid body colour. */
.case-study-details__description {
  margin: 0;   /* reset the default <dd> indent */
  color: var(--color-font);
}
/* =========================================================
   lightbox — case-study images and the full-screen modal they
   open. A .case-study-image is a button-wrapped <img> in the
   content flow; clicking it fills a single shared .lightbox
   dialog (a 70% black scrim) with the image enlarged. Closes on
   the ✕, an outside click, or Esc.
   ========================================================= */

/* ---------- Trigger (in the content flow) ---------- */

/* 16px above and below every nested image. These margins collapse with the
   adjacent heading/paragraph margins set by the case-study layout, so the gap
   to a neighbour resolves to the larger of the two. */
.case-study-image {
  margin: var(--spacing-05) 0;
}

.case-study-image__trigger {
  display: block;
  width: 100%;
  padding: 0;
  background: none;
  border: 0;
  border-radius: var(--border-radius-image);
  cursor: zoom-in;
}

.case-study-image__img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--border-radius-image);
}

/* Keep the image radius on the focus ring (overrides the global 5px default). */
.case-study-image__trigger:focus-visible {
  border-radius: var(--border-radius-image);
}

/* ---------- Modal ---------- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--spacing-07);   /* 32px gap between the image and the edges */
  background: var(--color-overlay);
  animation: lightbox-fade 120ms ease;   /* neutralised by the global reduced-motion rule */
}

.lightbox[hidden] {
  display: none;
}

.lightbox__img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: var(--border-radius-image);
}

.lightbox__close {
  position: absolute;
  top: var(--spacing-05);     /* 16px */
  right: var(--spacing-05);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--spacing-08);   /* 40px hit target */
  height: var(--spacing-08);
  color: var(--color-background);   /* near-white icon on the dark scrim */
  background: none;
  border: 0;
  border-radius: var(--border-radius-pill);
  cursor: pointer;
}

.lightbox__close:focus-visible {
  border-radius: var(--border-radius-pill);
}

@keyframes lightbox-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
/* =========================================================
   case-study — the page layout for a single case study. A 750px
   centred reading column holding the header, the details strip,
   the hero image and the body; the app-bar above it stays full
   width (its own component). Owns the vertical rhythm: 64px macro
   gaps between the top blocks, and a heading/body/image spacing
   system inside the body keyed to heading level.
   ========================================================= */

body {
  margin: 0;
}

/* The centred reading column. The app-bar is a sibling above this, full width,
   so the 784px cap applies only to the page content. The flex column lays out
   the four top blocks — header, details, hero, body — with a 64px macro gap
   between each (spec: all gaps outside the body's own headings are 64px). */
.case-study {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-10);              /* 64px macro gaps */
  max-width: 784px;
  margin-inline: auto;
  padding: var(--spacing-10) var(--spacing-07);   /* 64px block / 32px gutter */
}

/* The hero is a .case-study-image, which ships 16px block margins for in-flow
   use. As a flex child here the macro gap owns the spacing, so drop them. */
.case-study__hero {
  margin: 0;
}

/* ---------- Body: type + vertical rhythm ----------
   The body is a single flex child, so its block children collapse margins
   normally among themselves while staying sealed from the macro gaps above.
   Type is set by the body-02 class on the element; headings re-style via
   their heading-0x classes. */
.case-study__body {
  color: var(--color-font);
}

/* Zero the UA margins; the rules below own every vertical gap. */
.case-study__body > * { margin: 0; }

/* Gap BEFORE a heading, keyed to that heading's level. Because the value is
   tied to the level (not the pair), consecutive same-level headings keep the
   same gap automatically — e.g. every h3 sits 48px below whatever precedes it. */
.case-study__body > * + h2 { margin-top: var(--spacing-10); }   /* 64px — new major section */
.case-study__body > * + h3 { margin-top: var(--spacing-09); }   /* 48px */
.case-study__body > * + h4 { margin-top: var(--spacing-08); }   /* 40px */
.case-study__body > * + h5 { margin-top: var(--spacing-07); }   /* 32px */

/* Heading → its immediately following body text: a tight 8px. */
.case-study__body > :is(h2, h3, h4, h5) + p { margin-top: var(--spacing-03); }   /* 8px */

/* Paragraph → paragraph. */
.case-study__body > p + p { margin-top: var(--spacing-05); }   /* 16px */

/* Body images get 16px of block margin (collapses with neighbouring heading/text
   margins) plus 16px of block padding inside the figure — opening the gap between
   body text and the image so it doesn't crowd. The hero (.case-study__hero) is
   outside .case-study__body, so it keeps its 64px macro spacing untouched. */
.case-study__body > .case-study-image {
  margin-block: var(--spacing-05);    /* 16px */
  padding-block: var(--spacing-05);   /* 16px — breathing room around the image */
}

/* The body's first child needs no leading gap — the 64px macro gap above it
   already separates it from the hero. (Placed last so it wins on source order.) */
.case-study__body > :first-child { margin-top: 0; }

/* Inline links in prose (e.g. a resolved cross-study wikilink). */
.case-study__body a {
  color: var(--color-link);
  text-decoration: underline;
}

.case-study__body a:hover {
  color: var(--color-link-hover);
}
