/* Styles for the behavior in site.js, which replaced Framer's hosted runtime. */

:root {
  /* The condensed palette (see color-audit.html). Pages carry these values
     inline through Framer's tokens; these names are for site.css and site.js. */
  --site-canvas: rgb(16, 16, 16);
  --site-surface: rgb(27, 27, 27);
  --site-surface-hover: rgb(45, 45, 45);
  --site-line: rgb(58, 58, 58);
  --site-ink: rgb(247, 247, 247);
  --site-ink-muted: rgb(175, 175, 175);
  --site-accent: rgb(232, 163, 61);
  --site-ink-a04: rgba(247, 247, 247, 0.04);
  --site-ink-a12: rgba(247, 247, 247, 0.12);
  --site-ink-a32: rgba(247, 247, 247, 0.32);
  --site-ease-spring: cubic-bezier(0.22, 1.2, 0.36, 1);
  /* Framer's { type: "spring", bounce: 0.1, duration: 1 }, sampled frame by
     frame from the live site's project cards, including its slight overshoot. */
  --site-card-spring: linear(0, 0.0198 1.6%, 0.0513 3.2%, 0.0903 4.9%, 0.1386 6.6%, 0.1916 8.2%, 0.244 9.8%, 0.3007 11.6%, 0.3572 13.3%, 0.4126 14.9%, 0.4629 16.6%, 0.5141 18.3%, 0.5624 20%, 0.6051 21.6%, 0.6474 23.3%, 0.6864 25%, 0.7223 26.6%, 0.7532 28.3%, 0.7831 30%, 0.8102 31.6%, 0.8317 33.2%, 0.8551 35%, 0.8746 36.6%, 0.8911 38.3%, 0.9066 40%, 0.9203 41.6%, 0.9316 43.2%, 0.9421 45%, 0.9514 46.7%, 0.9589 48.3%, 0.9659 50%, 0.9719 51.7%, 0.9771 53.3%, 0.9812 55%, 0.9849 56.7%, 0.9881 58.4%, 0.9906 60%, 0.9929 61.7%, 0.9947 63.2%, 0.9962 64.9%, 0.9974 66.6%, 0.9985 68.4%, 0.9993 70%, 1 71.7%, 1.0008 75.1%, 1.0012 78.3%, 1.0015 81.7%, 1.0015 85%, 1.0014 88.4%, 1.0013 91.6%, 1.0011 95%, 1.0009 98.4%, 1);
}

/* Wordmark ("Raj S. Shah", header and footer): on mouse hover it switches to
   Season Mix SemiBold Italic, instantly both ways, as on the live site. Framer
   also springs the paragraph's color, but the link color on the inner span
   overrides it, so the visible text stays ink. The face is declared here
   because not every page's inline CSS includes it. */
@font-face {
  font-family: "Season Mix SemiBold Italic";
  src: url(/assets/fonts/SeasonMix-SemiBoldItalic.woff2) format("woff2");
  font-style: italic;
  font-weight: 670;
  font-display: swap;
}
@media (hover: hover) {
  .framer-1hhhC:hover .framer-styles-preset-5ii3bl {
    --framer-font-family: "Season Mix SemiBold Italic", "Season Mix SemiBold", sans-serif;
    --framer-font-style: italic;
  }
}

/* Testimonial card: vertical scrolling stays with the browser so site.js
   can read horizontal swipes. */
.testimonial-swipe { touch-action: pan-y; }

/* Testimonial arrows: grey on hover, on Framer's 0.4s spring (bounce 0.2). */
.testimonial-arrow {
  transition: background-color 0.5s linear(0, 0.0321 2.5%, 0.1105 5%, 0.2143 7.5%, 0.3281 10%, 0.4417 12.5%, 0.5483 15%, 0.644 17.5%, 0.727 20%, 0.7968 22.5%, 0.854 25%, 0.8996 27.5%, 0.935 30%, 0.9617 32.5%, 0.9812 35%, 0.9949 37.5%, 1.004 40%, 1.0097 42.5%, 1.0128 45%, 1.014 47.5%, 1.0139 50%, 1.0131 52.5%, 1.0117 55%, 1.0102 57.5%, 1.0085 60%, 1.007 62.5%, 1.0056 65%, 1.0043 67.5%, 1.0033 70%, 1.0024 72.5%, 1.0017 75%, 1.0011 77.5%, 1.0007 80%, 1.0004 82.5%, 1.0001 85%, 1);
}
.testimonial-arrow.is-hover { background-color: var(--site-ink-muted) !important; }
.testimonial-arrow:focus-visible { outline: 2px solid var(--site-accent); outline-offset: 3px; }

/* Homepage project cards: on hover the card lightens and the title row
   slides right (its left padding goes 16px -> 32px via Framer's .hover rules). */
