/* ==========================================================================
   Emma (Khai Hoan) Nguyen — Portfolio
   Plain CSS, mobile-first. Breakpoints:
     • Base            → mobile phones
     • 640px  (tablet) → small tablets / large phones landscape
     • 1024px (desktop)→ laptops / desktops  (2-column work grid kicks in)
   Above desktop the content width is fixed; the extra space becomes margin.
   ========================================================================== */

/* ---------- Design tokens (from the Figma file) ---------- */
:root {
  --bg: #fcfcfc;
  --nav-bg: #ffffff;
  --text: #000000;
  --muted: #5b5b5b;          /* tags + nav links */

  --font-head: "IBM Plex Sans", system-ui, sans-serif; /* tags + titles */
  --font-body: "Figtree", system-ui, sans-serif;        /* captions + descriptions */

  /* spacing scale mirrors Figma's tokens */
  --space-2: 8px;
  --space-3: 12px;
  --space-5: 20px;
  --space-7: 32px;
  --space-8: 40px;
  --space-12: 72px;

  --content-max: 1376px;     /* 2 × 682 project + 12 gap, matches Figma */
}

/* ---------- custom cursor ----------
   The umami egg replaces the arrow across the site. SVG first so it stays
   crisp on a retina screen, with a PNG behind it for browsers that decline
   SVG cursors; the hotspot sits at the egg's centre. Interactive elements
   keep the same shape rather than reverting to the system hand, so the
   cursor never flickers between two forms as you move around. */
:root {
  --cursor-egg: url("/assets/cursor/egg.svg") 12 12,
                url("/assets/cursor/egg.png") 12 12, auto;
}

html,
body,
a,
button,
summary,
[role="button"],
.project__image,
.cs-sidebar a,
.nav__links a {
  cursor: var(--cursor-egg);
}

/* a pointing device is the only thing this helps; leave touch alone */
@media (hover: none) {
  html, body, a, button, summary, [role="button"],
  .project__image, .cs-sidebar a, .nav__links a {
    cursor: auto;
  }
}

/* Once cursor.js is running it draws the egg itself, easing behind the
   pointer, so the real cursor goes away everywhere — including over the
   playground canvas, which would otherwise keep its grab/grabbing shapes.
   !important because those are more specific than anything sane here. */
html.has-custom-cursor,
html.has-custom-cursor * {
  cursor: none !important;
}

.cursor {
  position: fixed;
  top: 0;
  left: 0;
  width: 24px;
  height: 25px;
  z-index: 9999;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease, scale 0.15s ease;
  will-change: translate;
}

.cursor.is-visible { opacity: 1; }

/* a press shrinks it — this is what replaces the grab cursor */
.cursor.is-down { scale: 0.82; }

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

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

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;        /* safety net against accidental horizontal scroll */
}

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

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

/* ==========================================================================
   NAV
   ========================================================================== */
.nav {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--nav-bg);

  display: flex;
  flex-wrap: wrap;          /* lets links drop below the name on small screens */
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);

  padding: var(--space-3) var(--space-5);
  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}

.nav__brand,
.nav__links a {
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 14px;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: var(--muted);
  padding: var(--space-2);
  transition: color 0.15s ease;
}

.nav__brand {
  font-weight: 700;
  color: var(--text);
}

.nav__links {
  display: flex;
  align-items: center;
  gap: var(--space-5);
}

.nav__links a:hover {
  color: var(--text);
}

/* ==========================================================================
   HERO
   ========================================================================== */
.hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-8);

  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--space-12) var(--space-7);
  text-align: center;
}

.hero__signature {
  width: 100%;
  max-width: 320px;         /* mobile: smaller signature */
  height: auto;
}

.hero__caption {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 16px;
  line-height: 24px;
  width: 100%;              /* fill the narrow screen instead of shrink-wrapping */
  max-width: 512px;        /* but never wider than the design's 512px */
  margin: 0;
}

/* ==========================================================================
   PLAYGROUND — infinite canvas
   --------------------------------------------------------------------------
   Full-bleed: the canvas is the page. Cards run off every edge so the surface
   reads as continuing past the window rather than sitting in a box. The plane
   is one 2272x1820 tile repeated on a grid; panning wraps the offset by the
   tile size, so the same handful of cards covers an endless surface with only
   a few nodes in the DOM. Cards stay a fixed size at any screen size — a
   larger monitor shows more of the canvas, not bigger cards.
   ========================================================================== */
.pg {
  position: relative;
  width: 100%;
  overflow: hidden;
}

/* the canvas is the whole window; the nav floats over it so cards run under
   the top edge as well as the other three */
body.pg-page .nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
}

body.pg-page {
  overflow: hidden;
}

.pg__viewport {
  position: relative;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  background: var(--bg);
  cursor: grab;
  touch-action: none;            /* we handle the drag ourselves */
  overscroll-behavior: contain;
}

.pg__viewport.is-panning {
  cursor: grabbing;
}

.pg__viewport:focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: -2px;
}

.pg__plane {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
  will-change: transform;
}

/* How much of the canvas a screen shows. The tile was laid out to be read in
   a 3368px-wide Figma frame; at that size a laptop viewport would see barely a
   quarter of it and the canvas reads empty. Scaling down brings the density
   back to what the layout was designed to feel like. canvas.js reads this. */
.pg {
  --pg-scale: 0.6;
}

@media (min-width: 768px) and (max-width: 1023px) {
  .pg {
    --pg-scale: 0.46;
  }
}

.pg__tile {
  position: absolute;
  top: 0;
  left: 0;
  width: 2272px;
  height: 1820px;
}

.pg__card {
  position: absolute;
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0;
}

.pg__card img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 3px;
  pointer-events: none;          /* never start a native image drag */
  user-select: none;
}

.pg__card figcaption {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 16px;
  line-height: 24px;
  color: var(--text);
  user-select: none;
}

/* ---- drag hint ----
   Sits over the canvas until the first pan, then fades out for good. */
.pg__hint {
  position: fixed;
  left: 50%;
  bottom: calc(var(--space-7) + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 10px var(--space-5);
  border-radius: 999px;
  background: rgba(252, 252, 252, 0.92);
  border: 1px solid #e4e4e4;
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 12px;
  line-height: 18px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  pointer-events: none;
  transition: opacity 0.4s ease;
}

.pg__hint.is-gone {
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .pg__hint { transition: none; }
}

/* ---- phone: a single scrolling column, not a canvas ----
   Dragging a plane around is fiddly on a small screen, so the cards stack
   into one full-width feed and the page scrolls normally. The canvas markup
   is reused as-is; only the positioning is undone. */
@media (max-width: 767px) {
  body.pg-page {
    overflow: visible;
  }

  body.pg-page .nav {
    position: sticky;
  }

  .pg__viewport {
    height: auto;
    overflow: visible;
    cursor: auto;
    touch-action: auto;
  }

  .pg__plane {
    position: static;
    transform: none !important;
  }

  .pg__tile {
    position: static;
    width: auto;
    height: auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-8);
    padding: var(--space-5) var(--space-5) var(--space-12);
  }

  /* the cards carry inline left/top/width from the canvas layout */
  .pg__card {
    position: static !important;
    left: auto !important;
    top: auto !important;
    width: auto !important;
  }

  .pg__hint {
    display: none;
  }
}

/* ==========================================================================
   ABOUT
   --------------------------------------------------------------------------
   Copy beside a portrait, on the 635 / 605 split from the design. Two of the
   design's greys fall under WCAG AA at 16px (#777 is 4.36:1, the #f05500
   label 3.41:1), so both use the accessible equivalents already defined for
   the rest of the site.
   ========================================================================== */