.framer-rcOrV {
  transition: background-color 1s var(--site-card-spring);
}
.framer-rcOrV.hover { background-color: var(--site-surface-hover) !important; }
.framer-rcOrV .framer-1uj1i9i {
  transition: padding 1s var(--site-card-spring);
}

/* Liquid glass buttons (5 Nov 2026): Contact, View case study, Return Home.
   Today's #2d2d2d surface and white label sit in a glass pill. The surface (.lg-core) fades out just
   inside the rim, so the edge stays clear glass: site.js bends the backdrop there (Chromium) and lights
   the rim toward the cursor. A glass bead carries the direction: ↗ leaves the site, → stays, ← goes back.
   Sized in em off --type-button, so it follows the type scale. */
a.lg-btn {
  --x: 50%; --y: 50%; --a: 135deg;
  position: relative; isolation: isolate;
  display: inline-flex; align-items: center; gap: 0.85em; width: max-content; box-sizing: border-box;
  padding: 0.4em 0.4em 0.4em 1.45em; border-radius: 999px;
  font-family: var(--type-sans-semibold); font-weight: 650; font-size: var(--type-button, 18px); line-height: 1.2; letter-spacing: 0.005em;
  color: var(--site-ink); text-decoration: none; white-space: nowrap; cursor: pointer; -webkit-tap-highlight-color: transparent;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.13), rgba(255, 255, 255, 0.03) 50%, rgba(255, 255, 255, 0.07)), rgba(45, 45, 45, 0.55);
  -webkit-backdrop-filter: blur(4px) saturate(1.9);
  backdrop-filter: blur(4px) saturate(1.9);
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.5), inset 0 -2px 6px rgba(255, 255, 255, 0.08), 0 15px 35px rgba(247, 247, 247, 0.16), 0 3px 8px rgba(0, 0, 0, 0.35);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
  transform-origin: 30% 50%;
}
.cs a.lg-btn, .cs a.lg-btn:hover { color: var(--site-ink); text-decoration: none; }
/* Framer wraps each button in boxes that clip 16px below it, which cut the bloom off in a hard line. */
:has(> a.lg-btn), :has(> * > a.lg-btn), :has(> * > * > a.lg-btn) { overflow: visible !important; }
.lg-btn::before, .lg-btn::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; }
/* Rim: a faint chromatic edge, like light splitting at a water line. Its bright side turns toward the cursor. */
.lg-btn::before {
  padding: 1.25px; z-index: 1; opacity: 0.9;
  background: conic-gradient(from var(--a), rgba(255, 255, 255, 0.85), rgba(140, 220, 255, 0.45), rgba(255, 255, 255, 0.08), rgba(255, 170, 120, 0.4), rgba(255, 255, 255, 0.55), rgba(200, 160, 255, 0.35), rgba(255, 255, 255, 0.85));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude;
}
/* Specular highlight under the cursor. */
.lg-btn::after { z-index: 1; opacity: 0; transition: opacity 0.3s ease; background: radial-gradient(80px 50px at var(--x) var(--y), rgba(255, 255, 255, 0.2), transparent 70%); }
.lg-btn.is-lit::after { opacity: 1; }
.lg-core { position: absolute; inset: 5px 9px; z-index: 0; border-radius: inherit; background: rgba(45, 45, 45, 0.94); filter: blur(5px); pointer-events: none; }
.lg-label { position: relative; z-index: 2; }
.lg-bead {
  position: relative; z-index: 2; flex: none; display: grid; place-items: center;
  width: 2.2em; height: 2.2em; border-radius: 50%; color: var(--site-ink);
  background: radial-gradient(circle at 35% 25%, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0.06) 55%, rgba(255, 255, 255, 0.02)), rgb(62, 62, 62);
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.55), inset 0 -2px 4px rgba(0, 0, 0, 0.35), inset 0 0 0 1px rgba(255, 255, 255, 0.12), 0 4px 10px rgba(0, 0, 0, 0.4);
  transition: transform 0.55s var(--site-ease-spring);
}
.lg-bead svg { width: 1em; height: 1em; transition: transform 0.55s var(--site-ease-spring); }
.lg-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
.lg-btn:focus-visible { outline: 2px solid var(--site-accent); outline-offset: 4px; }
@media (hover: hover) {
  .lg-btn:hover { animation: lg-jelly 0.7s var(--site-ease-spring) both; }
  .lg-btn:hover .lg-bead { transform: translateX(4px) scale(1.06); }
  .lg-btn:hover .lg-bead .is-diag { transform: translate(1px, -1px); }
  .lg-btn:hover .lg-bead .is-right { transform: translateX(2px); }
  .lg-btn:hover .lg-bead .is-left { transform: translateX(-2px); }
}
.lg-btn:active { transform: scale(0.97); animation: none; }
@keyframes lg-jelly { 0% { transform: scale(1, 1); } 30% { transform: scale(1.06, 0.94); } 55% { transform: scale(0.985, 1.02); } 80% { transform: scale(1.01, 0.995); } 100% { transform: scale(1.02, 1.02); } }
@media (prefers-reduced-transparency: reduce) {
  a.lg-btn { -webkit-backdrop-filter: none; backdrop-filter: none !important; background: rgb(45, 45, 45); }
}
@media (forced-colors: active) {
  a.lg-btn { border: 1px solid ButtonText; background: ButtonFace; color: ButtonText; }
  .lg-btn::before, .lg-btn::after, .lg-core { display: none; }
}