.about {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--space-8) var(--space-7) var(--space-12);
  display: grid;
  gap: var(--space-8);
  align-items: start;
}

@media (min-width: 1024px) {
  .about {
    grid-template-columns: 635fr 605fr;
    gap: 40px;
  }
}

.about__copy {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  min-width: 0;
}

.about__title {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: clamp(26px, 3.4vw, 34px);   /* H-4 */
  line-height: 1.5;
  margin: 0;
}

.about__text {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 16px;
  line-height: 24px;
  margin: 0;
}

.about__contact {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 16px;
  line-height: 24px;
  color: #606060;
  margin: 0;
}

.about__contact a {
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color 0.15s ease;
}

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

.about__photo {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 3px;
}

/* ---- experience / education ---- */
.about__list-label {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 16px;
  line-height: 24px;
  text-transform: uppercase;
  color: var(--accent-text);
  margin: 0 0 var(--space-2);
}

.about__rows {
  list-style: none;
  margin: 0;
  padding: 0;
}

.about__row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 16px;
  line-height: 24px;
  padding: var(--space-2) 0;
  border-bottom: 1px solid #e4e4e4;
}

.about__row-sep {
  color: var(--label);
}

.about__row-role {
  color: var(--label);
}

.about__row-year {
  margin-left: auto;
  color: var(--label);
  white-space: nowrap;
}

/* ==========================================================================
   WORK GRID
   ========================================================================== */
.work {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 0 var(--space-7) var(--space-12);
}

.grid {
  display: grid;
  grid-template-columns: 1fr;   /* mobile: single column */
  column-gap: var(--space-3);
  row-gap: var(--space-8);
}

/* ---- one project card ---- */
.project {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.project__image {
  display: block;
  position: relative;          /* positioning context for the veil */
  width: 100%;
  aspect-ratio: 682 / 502.5;   /* keeps every image the same shape */
  overflow: hidden;
  background: #ededed;
}

.project__image img {
  width: 100%;
  height: 100%;
  object-fit: cover;           /* fill the box, crop overflow, no distortion */
  transition: transform 0.4s ease;
}

.project__image:hover img {
  transform: scale(1.03);      /* subtle zoom on hover */
}

/* Project 1 special: radial gradient tile with the Engramme wordmark on top */
.project__image--engramme {
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(
    ellipse 60% 55% at 50% 50%,
    #909090 0%,
    #bebebe 50%,
    #ebebeb 100%
  );
}

.project__image--engramme .project__wordmark {
  width: 63%;                  /* 430 / 682 from the design */
  height: auto;
  transition: transform 0.4s ease;
}

.project__image--engramme:hover .project__wordmark {
  transform: scale(1.03);
}

/* ---- veil ----
   For a project tile with no case study behind it: the card still reads as
   part of the work, but hovering says plainly why there is nothing to click
   through to, and where to go instead. Revealed on keyboard focus as well as
   hover. */
.project__veil {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  background: rgba(14, 14, 14, 0.55);
  color: #fff;
  opacity: 0;
  pointer-events: none;          /* nothing to click while the veil is hidden */
  transition: opacity 0.2s ease;
}

/* focus-within, not focus-visible: tabbing to the link inside has to reveal
   the veil, or a keyboard user would be focusing something invisible */
.project__image:hover .project__veil,
.project__image:focus-within .project__veil {
  opacity: 1;
  pointer-events: auto;
}

/* sentence case, not uppercase — an email address set in capitals is unreadable */
.project__veil__text {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 15px;
  line-height: 24px;
  text-align: center;
  max-width: 92%;   /* the line breaks are authored, so give them room */
}

.project__veil__text a {
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: opacity 0.15s ease;
}

.project__veil__text a:hover {
  opacity: 0.75;
}

@media (prefers-reduced-motion: reduce) {
  .project__veil { transition: none; }
}

/* ---- project text block ---- */
.project__meta {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.project__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 14px;
  line-height: 20px;
  text-transform: uppercase;
  color: var(--muted);
}

.project__title {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 24px;
  line-height: 1.3;
  margin: 0;
}

.project__desc {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 16px;
  line-height: 24px;
  margin: 0;
}

/* ==========================================================================
   RESPONSIVE — TABLET  (≥ 640px)
   ========================================================================== */
@media (min-width: 640px) {
  .nav {
    /* centre the bar's contents on the same 1408px cap the page uses, so the
       brand and links stop drifting apart on very wide monitors — the bar's
       background and bottom border still span the full viewport */
    padding: var(--space-3) max(var(--space-7), calc((100% - 1408px) / 2));
  }

  .hero__signature {
    max-width: 440px;
  }

  .project__title {
    font-size: 28px;
    line-height: 42px;
  }
}

/* ==========================================================================
   RESPONSIVE — DESKTOP  (≥ 1024px)  → 2-column work grid
   ========================================================================== */
@media (min-width: 1024px) {
  .hero {
    padding: 96px var(--space-7);
  }

  .hero__signature {
    max-width: 508px;         /* matches Figma */
  }

  .grid {
    grid-template-columns: 1fr 1fr;
    column-gap: var(--space-3);
    row-gap: var(--space-7);
  }
}

/* ==========================================================================
   LARGE MONITORS (> desktop)
   --------------------------------------------------------------------------
   The content width is fixed. Anything wider than the desktop layout becomes
   left/right margin rather than stretching the page, so a 4K monitor reads
   the same as a laptop instead of pulling lines uncomfortably wide.
   `.cs-layout` and `--content-max` do this on their own; the nav is the one
   full-bleed element, so its inner content is centred to the same cap while
   its background and bottom border still span the viewport.
   ========================================================================== */

/* ==========================================================================
   CASE STUDY  (project detail pages, e.g. /packaid/)
   Reuses the tokens above. Two-column layout: sticky sidebar + content.
   ========================================================================== */
:root {
  --label: #747474;          /* meta labels — lightest grey clearing WCAG AA 4.5:1 */
  --card-bg: #f4f4f4;        /* soft card background */
  --nav-h: 62px;             /* measured sticky nav height, for sticky offsets */
  --accent: #f05500;         /* brand orange — large text and non-text accents */
  --accent-text: #cc4800;    /* same hue, darkened to clear AA at small text sizes */
}

/* ---- overall layout ---- */
.cs-layout {
  max-width: 1408px;
  margin: 0 auto;
  padding: 0 var(--space-7);
}

@media (min-width: 1024px) {
  .cs-layout {
    display: grid;
    grid-template-columns: 199px minmax(0, 1fr);  /* fixed sidebar + fluid content */
    column-gap: var(--space-8);
    align-items: start;
  }
}

/* ---- sticky sidebar (section anchor nav) ---- */
.cs-sidebar {
  display: none;             /* hidden on mobile; content nav lives inline instead */
}

@media (min-width: 1024px) {
  .cs-sidebar {
    display: block;
    /* Stretch to the full height of the grid row so the nav inside it can stay
       stuck for the whole scroll. Left at the grid's default `start` the column
       is only as tall as its own links, and the nav would come unstuck as soon
       as it reached the bottom of that short box. */
    align-self: stretch;
    padding-top: var(--space-8);
  }

  /* The nav is what sticks, not the column — so the offset is measured straight
     to the links and lands them 16px clear of the page nav. */
  .cs-sidebar nav {
    position: sticky;
    top: calc(var(--nav-h) + 16px);
  }
}

.cs-sidebar nav {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  /* leaves a gutter to the left of the labels for the scroll-spy dot, so the
     dot appearing never nudges the text sideways */
  padding-left: 16px;
}

.cs-sidebar a {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 12px;           /* Figma Global Tokens/Body/B-3 */
  line-height: 18px;
  color: var(--muted);
  transition: color 0.15s ease;
}

.cs-sidebar a:hover {
  color: var(--text);
}

/* scroll-spy: the section currently in view. Marked by a dot in the gutter as
   well as a colour change, so the current section is not signalled by colour
   alone. */
.cs-sidebar a.is-active {
  color: var(--accent-text);
}

/* A single dot that slides between entries rather than one dot per link
   blinking on and off — scrollspy.js injects it and drives its position.
   It anchors to the nav, which is already a positioned element by virtue of
   being sticky; declaring `position: relative` here would land after that
   media query and quietly undo the sticky. */
.cs-side-dot {
  position: absolute;
  left: 2px;
  top: 0;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent-text);
  opacity: 0;
  pointer-events: none;
  transition:
    transform 0.32s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.2s ease;
}