/* Tablet and phone menu. */
.framer-3cMXQ[role="button"]:focus-visible {
  outline: 2px solid var(--site-accent);
  outline-offset: 2px;
}
.framer-3cMXQ .framer-159q9b4,
.framer-3cMXQ .framer-yhbedr,
.framer-3cMXQ .framer-6bu83x {
  transition: transform 0.35s var(--site-ease-spring), opacity 0.2s ease;
}
header nav[data-framer-name="Navbar Nav"] {
  transition: opacity 0.25s ease, visibility 0s linear 0.25s;
}
header nav[data-framer-name="Navbar Nav"].is-open {
  transition: opacity 0.25s ease, visibility 0s;
}
header [data-framer-name="Overlay"] { transition: opacity 0.25s ease; }

/* Ticker: soft fade at both edges. */
.site-ticker {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 25%, #000 75%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 25%, #000 75%, transparent 100%);
}

/* Experiments cards: description panel over the video. */
.exp-info {
  position: absolute;
  inset: auto 0 0 0;
  z-index: 2;
  display: grid;
  gap: 12px;
  padding: 72px 24px 24px;
  border-radius: inherit;
  background: linear-gradient(to top, rgba(16, 16, 16, 0.92) 0%, rgba(16, 16, 16, 0.75) 55%, rgba(16, 16, 16, 0) 100%);
  color: var(--site-ink);
  font: 400 18px/1.45 "Season Sans Regular", "Season Sans Regular Placeholder", sans-serif;
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.35s var(--site-ease-spring);
}
.exp-info p { margin: 0; max-width: 46ch; }
.exp-info a {
  justify-self: start;
  color: inherit;
  font-family: "Season Sans Medium", "Season Sans Medium Placeholder", sans-serif;
  text-decoration: underline;
  text-underline-offset: 4px;
}
.exp-info a:focus-visible { outline: 2px solid var(--site-accent); outline-offset: 3px; }
.exp-card { cursor: pointer; }
.exp-card:focus-visible { outline: 2px solid var(--site-accent); outline-offset: 4px; }
.exp-card.is-open .exp-info {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
@media (max-width: 809.98px) {
  .exp-info { padding: 56px 16px 16px; font-size: 16px; }
}

@media (prefers-reduced-motion: reduce) {
  .lg-bead,
  .lg-bead svg,
  .framer-3cMXQ .framer-159q9b4,
  .framer-3cMXQ .framer-yhbedr,
  .framer-3cMXQ .framer-6bu83x,
  header nav[data-framer-name="Navbar Nav"],
  header [data-framer-name="Overlay"],
  .exp-info,
  .framer-rcOrV,
  .framer-rcOrV .framer-1uj1i9i,
  .testimonial-arrow { transition: none; }
  .lg-btn:hover, .lg-btn:active { transform: none; animation: none; }
  .lg-btn:hover .lg-bead, .lg-btn:hover .lg-bead svg { transform: none; }
}

/* Text selection uses the accent, the same as focus rings. */
::selection { background: var(--site-accent); color: var(--site-canvas); }

/* About, "Working with AI, and teaching others too": after the original four
   practice cards, the point of view, then the Ship AI evidence for it
   (cards, hackathon photos, a dated line of events). Cards match the cards
   they replaced: 24px padding, 18px gap, a 1px line border, a 7px dot and a
   divider; the hover lift and dim come from .focus-card-group-Rkqlp. Type
   comes from data-type (type-scale.css). */
.ai-thesis,
.ai-proof,
.ai-photos,
.ai-ledger { width: 100%; }
/* Space between the practices above and the point of view (the section's 32px
   gap plus the top margin: 96px from tablet up, 64px on phones), and between
   the point of view and its evidence (64px / 48px). */
.ai-thesis { display: flex; flex-direction: column; gap: 24px; margin: 32px 0 16px; }
@media (min-width: 810px) { .ai-thesis { margin: 64px 0 32px; } }
/* Same extra space between the cards and the photos. */
.ai-proof { margin-bottom: 16px; }
@media (min-width: 810px) { .ai-proof { margin-bottom: 32px; } }
.ai-statement { max-width: 20em; }
.ai-statement .ai-line { display: block; }
.ai-intro { max-width: 40em; }
.ai-link {
  --framer-link-text-color: var(--site-ink);
  text-decoration: underline;
  text-decoration-color: var(--site-line);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  transition: text-decoration-color 0.2s ease;
}
.ai-link:hover { text-decoration-color: var(--site-ink); }
.ai-link:focus-visible { outline: 2px solid var(--site-accent); outline-offset: 3px; border-radius: 2px; }

.ai-proof { display: grid; grid-template-columns: 1fr; gap: 12px; }
/* Two classes so the card fill and border outrank the group's resting
   "revert"; its :hover rule has the same weight and comes later, so it wins. */
.ai-proof > .ai-card {
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 24px;
  border-radius: 12px;
  background-color: var(--site-surface);
  border: 1px solid var(--site-line);
}
/* Card art: a tick-field band bled to the card's top edge (drawn by initCardArt in site.js).
   Extra width becomes more field; the scene stays centred. */
.ai-card-art { margin: -24px -24px 6px; aspect-ratio: 64 / 30; max-height: 214px; border-bottom: 1px solid var(--site-line); border-radius: 11px 11px 0 0; overflow: hidden; }
.ai-card-art canvas { display: block; width: 100%; height: 100%; }
.ai-card-row { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; width: 100%; }
.ai-card-dot { flex: none; width: 7px; height: 7px; margin-top: 6px; border-radius: 50%; background-color: var(--site-ink-a32); }
.ai-card-divider { width: 100%; height: 1px; background-color: var(--site-line); }
.ai-card-foot {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: auto 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--site-line);
}
.ai-card-foot blockquote { margin: 0; }