.cs-side-dot.is-visible {
  opacity: 1;
}

/* the slide is decorative — hold still for anyone who asked for less motion */
@media (prefers-reduced-motion: reduce) {
  .cs-side-dot {
    transition: opacity 0.2s ease;
  }
}

.cs-sidebar .cs-side-home,
.cs-sidebar .cs-side-top {
  color: var(--text);
}

/* ---- "← Home" pill (per Figma 109-954) ----
   A soft grey chip, back-arrow (not up-arrow — it leaves the case study).
   align-self stops the flex column from stretching it to full width. */
.cs-sidebar .cs-side-home {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--card-bg);
  border-radius: 4px;
  padding: var(--space-2) var(--space-3);
  transition: background 0.15s ease, color 0.15s ease;
}

.cs-sidebar .cs-side-home:hover {
  background: #e9e9e9;
}

/* arrow tracks the text colour but never picks up the uppercase transform */
.cs-side-home__arrow {
  font-size: 14px;
  line-height: 1;
}

.cs-sidebar hr {
  border: none;
  border-top: 1px solid rgba(0, 0, 0, 0.08);
  margin: var(--space-2) 0;
  width: 100%;
}

/* ---- main content column ---- */
.cs-content {
  min-width: 0;              /* let flex/grid children shrink instead of overflowing */
  display: flex;
  flex-direction: column;
  gap: 64px;
  padding-block: var(--space-8) 96px;
}

/* Big hero image at the very top of the case study */
.cs-hero {
  aspect-ratio: 1145 / 536;
}

/* ---- overview block (title + subtitle + meta rows) ---- */
.cs-title {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: clamp(40px, 6vw, 58px);
  line-height: 1.08;
  margin: 0;
}

.cs-subtitle {
  font-family: var(--font-head);
  font-weight: 400;
  font-size: clamp(20px, 3vw, 28px);
  line-height: 1.4;
  margin: var(--space-2) 0 0;
  max-width: 1082px;
}

.cs-rows {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-7) var(--space-12);
  margin-top: var(--space-7);
}

.cs-row__label {
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 16px;
  line-height: 20px;
  text-transform: uppercase;
  color: var(--label);
  margin: 0 0 10px;
}

/* a link inside a meta row — e.g. the award citation */
.cs-row a {
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color 0.15s ease;
}

.cs-row a:hover {
  color: var(--accent-text);
}

.cs-row ul {
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 16px;
  line-height: 24px;
}

/* ---- generic section ---- */
.cs-section {
  scroll-margin-top: calc(var(--nav-h) + var(--space-5));  /* anchor lands below nav */
}

.cs-eyebrow {
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 14px;
  line-height: 20px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--accent-text);
  margin: 0;
}

.cs-heading {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: clamp(24px, 3vw, 28px);
  line-height: 1.35;
  margin: 10px 0 0;
  max-width: 960px;
}

.cs-text {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 16px;
  line-height: 24px;
  margin: var(--space-5) 0 0;
  max-width: 900px;
}

.cs-text + .cs-text {
  margin-top: var(--space-3);
}

.cs-list {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 16px;
  line-height: 24px;
  margin: var(--space-5) 0 0;
  padding-left: 1.2em;
  max-width: 900px;
}

.cs-list li {
  margin-bottom: 6px;
}

/* ---- image / video placeholder (swap for real assets later) ---- */
.cs-media {
  margin-top: var(--space-5);
  width: 100%;
  background:
    repeating-linear-gradient(
      45deg,
      #f0f0f0,
      #f0f0f0 12px,
      #e9e9e9 12px,
      #e9e9e9 24px
    );
  border: 1px dashed #cfcfcf;
  border-radius: 3px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  color: #9a9a9a;
  font-family: var(--font-body);
  font-size: 13px;
  padding: var(--space-5);
}

/* placeholders (and images) carrying an inline `--ratio` get that aspect ratio */
.cs-media[style*="--ratio"] { aspect-ratio: var(--ratio); }

/* prototype walkthrough video — sized by its own width/height attrs, so no
   letterboxing; the grey matches the recording's backdrop while it loads */
.cs-video {
  display: block;
  width: 100%;
  height: auto;
  margin-top: var(--space-5);
  border-radius: 3px;
  background: #e9e9e9;
}

/* an interactive embed, sized to the frame it occupies in the design */
.cs-embed {
  display: block;
  width: 100%;
  aspect-ratio: 1145 / 620;
  margin-top: var(--space-5);
  border: 0;
  border-radius: 3px;
  background: #fff;
}

/* real images swapped in for placeholders */
.cs-img {
  display: block;
  width: 100%;
  height: auto;
  margin-top: var(--space-5);
  border-radius: 3px;
}

/* an image carrying an inline `--ratio` fills that frame instead of showing its
   native proportions — used where the design crops a photo to a set band */
.cs-img[style*="--ratio"] {
  aspect-ratio: var(--ratio);
  object-fit: cover;
}

/* a phone screenshot, shown at device scale rather than stretched to the column */
.cs-img--phone {
  max-width: 380px;
  margin-left: auto;
  margin-right: auto;
}

/* ---- source citation ----
   Full citation caption under a data image. Sentence case (a reference in
   uppercase is unreadable), body face, muted — only the title is a link. */
.cs-source {
  display: block;
  max-width: 960px;
  margin: var(--space-2) 0 0;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 13px;
  line-height: 1.5;
  color: var(--muted);
}

.cs-source a {
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color 0.15s ease;
}

.cs-source a:hover {
  color: var(--text);
}

.cs-source cite {
  font-style: italic;
}

.cs-stat {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: clamp(18px, 2.2vw, 24px);
  line-height: 1.5;
  margin: 0;
  max-width: 960px;
}

.cs-data { margin-top: 44px; }

/* ---- card grids (exploration, strategies, user testing) ---- */
.cs-cards {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-5);
  margin-top: var(--space-7);
}

@media (min-width: 768px) {
  .cs-cards--2 { grid-template-columns: repeat(2, 1fr); }
  .cs-cards--3 { grid-template-columns: repeat(3, 1fr); }
}

.cs-card {
  background: var(--card-bg);
  border-radius: 4px;
  padding: var(--space-7);
}

.cs-card__title {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 16px;
  line-height: 1.4;
  margin: 0;
}

.cs-card__text {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 15px;
  line-height: 23px;
  margin: var(--space-3) 0 0;
  color: #333;
}

/* inline emphasis in the brand accent — e.g. the "→ Umami" lead-in */
.cs-accent {
  color: var(--accent-text);
  font-weight: 700;
}

/* ---- outlined card ----
   The umami case study draws its cards as an outline rather than a filled
   block, and titles them in the body face at sentence case. */
.cs-card--outline {
  background: transparent;
  border: 1px solid #777;
  border-radius: 10px;
  padding: var(--space-7);
}

.cs-card--outline .cs-card__title {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 16px;
  line-height: 24px;
}