.ai-photos { display: grid; grid-template-columns: 1fr; gap: 12px; margin: 0; }
.ai-photo { overflow: hidden; border-radius: 12px; background-color: var(--site-surface); }
.ai-photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.ai-photo-group { aspect-ratio: 4 / 3; }
.ai-photo-winners { aspect-ratio: 1 / 1; }
.ai-caption { margin-top: 0; }

/* Ship AI timeline: one dot per event on a rail, in the same dot-and-line
   language as the practice diagrams. The ongoing office hours end on a hollow
   ring and a dashed rail. Five columns on desktop; vertical below 1024px. */
.ai-ledger { padding-top: 28px; border-top: 1px solid var(--site-line); }
.ai-ledger-head { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 16px; row-gap: 4px; }
.ai-ledger-title { margin: 0; font-family: "Season Mix Regular", serif; font-weight: 420; font-size: var(--type-h3); line-height: 1.25; color: var(--site-ink); }
.ai-ledger-span { margin: 0; font-family: "Season Sans Regular", sans-serif; font-size: var(--type-small); color: var(--site-ink-muted); }
.ai-timeline { --node: 9px; --rail-top: 34px; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); margin: 32px 0 0; padding: 0; list-style: none; }
.ai-timeline-item { position: relative; display: flex; flex-direction: column; padding-right: 24px; }
.ai-timeline-item::before { content: ""; position: absolute; left: 0; right: 0; top: calc(var(--rail-top) + var(--node) / 2); height: 1px; background-color: var(--site-line); }
.ai-timeline-item:first-child::before { left: calc(var(--node) / 2); }
.ai-timeline-item.is-ongoing::before { background: repeating-linear-gradient(90deg, var(--site-ink-a32) 0 6px, transparent 6px 12px); }
.ai-timeline-date { height: 22px; font-family: "Season Sans Medium", sans-serif; font-weight: 550; font-size: var(--type-small); line-height: 1.4; color: var(--site-ink-muted); font-variant-numeric: tabular-nums; }
.ai-timeline-node { position: relative; z-index: 1; width: var(--node); height: var(--node); margin: calc(var(--rail-top) - 22px) 0 18px; border-radius: 50%; background-color: var(--site-ink); box-shadow: 0 0 0 6px var(--site-canvas); }
.ai-timeline-item.is-ongoing .ai-timeline-node { background-color: var(--site-canvas); border: 1.5px solid var(--site-ink); }
.ai-timeline-name { margin-bottom: 6px; font-family: "Season Mix Regular", serif; font-weight: 420; font-size: var(--type-h3); line-height: 1.25; color: var(--site-ink); }
.ai-timeline-role { font-family: "Season Sans Regular", sans-serif; font-size: var(--type-small); line-height: 1.45; color: var(--site-ink-muted); }
@media (max-width: 1199.98px) { .ai-timeline-item { padding-right: 16px; } }
@media (max-width: 1023.98px) {
  .ai-timeline { grid-template-columns: 1fr; row-gap: 24px; }
  .ai-timeline-item { display: grid; grid-template-columns: 28px 1fr; grid-template-areas: "node date" "node name" "node role"; padding-right: 0; }
  .ai-timeline-item::before, .ai-timeline-item:first-child::before { left: calc(var(--node) / 2); right: auto; top: 6px; bottom: -30px; width: 1px; height: auto; }
  .ai-timeline-item.is-ongoing::before { bottom: -6px; background: repeating-linear-gradient(180deg, var(--site-ink-a32) 0 6px, transparent 6px 12px); }
  .ai-timeline-date { grid-area: date; height: auto; }
  .ai-timeline-node { grid-area: node; margin: 6px 0 0; }
  .ai-timeline-name { grid-area: name; margin: 2px 0; }
  .ai-timeline-role { grid-area: role; }
}
@media (max-width: 809.98px) { .ai-ledger { padding-top: 24px; } .ai-timeline { margin-top: 24px; } }