.cs-card--outline .cs-card__text {
  font-size: 16px;
  line-height: 24px;
  color: #0e0e0e;
}

/* persona header — a thumbnail with the name and one-line description.
   Stacked by default: once .cs-cards--2 splits into two columns the card is
   too narrow for the design's 219px thumbnail to sit alongside the text, so
   the side-by-side arrangement only kicks in once the card can hold it. */
.cs-persona {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-5);
  width: 100%;
}

.cs-persona > div {
  min-width: 0;              /* let the text wrap instead of forcing the row wide */
}

.cs-persona__thumb {
  width: 100%;
  height: auto;
  aspect-ratio: 219 / 164;
  object-fit: cover;
  border-radius: 16px;
  margin-top: 0;
}

.cs-persona__name {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 16px;
  line-height: 24px;
  color: var(--accent-text);
  margin: 0;
}

@media (min-width: 1280px) {
  .cs-persona { flex-direction: row; align-items: center; }
  .cs-persona__thumb {
    flex: none;
    width: 219px;
    height: 164px;
    aspect-ratio: auto;
  }
}

/* ---- prefixed lines (+ / \u2013 / \u2192) ----
   The design sets these as plain paragraphs, so the prefix character is the
   only marker — a list bullet on top of it would read as a double marker. */
.cs-lines { margin: var(--space-3) 0 0; }

.cs-lines p {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 16px;
  line-height: 24px;
  color: #0e0e0e;
  margin: 0;
}

.cs-lines__label {
  font-weight: 700;
  margin-top: var(--space-5) !important;
}

.cs-lines > .cs-lines__label:first-child { margin-top: 0 !important; }

/* exploration cards carry an image + caption */
.cs-card--explore { background: transparent; padding: 0; }
.cs-card--explore .cs-media { margin-top: var(--space-3); aspect-ratio: 1 / 1; }

/* full-card images sitting directly in a card grid: no extra top margin */
.cs-cards > .cs-img { margin-top: 0; align-self: start; }

/* hero image sits flush at the top of the case study */
.cs-img--hero { margin-top: 0; }

/* images inside a gallery grid: gap handles the spacing */
.cs-gallery > .cs-img { margin-top: 0; align-self: start; }

/* ---- highlighted research question ----
   Per Figma: no fill — a 2px orange rule on the left with the text indented
   off it, regular weight (not bold), ~26px type. Indent collapses on mobile,
   where the rule sits flush with the content column. */
.cs-question {
  margin-top: var(--space-7);
  border-left: 2px solid var(--accent);
  padding: var(--space-2) 0 var(--space-2) var(--space-5);
  font-family: var(--font-head);
  font-weight: 400;
  font-size: clamp(18px, 2.4vw, 26px);
  line-height: 1.45;
  text-align: left;
}

@media (min-width: 1024px) {
  .cs-question {
    margin-left: 56px;
    padding-left: var(--space-7);
  }
}

/* ---- outcomes rows ---- */
.cs-outcome {
  border-top: 1px solid rgba(0, 0, 0, 0.1);
  padding: var(--space-7) 0;
}

.cs-outcome__title {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 16px;
  margin: 0;
}

.cs-outcome__text {
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 24px;
  margin: 10px 0 0;
}

/* two-up image grid for prototype galleries */
.cs-gallery {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-5);
  margin-top: var(--space-5);
}

@media (min-width: 768px) {
  .cs-gallery--2 { grid-template-columns: 1fr 1fr; }

  /* five small squares in a row — the illustration-process cards */
  .cs-gallery--5 { grid-template-columns: repeat(5, 1fr); }

  /* uneven pair, mirroring the 358 / 777 split in the design */
  .cs-gallery--asym { grid-template-columns: 358fr 777fr; }

  /* design-process pair: the wide reference beside the tall sketch */
  .cs-gallery--process { grid-template-columns: 728fr 417fr; }
}

.cs-gallery .cs-media { margin-top: 0; }