@media (min-width: 1200px) {
  .ai-proof { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 810px) {
  /* The square photo sets the row height; the group shot crops its ceiling and floor. */
  .ai-photos { grid-template-columns: 2fr 1fr; }
  .ai-photo-group { position: relative; aspect-ratio: auto; }
  .ai-photo-group img { position: absolute; inset: 0; object-position: 50% 62%; }
  .ai-caption { grid-column: 1 / -1; }
}

/* Selected work: three full-width projects followed by a shared row. */
#work .work-project-wide { flex: none; width: 100%; height: auto; }
@media (min-width: 1200px) {
  #work .work-pair { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: stretch; gap: 24px; }
  #work .work-project-half { min-width: 0; width: 100%; height: auto; }
  #work .work-project-half > .ssr-variant > div { height: 100%; }
  #work .work-project-half .framer-rcOrV { height: 100%; gap: 24px; }
  #work .work-project-half .framer-1b8sotj { aspect-ratio: 4 / 3; }
  #work .work-project-half .framer-k6tmrg-container { height: 100%; }
  #work .work-project-half video { object-fit: contain !important; }
  #work .work-project-half .framer-1uj1i9i { flex: 1 0 auto; flex-wrap: nowrap; }
  #work .work-project-half .framer-uz5kbl { margin-top: auto; }
}

/* About, "How I use AI" practices: titles on the left; on the right a line
   diagram (in the dot-and-line language of the homepage signal field) with the
   description under it. Without JavaScript, and on phones, every practice shows
   in sequence; initPractice() in site.js adds .is-tabs from 810px up. Each
   diagram plays once (about 3s) when its practice is shown, then holds. */
.practice { width: 100%; --practice-ease: cubic-bezier(0.22, 1, 0.36, 1); --practice-dwell: 6.5s; }
.practice-list { display: none; }
.practice-stage { display: flex; flex-direction: column; gap: 48px; }
.practice-mtitle { margin: 0 0 16px; font-family: "Season Mix Regular", serif; font-weight: 420; font-size: var(--type-h3); line-height: 1.25; color: var(--site-ink); }
.practice-visual { position: relative; aspect-ratio: 16 / 10; background-color: var(--site-surface); border: 1px solid var(--site-line); border-radius: 12px; overflow: hidden; }
.practice-desc { margin: 16px 0 0; max-width: 40em; font-family: "Season Sans Regular", sans-serif; font-size: var(--type-body); line-height: 1.5; color: var(--site-ink-muted); }

@media (min-width: 810px) {
  .practice.is-tabs .practice-grid { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 64px; align-items: center; }
  .practice.is-tabs .practice-list { display: flex; flex-direction: column; border-top: 1px solid var(--site-line); }
  .practice.is-tabs .practice-stage { display: grid; gap: 0; }
  .practice.is-tabs .practice-panel { grid-area: 1 / 1; opacity: 0; visibility: hidden; transition: opacity 0.45s ease, visibility 0s linear 0.45s; }
  .practice.is-tabs .practice-panel.is-active { opacity: 1; visibility: visible; transition: opacity 0.45s ease; }
  .practice.is-tabs .practice-mtitle { display: none; }
  .practice-desc { margin-top: 20px; }
}
@media (min-width: 810px) and (max-width: 1199.98px) { .practice.is-tabs .practice-grid { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: 40px; } }

.practice-tab { appearance: none; background: none; border: 0; border-bottom: 1px solid var(--site-line); margin: 0; padding: 22px 0; position: relative; display: block; width: 100%;
  text-align: left; cursor: pointer; color: var(--site-ink-muted); transition: color 0.3s ease; }
.practice-tab:hover, .practice-tab[aria-selected="true"] { color: var(--site-ink); }
.practice-tab:focus-visible { outline: 2px solid var(--site-accent); outline-offset: 4px; border-radius: 2px; }
.practice-title { font-family: "Season Mix Regular", serif; font-weight: 420; font-size: var(--type-h2); line-height: 1.2; }
.practice-bar { position: absolute; left: 0; right: 0; bottom: -1px; height: 1px; overflow: hidden; }
.practice-bar span { display: block; height: 100%; background-color: var(--site-ink); transform: scaleX(0); transform-origin: left; }
.practice-tab[aria-selected="true"] .practice-bar span { transform: scaleX(1); }
.practice.is-timing .practice-tab[aria-selected="true"] .practice-bar span { animation: practice-progress var(--practice-dwell) linear both; }
.practice.is-paused .practice-bar span { animation-play-state: paused !important; }
@keyframes practice-progress { from { transform: scaleX(0); } }
@media (max-width: 1199.98px) { .practice-tab { padding: 18px 0; } }

/* Diagrams. Each shape's resting style is its final state; .play runs the sequence. */
.practice .dg { position: absolute; inset: 0; width: 100%; height: 100%; }
.practice .dg text { font-family: "Season Sans Regular", sans-serif; font-size: 13px; fill: var(--site-ink-muted); }
@keyframes practice-draw { from { stroke-dashoffset: 1; } }
@keyframes practice-fade-in { from { opacity: 0; } }
@keyframes practice-fill-in { from { fill: transparent; } }

/* Find the signal: fragments drift in, noise falls away, the rest stack into a
   ranked dot chart, and the strongest pattern lights up. */
.dg-signal .pt { fill: var(--site-ink-muted); }
.dg-signal .pt.lead { fill: var(--site-ink); }
.dg-signal .noise { fill: var(--site-ink-a32); opacity: 0; }
.dg-signal .base { stroke: var(--site-line); stroke-width: 1.5; stroke-dasharray: 1; }
.dg-signal .lbl.lead { fill: var(--site-ink); }
.dg-signal.play .pt { animation: signal-sort 1.6s var(--practice-ease) var(--d) both; }
.dg-signal.play .pt.lead { animation: signal-sort 1.6s var(--practice-ease) var(--d) both, signal-lead 0.6s ease 2.3s both; }
.dg-signal.play .noise { animation: signal-noise 1.4s ease var(--d) both; }
.dg-signal.play .base { animation: practice-draw 0.8s ease 1.4s both; }
.dg-signal.play .lbl { animation: practice-fade-in 0.5s ease 1.9s both; }
@keyframes signal-sort { from { transform: translate(var(--x), var(--y)); fill: var(--site-ink-a32); } }
@keyframes signal-lead { from { fill: var(--site-ink-muted); } }
@keyframes signal-noise { 0% { opacity: 1; } 45% { opacity: 1; } 100% { opacity: 0; } }

/* Make ideas real: a dashed wireframe gives way to a finished interface. */
.dg-real .wire rect { fill: none; stroke: var(--site-ink-a32); stroke-width: 1.5; stroke-dasharray: 6 6; }
.dg-real .wire .blk { fill: var(--site-ink-a12); stroke: none; }
.dg-real .wire { opacity: 0; }
.dg-real .outline { fill: var(--site-surface-hover); stroke: var(--site-ink-muted); stroke-width: 1.5; stroke-dasharray: 1; }
.dg-real .ln { fill: var(--site-ink-a32); }
.dg-real .ln.m { fill: var(--site-ink-a12); }
.dg-real .dotk { fill: var(--site-ink); }
.dg-real .dotm { fill: var(--site-ink-a32); }
.dg-real .btn { fill: var(--site-ink); }
.dg-real .t { font-size: 15px; fill: var(--site-ink); }
.dg-real.play .wire { animation: real-wire 2.4s linear both; }
.dg-real.play .outline { animation: practice-draw 1s ease 1.1s both, practice-fill-in 1s ease 1.1s both; }
.dg-real.play .inner { animation: practice-fade-in 0.6s ease 1.7s both; }
@keyframes real-wire { 0%, 45% { opacity: 1; } 70%, 100% { opacity: 0; } }

/* Explore in parallel: one point branches into four directions at once. */
.dg-par .origin, .dg-kill .origin { fill: var(--site-ink); }
.practice .dg .br { fill: none; stroke: var(--site-ink-muted); stroke-width: 1.5; stroke-dasharray: 1; }
.dg-par .fr rect:first-child { fill: none; stroke: var(--site-ink-muted); stroke-width: 1.5; }
.dg-par .ln { fill: var(--site-ink-a32); }
.dg-par .ln.m { fill: var(--site-ink-a12); }
.dg-par.play .br { animation: practice-draw 1.1s var(--practice-ease) var(--d, 0s) both; }
.dg-par.play .fr { animation: practice-fade-in 0.5s ease var(--d) both; }

/* Kill bad ideas: three branches are crossed out; one carries on to a finished frame. */
.dg-kill .fr { fill: none; stroke: var(--site-ink-muted); stroke-width: 1.5; }
.dg-kill .x { fill: none; stroke: var(--site-ink-muted); stroke-width: 1.5; }
.dg-kill .cut { opacity: 0.22; }
.dg-kill .go { stroke: var(--site-ink); }
.dg-kill .winrect { fill: var(--site-surface-hover); stroke: var(--site-ink); stroke-width: 1.5; stroke-dasharray: 1; }
.dg-kill .check { fill: none; stroke: var(--site-ink); stroke-width: 2; stroke-dasharray: 1; stroke-linecap: round; stroke-linejoin: round; }
.dg-kill.play .br { animation: practice-draw 1s var(--practice-ease) both; }
.dg-kill.play .fr { animation: practice-fade-in 0.4s ease 0.8s both; }
.dg-kill.play .x { animation: practice-fade-in 0.3s ease 1.5s both; }
.dg-kill.play .cut { animation: kill-cut 0.6s ease 1.5s both; }
.dg-kill.play .go { animation: practice-draw 0.8s var(--practice-ease) 2s both; }
.dg-kill.play .winrect { animation: practice-draw 0.8s ease 2.5s both, practice-fill-in 0.8s ease 2.5s both; }
.dg-kill.play .check { animation: practice-draw 0.5s ease 3s both; }
@keyframes kill-cut { from { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .practice *, .practice *::before, .practice *::after { animation-duration: 1ms !important; animation-delay: 0s !important; transition-duration: 1ms !important; }
}

/* Case-study navigation follows the selected-work order on the homepage. */
.case-study-pagination {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 48px;
  width: calc(100% - 64px);
  max-width: 1264px;
  align-self: center;
  margin: 24px auto 0;
  padding: 48px 0;
  border-top: 1px solid var(--site-line);
}
.case-study-pagination a {
  display: flex;
  align-items: center;
  gap: 20px;
  min-width: 0;
  min-height: 64px;
  padding: 8px 0;
  color: var(--site-ink);
  text-decoration: none;
}
.case-study-pagination-previous { grid-column: 1; justify-content: flex-start; text-align: left; }
.case-study-pagination-next { grid-column: 2; justify-content: flex-end; text-align: right; }
.case-study-pagination > a:only-child { grid-column: 1 / -1; }
.case-study-pagination-copy { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.case-study-pagination-direction { font-family: 'Season Sans Regular', sans-serif; font-size: 15px; line-height: 1.4; color: var(--site-ink-muted); }
.case-study-pagination-title { font-family: 'Season Mix Regular', sans-serif; font-size: 32px; font-weight: 420; line-height: 1.2; letter-spacing: -.02em; text-wrap: balance; }
.case-study-pagination svg { width: 26px; height: 26px; flex: none; }
.case-study-pagination a:hover .case-study-pagination-title { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 6px; }
.case-study-pagination a:focus-visible { outline: 2px solid var(--site-accent); outline-offset: 8px; border-radius: 2px; }
@media (max-width: 809px) {
  .case-study-pagination { width: calc(100% - 48px); gap: 24px; margin-top: 16px; padding: 32px 0; }
  .case-study-pagination a { gap: 12px; align-items: flex-start; }
  .case-study-pagination-direction { font-size: 13px; }
  .case-study-pagination-title { font-size: 24px; }
  .case-study-pagination svg { width: 20px; height: 20px; margin-top: 2px; }
}

/* Case-study body, hand-built (Ship AI Studio first). Replaces Framer's three
   per-breakpoint copies of each block with one semantic column. Text sits in a
   700px measure; figures bleed past the text edge and their captions line up
   with it. Spacing follows the Framer pages: 120 / 96 / 72px between sections.
   The eyebrow rests 96px below the nav at every width, as on the live site
   (176px from the top on desktop under the 80px nav, 160px under the 64px one):
   .cs-intro's 64px top padding recreates the Framer hero section's 48 + 16px. */
.cs {
  --cs-pad: 30px; --cs-bleed: 30px; --cs-video-bleed: 30px;
  --cs-section: 72px; --cs-gap: 40px; --cs-radius: 24px;
  width: 100%; box-sizing: border-box;
  padding: 0 var(--cs-pad);
  color: var(--site-ink-muted);
  font-family: var(--type-sans); font-size: var(--type-body); line-height: 1.5;
}
@media (min-width: 810px) {
  .cs { --cs-pad: 94px; --cs-bleed: 64px; --cs-video-bleed: 64px; --cs-section: 96px; --cs-gap: 48px; }
}
@media (min-width: 1200px) {
  .cs { --cs-pad: max(118px, calc((100% - 1204px) / 2)); --cs-bleed: 30px; --cs-video-bleed: 54px; --cs-section: 120px; --cs-gap: 64px; }
}
.cs > * { max-width: 1204px; margin-left: auto; margin-right: auto; }
.cs :where(p) { margin: 0; }
.cs a { color: var(--site-ink); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 4px; }
.cs a:hover { text-decoration-color: var(--site-ink-muted); }

.cs-eyebrow { margin: 0 0 48px; font-family: var(--type-sans-medium); font-weight: 550; font-size: var(--type-label); line-height: 1.25; color: var(--site-ink-muted); }
.cs-title { margin: 0; padding-bottom: 32px; border-bottom: 2px solid var(--site-ink); font-family: var(--type-mix); font-weight: 420; font-size: var(--type-h1); line-height: 1.2; letter-spacing: -0.005em; color: var(--site-ink); }
.cs-title em { font-family: "Season Mix Medium Italic", serif; font-weight: 580; font-style: italic; }

.cs-meta { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px 24px; margin: 32px 0 40px; }
@media (min-width: 810px) { .cs-meta { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.cs-meta dt { margin-bottom: 4px; font-family: var(--type-sans-medium); font-weight: 550; font-size: var(--type-small); line-height: 1.45; color: var(--site-ink-muted); }
.cs-meta dd { margin: 0; font-size: var(--type-small); line-height: 1.45; color: var(--site-ink); }

.cs-text { max-width: 700px; margin-left: 0; display: flex; flex-direction: column; gap: calc(var(--type-body) * 1.5); }
.cs-text h2 { margin: 0 0 calc(32px - var(--type-body) * 1.5); font-family: var(--type-mix); font-weight: 420; font-size: var(--type-h2); line-height: 1.25; color: var(--site-ink); }
.cs-goal strong { font-family: var(--type-sans-medium); font-weight: 550; color: var(--site-ink); }
/* Passcom puts the intro straight under the title (Ship AI puts the meta row
   there), so it needs the same 32px the meta row gets. */
.cs-title + .cs-text { margin-top: 32px; }

.cs-section { margin-top: var(--cs-section); }
.cs-section > * + * { margin-top: var(--cs-gap); }

.cs-figure { margin: var(--cs-gap) calc(-1 * var(--cs-bleed)) 0; max-width: none; }
.cs-figure img, .cs-figure video { display: block; width: 100%; height: auto; border-radius: var(--cs-radius); background-color: var(--site-surface); }
.cs-figure video { aspect-ratio: 3200 / 2120; object-fit: cover; }
.cs-figure-video { margin-left: calc(-1 * var(--cs-video-bleed)); margin-right: calc(-1 * var(--cs-video-bleed)); }
.cs-figure figcaption { margin-top: 12px; padding: 0 var(--cs-bleed); max-width: 700px; font-size: var(--type-small); line-height: 1.45; color: var(--site-ink-muted); }
.cs-figure-video figcaption { padding: 0 var(--cs-video-bleed); }
.cs-figure-inline { margin: 0; }
.cs-figure-inline figcaption { padding: 0; }
/* The hero section as Framer built it: 64px above the eyebrow and below the
   intro, with the dithered signal field filling it (up to 1392px wide) behind
   the text. The signal sits outside the appear-animated header, so it stays put
   while the text rises. 64 + 24 keeps the 88px gap above the video. */
.cs-intro { position: relative; padding: 64px 0; }
.cs-signal { position: absolute; z-index: 0; top: 0; bottom: 0; left: calc(-1 * var(--cs-pad)); right: calc(-1 * var(--cs-pad)); max-width: 1392px; margin: 0 auto; overflow: hidden; pointer-events: none; }
.cs-hero { position: relative; z-index: 1; }
.cs-intro + .cs-figure { margin-top: 24px; }

.cs-split { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--cs-gap); }
.cs-split > * + * { margin-top: 0; }
@media (min-width: 1200px) {
  .cs-split { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px; align-items: center; }
}

.cs-outcomes .cs-eyebrow { margin-bottom: 48px; }
.cs-outcomes > .cs-eyebrow + * { margin-top: 0; }
.cs-stat { display: flex; flex-direction: column; gap: 8px; }
.cs-stat > span:first-child { font-family: "Season Mix SemiBold", serif; font-weight: 670; font-size: var(--type-h1); line-height: 1.2; color: var(--site-ink); }
.cs-stat-sub { font-size: var(--type-lead); line-height: 1.5; color: var(--site-ink-muted); }
.cs-results { list-style: none; margin: var(--cs-gap) 0 0; padding: 0; border-top: 1px solid var(--site-line); }
.cs-results li { display: grid; grid-template-columns: minmax(0, 1fr); gap: 2px; padding: 16px 0; border-bottom: 1px solid var(--site-line); color: var(--site-ink); }
@media (min-width: 810px) { .cs-results li { grid-template-columns: 160px minmax(0, 1fr); gap: 24px; align-items: baseline; } }
.cs-results-label { font-family: var(--type-sans-medium); font-weight: 550; font-size: var(--type-small); color: var(--site-ink-muted); }
/* With the pagination's 24px margin this leaves 72px above its divider. */
.cs .cs-outcomes { margin-bottom: 48px; }

/* Two related images side by side (Cassette's track pages). Stacked on phones;
   from 810px they share one row, cropped to 4:3 so their heights match. */
.cs-pair { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
@media (min-width: 810px) {
  .cs-pair { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; }
  .cs-pair img { aspect-ratio: 4 / 3; object-fit: cover; }
  .cs-pair img:first-child { object-position: 58% 50%; }
}
