/* app/styles/globals.css */
/* Design tokens and base styles, copied verbatim from the static site (legacy/index.html, lines 12-120).
   Component styles move in with their components (stage 3 and later); values are never changed during the migration. */
/* ============================================================
   DESIGN TOKENS (temporary wireframe values, replace with final design)
   ============================================================ */
:root {
  /* Approved palette */
  --ink: #0A0D14;          /* Portfolio Ink: primary type, navigation, key outlines */
  --cyan: #00DFFF;         /* Signal Cyan: CTA, badges, bullets, active states. Use sparingly */
  --canvas: #FFFFFF;       /* Canvas White: page background, image borders */
  --rule: #D9DEE7;         /* Quiet Rule: dividers, subtle borders */
  --soft: #F7F8FA;         /* Soft Canvas: section backgrounds, subtle surfaces */
  --secondary: #536071;
  --color-accent-warm: #D7990F;   /* Warm Accent (mustard, from the Home armchair): small decorative marks only; never CTAs, links or active states (cyan stays the main accent) */
  /* Timeline active state, shared by Resume and case study timelines: soft Signal Cyan halo around the current dot */
  --tl-halo-size: 32px;
  --tl-halo: radial-gradient(circle, color-mix(in srgb, var(--cyan) 22%, transparent) 0 40%, color-mix(in srgb, var(--cyan) 8%, transparent) 62%, transparent 72%);    /* Figma variable "secondary": stage labels and product icons in The Process */

  /* Semantic tokens */
  --bg: var(--canvas);
  --surface: var(--soft);
  --placeholder: #EEF0F4;          /* temporary, placeholders only */
  --placeholder-line: var(--rule);
  --text: var(--ink);
  --text-muted: #5B6270;           /* temporary: secondary text not defined in palette yet */
  --border: var(--rule);
  --accent: var(--cyan);
  --focus: var(--ink);

  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-display: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
  --font-body: "Instrument Sans", system-ui, -apple-system, "Segoe UI", Arial, sans-serif;

  --container: 1200px;
  --gutter: clamp(20px, 4vw, 40px);   /* mobile minimum = --page-x-m */
  --section-y: clamp(56px, 8vw, 104px);
  --radius: 8px;

  /* Typography & spacing system (shared by all pages) */
  --space-label: 16px;     /* section label → H2 */
  --space-title: 20px;     /* H2 → body text */
  --space-lead: 24px;      /* H1 → intro text */
  --space-list: 16px;      /* between list-like paragraphs */
  --page-x: clamp(20px, 8.4375vw, 162px);   /* main container side padding: 162 at 1920 */
  --page-x-m: 20px;        /* mobile container side padding (≤ 600 px) */
  /* Content frame: the 1920 px Figma frame. Wider screens add equal margins on both sides, as the Home and About stages
     (max-width: var(--frame-max); margin: 0 auto). Full-width bands (header, footer, Resume) keep their background
     edge to edge and add --frame-gutter to their side paddings; it is 0 up to 1920 px (percent of the band's width). */
  --frame-max: 1920px;
  --frame-gutter: max(0px, calc((100% - var(--frame-max)) / 2));
  --fs-h2: clamp(34px, calc(2.5vw + 24.25px), 48px);   /* H2 below desktop: 34 at 390 → 48 from ~950 */
  --fs-h3-m: 26px;         /* H3 on mobile */

  color-scheme: light;
  box-sizing: border-box;
  padding-top: env(safe-area-inset-top, 0px);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

*, *::before, *::after { box-sizing: inherit; }
html { scroll-padding-top: env(safe-area-inset-top, 0px); }
/* The scrollbar's space is always reserved: a short page (Contact, no scrollbar on a tall window) keeps the same width as the
   others, so the header, footer and centred content do not jump sideways between pages. No effect with overlay scrollbars. */
html { scrollbar-gutter: stable; }
#main { flex: 1 0 auto; }   /* main takes the free height, so a short page still ends with the footer at the viewport bottom */
.site-header, .site-footer { flex-shrink: 0; }
/* Text selection: very light Signal Cyan with Ink text, site-wide */
::selection { background: #D9FAFF; color: #0A0D14; }
::-moz-selection { background: #D9FAFF; color: #0A0D14; }
body {
  margin: 0;
  min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column;   /* header · main · footer: footer closes the page */
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
a { color: inherit; }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; border-radius: 4px; }

.container { width: 100%; max-width: var(--container); margin: 0 auto; padding: 0 var(--gutter); }
.section { padding: var(--section-y) 0; }
.section + .section { border-top: 1px solid var(--border); }

h1, h2, h3 { margin: 0; line-height: 1.15; font-weight: 650; }
h1 { font-size: clamp(2rem, 5vw, 3.5rem); letter-spacing: -0.02em; }
h2 { font-size: clamp(1.5rem, 3vw, 2.25rem); letter-spacing: -0.01em; }
h3 { font-size: 1.125rem; }
p { margin: 0; max-width: 65ch; }
.muted { color: var(--text-muted); }
/* Line breaking, site-wide (see CLAUDE.md "Typography: line breaking"): headings balance their lines, running text avoids a one-word
   last line. :where() keeps both at zero specificity, so a component can override them locally. Sizes, weights and line heights are untouched;
   unsupported browsers simply wrap as before. */
:where(h1, h2, h3, h4, h5, h6) { text-wrap: balance; }
:where(p, li, dd, figcaption, blockquote) { text-wrap: pretty; }

/* Placeholder marker: every temporary element uses this so it is easy to find & replace */
.ph-text { color: var(--text-muted); }
.ph-media {
  background:
    repeating-linear-gradient(135deg, transparent 0 14px, var(--placeholder-line) 14px 15px),
    var(--placeholder);
  border-radius: var(--radius);
  display: grid;
  place-items: center;
  color: var(--text-muted);
  font-size: 0.875rem;
  text-align: center;
  padding: 16px;
}

/* ===== Responsive images (components/ui/Picture.tsx) ===== */
/* <picture> only chooses the file: it takes no box, so the <img> inside keeps the layout and selectors of the legacy site. */
picture { display: contents; }
/* Its <source> elements draw nothing, but as children of a flex or grid container they would count as items (and get
   the container's gap): take them out of the layout. */
picture > source { display: none; }
/* width / height attributes (from the original) reserve the space; the CSS width decides the size, the height follows
   the original's exact aspect ratio (--img-ratio, set by <Picture>) whichever variant loads. Zero specificity: any
   component rule that sets a height or an aspect-ratio wins. */
:where(picture > img) { height: auto; aspect-ratio: var(--img-ratio, auto); }

/* app/styles/site.css */
/* Site styles, ported verbatim from the static site (legacy/index.html, lines 121 to 2246), in the original order.
   One stylesheet on purpose: the cascade (order and specificity) and every class name stay exactly as before, so the
   React components render with the same look and the QA harness finds the same selectors. Sections for pages that are
   not ported yet (Home, About, Resume, Contact, case studies) are inactive until their markup arrives (stages 4 to 6).
   Base tokens and resets are in globals.css (legacy lines 12 to 120). */

/* ============== Skip link ============== */
.skip {
  position: absolute; left: 8px; top: -60px;
  background: var(--text); color: var(--bg);
  padding: 8px 12px; border-radius: 6px; z-index: 100; text-decoration: none;
}
.skip:focus { top: calc(8px + env(safe-area-inset-top, 0px)); }

/* ============== Header / Navigation (Figma 451:2105) ============== */
.site-header {
  position: sticky; top: env(safe-area-inset-top, 0px); z-index: 50;
  background: var(--canvas);
}
.nav {
  position: relative; height: 72px;
  /* 1920 frame: logo at x 165 (--nav-x); the menu ends --nav-x from the right edge (see .nav-list), so both sides match */
  --nav-x: clamp(16px, 8.594vw, 165px);
  padding: 0 calc(clamp(16px, 8.281vw, 159px) + var(--frame-gutter)) 0 calc(var(--nav-x) + var(--frame-gutter));
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
.logo { display: block; line-height: 0; color: var(--ink); text-decoration: none; }
.logo svg { display: block; width: 118px; height: auto; }   /* wordmark ~17 px type (was 100 x 22, ~14 px): a touch above the 14 px menu */
.logo svg path[fill="#0A0D14"] { stroke: currentColor; stroke-width: .18; paint-order: stroke; }   /* outlined glyphs: a hairline stroke lifts the weight slightly, toward the menu's Medium */
.nav-list {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  display: flex; align-items: flex-start; gap: 36px;
  list-style: none; margin: 0; padding: 0;
}
/* Desktop: the menu sits on the right, its right edge as far from the frame edge as the logo's left edge (--nav-x, centred
   frame above 1920 through --frame-gutter). The mobile menu (≤ 900 px) is unchanged. */
@media (min-width: 901px) {
  .nav-list { left: auto; right: calc(var(--nav-x) + var(--frame-gutter)); transform: translateY(-50%); }
}
.nav-list > li > a, .nav-trigger {
  display: inline-flex; flex-direction: column; gap: 8px;
  font-family: var(--font-display); font-weight: 500; font-size: 14px; line-height: 1.2;
  letter-spacing: 0; color: var(--ink); text-decoration: none; white-space: nowrap;
}
/* Underline. Hover: a short 18 x 2 px line in Secondary, centred under the label, grows from the centre (220 ms ease-out) and
   collapses back on leave; Projects keeps it while its dropdown is open. Active: the full-width 2 px Signal Cyan line,
   always shown, no hover animation (the active item never switches to the hover line). */
.nav-list > li > a::after, .nav-trigger::after {
  content: ""; display: block; height: 2px;   /* full label width, as before; only the paint differs per state */
  background: linear-gradient(var(--secondary), var(--secondary)) center / 18px 100% no-repeat;   /* hover: 18 px, centred */
  transform: scaleX(0); transform-origin: center; transition: transform 220ms ease-out;
}
.nav-list > li > a:hover::after, .nav-list > li > a:focus-visible::after,
.nav-trigger:hover::after, .nav-trigger:focus-visible::after, .nav-trigger[aria-expanded="true"]::after { transform: scaleX(1); }
.nav-list > li > a[aria-current="page"], .nav-trigger[aria-current="page"] {
  font-family: var(--font-body); font-weight: 700; line-height: normal;
}
.nav-list > li > a[aria-current="page"]::after, .nav-trigger[aria-current="page"]::after { background: var(--cyan); transform: none; transition: none; }   /* active: full-width cyan line */
@media (prefers-reduced-motion: reduce) { .nav-list > li > a::after, .nav-trigger::after { transition: none; } }

/* Projects dropdown (adapted from Aceternity "Navbar Menu"): the trigger is the old Projects item as a button (same type and
   underline). Panel under it, over the page, never moves the header: Canvas White, 1 px Quiet Rule, 8 px radius, the TwentySix card
   shadow. A 12 px invisible bridge (padding-top) keeps it open on the way down. Open 240 ms (site curve) from opacity 0 /
   scale .96 / -4 px; close 160 ms ease-in; the 80 / 150 ms hover delays live in JS. One Signal Cyan line (3 x 20, 8 px from
   the text) grows from its centre on hover (180 ms in / 120 ms out) and glides between items (200 ms); text never shifts. */
.nav-item { position: relative; }
.nav-trigger { background: none; border: 0; padding: 0; margin: 0; cursor: pointer; text-align: left; }
.nav-dropdown {
  position: absolute; left: 0; top: 100%; z-index: 60; padding-top: 12px;   /* panel's outer left edge on the left edge of "Projects" */
  visibility: hidden; pointer-events: none; transition: visibility 0s linear 160ms;
}
.nav-dropdown-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 20px; }
.nav-panel {
  position: relative; padding: 28px 24px 28px 12px;   /* top / bottom 20 + 8; left 12 = where the cyan line sits */
  background: var(--canvas); border: 0; border-radius: var(--radius); box-shadow: 0 4px 32px rgba(38, 38, 73, .10);
  opacity: 0; transform: translateY(-4px) scale(.96); transform-origin: top center;
  transition: opacity 160ms ease-in, transform 160ms ease-in;
}
.nav-item.is-open .nav-dropdown { visibility: visible; pointer-events: auto; transition: none; }
.nav-item.is-open .nav-panel {
  opacity: 1; transform: none;
  transition: opacity 240ms cubic-bezier(0.22, 1, 0.36, 1), transform 240ms cubic-bezier(0.22, 1, 0.36, 1);
}
.nav-dropdown-list a {
  position: relative; display: block; padding-left: 6px; margin-right: 2.6px;   /* text 18 px from the panel edge, 16 px clear of the edge line; 2.6 px keeps the panel at its 239 px */
  font-family: var(--font-display); font-weight: 500; font-size: 14px; line-height: 20px;
  color: var(--ink); text-decoration: none; white-space: nowrap;
}
/* Width is always reserved for the Semibold label (hidden copy), so the panel keeps one size whichever case is current */
.nav-dropdown-list a::after { content: attr(data-label); display: block; height: 0; overflow: hidden; visibility: hidden; font-weight: 600; }
/* Current case: Semibold + a fixed Signal Cyan line (2 x 20) on the panel's left edge (12 px panel padding to the left of the link).
   The moving hover line then turns Secondary and only marks the other case. */
.nav-dropdown-list a[aria-current="page"] { font-weight: 600; }
.nav-dropdown-list a[aria-current="page"]::before {
  content: ""; position: absolute; left: -12px; top: calc(50% - 10px); width: 2px; height: 20px; background: var(--cyan);
}
.nav-panel.has-current .nav-indicator { background: var(--secondary); }
.nav-dropdown-list a:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; border-radius: 2px; }
.nav-indicator {
  position: absolute; left: 0; top: 0; width: 2px; height: 20px; background: var(--cyan); pointer-events: none;   /* on the panel's left edge, inside it */
  translate: 0 var(--ind-y, 16px); scale: 1 0; opacity: 0;
  transition: translate 200ms cubic-bezier(0.22, 1, 0.36, 1), scale 120ms ease-in, opacity 120ms ease-in;
}
.nav-indicator.is-on { scale: 1 1; opacity: 1; transition: translate 200ms cubic-bezier(0.22, 1, 0.36, 1), scale 180ms cubic-bezier(0.22, 1, 0.36, 1), opacity 180ms cubic-bezier(0.22, 1, 0.36, 1); }
.nav-indicator.no-move { transition: none; }
@media (prefers-reduced-motion: reduce) {
  .nav-dropdown, .nav-item.is-open .nav-dropdown { transition: none; }
  .nav-panel, .nav-item.is-open .nav-panel { transform: none; transition: none; }
  .nav-indicator, .nav-indicator.is-on { transition: none; }
}

/* WhatsApp link (Figma 451:1865) */
.nav-actions { order: 3; display: flex; align-items: center; gap: 12px; }
/* Floating WhatsApp button (replaces the header pill). WhatsApp green is the brand colour of the service, not a palette token.
   Fixed bottom-right; JS lifts it (--wa-shift) so it stays 28 px above the footer once the footer scrolls in.
   Floating group: WhatsApp on top, Back to top below it, on one vertical axis. While Back to top is hidden WhatsApp
   sits in the bottom slot; when it shows (html.has-to-top) WhatsApp glides up by one button size + gap. Safe areas included. */
:is(.wa-float, .to-top) { --wa-size: 54px; --float-right: 30px; --float-bottom: 30px; --float-gap: 20px; }
@media (max-width: 900px) { :is(.wa-float, .to-top) { --wa-size: 50px; --float-right: 16px; --float-bottom: 20px; --float-gap: 16px; } }
.wa-float {
  position: fixed; z-index: 40;
  right: calc(var(--float-right) + env(safe-area-inset-right, 0px));
  bottom: calc(var(--float-bottom) + env(safe-area-inset-bottom, 0px));
  width: var(--wa-size); height: var(--wa-size); border-radius: 50%; background: #25D366;
  display: grid; place-items: center; text-decoration: none;
  box-shadow: 0 4px 14px rgba(10, 13, 20, 0.12);
  translate: 0 calc(-1 * var(--wa-shift, 0px));
  transition: transform 180ms ease-out, bottom 280ms cubic-bezier(0.22, 1, 0.36, 1), opacity 180ms ease-out, visibility 180ms;
}
.wa-float.is-yielding { opacity: 0; visibility: hidden; }   /* JS: the button is over a Hero word, CTA or text; it comes back as soon as it is clear */
html.has-to-top .wa-float { bottom: calc(var(--float-bottom) + env(safe-area-inset-bottom, 0px) + var(--wa-size) + var(--float-gap)); }
.wa-float svg { display: block; width: 28px; height: 28px; }
.wa-float:hover { transform: translateY(-2px); }
.wa-float:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; border-radius: 50%; }
@media (max-width: 900px) { .wa-float svg { width: 26px; height: 26px; } }
@media (prefers-reduced-motion: reduce) { .wa-float { transition: none; } .wa-float:hover { transform: none; } }
/* WhatsApp glyph: the logo is filled shapes; a 2.25-unit white stroke (viewBox 120, ~0.5 px) on both paths makes the ring and handset read heavier */
html:is(.is-lightbox-open, .is-proto-panel-open) :is(.wa-float, .to-top) { visibility: hidden; }   /* never over the Lightbox or the open TwentySix prototype panel */

/* Back to top: same size as WhatsApp (54 / 50 px), Ink circle, no border, Signal Cyan arrow like the CTA arrows (the site's ↗ glyph turned to ↑),
   bottom slot of the floating group, centred under WhatsApp; follows it when the footer pushes the group up (--wa-shift).
   Hidden until the page is scrolled about one viewport; hover / focus = the shared CTA active state (Signal Cyan). */
.to-top {
  position: fixed; z-index: 40;
  right: calc(var(--float-right) + env(safe-area-inset-right, 0px));
  bottom: calc(var(--float-bottom) + env(safe-area-inset-bottom, 0px));
  width: var(--wa-size); height: var(--wa-size); padding: 0; border: 0; border-radius: 50%; cursor: pointer;
  background: var(--ink); color: var(--cyan);
  display: grid; place-items: center;
  box-shadow: 0 0 0 1px var(--rule), 0 4px 14px rgba(10, 13, 20, 0.12);   /* 1 px Quiet Rule ring (no size change): melts into light pages, outlines the button on the Ink stats band */
  translate: 0 calc(-1 * var(--wa-shift, 0px));
  opacity: 0; visibility: hidden; transform: translateY(8px);
  transition: opacity 240ms ease-out, transform 240ms ease-out, visibility 0s linear 240ms, background-color 380ms cubic-bezier(0.22, 1, 0.36, 1);
}
.to-top.is-visible { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }
.to-top .btn-arrow-svg { width: 36px; height: 36px; translate: 0 0.5px; }   /* same SVG scaled (arrow 12.5 x 14 px, line ~2.3 px like the WhatsApp glyph); 0.5 px down = arrow box on the circle's centre */
@media (max-width: 900px) { .to-top .btn-arrow-svg { width: 34px; height: 34px; translate: 0 0.38px; } }
.to-top .btn-arrow-svg path { fill: var(--cyan); transition: fill 380ms cubic-bezier(0.22, 1, 0.36, 1); }   /* same as .work-cta */
.to-top:is(:hover, :focus-visible) { background: var(--cyan); }                                            /* shared CTA active state: */
.to-top:is(:hover, :focus-visible) .btn-arrow-svg path { fill: var(--ink); }                               /* Cyan fill, Ink arrow */
.to-top:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .to-top, .to-top.is-visible { transform: none; } }

/* Arrow icons: the provided SVGs (Property 1=Default / down), 22 x 22, used as is */
.btn-arrow-svg { display: block; width: 22px; height: 22px; }
/* The arrow sits 0.87 px off-centre inside each 22 px artboard (up-right arrow higher, down-right lower);
   nudge the SVG so the glyph lines up with the button's centre line and the label. */
.btn-arrow-svg--up   { transform: translateY(0.8715px); }
.btn-arrow-svg--down { transform: translateY(-0.8715px); }

.menu-btn {
  display: none; background: none; border: 1px solid var(--ink); color: var(--ink);
  border-radius: 999px; padding: 6px 14px; cursor: pointer;
  font-family: var(--font-display); font-weight: 500; font-size: 14px;
}
@media (max-width: 900px) {
  .menu-btn { display: block; }
  .nav-list {
    display: none; transform: none; left: 0; right: 0; top: 72px;
    flex-direction: column; gap: 0; padding: 8px 16px 16px;
    background: var(--canvas); border-bottom: 1px solid var(--rule);
  }
  .nav-list.open { display: flex; }
  .nav-list > li > a, .nav-trigger { padding: 12px 0; font-size: 16px; }
  /* mobile menu: Projects toggles its two cases as an indented list, no panel, no motion */
  .nav-dropdown { position: static; translate: none; padding: 0; display: none; visibility: visible; pointer-events: auto; transition: none; }
  .nav-item.is-open .nav-dropdown { display: block; }
  .nav-dropdown-list { gap: 0; }
  .nav-panel, .nav-item.is-open .nav-panel { padding: 0 0 8px 16px; background: none; border: 0; border-radius: 0; box-shadow: none; opacity: 1; transform: none; transition: none; }
  .nav-dropdown-list a { padding: 10px 0 10px 11px; font-size: 16px; line-height: 20px; }
  .nav-indicator { display: none; }
}

/* ============== Buttons ============== */
/* Port note: on the static site a stray "}" stood right before this rule, so browsers dropped `.btn` and it never
   applied. Kept inactive (commented out) to render exactly as before; the build's CSS parser rejects the stray brace.
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 48px; padding: 0 24px; border-radius: 999px;
  background: var(--text); color: var(--bg);
  text-decoration: none; font-weight: 550;
}
*/
.link { color: var(--ink); font-weight: 550; text-decoration: underline; text-decoration-color: var(--cyan); text-decoration-thickness: 2px; text-underline-offset: 4px; }

/* ============== Home: Hero (Figma 345:7779 "Clean light hero") ==============
   Desktop reproduces the 1920 x 1080 frame (hero area = 1008px under the 72px nav).
   --u = 1 Figma px at 1920 wide, scales down proportionally.                     */
.hero { container-type: inline-size; max-width: 1920px; margin: 0 auto; background: var(--canvas); overflow: hidden; }
.hero-stage {
  --u: calc(100cqw / 1920);
  position: relative; height: calc(1008 * var(--u) + clamp(0px, (1440px - 100cqw) * 0.3, 120px));   /* below 1440 the text stops scaling (min sizes), so the stage gets up to 120 px more room under the group */
  color: var(--ink);
}
.hero-stage > * { position: absolute; margin: 0; }

.sr-only { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* "Senior / Product" 345:7991 */
.hero-title-top {
  left: calc(160 * var(--u)); top: calc(66 * var(--u));
  display: flex; flex-direction: column; gap: calc(8 * var(--u));
  font-family: var(--font-display); text-transform: uppercase; line-height: 1;
  z-index: 2;
}
.hero-senior { font-weight: 400; font-size: max(16px, calc(40 * var(--u))); }   /* 16 px floor: only below 768 px */
.hero-display {
  font-family: var(--font-display); font-weight: 700; font-size: calc(150 * var(--u));
  line-height: 1; letter-spacing: -0.04em; text-transform: uppercase; white-space: nowrap;
}

/* "Designer" + description 345:7968 */
.hero-bottom {
  left: calc(964 * var(--u)); top: calc(755 * var(--u));
  display: flex; flex-direction: column; gap: calc(4 * var(--u));
  z-index: 2;
}
.hero-desc {
  width: max(calc(410 * var(--u)), 272px);
  font-family: var(--font-body); font-weight: 400; font-size: max(calc(20 * var(--u)), clamp(15px, calc(15px + (1280px - 100cqw) / 180), 16px)); line-height: 1.6;   /* 15 px at 1280+, 16 px from 1100 down */
}

/* Photo stack 345:7958. Box 820 x 820 centred on the group centre (958, 454) */
.hero-photos {
  left: calc(548 * var(--u)); top: calc(44 * var(--u));
  width: calc(820 * var(--u)); aspect-ratio: 1;
  container-type: inline-size;
  z-index: 1;
}
.photo {
  --p: calc(100cqw / 820);
  position: absolute; left: 50%; top: 50%;
  border: max(3px, calc(6 * var(--p))) solid var(--canvas);
  background: var(--placeholder);
  overflow: hidden;
}
.photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.photo--1, .photo--2 {
  width: calc(504.489 * var(--p)); height: calc(345.177 * var(--p));
  box-shadow: 0 0 calc(32 * var(--p)) rgba(99, 99, 99, 0.1);
}
/* One transform chain for every photo:
   position → layout angle (--r) → sway (--sway) around a pin in the photo's top-left corner.
   --r / --off are the final Figma values; the intro animates them from a flat stack.
   --pin moves the pivot slightly inside the frame corner, where a real pin would sit. */
@property --r    { syntax: "<angle>";  inherits: false; initial-value: 0deg; }
@property --off  { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --sway { syntax: "<angle>";  inherits: false; initial-value: 0deg; }
.photo {
  --pin: 0px;
  transform: translate(-50%, calc(-50% + var(--off))) rotate(var(--r))
             translate(calc(-50% + var(--pin)), calc(-50% + var(--pin)))
             rotate(var(--sway))
             translate(calc(50% - var(--pin)), calc(50% - var(--pin)));
}
.photo--1 { --r: -6.29deg; --off: calc(8 * var(--p)); }
.photo--2 { --r: 4.48deg;  --off: calc(8 * var(--p)); }
.photo--3 {
  --r: 24.56deg; --off: 0px; --pin: calc(9 * var(--p));
  width: calc(509.345 * var(--p)); height: calc(636.455 * var(--p));
  box-shadow: 0 calc(18 * var(--p)) calc(40 * var(--p)) rgba(0, 0, 0, 0.13);
}

/* Intro, stage 1: the stack fades in, flat and aligned. Stage 2: the photos spread to their angles. */
/* The fade runs on the stack as a whole, so the photos never show through each other */
.hero-photos.is-pending { opacity: 0; }
.hero-photos.is-intro { animation: stackIn 520ms cubic-bezier(.3, 0, .2, 1) 0ms both; }
.hero-photos.is-intro .photo {
  animation: stackSpread 1100ms cubic-bezier(.35, 0, .15, 1) var(--spread-delay, 620ms) both;
  will-change: transform;
}
.hero-photos.is-intro .photo--2 { --spread-delay: 660ms; }
.hero-photos.is-intro .photo--1 { --spread-delay: 700ms; }
@keyframes stackIn     { from { opacity: 0; translate: 0 14px; } to { opacity: 1; translate: 0 0; } }
@keyframes stackSpread { from { --r: 0deg; --off: 0px; } }
/* The front photo is not animated by CSS: JS drives its spread and swing as one motion. */
.hero-photos.is-intro .photo--3 { animation: none; }

/* Hero text entrance: starts when the photos have spread (JS), independent of the pendulum.
   Left group (SENIOR + PRODUCT) comes from the left, right group (badge, DESIGNER + text) from the right. */
.hero-stage.text-pending :is(.hero-title-top, .hero-badge, .hero-bottom) { opacity: 0; }
/* Motion: 1300 ms, 24 px. Both movement and opacity start from zero speed (no jolt at the start) and
   spend their last third settling very slowly (no hard stop). Opacity follows the slide, so the text
   is visible for most of its travel instead of arriving already in place. */
.hero-stage { --text-in: 1300ms; --text-shift: 24px; }
.hero-stage.text-in .hero-title-top {
  animation: heroTextFromLeft var(--text-in) cubic-bezier(.4, 0, .1, 1) both,
             heroTextFade var(--text-in) cubic-bezier(.35, 0, .25, 1) both;
}
.hero-stage.text-in :is(.hero-badge, .hero-bottom) {
  animation: heroTextFromRight var(--text-in) cubic-bezier(.4, 0, .1, 1) both,
             heroTextFade var(--text-in) cubic-bezier(.35, 0, .25, 1) both;
}
@keyframes heroTextFromLeft  { from { translate: calc(-1 * var(--text-shift)) 0; } to { translate: 0 0; } }
@keyframes heroTextFromRight { from { translate: var(--text-shift) 0; } to { translate: 0 0; } }
@keyframes heroTextFade      { from { opacity: 0; } to { opacity: 1; } }

/* Only the photo itself reacts to the pointer: decorative headline boxes let it through */
.hero-title-top, .hero-bottom { pointer-events: none; }
.hero-desc { pointer-events: auto; }
.photo.is-empty {
  background:
    repeating-linear-gradient(135deg, transparent 0 14px, var(--placeholder-line) 14px 15px),
    var(--placeholder);
  display: grid; place-items: center; text-align: center;
  font-family: var(--font-body); font-size: 12px; color: var(--text-muted); padding: 12px;
}

/* Industry list 345:7975 */
.hero-services {
  left: calc(1301 * var(--u)); top: min(calc(473 * var(--u)), calc(739 * var(--u) - 111px));   /* small stages: the list rises just enough to end 8 px above the badge (111 = badge clearance 40 + gap 8 + three 14 px lines 63); unchanged from ~800 px up */
  list-style: none; padding: 0;
  display: flex; flex-direction: column; gap: calc(8 * var(--u));
  z-index: 2;
}
.hero-services li {
  display: flex; align-items: center; gap: 12px;
  font-family: var(--font-display); font-size: max(calc(14 * var(--u)), clamp(12px, calc(12px + (1280px - 100cqw) / 90), 14px)); line-height: 1.5;   /* 12 px at 1280+, 14 px (the phone size) from 1100 down */
  letter-spacing: -0.04em; white-space: nowrap;
}
.hero-services li::before { content: ""; width: 4px; height: 4px; background: var(--cyan); flex: none; }

/* Experience badge 345:7962 */
.hero-badge {
  left: calc(1060 * var(--u)); top: min(calc(659 * var(--u)), calc(755 * var(--u) - 40px));   /* the badge is 32 px tall at every size: on small stages it stays 8 px clear of DESIGNER */
  background: var(--cyan); border: 1px solid var(--cyan); border-radius: 0;   /* square corners, per review comment */
  padding: 8px;   /* same padding as the "A little about me" label */
  font-family: var(--font-display); font-weight: 500; font-size: clamp(12px, calc(12px + (1280px - 100cqw) / 180), 13px); line-height: 1.2;   /* 12 px at 1280+, 13 px from 1100 down */
  letter-spacing: -0.04em; white-space: nowrap;
  z-index: 3;
}

/* Hero CTAs (Figma 479:1568 "btns"): primary 479:1564 + secondary 451:1406, 24 px apart */
.hero-ctas {
  left: calc(162 * var(--u)); top: calc(843 * var(--u));
  max-width: calc(700 * var(--u));   /* the space left of DESIGNER minus a clear gap: below ~960 px the two buttons stack instead of crowding it */
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px 24px;
  z-index: 3;
}
.hero-btn {
  display: inline-flex; align-items: center; gap: 12px;
  padding: 12px 16px 12px 24px; border-radius: 50px;
  font-family: var(--font-body); font-weight: 700; font-size: 12px; line-height: normal;
  letter-spacing: 0; text-transform: uppercase; white-space: nowrap; text-decoration: none;
}
.hero-btn:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
.hero-btn--primary { background: var(--ink); color: var(--canvas); }
.hero-btn--secondary {
  background: var(--canvas); color: var(--ink);
  border: 1px solid var(--cyan); padding: 11px 15px 11px 23px;   /* inside stroke: same 46 px height as primary */
}
.hero-btn-arrow { position: relative; width: 22px; height: 22px; overflow: hidden; flex: none; }
#first-project { scroll-margin-top: calc(72px + 24px); }   /* VIEW CASE STUDY lands here: clear of the sticky nav */

/* Tablet (601-900) keeps the desktop artboard above: same positions, same proportions, so there is no jump at 900/901.
   Phones: the words need the full width to stay expressive, so the diagonal is kept vertically:
   SENIOR PRODUCT, the stack tucked under PRODUCT, the badge on the stack's lower right (as on desktop),
   DESIGNER overlapping the stack's lower corner, then description, industries and the CTAs last.
   --hd is the display size; every overlap is a fraction of it, so it scales with the type. */
@media (max-width: 600px) {
  .hero-stage { --hd: clamp(56px, 17vw, 120px); --u: 1px; height: auto; display: grid; grid-template-columns: minmax(0, 1fr); align-content: start; padding: 32px var(--gutter) 56px; }
  .hero-stage > * { position: static; grid-column: 1; }   /* one column: the badge shares the stack's cell */
  .hero-title-top { grid-row: 1; gap: 4px; }
  .hero-senior { font-size: clamp(20px, 5vw, 32px); }
  .hero-display { font-size: var(--hd); }
  .hero-photos { grid-row: 2; position: relative; left: auto; top: auto; width: 100%; margin: calc(var(--hd) * -0.65) 0 calc(var(--hd) * -0.63); }   /* relative: the .photo cards are placed in THIS box. PRODUCT overlaps the top of the stack, DESIGNER its lower corner (both have the higher z-index) */
  .hero-badge { grid-row: 2; justify-self: end; align-self: end; margin-bottom: calc(var(--hd) * 0.3); }   /* on the stack, just above DESIGNER, straddling the photo edge like on desktop */
  .hero-bottom { grid-row: 3; align-items: flex-end; gap: 12px; }
  .hero-desc { width: 100%; max-width: 410px; align-self: flex-start; font-size: 17px; }
  .hero-services { grid-row: 4; flex-direction: row; flex-wrap: wrap; gap: 8px 20px; margin-top: 20px; }
  .hero-services li { font-size: 14px; }
  .hero-ctas { grid-row: 5; max-width: none; justify-self: start; margin-top: 28px; gap: 12px; }
}

/* ============== Project page: hero (Figma 341:6908 "B2B financial management case study") ==============
   Frame 1920 x 1443. Content column 1432px (x 244), starts 58px under the 72px nav.        */
.case-hero { background: var(--canvas); padding: 58px 0 104.38px; }
.case-hero-inner {
  width: min(1432px, calc(100% - 2 * var(--gutter)));
  margin: 0 auto;
  display: flex; flex-direction: column; align-items: center; gap: 48px;
}
.case-title { width: min(1191.23px, 100%); display: flex; flex-direction: column; align-items: center; gap: 48px; color: var(--ink); }
.case-heading { width: min(1090.56px, 100%); display: flex; flex-direction: column; align-items: center; gap: 5.593px; text-align: center; }
.case-eyebrow {
  display: flex; align-items: flex-start; justify-content: center; gap: 8px; margin: 0;
  font-family: var(--font-body); font-weight: 700; font-size: 16px; line-height: normal;
  letter-spacing: 0; text-transform: uppercase; white-space: nowrap;
}
.case-eyebrow-icon { width: 20.168px; height: 19.454px; flex: none; display: block; object-fit: contain; }
.case-eyebrow-icon.is-empty { background: var(--placeholder); outline: 1px dashed var(--rule); }
.case-h1 {
  margin: 0;
  font-family: var(--font-body); font-weight: 700; font-size: clamp(34px, 5vw, 64px); line-height: 1.1; letter-spacing: 0;
}
.case-meta { list-style: none; margin: 0; padding: 0; width: 100%; display: flex; gap: 44px; }
.case-meta li {
  flex: 1 0 0; min-width: 0;
  display: flex; flex-direction: column; gap: 4px;
  font-family: var(--font-body); line-height: normal; letter-spacing: 0; color: var(--ink);
}
.case-meta li:not(:last-child) { border-right: 1px solid var(--rule); }
.case-meta-label { font-weight: 400; font-size: 12px; }
.case-meta-value { font-weight: 600; font-size: 16px; }

/* Product visuals: desktop dashboard 1432 x 863 + mobile screen 280 x 608.96 overlapping it */
.case-visual { position: relative; width: 100%; container-type: inline-size; }
.case-dashboard {
  width: 100%; aspect-ratio: 1432 / 863;
  border-radius: calc(16 / 1432 * 100cqw);
  overflow: hidden;
  filter: drop-shadow(0 calc(8 / 1432 * 100cqw) calc(85 / 1432 * 100cqw) rgba(38, 38, 73, 0.2));
  background: var(--canvas);
}
.case-mobile {
  position: absolute;
  left: calc(1172 / 1432 * 100%); top: calc(270.38 / 863 * (100cqw * 863 / 1432));   /* right edge 20 px past the dashboard (was x 1106 in Figma) */
  width: calc(280 / 1432 * 100%); aspect-ratio: 280 / 608.96;
  border-radius: calc(24.362 / 1432 * 100cqw);
  overflow: hidden;
  background: #fbfbfb;  /* mockup surface from Figma, not a palette colour */
  box-shadow: 0 calc(6.09 / 1432 * 100cqw) calc(129.422 / 1432 * 100cqw) rgba(38, 38, 73, 0.25);
}
.case-dashboard img, .case-mobile img { width: 100%; height: 100%; object-fit: cover; display: block; }
.case-shot-empty {
  width: 100%; height: 100%;
  background:
    repeating-linear-gradient(135deg, transparent 0 14px, var(--placeholder-line) 14px 15px),
    var(--placeholder);
  display: grid; place-items: center; text-align: center; padding: 8px;
  font-family: var(--font-body); font-size: 12px; color: var(--text-muted);
}

/* ---------- Hero intro animation (runs once per page view) ----------
   The end-state PNGs are always the visible truth. Small "base state" patches cut from the
   base exports cover the KPIs, bars, labels, dates and the donut ring, then get removed.   */
@property --sweep { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
.case-dashboard { position: relative; }
.case-anim { position: absolute; inset: 0; pointer-events: none; }
.anim-patch { position: absolute; display: block; background-repeat: no-repeat; }
/* Stage 1: the two screens rise into place (outer containers only). */
.case-visual.is-pending .case-dashboard,
.case-visual.is-pending .case-mobile { opacity: 0; }
.case-visual { --ease-rise: cubic-bezier(.3, 0, .15, 1); }
.case-visual.is-intro .case-dashboard { --rise: 40px; animation: riseIn 850ms var(--ease-rise) 0ms both; }
.case-visual.is-intro .case-mobile    { --rise: 36px; animation: riseIn 850ms var(--ease-rise) 200ms both; }
.case-visual.is-intro .case-dashboard,
.case-visual.is-intro .case-mobile { will-change: transform, opacity; }
@keyframes riseIn {
  from { opacity: 0; transform: translate3d(0, var(--rise), 0); }
  to   { opacity: 1; transform: none; }
}
/* Stage 2: data inside the screens (patches). Starts only after both screens have stopped. */
/* Easing: soft start, long gentle landing. One family of curves for every stage. */
.case-visual { --ease-fade: cubic-bezier(.45, 0, .25, 1); --ease-grow: cubic-bezier(.4, 0, .15, 1); }
.is-playing .anim-kpi,
.is-playing .anim-date,
.is-playing .anim-label { animation: patchOut var(--t) var(--ease-fade) var(--d) both; }
.is-playing .anim-bar { animation: barGrow var(--t) var(--ease-grow) var(--d) both; }
.anim-donut {
  -webkit-mask-image: conic-gradient(from 0deg at 50% 50%, transparent var(--sweep), #000 0);
          mask-image: conic-gradient(from 0deg at 50% 50%, transparent var(--sweep), #000 0);
}
.is-playing .anim-donut { animation: donutSweep var(--t) cubic-bezier(.45, 0, .2, 1) var(--d) both; }
@keyframes patchOut { to { opacity: 0; } }
@keyframes barGrow { from { clip-path: inset(0 0 0 0); } to { clip-path: inset(0 0 100% 0); } }
@keyframes donutSweep { from { --sweep: 0deg; } to { --sweep: 360deg; } }

@media (max-width: 900px) {
  .case-hero { padding: 40px 0 96px; }
  .case-title { gap: 32px; }
  .case-meta { display: grid; grid-template-columns: 1fr 1fr; gap: 20px 24px; }
  .case-meta li:not(:last-child) { border-right: 0; }
  .case-meta li { padding-bottom: 12px; border-bottom: 1px solid var(--rule); }
  .case-eyebrow { white-space: normal; }
}


/* ============== Project page: stats (Figma 423:1380 "section-kpi") ============== */
.case-stats { background: var(--ink); }
.case-stats-inner {
  width: min(1272px, calc(100% - 2 * var(--gutter))); margin: 0 auto;
  padding: 60px 0 60px 5px;                /* frame content starts at x 329 */
  display: flex; align-items: flex-start; gap: 24px;
}
.case-stats-label {
  flex: none; width: 292px; margin: 0;
  font-family: var(--font-display); font-weight: 500; font-size: 24px; line-height: 1.25; letter-spacing: 0;
  color: var(--rule); opacity: .8; white-space: nowrap;
}
.case-stats-list { list-style: none; margin: 0; padding: 0; display: flex; align-items: flex-start; gap: 10px; height: 134px; }
.case-stat { display: flex; align-items: center; gap: 100px; }
.case-stat + .case-stat { padding-left: 100px; }
.case-stat-body { display: flex; flex-direction: column; gap: 12px; white-space: nowrap; }
.case-stat-value { font-family: var(--font-body); font-weight: 700; font-size: 64px; line-height: 1.1; color: var(--cyan); }
/* Count-up: while counting, the number box keeps its final width and is right-aligned,
   so the "K+" suffix never moves. Nothing else about the value changes. */
.case-stat-num { display: inline-block; text-align: right; }
.case-stat-caption { font-family: var(--font-body); font-weight: 400; font-size: 20px; line-height: 1.6; color: var(--canvas); }
.case-stat-divider { align-self: stretch; width: 1px; background: var(--rule); opacity: .3; }
/* Isracard: label (292) + 24 + the two stats with their 100 px spacing (612) need 933 px of content width, which the row no longer has
   below ~1013 px (about 150 % zoom on a 1440 screen), so the stats ran 11-68 px past the screen. In that range the label moves above
   the stats (as on phones) while the stats keep their desktop row, divider and spacing. */
@media (min-width: 901px) and (max-width: 1040px) {
  .case-stats:not(.ts-stats) .case-stats-inner { flex-direction: column; gap: 32px; }
  .case-stats:not(.ts-stats) .case-stats-label { width: auto; }
}

/* ============== Project page: overview (Figma 442:2075) ============== */
/* Content column (Figma 486:1614): 1276 px wide at x 319 of the 1920 frame */
.case-content {
  width: min(1276px, calc(100% - 2 * var(--gutter)));
  margin-left: max(var(--gutter), calc(50% - 641px));
  padding-bottom: 120px;
  color: var(--ink);
}
.case-overview { width: 100%; color: var(--ink); }
.ov-company { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-title); padding: 100px 0 60px; }   /* Figma 409:2820 */
.ov-title { margin: 0; font-family: var(--font-display); font-weight: 700; font-size: 48px; line-height: 1.1; letter-spacing: 0; }
.ov-text { width: 937px; max-width: 100%; font-family: var(--font-body); font-weight: 400; font-size: 20px; line-height: 1.6; }
.ov-text p { margin: 0; max-width: none; }
.case-overview p, .case-stats p { max-width: none; }
.ov-text p + p { margin-top: 32px; }            /* one empty line, as in Figma */
.ov-details { width: 1252px; max-width: 100%; display: flex; flex-direction: column; gap: 40px; }   /* Overview → Design goals: the section gap only (120 / 80) */
.ov-label {
  margin: 0; font-family: var(--font-display); font-weight: 400; font-size: 12px; line-height: 1.2;
  letter-spacing: 1.2px; text-transform: uppercase; white-space: nowrap;
  color: var(--secondary);   /* section / service labels; state and decorative labels override */
}
.ov-row { display: flex; align-items: flex-start; gap: 144px; }
.ov-block { display: flex; flex-direction: column; align-items: flex-start; gap: 24px; padding-top: 24px; }
.ov-block--timeline { padding-right: 32px; }
.ov-block--platforms { width: 227px; padding-bottom: 24px; align-self: stretch; }
.ov-timeline { position: relative; width: 132px; height: 70px; }
.ov-timeline-value { position: absolute; left: 0; top: 0; font-family: var(--font-body); font-weight: 700; font-size: 64px; line-height: 1.1; white-space: nowrap; }
.ov-timeline-unit { position: absolute; left: 85px; top: 35px; white-space: pre; line-height: 32px; }
.ov-timeline-unit .sp { font-family: var(--font-display); font-weight: 700; font-size: 16px; }
.ov-timeline-unit .word { font-family: var(--font-body); font-weight: 400; font-size: 20px; }
.ov-body { margin: 0; font-family: var(--font-body); font-weight: 400; font-size: 20px; line-height: 1.6; white-space: pre; }
.ov-body--strong { font-weight: 600; }
.ov-role { display: flex; flex-direction: column; gap: 32px; padding-top: 24px; }
.ov-role-list { list-style: none; margin: 0; padding: 0; display: flex; align-items: flex-start; width: 100%; }
.ov-role-item { flex: 0 0 250px; display: flex; flex-direction: column; justify-content: center; gap: 16px; }
.ov-role-mark { display: flex; align-items: center; }
.ov-role-mark::before { content: ""; width: 12px; height: 12px; border-radius: 10px; background: var(--cyan); flex: none; }
.ov-role-mark::after { content: ""; flex: 1 0 0; height: 1px; background: var(--rule); }
.ov-role-name { font-family: var(--font-body); font-weight: 600; font-size: 20px; line-height: 1.6; }
/* Progressive reveal (JS adds .is-armed only when motion is allowed, removes it when done).
   The line segment of each step is drawn via --seg; dot and label get .is-dot / .is-text in turn. */
.ov-role-list.is-armed .ov-role-mark::after { transform: scaleX(var(--seg, 0)); transform-origin: left center; }
.ov-role-list.is-armed .ov-role-mark::before {
  opacity: 0; transform: scale(.6);
  transition: opacity 220ms ease-out, transform 220ms cubic-bezier(.2, .7, .2, 1);
}
.ov-role-list.is-armed .ov-role-item.is-dot .ov-role-mark::before { opacity: 1; transform: none; }
.ov-role-list.is-armed .ov-role-name {
  opacity: 0; transform: translateY(8px);
  transition: opacity 350ms cubic-bezier(.2, .7, .2, 1), transform 350ms cubic-bezier(.2, .7, .2, 1);
}
.ov-role-list.is-armed .ov-role-item.is-text .ov-role-name { opacity: 1; transform: none; }
.ov-collab { padding-right: 32px; }
/* Collaborated with (Figma 471:1638) */
.ov-collab-body { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.ov-team { display: flex; align-items: center; gap: 4px; }
.ov-avatars { display: flex; align-items: center; list-style: none; margin: 0; padding: 0; }
/* One avatar style for every case study: 44 px circle, 2 px white ring, overlap 4 px; colour per avatar (inline), photo or initials */
.ov-avatar {
  width: 44px; height: 44px; border-radius: 24px; flex: none;
  box-shadow: 0 0 0 2px var(--canvas);   /* 2 px white ring (review): separates overlapping avatars, no layout shift */
  display: flex; align-items: center; justify-content: center;
  padding: 7.5px 8px 8.5px;          /* initials optically centred: caps sit 0.5 px higher (Figma had 8/8/8/9) */
  font-family: var(--font-display); font-weight: 600; font-size: 16px; line-height: 1.4; color: var(--canvas);
}
.ov-avatar--ink { color: var(--ink); }   /* initials on a light avatar colour */
/* The next avatar covers the right 4 px, so the visible circle's centre sits further left:
   move the initials 1.25 px left on every avatar except the last, uncovered one. */
.ov-avatar:not(:last-child) { margin-right: -4px; padding-right: 10.5px; }
.ov-avatar.ov-avatar--photo { padding: 0; overflow: hidden; }   /* photo fills the same 44 px circle */
.ov-avatar--photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.ov-team-more { font-family: var(--font-body); font-weight: 400; font-size: 20px; line-height: 1.6; }
/* Avatar tooltip (after Avatar Group by Chetan Verma, motion principle only): one white card per group above the hovered / tapped /
   focused avatar: name (display 600, Ink) over role (body 14, Secondary), radius 12, soft shadow. Out of flow, so nothing moves;
   mountAvatarTips places it, keeps it inside the screen and below the sticky header. +6 has none. */
.ov-team { position: relative; }
.ov-avatar { position: relative; }
.ov-avatar-btn { position: absolute; inset: 0; margin: 0; padding: 0; border: 0; border-radius: inherit; background: transparent; cursor: default;
  -webkit-tap-highlight-color: transparent; }
.ov-avatar-btn:focus-visible { outline: none; }
.ov-avatar:has(.ov-avatar-btn:focus-visible) { outline: 2px solid var(--focus); outline-offset: 3px; z-index: 1; }   /* the photo circle clips its content, so the ring sits on the avatar */
.ov-tip { position: absolute; left: 0; top: 0; z-index: 5; display: flex; flex-direction: column; align-items: center; gap: 2px;
  width: max-content; max-width: calc(100vw - 32px); padding: 10px 16px;   /* own width (not the narrow avatar row's), wraps only on a very narrow screen */ border-radius: 12px; background: var(--canvas);
  box-shadow: 0 4px 32px 0 rgba(38, 38, 73, .14), 0 1px 3px rgba(38, 38, 73, .08); text-align: center; pointer-events: none;
  opacity: 0; visibility: hidden; transform: translateY(6px);
  transition: opacity 150ms ease, transform 150ms ease, visibility 0s 150ms; }
.ov-tip.is-on { opacity: 1; visibility: visible; transform: none;
  transition: opacity 220ms cubic-bezier(.22, 1, .36, 1), transform 260ms cubic-bezier(.22, 1, .36, 1), visibility 0s; }
.ov-tip.is-below { transform: translateY(-6px); }
.ov-tip.is-below.is-on { transform: none; }
.ov-tip-name { font-family: var(--font-display); font-weight: 600; font-size: 16px; line-height: 1.4; color: var(--ink); }
.ov-tip-role { font-family: var(--font-body); font-weight: 400; font-size: 14px; line-height: 1.5; color: var(--secondary); }
@media (prefers-reduced-motion: reduce) { .ov-tip, .ov-tip.is-on { transform: none; transition: none; } }

/* ============== Design goals (Figma 490:1660) ============== */
.case-goals { margin-top: 120px; display: flex; flex-direction: column; gap: 40px; }
.case-h2 { margin: 0; font-family: var(--font-display); font-weight: 700; font-size: 48px; line-height: 1.1; letter-spacing: 0; color: var(--ink); }
.goals { list-style: none; margin: 0; padding: 0; display: flex; align-items: flex-start; gap: 32px; width: 1271px; max-width: 100%; }
.goal {
  flex: 1 0 0; min-width: 1px;
  position: relative; padding: 19px 32px 40px 0;   /* text exactly where it was (the removed 3 px top rule's height added to the top padding) */
  display: flex; flex-direction: column; align-items: flex-start; gap: 16px;
}
/* Accent: a short vertical Signal Cyan rule hanging 20 px left of the text (in the column gap / page margin, so the text keeps its grid),
   from the title's cap height over the title and the start of the description. Phones: inside the column, text 20 px in. */
.goal::before { content: ""; position: absolute; left: -20px; top: calc(19px + var(--goal-cap, 7px)); width: 3px; height: var(--goal-rule, 72px); background: var(--cyan); }
.case-h3 { margin: 0; font-family: var(--font-display); font-weight: 700; font-size: 32px; line-height: 1.2; letter-spacing: 0; color: var(--ink); white-space: nowrap; }
@media (min-width: 1300px) { .goals { gap: 40px; } }   /* more air between the three goals; below 1300 the 32 px keeps every title on one line */
.goal p { margin: 0; width: 326px; max-width: 100%; font-family: var(--font-body); font-weight: 400; font-size: 20px; line-height: 1.6; }

/* ============== Impact (Figma 479:1554) ============== */
.case-impact { margin-top: 120px; width: 955px; max-width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 32px; }
.impact-list { width: 100%; display: flex; flex-direction: column; gap: 40px; }

/* Impact diagram: Business (Web + Mobile → unified experience) → User (complex → structure → key information).
   Built in code: SVG for lines, HTML for labels. Geometry follows the reference (290 x 424 units). */
@media (min-width: 1521px) {
  .case-impact { width: auto; max-width: none; }
  .impact-list {
    display: grid; row-gap: 40px;
    column-gap: clamp(56px, 5.05vw, 97px);
    grid-template-columns: 955px min(448px, calc(100vw - var(--gutter) - max(var(--gutter), 50vw - 641px) - 955px - clamp(56px, 5.05vw, 97px)));
  }
  .impact-list > .impact-item { grid-column: 1; }
  .impact-list .impact-diagram { grid-column: 2; grid-row: 1 / span 2; margin-top: 46px; }   /* top aligns with the first H3 */
}
.impact-diagram {
  position: relative; margin: 0; width: 100%; max-width: 448px; aspect-ratio: 290 / 424;
  container-type: inline-size; color: var(--ink);
}
.impact-diagram svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.impact-diagram .d-line { stroke: var(--ink); stroke-width: 1; fill: none; vector-effect: non-scaling-stroke; }
.impact-diagram .d-cyan { stroke: var(--cyan); stroke-width: 2; vector-effect: non-scaling-stroke; }
.impact-diagram .d-soft { stroke: var(--rule); stroke-width: 1; vector-effect: non-scaling-stroke; }
.impact-diagram .d-strong { stroke: var(--ink); stroke-width: 1; vector-effect: non-scaling-stroke; }
.impact-diagram .d-key { stroke: var(--ink); stroke-width: 3; vector-effect: non-scaling-stroke; }
.d-label {
  position: absolute; margin: 0;
  font-family: var(--font-display); font-weight: 500; font-size: max(10px, 2.679cqw); line-height: 1.2;
  letter-spacing: 0.1em; text-transform: uppercase; white-space: nowrap;
}
.d-label--wrap { white-space: normal; width: 28%; }
.d-title {
  position: absolute; margin: 0; transform: translateX(-50%);
  font-family: var(--font-body); font-weight: 600; font-size: max(14px, 4.464cqw); line-height: 1.6; white-space: nowrap;
}
.impact-item { display: flex; flex-direction: column; gap: 40px; }
.impact-body { width: 950px; max-width: 100%; padding-right: 32px; display: flex; flex-direction: column; align-items: flex-start; gap: 32px; }
.impact-text { display: flex; flex-direction: column; gap: var(--space-label); width: 100%; }   /* label → H3: 16 px, the shared label rule */
.impact-copy { display: flex; flex-direction: column; gap: 16px; }
.impact-copy p { margin: 0; font-family: var(--font-body); font-weight: 400; font-size: 20px; line-height: 1.6; }
.impact-enabled { border-left: 3px solid var(--cyan); padding-left: 16px; display: flex; flex-direction: column; gap: 8px; }
.impact-enabled ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; font-family: var(--font-body); font-weight: 400; font-size: 20px; line-height: 1.6; }   /* shared Impact list (Isracard, TwentySix): separate points, 12 px apart (8 on mobile) */
.impact-rule { width: 943px; max-width: 100%; height: 1px; background: var(--rule); border: 0; margin: 11px 0 12px; }   /* Figma: 0-height line drawn 1 px up (-1), plus 12 px above and below per comment */
.case-content p { max-width: none; }

/* ============== The Process (Figma 657:2420, 1274 x 2888.606) ============== */
.case-process { margin-top: 120px; width: 1274px; max-width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 80px; }
.process-header { width: 100%; display: flex; flex-direction: column; gap: var(--space-title); }
.process-header .case-h2 { width: 1115px; max-width: 100%; }
.process-text { margin: 0; font-family: var(--font-body); font-weight: 400; font-size: 20px; line-height: 1.6; color: var(--ink); }
.process-header .process-text { width: 1083px; max-width: 100%; }
.process-body { position: relative; width: 100%; display: flex; align-items: flex-start; gap: 62px; }          /* Figma 38 + 24 px more air between the rail and the text (review) */
.process-rail { position: relative; flex: none; width: 12px; align-self: stretch; }                             /* Figma 614:1947 */
/* Base track (Quiet Rule) + progress overlay (Signal Cyan): same x, same 1 px width.
   The overlay covers the track on the whole passed length; only its height changes with scroll. Figma start: 119 of 2086 px. */
.process-rail-track, .process-rail-progress { position: absolute; left: 5.5px; top: 0; width: 1px; display: block; }
.process-rail-track { height: 100%; background: var(--rule); }   /* runs to the end of the section (review), Figma had 2086 px */
.process-rail-progress { height: 119px; background: var(--cyan); }   /* after the track in the DOM, so it covers it; dots stay on top */
.process-stages { flex: 1 1 auto; min-width: 0; width: 1224px; max-width: 100%; display: flex; flex-direction: column; gap: 120px; }   /* Figma 657:2418 */
.process-stage { position: relative; width: 100%; }
.process-dot { position: absolute; left: -73px; top: 0; width: 12px; height: 12px; border-radius: 10px; background: var(--rule); }   /* Figma 614:1952, x 1 inside the rail */
.process-dot.is-active { background: var(--cyan); }
/* Isracard: no small stage labels, so each stage starts with its H3; the 12 px dot is centred on the H3's first line (38.4 px) */
.case-process--isr { --dot-top: 13.2px; }
@media (max-width: 600px) { .case-process--isr { --dot-top: 9.6px; } }   /* H3 26 px on phones: first line 31.2 px */
.case-process--isr .process-dot { top: var(--dot-top); }
.case-process--isr .process-rail { margin-top: var(--dot-top); }
.case-process--isr .process-insight { min-height: 0; }   /* icon + title only: cards take their content height (equal per row via stretch) */
/* Key patterns (Figma 845:2656): the four cards 2 x 2 (600 px, 24 px gaps) and the Zoom / Axure photo (593 x 379) 32 px to the right.
   The photo is part of the layout: never shown larger than its own 594 px, no Lightbox. Below 1100 it moves under the cards
   (full content width on phones, its own width at most); phones stack the cards (the shared breakpoints). Cards share one height via the grid rows. */
.process-insights-row { display: flex; align-items: flex-start; gap: 32px; width: 100%; }
.case-process--isr .process-insights { flex: 0 0 600px; width: 600px; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: 1fr; gap: 24px; }
.process-insights-photo { flex: 0 1 593px; min-width: 0; margin: 0; }
.process-insights-photo img { display: block; width: 100%; max-width: 594px; height: auto; border-radius: 4px; }   /* Figma radius 4.4 */
@media (max-width: 1100px) {
  .process-insights-row { flex-direction: column; gap: 24px; }
  .case-process--isr .process-insights { flex: none; width: 100%; }
  .process-insights-photo { flex: none; width: 100%; }
}
@media (max-width: 600px) { .case-process--isr .process-insights { grid-template-columns: minmax(0, 1fr); } }   /* the line still starts at the first dot */
.process-dot { transition: background-color 220ms ease-in-out; }
/* Timeline halo (reusable): place <span class="tl-halo"> centred on a dot, turn it on with .is-on.
   Same look in Resume and The Process. Completed dots: cyan, no halo. Upcoming: Quiet Rule. */
.tl-halo {
  position: absolute; width: var(--tl-halo-size); height: var(--tl-halo-size); border-radius: 50%;
  background: var(--tl-halo); pointer-events: none;
  opacity: 0; transform: translate(-50%, -50%) scale(.5);
  transition: opacity 360ms ease-in-out, transform 360ms ease-in-out;
}
.tl-halo.is-on { opacity: 1; transform: translate(-50%, -50%); }
.tl-halo.no-motion { transition: none; }
.process-dot .tl-halo { left: 50%; top: 50%; }
.process-row { display: flex; align-items: flex-start; gap: 136px; }
.process-row--center { align-items: center; }
.process-subtitle { display: flex; flex-direction: column; align-items: flex-start; gap: 16px; }
.process-subtitle .case-h3 { width: 388px; max-width: 100%; white-space: normal; }
.process-stage--existing .process-subtitle { flex: 0 1 462px; }
.process-research-col { flex: 0 1 464px; display: flex; flex-direction: column; gap: 10px; }
/* Body / SemiBold (Figma): Instrument Sans 600, 20 / 1.6. One shared text style for small titles in the case studies */
.text-body-strong { margin: 0; font-family: var(--font-body); font-weight: 600; font-size: 20px; line-height: 1.6; }
.process-h4 { margin: 0; font-family: var(--font-display); font-weight: 600; font-size: 24px; line-height: 1.25; letter-spacing: 0; color: var(--ink); }
.process-card { background: var(--soft); border-radius: 8px; display: flex; flex-direction: column; align-items: flex-start; gap: 16px; }
.process-card--problems { flex: 0 1 458px; padding: 24px; }       /* Figma 598:2084 */
.process-card--questions { flex: 0 1 624px; min-width: 0; padding: 32px; }     /* Figma 598:2107. min-width 0: the 512 px question text must not set the card's minimum (overflowed 1101–1160 px) */
.process-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.process-problems { gap: 24px; }
.process-problems li { display: flex; align-items: flex-start; gap: 12px; font-family: var(--font-body); font-size: 20px; line-height: 1.6; white-space: nowrap; }
.process-problems svg, .process-insight-icon svg { display: block; flex: none; }
.process-products-wrap { display: flex; flex-direction: column; gap: 12px; }
.process-questions { width: 100%; gap: 16px; }
.process-questions li { display: flex; align-items: flex-start; gap: 12px; font-family: var(--font-body); font-size: 20px; line-height: 1.6; }
.process-questions li::before { content: ""; flex: none; width: 8px; height: 8px; margin-top: 12px; border-radius: 50px; background: var(--cyan); }
.process-questions li span { width: 512px; max-width: 100%; }
.process-insights-stage { display: flex; flex-direction: column; gap: 40px; }
.process-insights-stage .process-text { width: 100%; }
.process-insights { list-style: none; margin: 0; padding: 0; width: 100%; display: flex; align-items: stretch; gap: 24px; }   /* Figma 618:2217 */
.process-insight { flex: 1 0 0; min-width: 1px; min-height: 320px; padding: 32px; background: var(--soft); border-radius: 8px; display: flex; flex-direction: column; align-items: flex-start; gap: 16px; }
.process-insight-head { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; }
.process-insight-icon { width: 40px; height: 40px; }
.process-direction { display: flex; flex-direction: column; gap: 60px; }   /* Figma 657:2352 */
.process-direction-header { display: flex; flex-direction: column; gap: 16px; }
.process-direction-header .process-subtitle { width: 550px; max-width: 100%; }
.process-direction-header .process-subtitle .case-h3 { width: auto; }
.process-direction-header .process-text { width: 731px; max-width: 100%; }
.process-context { width: 100%; display: flex; align-items: flex-start; }          /* Figma 657:2358 */
.process-visual { flex: none; display: flex; flex-direction: column; align-items: flex-start; gap: 16px; }
.process-visual--desktop { width: 528px; }
.process-visual--mobile { width: 282px; }
.process-wire-slot { border-radius: 8px; overflow: hidden; display: flex; align-items: center; justify-content: center; }
.process-visual--desktop .process-wire-slot { background: var(--rule); border: 1px solid var(--rule); padding: 15px; }   /* p 16 incl. the 1 px stroke */
.process-visual--mobile .process-wire-slot { background: var(--soft); padding: 16px; }
.process-wire { position: relative; flex: none; max-width: 100%; }
.process-wire img { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.process-wire.is-pending::after { content: ""; position: absolute; inset: 0; border: 1px solid var(--rule); pointer-events: none; }   /* exported PNGs carry their own 1 px frame */
.process-wire--desktop { width: 496px; height: 500.392px; }
.process-wire img { object-fit: contain; }   /* PNG 2x export of the Figma frame, same aspect ratio: no stretch, no crop */
.process-wire--mobile { width: 250px; height: 534.607px; overflow: hidden; }
.process-priorities { width: 100%; display: flex; flex-direction: column; gap: 8px; }
.process-checks { gap: 8px; }
.process-checks li { display: flex; align-items: center; gap: 10px; font-family: var(--font-display); font-weight: 400; font-size: 20px; line-height: 1.5; }
.process-checks svg { display: block; flex: none; }
/* Mobile priorities: one line per item, like the Desktop list (review comment). The list may run past the 282 px wireframe column. */
.process-visual--mobile .process-priorities { width: max-content; }
.process-visual--mobile .process-checks li span { white-space: nowrap; }
/* a wrapped item keeps its check on the first line (same position as before for one-line items) */
.process-visual--mobile .process-checks li { align-items: flex-start; }
.process-visual--mobile .process-checks svg { margin-top: calc((1.5em - 14px) / 2); }
/* The list never passes the content grid: it may use the last column up to the grid edge; only an item longer than that wraps */
@media (min-width: 1412px) {
  .process-visual--mobile .process-priorities { max-width: 100%; }
  .process-visual--mobile .process-checks li span { white-space: normal; }
}
/* 1101-1411 px: the one-line list would pass the column or viewport edge, so it wraps there; phones wrap too */
@media (min-width: 1101px) and (max-width: 1411px), (max-width: 600px) {
  .process-visual--mobile .process-priorities { width: 100%; }
  .process-visual--mobile .process-checks li span { white-space: normal; }
}
.process-bridge { flex: none; width: 364px; height: 532px; display: flex; align-items: center; justify-content: center; }   /* Figma 657:2360 */
/* Soft hand-drawn arrows from the Shared logic card out to Desktop (left) and Mobile (right), per the review sketch */
.process-bridge-line { flex: 1 1 0; min-width: 0; display: block; }
.process-bridge-line svg { display: block; width: 100%; height: auto; overflow: visible; }
.process-bridge-line path { fill: none; stroke: var(--secondary); stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
/* Scroll reveal, once per page view: the arrows slide out from under the Shared logic card, each toward its own screen.
   The card sits above them (opaque Soft fill), so the hidden part is covered, not faded. */
.process-shared { position: relative; z-index: 1; }
.process-bridge.is-pending .process-bridge-line:first-child { transform: translateX(100%); }
.process-bridge.is-pending .process-bridge-line:last-child  { transform: translateX(-100%); }
.process-bridge.is-revealed .process-bridge-line { transition: transform 700ms cubic-bezier(0.22, 1, 0.36, 1); }
.process-bridge.is-revealed .process-bridge-line:last-child { transition-delay: 60ms; }
.process-shared { flex: none; }
/* 2. Desktop screen, Shared logic card and Mobile screen share one horizontal axis:
   screens and bridge sit in one grid row (centred), the Desktop / Mobile lists in the row below. */
@media (min-width: 1321px) {
  .process-context { display: grid; grid-template-columns: 528px 364px minmax(282px, 1fr); row-gap: 16px; align-items: center; }   /* last column runs to the grid edge */
  .process-visual { display: contents; }
  .process-visual--desktop > .process-wire-slot { grid-column: 1; grid-row: 1; }
  .process-visual--mobile > .process-wire-slot { grid-column: 3; grid-row: 1; justify-self: start; width: 282px; }
  .process-bridge { grid-column: 2; grid-row: 1; height: auto; align-self: center; }
  .process-visual--desktop > .process-priorities { grid-column: 1; grid-row: 2; align-self: start; }
  .process-visual--mobile > .process-priorities { grid-column: 3; grid-row: 2; align-self: start; }
}
@media (max-width: 1320px) { .process-bridge-line { display: none; } }
.process-shared { background: var(--soft); border-radius: 8px; padding: 32px; display: flex; flex-direction: column; gap: 8px; }   /* no stroke, 8 px radius like the cards in the previous step (review) */
.process-shared ul { list-style: none; margin: 0; padding: 0; font-family: var(--font-display); font-weight: 400; font-size: 14px; line-height: 1.5; }

/* ============== Target audience (Figma 657:2351) ============== */
.case-audience { margin-top: 120px; width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 40px; }   /* intro → personas 40, personas 40 apart */

/* ============== Before / After (Claude Design concept "Isracard Before After") ==============
   Scroll-driven reveal: each comparison sits in a short track; its stage is sticky under the 72 px nav.
   The After frame defines the box (its own aspect ratio). Before keeps its own ratio, top-aligned,
   scaled down only (never stretched or enlarged). Only the visible area of After changes. */
.case-ba { margin-top: 120px; width: 100%; display: flex; flex-direction: column; }
.ba-header { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 48px; align-items: end; padding-bottom: 32px; }
.ba-header-title { display: flex; flex-direction: column; gap: var(--space-label); }
.ba-header-title > .case-h2 + * { margin-top: calc(var(--space-title) - var(--space-label)); }   /* label → H2 16, H2 → text 20 */
/* Shared caption under mobile screens (Mobile web / App, Quick view, biometrics): one style, 12 px below the image */
.screen-caption { margin: 0; font-family: var(--font-display); font-weight: 500; font-size: 14px; line-height: 1.5; color: var(--secondary); }
.ba-meta { margin: 0; font-family: var(--font-display); font-weight: 400; font-size: 14px; line-height: 1.5; color: var(--secondary); }
.ba-track { position: relative; }
.ba-track--dash { height: 175vh; }
.ba-track--reg, .ba-track--flow { height: 160vh; }
.ba-track--mobile { height: 170vh; }
.ba-sticky { position: sticky; top: 72px; height: calc(100vh - 72px); display: flex; justify-content: center; align-items: flex-start; padding-top: 24px; }
.ba-track--reg .ba-sticky, .ba-track--flow .ba-sticky, .ba-track--mobile .ba-sticky { align-items: center; padding-top: 0; }
/* Same comparison width for Dashboard and Registration: sized so the Dashboard After frame
   (3840 x 3512) fits under the nav together with its title and progress row. */
.ba-stage { margin: 0; width: min(100%, calc((100vh - 72px - 170px) * 3840 / 3512)); display: flex; flex-direction: column; gap: 20px; }
.ba-head { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; padding-bottom: 14px; border-bottom: 1px solid var(--ink); }
.ba-track--reg .ba-head { border-bottom-color: var(--rule); }
.ba-head .case-h3, .ba-head .process-h4 { white-space: normal; }
.ba-frame { position: relative; width: 100%; aspect-ratio: var(--ba-ratio); overflow: hidden; background: var(--soft); }
.ba-frame::after { content: ""; position: absolute; inset: 0; border: 1px solid var(--rule); pointer-events: none; z-index: 3; }
/* Before: proportional, top-aligned, centred; max-width/max-height only scale it down. Centred by left/right 0 + auto margins
   (not translateX(-50%)), so the image lands on whole pixels and is not resampled at a sub-pixel offset. */
.ba-before { position: absolute; top: 0; left: 0; right: 0; margin: 0 auto; width: auto; height: auto; max-width: 100%; max-height: 100%; }
.ba-after { position: absolute; inset: 0; background: var(--soft); clip-path: inset(0 0 0 100%); z-index: 1; }   /* opens from the right edge */
.ba-after img { display: block; width: 100%; height: auto; }
.ba-line { position: absolute; top: 0; bottom: 0; left: 100%; width: 2px; margin-left: -1px; background: var(--cyan); opacity: 0; z-index: 2; }
/* Notes on the Results screen (Figma 856:3644): white cards (12 px radius, the Figma 0 0 15 px shadow) laid over the frame at the
   Figma positions, partly outside it; they fade in only once Results is fully open, so they never sit on Filtering, and take no
   pointer events (the frame stays clickable). Below 1100 px they leave the image and follow the slider as a plain list. */
.ba-stage { position: relative; }
.ba-notes { position: absolute; left: 0; top: 0; width: 100%; pointer-events: none; z-index: 4; }
.ba-note { background: var(--canvas); border-radius: 12px; box-shadow: 0 0 15px rgba(0, 0, 0, .1); padding: 24px; display: flex; flex-direction: column; gap: 16px; }
.ba-note .process-text { color: var(--secondary); }
.ba-note-shot { width: 100%; }
.ba-note-shot img { display: block; width: 100%; height: auto; }
.ba-note-shot.is-pending { background: var(--placeholder); outline: 1px dashed var(--rule); }
.ba-notes .ba-note { position: absolute; opacity: 0; transform: translateY(8px); transition: opacity 300ms cubic-bezier(0.22, 1, 0.36, 1), transform 300ms cubic-bezier(0.22, 1, 0.36, 1); }
.ba-notes .ba-note--filters { right: 61%; top: 14.6%; width: 480px; }   /* covers the top-left 39 % of Results, rest outside */
.ba-notes .ba-note--totals { left: 72.9%; top: 29.2%; width: 380px; }   /* on the totals row, partly outside on the right */
/* TwentySix Product page After: notes mostly outside the screen, ~20 % of each card over its edge (64 / 93 px).
   The screen is centred, so its side margin is (100vw - 100%) / 2; when that is too narrow a card moves in just enough
   to stay 24 px inside the window (no clipping, no horizontal scroll) */
.ba-notes :is(.ba-note--stock, .ba-note--shipping, .ba-note--wl-status, .ba-note--wl-restock) { right: min(calc(100% - 64px), calc(100% - 344px + (100vw - 100%) / 2)); width: 320px; }
.ba-notes .ba-note--stock    { top: 33%; }
.ba-notes .ba-note--shipping { top: 55%; }
.ba-notes .ba-note--details  { left: min(calc(100% - 93px), calc((100vw + 100%) / 2 - 490px)); top: 24%; width: 466px; }
/* TwentySix Shopping bag After: the bag sits on the right of the screen, so the notes go on the left, over the dimmed page
   behind it (~20 % over the screen when there is room, never closer than 24 px to the window). One scale for the three fragments (0.4) */
.ba-notes :is(.ba-note--bag-shipping, .ba-note--bag-stock, .ba-note--bag-actions) { right: min(calc(100% - 77px), calc(100% - 411px + (100vw - 100%) / 2)); width: 387px; }
.ba-notes .ba-note--bag-shipping { top: 8%; }
.ba-notes .ba-note--bag-stock    { top: 39%; }
.ba-notes .ba-note--bag-actions  { top: 67%; }
.ba-note--bag-stock .ba-note-shot   { width: 102px; align-self: flex-end; }
.ba-note--bag-actions .ba-note-shot { width: 237px; align-self: flex-end; }
/* TwentySix Wishlist After: availability + restock beside the out-of-stock item (left), sizes + add to bag beside the in-stock items (right); four 610 px fragments at one scale */
.ba-notes :is(.ba-note--wl-sizes, .ba-note--wl-add) { left: min(calc(100% - 64px), calc((100vw + 100%) / 2 - 344px)); width: 320px; }
.ba-notes .ba-note--wl-status  { top: 40%; }
.ba-notes .ba-note--wl-restock { top: 64%; }
.ba-notes .ba-note--wl-sizes   { top: 40%; }
.ba-notes .ba-note--wl-add     { top: 66%; }
.ba-note--stock .ba-note-shot    { width: 173px; align-self: flex-end; }   /* one-line UI rows at one scale (0.55 of the export), right-aligned like the RTL screen */
.ba-note--shipping .ba-note-shot { width: 265px; align-self: flex-end; }
.ba-track.is-end .ba-notes .ba-note { opacity: 1; transform: none; }
/* Below 1100 px: the same notes stacked under the progress row inside the pinned stage, outside the image, same fade-in */
.ba-notes-list { display: none; }
@media (max-width: 1100px) {
  .ba-notes { display: none; }
  .ba-notes-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; align-items: start; margin-top: 4px; }
  .ba-notes-list .ba-note { opacity: 0; transform: translateY(8px); transition: opacity 300ms cubic-bezier(0.22, 1, 0.36, 1), transform 300ms cubic-bezier(0.22, 1, 0.36, 1); }
  .ba-track.is-end .ba-notes-list .ba-note { opacity: 1; transform: none; }
  /* TwentySix: the listed notes make the stage taller than one screen; the pinned box grows with it (never shorter than the screen),
     so the notes stay inside their track and the next block starts after them instead of under them */
  .ts-ba .ba-sticky { height: auto; min-height: calc(100vh - 72px); }
}
@media (max-width: 600px) { .ba-notes-list { grid-template-columns: minmax(0, 1fr); gap: 16px; margin-top: 0; } .ba-note { padding: 20px; } .ba-note .process-text { font-size: 18px; } }
@media (prefers-reduced-motion: reduce) { .ba-notes .ba-note, .ba-notes-list .ba-note { transition: none; opacity: 1; transform: none; } }
.ba-progress { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 16px; align-items: center; }
.ba-progress .ov-label { color: var(--secondary); transition: color 200ms ease-in-out; }
.ba-progress .ov-label.is-on { color: var(--ink); }
/* Every comparison slider (Dashboard, Registration, Filtering / Results): the leading screen's label turns Bold 700. A hidden bold copy (data-label) reserves its width,
   so the labels and the Cyan bar never shift. Size, colour and position stay as they are. */
.ba-progress .ov-label { display: inline-flex; flex-direction: column; }
.ba-progress .ba-label-after { align-items: flex-end; }
.ba-progress .ov-label::after { content: attr(data-label); font-weight: 700; padding-right: 1px; height: 0; overflow: hidden; visibility: hidden; pointer-events: none; }
.ba-progress .ov-label.is-lead { font-weight: 700; }
.ba-bar { position: relative; height: 1px; background: var(--rule); }
.ba-fill { position: absolute; left: 0; top: -1px; height: 3px; width: 0; background: var(--cyan); }
/* Mobile web + App: Soft Canvas band, full bleed without horizontal overflow */
.ba-track--mobile { background: var(--soft); box-shadow: 0 0 0 100vmax var(--soft); clip-path: inset(0 -100vmax);
  border-top: 1px solid var(--rule); border-image: linear-gradient(var(--rule), var(--rule)) 1 / 1px 0 0 0 / 0 100vmax; }
.ba-mobile { width: 100%; display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 64px; align-items: center; }
.ba-mobile-text { display: flex; flex-direction: column; gap: 16px; max-width: 420px; }
.ba-mobile-text .case-h3 { white-space: normal; }
.ba-mobile-text .case-h2 { white-space: normal; }
:is(.ba-mobile-text, .beyond-text, .case-brand) .process-text strong { font-weight: 600; }   /* highlighted phrases: Instrument Sans SemiBold */   /* section H2, same style as "Beyond the dashboard" */
.ba-phones { display: flex; gap: 40px; align-items: flex-start; }
.ba-phone { margin: 0; display: flex; flex-direction: column; gap: 12px; }
.ba-phone + .ba-phone { padding-top: 64px; }
.ba-phone-frame { position: relative; height: min(680px, calc(100vh - 72px - 200px)); aspect-ratio: 375 / 812; overflow: hidden; background: var(--canvas); }
.ba-phone-frame::after { content: ""; position: absolute; inset: 0; border: 1px solid var(--rule); pointer-events: none; }
.ba-phone-frame img { display: block; width: 100%; height: auto; will-change: transform; }

@media (max-width: 900px) {
  .case-ba { margin-top: 80px; }
  .ba-header { grid-template-columns: 1fr; gap: 16px; }
  .ba-header .process-text, .ba-mobile-text .process-text { font-size: 18px; }
  .ba-mobile { grid-template-columns: 1fr; gap: 32px; }
  .ba-phones { gap: 16px; }
  .ba-phone { width: calc((100% - 16px) / 2); }
  .ba-phone + .ba-phone { padding-top: 32px; }
  .ba-phone-frame { height: auto; width: 100%; max-height: calc(100vh - 72px - 370px); }   /* 370: room for the longer H2 + text (was 340) */
}
/* ============== Lightbox: one shared viewer for interface images (all case studies) ==============
   Any element with [data-lightbox] opens the original image in a native <dialog>: fit to screen, zoom and pan,
   close by Esc, the close button or a tap on the dark area. Page images keep their look; only the cursor changes. */
html.is-lightbox-open { overflow: hidden; }
@media (hover: hover) and (pointer: fine) { [data-lightbox] { cursor: zoom-in; } }
.lightbox { position: fixed; inset: 0; width: 100%; height: 100%; max-width: none; max-height: none; margin: 0; padding: 0; border: 0;
  background: color-mix(in srgb, var(--ink) 88%, transparent); color: var(--canvas); overflow: hidden; }
.lightbox::backdrop { background: transparent; }
.lightbox-stage { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  padding: clamp(56px, 6vw, 72px) clamp(16px, 4vw, 72px); overflow: hidden; touch-action: none; }
.lightbox-img { display: block; max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain;
  transform-origin: center; user-select: none; -webkit-user-drag: none; cursor: zoom-in; }
.lightbox-img.is-zoomed, .lightbox-img.is-tall { cursor: grab; }
/* long scrolling screenshots: fit to a readable width and pan vertically instead of shrinking to a sliver */
.lightbox-img.is-tall { max-height: none; width: min(100%, 480px); flex: none; }
.lightbox-img.is-dragging { cursor: grabbing; }
@media (prefers-reduced-motion: no-preference) { .lightbox-img.is-animating { transition: transform 200ms cubic-bezier(.22, 1, .36, 1); } }
.lightbox-close { position: absolute; top: 16px; right: 16px; z-index: 1; width: 40px; height: 40px; padding: 0; border: 0; border-radius: 50%;
  display: grid; place-items: center; background: var(--canvas); color: var(--ink); cursor: pointer; }
.lightbox-close:focus-visible { outline-color: var(--cyan); }

/* ============== Translating brand into digital (Figma 771:12943): after Beyond the dashboard ==============
   Header reuses .process-header / .case-h2 / .process-text. The stack is the Figma 1397 x 1483 page area:
   three 1000 x 754 pages, back to front 01 (x 315, y 0), 02 (x 0, y 351), 03 (x 397, y 729), positions in %.
   From 1440 px it hangs 72 px left and 49 px right of the 1276 column, as in Figma; narrower it fits the column. */
.case-brand { margin-top: 120px; width: 100%; display: flex; flex-direction: column; gap: 98px; }
.case-brand .process-text + .process-text { margin-top: calc(var(--space-list) - var(--space-title)); }   /* paragraphs 16 apart (Figma), H2 → text stays 20 */
.brand-stack { position: relative; width: 100%; aspect-ratio: 1397 / 1483; margin: 0; }
.brand-page { position: absolute; margin: 0; width: calc(1000 / 1397 * 100%); box-shadow: 0 5px 60px rgba(38, 38, 73, .2); background: var(--canvas); }
.brand-page img { display: block; width: 100%; height: auto; }
.brand-page--01 { left: calc(315 / 1397 * 100%); top: 0; }
.brand-page--02 { left: 0; top: calc(351 / 1483 * 100%); width: calc(1000.124 / 1397 * 100%); }
.brand-page--03 { left: calc(397 / 1397 * 100%); top: calc(729 / 1483 * 100%); }
@media (min-width: 1440px) { .brand-stack { width: calc(1397 / 1276 * 100%); margin-left: calc(-72 / 1276 * 100%); } }
@media (max-width: 900px) { .case-brand { margin-top: 80px; gap: 48px; } }
@media (max-width: 600px) {
  .brand-stack { aspect-ratio: auto; display: flex; flex-direction: column; gap: 24px; }
  .brand-page { position: static; width: 100%; }
}

/* ============== Next project (Figma 781:2891): last block of the case study, right before the footer ==============
   Soft Canvas band, one white card per case study (Next / Previous project) with the project's Desktop + Mobile shots (below).
   Reuses .process-h4, .case-h3, .work-client--meta and .work-cta. */
.case-next { background: var(--soft); padding: 126px var(--gutter) 160px; }   /* 160 px from the card to the footer (review: 40 + 120) */
/* Navigation block: the card is one link (title, client, VIEW CASE STUDY, shots). */
.next-wrap { width: min(920px, 100%); margin: 0 auto; display: flex; flex-direction: column; gap: 24px; }
.next-card { position: relative; width: 100%; min-height: 556px; background: var(--canvas); overflow: hidden;
  box-shadow: 0 5px 60px rgba(38, 38, 73, .2); }   /* same shadow as the Design System pages (.brand-page) */
.next-title { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; width: 100%; }
/* Hover / focus: the card lifts 6 px (top, not transform: a transform re-samples the raster shots and drops their 1 px lines) with an
   extra soft shadow; the shots themselves are not scaled, for the same reason. */
.next-card--link { display: block; top: 0; color: inherit; text-decoration: none; cursor: pointer;
  transition: top 280ms cubic-bezier(0.22, 1, 0.36, 1), box-shadow 280ms cubic-bezier(0.22, 1, 0.36, 1); }
.next-card--link:is(:hover, :focus-visible) { top: -6px; box-shadow: 0 5px 60px rgba(38, 38, 73, .2), 0 24px 56px -20px rgba(10, 13, 20, .12); }
.next-card--link:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; border-radius: 0; }
/* Figma 859:3695 composition (cards with Desktop + Mobile shots): 1024 x 528 white card, label 16 px above it (H4 24 / 600).
   Text block at x 40 / y 126, 327 wide, 24 px to the button. Shots scale with the card: Desktop 684 x 455 at 318 / 40, Mobile
   168 x 257 at 834 / 271 (its lower edge is the card edge, as in Figma). Shadows: the site's own (card = Design System pages,
   shots = the nav panel / TwentySix card shadow), not the Figma ones. */
.next-wrap--shots { width: min(1024px, 100%); gap: 16px; }
.next-card--shots { min-height: 0; aspect-ratio: 1024 / 528; }
.next-info { position: relative; z-index: 1; box-sizing: border-box; width: calc(327px + 40px); padding: 126px 0 0 40px; display: flex; flex-direction: column; align-items: flex-start; gap: 24px; }
.next-info .case-h3 { white-space: normal; }
.next-shots { position: absolute; left: calc(318 / 1024 * 100%); top: calc(40 / 528 * 100%); width: calc(684 / 1024 * 100%); aspect-ratio: 684 / 488; }
.next-shot { position: absolute; display: block; height: auto; box-shadow: 0 4px 32px rgba(38, 38, 73, .10); }
.next-shot--desktop { left: 0; top: 0; width: 100%; border-radius: 12px; }
/* Mobile export carries its own rounded corners and soft shadow (opaque screen 180 px wide at 37 / 37, transparent margins around):
   scaled so the screen keeps the Figma 168 px width and right edge, its lower edge on the card's lower edge */
.next-shot--mobile { left: calc((516 - 37 * 168 / 180) / 684 * 100%); bottom: 0; width: calc(239 * 168 / 180 / 684 * 100%); box-shadow: none; border-radius: 0; }
/* Framed mobile export (Isracard): the phone screen itself, 168 wide, right edge on the Desktop's right edge (516 + 168 = 684, as the
   TwentySix phone), lower edge on the card edge; the same site shadow, drawn around its rounded top corners */
.next-shots--framed .next-shot--mobile { left: calc(516 / 684 * 100%); width: calc(168 / 684 * 100%); box-shadow: none; filter: drop-shadow(0 4px 32px rgba(38, 38, 73, .10)); }
.next-card--link:is(:hover, :focus-visible) .work-cta { background: var(--cyan); color: var(--ink); }   /* same as the Home project cards */
.next-card--link:is(:hover, :focus-visible) .work-cta-arrow { transform: translate(var(--cta-dx), var(--cta-dy)); }
.next-card--link:is(:hover, :focus-visible) .work-cta .btn-arrow-svg path { fill: var(--ink); }
/* Tablet / mobile: text and button first, then the shots (Mobile still over Desktop), flush with the card's lower edge */
@media (max-width: 1100px) {
  .next-card--shots { aspect-ratio: auto; }
  .next-info { width: 100%; padding: 40px max(40px, (100% - 684px) / 2) 32px; }   /* text starts where the centred Desktop shot starts */
  .next-shots { position: relative; left: auto; top: auto; width: min(684px, 100% - 80px); margin: 0 auto; }   /* never above the exports' own size */
}
@media (max-width: 600px) {
  .next-info { padding: 32px 20px 24px; gap: 20px; }
  .next-info .work-cta { padding: 9px 8px 9px 10px; }   /* compact CTA on phones only: ~159 x 40 */
  .next-shots { width: calc(100% - 40px); }
  .next-shot--desktop { border-radius: 8px; }
}
@media (hover: none) { .next-card--link:hover .work-cta { background: var(--ink); color: var(--canvas); } .next-card--link:hover .work-cta-arrow { transform: none; } .next-card--link:hover .work-cta .btn-arrow-svg path { fill: var(--cyan); } }
/* Scroll reveal, once (Slide-up Reveal): the white card rises over the fixed Soft Canvas band, its label stays put. JS arms it
   (64 px lower, transparent) only when motion is allowed, then reveals it in view (700 ms). Transform only: no layout shift */
.next-card.is-armed { opacity: 0; transform: translateY(64px); }
.next-card.is-revealing { opacity: 1; transform: none;
  transition: opacity 700ms cubic-bezier(0.22, 1, 0.36, 1), transform 700ms cubic-bezier(0.22, 1, 0.36, 1),
    top 280ms cubic-bezier(0.22, 1, 0.36, 1), box-shadow 280ms cubic-bezier(0.22, 1, 0.36, 1); }   /* hover lift / shadow keep their own timing */
@media (hover: none) { .next-card--link:hover { top: 0; box-shadow: 0 5px 60px rgba(38, 38, 73, .2); } }
@media (prefers-reduced-motion: reduce) { .next-card--link, .next-card--link:is(:hover, :focus-visible) { top: 0 !important; } }
@media (max-width: 900px) { .case-next { padding-top: 80px; } }

/* ============== Isracard: one rhythm between the case-study sections ==============
   200 px on desktop, 96 px on mobile, as the only space between two sections (margin-top of the next one; the Soft Canvas band and
   the content end use the same value as padding). Only section-level spacing; nothing inside the sections changes. */
/* Section rhythm, one gap per case study: Isracard 200 px, TwentySix 160 px (96 px on both below 900) */
.case-content:is(.case-content--isr, .case-content--ts) { --section-gap: 200px; padding-bottom: var(--section-gap); }   /* last section → Next project band */
.case-content.case-content--ts { --section-gap: 160px; padding-bottom: 0; }   /* TwentySix ends on the Visual direction band, whose own bottom padding is the gap */
.case-content:is(.case-content--isr, .case-content--ts) .ov-company { padding-top: var(--section-gap); }                 /* numbers band → Overview */
.case-content:is(.case-content--isr, .case-content--ts) > :is(.case-goals, .case-impact, .case-constraints, .case-process, .case-audience, .case-ba, .case-workflows, .case-brand) { margin-top: var(--section-gap); }
.case-content:is(.case-content--isr, .case-content--ts) > :is(.case-beyond, .ts-prod) { margin-top: 0; padding-top: var(--section-gap); padding-bottom: var(--section-gap); }   /* the band starts right after Before & after */
@media (max-width: 900px) { .case-content.case-content:is(.case-content--isr, .case-content--ts) { --section-gap: 96px; } }

/* ============== TwentySix case study (#/projects/project-2) ==============
   Built from the Isracard system: .case-hero / .case-meta / .case-dashboard, .case-stats, .case-overview / .ov-*, .case-goals / .goal,
   .case-impact, .case-constraints / .constraint-card, .process-*, .case-audience, .case-workflows / .wf-* (pins), .case-beyond band, nextSection().
   Local classes below only place things (layout, widths) or mark provisional assets; no new colours, type styles or cards. */
.ts-lead { width: 760px; max-width: 100%; margin: 0; text-align: center; }
/* Desktop hero rhythm, tighter than the shared 48 / 48 / 48: title → lead 32, lead → project facts 38, facts → screenshot 38 */
@media (min-width: 901px) {
  .case-hero--ts .case-hero-inner { gap: 38px; }
  .case-hero--ts .case-title { gap: 0; }
  .case-hero--ts .ts-lead { margin-top: 32px; }
  .case-hero--ts .case-meta { margin-top: 38px; }
}
/* Hero visual: the Isracard dashboard frame (radius, drop shadow) at the full hero width, with the screen's own ratio */
.ts-hero-visual .case-dashboard { aspect-ratio: 2880 / 1846; }
/* Pull-back (Detail-to-system): the frame fades in on its final place and size (300 ms); then, inside the still frame
   (overflow: hidden), the screenshot pulls back from a 1.6x close-up of card 2 (stock status, sizes, Add to bag) to 1x in 1200 ms,
   long ease-out, no overshoot. Only the image moves. 2D only (translate + scale of the image inside the clipped frame); classes removed
   at the end, so the resting hero is the static image. */
.ts-hero-visual.is-pull-armed { opacity: 0; }
.ts-hero-visual.is-pull-armed .case-dashboard img { transform-origin: 0 0; transform: translate(var(--pull-tx), var(--pull-ty)) scale(var(--pull-s)); }
.ts-hero-visual.is-pulling { animation: tsHeroFade 300ms ease-out both; }
.ts-hero-visual.is-pulling .case-dashboard img { transform-origin: 0 0; animation: tsHeroPull 1200ms cubic-bezier(.2, .7, .2, 1) 300ms both; }
@keyframes tsHeroFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes tsHeroPull { from { transform: translate(var(--pull-tx), var(--pull-ty)) scale(var(--pull-s)); } to { transform: none; } }
.ts-eyebrow-icon { width: 30px; height: 30px; margin: -5px 0; }   /* 109-unit monogram artboard (glyph 72% of it, as before): glyph lands at the Isracard icon size */



/* Overview (Isracard component): unit after a one-digit value keeps the Isracard 8.7 px gap after "1.5" (24.6 + 8.7);
   four role steps share the full 1252 px line evenly on wide screens (Isracard: five 250 px steps); below 1321 the shared wrap rules apply */
.ts-stats .case-stat-caption { white-space: normal; }   /* the long ranking caption wraps on narrow screens instead of overflowing */
.ts-overview .ov-timeline-unit { left: 33px; }
@media (min-width: 1321px) { .ts-overview .ov-role-item { flex: 1 1 0; min-width: 0; } }
/* Collaborated with: light TwentySix palette backgrounds (City Edit: soft cream, light blue, soft blush), so initials take the ink colour */

/* Target audience: Soft Canvas band (full bleed, .case-beyond technique); text left, compact card with a 4:5 portrait right */
.case-audience.audience-band { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 64px; align-items: center; padding: 104px 0;
  background: var(--soft); box-shadow: 0 0 0 100vmax var(--soft); clip-path: inset(0 -100vmax); }
.audience-text { display: flex; flex-direction: column; }
.audience-text .case-h2 { margin-top: var(--space-label); }
.audience-text .process-text { margin-top: var(--space-title); }
.audience-card { display: flex; align-items: center; gap: 40px; padding: 24px; background: var(--canvas); border-radius: 8px; }
.audience-card img { display: block; flex: none; width: 240px; height: auto; aspect-ratio: 4 / 5; object-fit: cover; border-radius: 8px; }
.audience-card-text { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.audience-card-text .case-h3 { margin-top: 4px; white-space: normal; }
/* Wide variant (both case studies): the card carries audiences + pain points, so it takes 8 of 12 columns and the photo matches the text
   height; texts follow the card rhythm (label 16, groups 24, pain points title 12 above its list) */
.case-audience.audience-band--wide { grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); }
.audience-band--wide .audience-text .case-h2 { margin-top: 0; }
.audience-band--wide .audience-card { align-items: stretch; }
.audience-band--wide .audience-card img { width: 44%; height: auto; min-height: 100%; aspect-ratio: auto; object-position: 60% center; }
.audience-band--wide .audience-card-text { gap: 0; padding: 16px 16px 16px 0; }
.audience-card-text .ov-label + .audience-groups { margin-top: var(--space-label); }
.audience-groups { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 24px; }
.audience-groups li { display: flex; flex-direction: column; gap: 4px; }
.audience-groups + .text-body-strong { margin-top: 40px; }
.audience-card-text .text-body-strong + .process-questions { margin-top: 12px; gap: 8px; }
@media (max-width: 1100px) { .case-audience.audience-band { grid-template-columns: minmax(0, 1fr); gap: 40px; } }
@media (max-width: 900px) { .case-audience.audience-band { padding: 64px 0; } }
@media (max-width: 600px) {
  .audience-card { flex-direction: column; align-items: flex-start; gap: 24px; }
  .audience-card img { width: min(240px, 100%); }
  .audience-band--wide .audience-card img { width: 100%; min-height: 0; aspect-ratio: 4 / 5; }
  .audience-band--wide .audience-card-text { padding: 0; }
}
/* Card shadow: the hero screen's shadow (same hue, low Y offset, wide soft blur), scaled down for cards that sit 24 px apart */
.ts-process { --ts-card-shadow: 0 4px 32px 0 rgba(38, 38, 73, .10); }
.ts-frame { width: 100%; display: grid; grid-template-columns: minmax(0, 1fr) 160px minmax(0, 1fr); align-items: center; }
.ts-frame-inputs { display: grid; grid-auto-rows: 1fr; gap: 24px; }
.ts-frame-card { padding: 32px; gap: 12px; }
.ts-frame-card .ov-label { margin-top: 4px; }
.ts-frame-icon, .ts-issue-icon { display: block; width: 32px; height: 32px; color: var(--cyan); flex: none; }
.ts-frame-icon svg, .ts-issue-icon svg { display: block; }
.ts-frame-card--focus { background: var(--canvas); border-left: 3px solid var(--cyan); border-radius: 0 8px 8px 0;
  box-shadow: var(--ts-card-shadow); }
.ts-frame-links { position: relative; align-self: stretch; }
.ts-frame-curves { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.ts-frame-curves path, .ts-frame-head path { fill: none; stroke: var(--secondary); stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }   /* the Isracard bridge line */
.ts-frame-curves { padding: 0 12px; box-sizing: border-box; }
.ts-frame-head { position: absolute; right: 8px; top: 50%; width: 12px; height: 12px; transform: translateY(-50%); overflow: visible; }
.ts-frame-down { display: none; }
/* Key interface issues: white cards with a soft shadow on the page background, middle card lowered (old TwentySix stagger) */
.ts-issues { padding-bottom: 0; }   /* the lowered middle card already sets the list height */
.ts-issues .process-insight { background: var(--canvas); border-radius: 0; min-height: 0; box-shadow: var(--ts-card-shadow); align-self: flex-start; }
.ts-issues .process-insight:nth-child(2) { margin-top: 44px; }
.ts-issues .wf-frame { max-width: 400px; }   /* evidence fragment: card width at 1440; stays compact when a card spans the row */
@media (max-width: 1100px) {
  .ts-frame { grid-template-columns: minmax(0, 1fr) 96px minmax(0, 1fr); }
  .ts-issues .process-insight:nth-child(2) { margin-top: 0; }
}
@media (max-width: 900px) {
  .ts-frame { grid-template-columns: minmax(0, 1fr); }
  .ts-frame-curves, .ts-frame-head { display: none; }
  .ts-frame-down { display: flex; justify-content: center; padding: 16px 0; }
  .ts-frame-down svg { transform: rotate(90deg); }
  .ts-frame-card { padding: 24px; }
  .ts-issues { padding-bottom: 0; }
}
/* Problem framing, once on entry: the two curves draw toward UX focus (dash offset), the head follows, then the focus card opens
   left to right behind its Cyan line (clip-path, width untouched) and its content fades in. ≤900: the down arrow wipes in instead.
   All classes are removed at the end, so the resting block is the static one. */
.ts-frame.is-armed .ts-frame-curves path, .ts-frame.is-armed .ts-frame-head path { stroke-dasharray: var(--len) var(--len); stroke-dashoffset: var(--len); }   /* --len: on-screen length in px (non-scaling strokes dash in screen space), set by mountFrameReveal */
.ts-frame.is-armed .ts-frame-down svg { clip-path: inset(0 100% 0 0); }
.ts-frame.is-armed .ts-frame-card--focus { clip-path: inset(0 100% 0 0); }
.ts-frame.is-armed .ts-frame-card--focus > * { opacity: 0; }
.ts-frame.is-in .ts-frame-curves path { animation: tsFrameDraw 800ms cubic-bezier(0.45, 0, 0.25, 1) both; }
.ts-frame.is-in .ts-frame-head path { animation: tsFrameDraw 240ms cubic-bezier(0.33, 0, 0.2, 1) 720ms both; }
.ts-frame.is-in .ts-frame-card--focus { animation: tsFrameOpen 680ms cubic-bezier(0.4, 0, 0.2, 1) 940ms both; }
.ts-frame.is-in .ts-frame-card--focus > * { animation: tsFrameFade 460ms cubic-bezier(0.25, 0, 0.2, 1) both; }
.ts-frame.is-in .ts-frame-card--focus > .ts-frame-icon { animation-delay: 1280ms; }
.ts-frame.is-in .ts-frame-card--focus > :is(.ov-label, .process-h4) { animation-delay: 1340ms; }
.ts-frame.is-in .ts-frame-card--focus > .process-text { animation-delay: 1400ms; }
@media (max-width: 900px) {
  .ts-frame.is-in .ts-frame-down svg { animation: tsFrameWipe 420ms cubic-bezier(0.45, 0, 0.25, 1) both; }
  .ts-frame.is-in .ts-frame-card--focus { animation-delay: 380ms; }
  .ts-frame.is-in .ts-frame-card--focus > .ts-frame-icon { animation-delay: 720ms; }
  .ts-frame.is-in .ts-frame-card--focus > :is(.ov-label, .process-h4) { animation-delay: 780ms; }
  .ts-frame.is-in .ts-frame-card--focus > .process-text { animation-delay: 840ms; }
}
@keyframes tsFrameDraw { to { stroke-dashoffset: 0; } }
@keyframes tsFrameWipe { to { clip-path: inset(0 0 0 0); } }
@keyframes tsFrameOpen {   /* the 3 px Cyan line appears at full height at once, then the card opens; the box shadow comes in with it (-48 px) */
  0% { clip-path: inset(0 100% 0 0); }
  0.1% { clip-path: inset(0 calc(100% - 3px) 0 0); }
  30% { clip-path: inset(0 calc(100% - 3px) 0 0); }
  100% { clip-path: inset(-48px -48px -48px -48px); }
}
@keyframes tsFrameFade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* Product opportunity (UX Design Solutions): header, a static flowchart, then the business value under a Quiet Rule line.
   Yes path in Ink, No path in Secondary; Signal Cyan only on Add to Bag. Up to 1100 px the chart turns vertical. */
/* Desktop: header left, the business value card right in the same top row, the flowchart full width below */
.ts-opp { display: grid; grid-template-columns: minmax(0, 1fr) 420px; column-gap: 64px; row-gap: 56px; align-items: start; margin-top: 76px; }   /* + the stage's 60 px gap = 136 px under the UX focus framing */
.ts-opp > .process-subtitle { grid-column: 1; grid-row: 1; }
.ts-opp > .ts-opp-flow { grid-column: 1 / -1; grid-row: 2; }
.ts-opp-flow { display: grid; grid-template-columns: auto 48px auto 104px auto 48px auto; grid-template-rows: repeat(2, minmax(104px, 1fr)); justify-content: start; align-items: center; color: var(--ink); }   /* two equal rows: the branch lines meet them at 25 % / 75 % */
.ts-opp-node { display: flex; align-items: center; justify-content: center; min-height: 64px; padding: 12px 32px; text-align: center; box-sizing: border-box; color: var(--ink); }
.ts-opp-node--start   { grid-column: 1; grid-row: 1 / 3; border: 1.5px solid var(--ink); border-radius: 999px; }
.ts-opp-node--choose  { grid-column: 5; grid-row: 1; background: var(--soft); border: 1px solid var(--rule); border-radius: 8px; }
.ts-opp-node--add     { grid-column: 7; grid-row: 1; background: var(--cyan); border-radius: 999px; }
.ts-opp-node--restock { grid-column: 5 / 8; grid-row: 2; justify-self: start; border: 1.5px solid var(--secondary); border-radius: 999px; }
.ts-opp-arrow { grid-column: 2; grid-row: 1 / 3; position: relative; width: 48px; height: 12px; justify-self: center; }
.ts-opp-arrow--2 { grid-column: 6; grid-row: 1; }
.ts-opp-arrow svg { position: absolute; left: 50%; top: 50%; width: 48px; height: 12px; transform: translate(-50%, -50%); overflow: visible; }
.ts-opp-flow svg path { fill: none; stroke: var(--ink); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.ts-opp-flow svg path.ts-opp-head, .ts-opp-flow .ts-opp-tip path { fill: var(--ink); stroke: none; }
.ts-opp-flow svg path.is-no { stroke: var(--secondary); }
.ts-opp-flow .ts-opp-tip.is-no path { fill: var(--secondary); }
.ts-opp-decision { grid-column: 3; grid-row: 1 / 3; position: relative; width: 152px; aspect-ratio: 1; display: grid; place-items: center; text-align: center; color: var(--ink); }
.ts-opp-decision svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.ts-opp-decision svg path { fill: var(--canvas); }
.ts-opp-decision span { position: relative; }
.ts-opp-branch { grid-column: 4; grid-row: 1 / 3; position: relative; align-self: stretch; }
.ts-opp-branch svg:not(.ts-opp-tip) { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.ts-opp-branch-v { display: none; }
.ts-opp-tip { position: absolute; right: 0; width: 10px; height: 10px; transform: translateY(-50%); }
.ts-opp-tip.is-yes { top: 25%; }
.ts-opp-tip.is-no  { top: 75%; }
.ts-opp-tag { position: absolute; left: 48%; color: var(--ink); }
.ts-opp-tag--yes { top: calc(25% - 24px); }
.ts-opp-tag--no  { top: calc(75% - 24px); color: var(--secondary); }
/* Potential business value: compact light card (420 px on desktop), 12 px radius, 20 px padding, no border, no shadow;
   Angela's lightbulb icon (32 px, Figma 865:2824) beside the text; title SemiBold 18, text Regular 16, both 1.6 */
.ts-opp-value { grid-column: 2; grid-row: 1; display: flex; align-items: flex-start; gap: 8px; box-sizing: border-box; padding: 20px; background: color-mix(in srgb, var(--cyan) 7%, var(--canvas)); border-radius: 12px; color: var(--ink); }   /* very light Signal Cyan tint, no border, no shadow */
.ts-opp-value .text-body-strong { font-size: 18px; line-height: 1.6; }
.ts-opp-value .process-text { font-size: 16px; line-height: 1.6; }
.ts-opp-value-icon { display: block; flex: none; width: 32px; height: 32px; }   /* same height as the 32 px first line */
.ts-opp-value-text { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
@media (max-width: 1100px) {
  /* vertical: start → decision → two branches side by side; Yes continues to Add to Bag */
  .ts-opp-flow { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: none; row-gap: 0; justify-content: stretch; justify-items: center; align-items: start; }
  .ts-opp-node { padding: 12px 24px; max-width: calc(100% - 16px); }
  .ts-opp-node--start   { grid-column: 1 / 3; grid-row: 1; }
  .ts-opp-arrow         { grid-column: 1 / 3; grid-row: 2; width: 12px; height: 40px; }
  .ts-opp-arrow svg     { width: 40px; transform: translate(-50%, -50%) rotate(90deg); }
  .ts-opp-decision      { grid-column: 1 / 3; grid-row: 3; width: 136px; }
  .ts-opp-branch        { grid-column: 1 / 3; grid-row: 4; width: 100%; height: 72px; }
  .ts-opp-branch-h { display: none; }
  .ts-opp-branch-v { display: block; }
  .ts-opp-tip { top: auto; bottom: 0; right: auto; transform: translate(-50%, 0) rotate(90deg); }
  .ts-opp-tip.is-yes { top: auto; left: 25%; }
  .ts-opp-tip.is-no  { top: auto; left: 75%; }
  .ts-opp-tag--yes { top: auto; bottom: 16px; left: calc(25% + 12px); }
  .ts-opp-tag--no  { top: auto; bottom: 16px; left: calc(75% + 12px); }
  .ts-opp-node--choose  { grid-column: 1; grid-row: 5; }
  .ts-opp-arrow--2      { grid-column: 1; grid-row: 6; }
  .ts-opp-node--add     { grid-column: 1; grid-row: 7; }
  .ts-opp-node--restock { grid-column: 2; grid-row: 5 / 8; justify-self: center; }   /* spans the Yes column's three rows, so a taller No box never pushes its arrow away */
}
@media (max-width: 900px) {   /* one column: header → business value → flowchart */
  .ts-opp { grid-template-columns: minmax(0, 1fr); }
  .ts-opp-value { grid-column: 1; grid-row: 2; width: min(420px, 100%); }
  .ts-opp > .ts-opp-flow { grid-row: 3; }
}
@media (max-width: 600px) {
  .ts-opp { gap: 40px; }
  .ts-opp-node { min-height: 56px; padding: 10px 16px; font-size: 16px; line-height: 1.4; }
  .ts-opp-decision { width: 120px; font-size: 16px; }
  .ts-opp { margin-top: 20px; }   /* + 60 = 80 px on phones */
}

/* Key interface issues inside the timeline: Isracard's 2 x 2 grid rule does not apply, the three cards stay in one row (wrap below 1100) */
.ts-process.case-process--isr .process-insights { flex: none; width: 100%; display: flex; }

/* Before & after: per screen the goal, Isracard's scroll comparison (baComparison) and the main changes */
.ts-area + .ts-area { margin-top: 72px; }
.ts-ba { --ts-shot-shadow: 0 4px 32px 0 rgba(38, 38, 73, .10); }
.ts-ba .ba-stage { width: min(100%, calc((100vh - 72px - 112px) * var(--ba-ratio))); }   /* pinned stage fits the viewport at the image's own ratio (frame + progress row) */
.ts-ba :is(.ba-frame, .ba-after) { background: var(--canvas); }   /* a shorter Before capture ends on page white, not on grey */
.ts-area { display: flex; flex-direction: column; gap: 48px; }
/* Wishlist restock block: two original screens overlapped on a stage, with the TwentySix card shadow */
.ts-pp-shot { position: relative; background: var(--canvas); box-shadow: var(--ts-shot-shadow); }
.ts-pp-shot img { display: block; width: 100%; height: auto; }
.ts-pp-stage { position: relative; aspect-ratio: 100 / 67.5; }
.ts-pp-shot--back  { position: absolute; left: 0; top: 26%; width: 60%; }
.ts-pp-shot--front { position: absolute; right: 0; top: 0; width: 60%; z-index: 1; }
.ts-pp-after { display: flex; flex-direction: column; gap: 40px; }

/* Visual direction: white section (Canvas White) after the Soft Canvas Vibe coding band, so it does not merge with the grey Next project
   block below. The .case-beyond padding and the Newsletter track keep their layout; only the band colour changes. */
.ts-visual { gap: 64px; margin-top: 0; }
.case-beyond.ts-visual { background: var(--canvas); box-shadow: 0 0 0 100vmax var(--canvas); }
.ts-visual .ts-nl.ba-track--mobile { background: var(--canvas); box-shadow: 0 0 0 100vmax var(--canvas); }
.ts-visual-intro { display: flex; flex-direction: column; gap: var(--space-list); max-width: 100%; }   /* two intro paragraphs, 16 apart (same as .case-brand) */
.ts-visual .beyond-header .case-h2 { white-space: normal; flex: 1 1 auto; min-width: 0; }   /* the longer TwentySix title wraps (balanced) beside the 527 px intro instead of pushing it off screen */
.ts-visual .ts-visual-intro { flex: none; max-width: min(527px, 100%); }
/* City Edit: Angela's 2x export of the original PDF (2880 x 3744 PNG, unmodified), full content width, natural ratio */
.ts-ce { margin: 0; }
.ts-ce img { display: block; width: 100%; height: auto; }
/* Newsletter: Isracard's "Mobile web" track reused as is (.ba-track--mobile + .ba-sticky + .ba-mobile, scrubbed by mountBeforeAfter):
   the stage pins under the nav and the email moves up inside its frame with page scroll. Local overrides only place it:
   text on 4 of 12 columns right next to one wider frame (440 x up to 620) for a single 1280 x 6070 email. */
@media (min-width: 901px) { .ts-nl .ba-mobile { grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); } }   /* 900 and below: Isracard stacks text over the frame */
.ts-nl .ba-phone-frame { aspect-ratio: auto; width: 440px; height: min(820px, calc(100vh - 72px - 48px)); }   /* 620 + 200, capped to the pinned stage minus 24 px above and below (780 at 900 px tall) */
.ts-nl.ba-track--mobile { height: 220vh; }
/* Desktop: City Edit bottom -> Newsletter frame top = 120 px on any screen height. The pinned stage is only as tall as the frame
   (24 px above and below, as Isracard's dashboard stage) and starts at the top instead of centring the frame in 100vh, so tall
   screens no longer add empty space above or below. 96 + 24 = 120. */
@media (min-width: 901px) {
  .ts-visual > .ts-nl { margin-top: calc(96px - 140px); }
  .ts-nl .ba-sticky { align-items: flex-start; padding-top: 24px; height: calc(min(820px, 100vh - 72px - 48px) + 48px); }
}
@media (min-width: 601px) and (max-width: 900px) {   /* tablets: text over the frame, stage sized to its content, no centring void */
  .ts-nl .ba-sticky { align-items: flex-start; padding: 24px 0; height: auto; }
}   /* longer track than Isracard's 170vh: the 1280 x 6070 email travels ~1.5x the page scroll instead of ~2.5x */
@media (max-width: 600px) {   /* phones: no pinning or scrub, a static top-of-email preview; the full email opens in the Lightbox */
  .ts-nl.ba-track--mobile { height: auto; }
  .ts-nl .ba-sticky { position: static; height: auto; padding: 0; }
}

/* Vibe coding: heading block, then the working prototype on the full content width (in the .wf-frame 1 px frame) */
/* Soft Canvas band, full bleed (.case-beyond technique). The former 120 px top margin becomes padding, and 120 px bottom padding replaces
   Visual direction's top margin, so every element keeps its position. */
.ts-prod { display: flex; flex-direction: column; gap: 48px; padding: 120px 0;
  background: var(--soft); box-shadow: 0 0 0 100vmax var(--soft); clip-path: inset(0 -100vmax); }
.case-content--ts > .case-workflows + .ts-prod { margin-top: 120px; }   /* white space before the Soft Canvas band, as Isracard (.case-workflows + .ba-track--mobile): the restock screens no longer touch the band */
.ts-proto { overflow: hidden; background: var(--canvas); }
/* "Interactive prototype" cue: label with a click icon, then the two scenarios to try, on one line above the frame (wraps on narrow screens) */
.ts-proto-wrap { display: flex; flex-direction: column; gap: 20px; }
.ts-proto-hint { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 32px; }
.ts-proto-hint-label { display: inline-flex; align-items: center; gap: 8px; margin: 0; font-family: var(--font-body); font-weight: 600; font-size: 16px; line-height: 1.5; color: var(--ink); }
.ts-proto-hint-label svg { flex: none; color: var(--cyan); }
.ts-proto-hint-list { display: flex; flex-wrap: wrap; gap: 8px 24px; margin: 0; padding: 0; list-style: none; }
.ts-proto-hint-list li { display: flex; align-items: flex-start; gap: 8px; font-family: var(--font-body); font-size: 16px; line-height: 1.5; color: var(--secondary); }
.ts-proto-hint-n { display: grid; place-items: center; flex: none; width: 22px; height: 22px; margin-top: 1px; border: 1px solid var(--rule); border-radius: 50%; background: var(--canvas);
  font-size: 12px; font-weight: 600; line-height: 1; color: var(--ink); }
@media (max-width: 600px) { .ts-proto-hint { flex-direction: column; align-items: flex-start; } .ts-proto-hint-list { flex-direction: column; } .ts-proto-wrap { gap: 16px; } }
.ts-proto-frame { display: block; width: 100%; height: 760px; border: 0; background: #fff; }   /* the Embed's own heights until the page reports its real one */
@media (max-width: 900px) { .ts-proto-frame { height: 1100px; } }
@media (max-width: 560px) { .ts-proto-frame { height: 2250px; } }
.ts-prod .ba-header-title { gap: var(--space-label); }
.ts-prod .ba-header-title .case-h2 { max-width: 760px; text-wrap: balance; }   /* two balanced lines on desktop */
.ts-prod .ba-header-title .process-text { max-width: 640px; }   /* same text measure as the TwentySix process column */

@media (max-width: 1100px) {
  .ts-prod { gap: 40px; }
}
@media (max-width: 900px) {
  .ts-nl .ba-phone { width: min(100%, 440px); }
  .ts-nl .ba-phone-frame { width: 100%; height: min(560px, calc(100vh - 72px - 300px)); max-height: none; }
  .ts-prod { padding: 80px 0; }
  .case-content--ts > .case-workflows + .ts-prod { margin-top: 80px; }
}

/* ============== Beyond the dashboard (Figma 771:13652): after Mobile web + App ==============
   Soft Canvas band, full bleed. Header: H2 + intro 120 px apart. Each group is the Figma 1276 x 970 stage:
   text 464 wide top-left, screen A (375 x 796) at x 419 / y 174, screen B at x 901 / y 0, positions in % so it scales with the column. */
.case-beyond { position: relative; width: 100%; padding: 120px 0; display: flex; flex-direction: column; gap: 140px;
  background: var(--soft); box-shadow: 0 0 0 100vmax var(--soft); clip-path: inset(0 -100vmax); }
.beyond-header { display: flex; gap: 120px; align-items: flex-start; }
.beyond-header .case-h2 { white-space: nowrap; }
.beyond-header .process-text { width: 527px; max-width: 100%; }
.beyond-groups { display: flex; flex-direction: column; gap: 154px; }
.beyond-group { position: relative; width: 100%; aspect-ratio: 1276 / 970; }
.beyond-text { position: absolute; left: 0; top: 0; width: calc(387 / 1276 * 100%); display: flex; flex-direction: column; gap: 12px; }   /* Figma 464; narrowed to end 32 px before screen A (x 419) so the longer copy never runs under the screen or its caption */
.beyond-text .case-h3 { white-space: normal; }
.beyond-screen { position: absolute; margin: 0; width: calc(375 / 1276 * 100%); aspect-ratio: 375 / 796; }
.beyond-screen--a { left: calc(419 / 1276 * 100%); top: calc(174 / 970 * 100%); }
.beyond-screen--b { left: calc(901 / 1276 * 100%); top: 0; }
/* Screen frame: white with the original 38 px corners, no outline (review) */
.beyond-frame { width: 100%; height: 100%; background: var(--canvas); border-radius: calc(38 / 375 * 100%) / calc(38 / 796 * 100%); overflow: hidden; }
.beyond-frame img { display: block; width: 100%; height: 100%; object-fit: contain; }
/* Caption under each screen: sits outside the screen box (12 px below), so screen positions stay as in Figma */
.beyond-caption { position: absolute; left: 0; right: 0; top: calc(100% + 12px); }   /* position only; type comes from .screen-caption */
@media (max-width: 1100px) {
  .beyond-header { flex-direction: column; gap: 20px; }
  .beyond-header .case-h2 { white-space: normal; }
  .beyond-group { aspect-ratio: auto; display: flex; flex-wrap: wrap; align-items: flex-start; gap: 32px 24px; }
  .beyond-text { position: static; }
  .beyond-screen { position: relative; left: auto; top: auto; }
  .beyond-screen { aspect-ratio: auto; }
  .beyond-frame { height: auto; aspect-ratio: 375 / 796; }
  .beyond-caption { position: static; margin-top: 12px; }   /* in the flow: caption right under its own screen */
  .beyond-text { width: 100%; max-width: 560px; }
  .beyond-screen { width: min(375px, calc((100% - 24px) / 2)); }
  .beyond-screen--b { margin-top: 0; }
}
@media (max-width: 900px) {
  .case-beyond { padding: 80px 0; gap: 64px; }
  .beyond-groups { gap: 80px; }
  .beyond-header .process-text, .beyond-text .process-text { font-size: 18px; }
  .beyond-text .case-h3 { font-size: var(--fs-h3-m); }
}
@media (max-width: 600px) {
  .beyond-group { flex-direction: column; align-items: center; gap: 32px; }
  .beyond-screen { width: min(320px, 100%); }
}

/* ============== More key workflows (after the Dashboard and Registration Before / After, before Mobile web + App): final screens only, no Before ============== */
.case-workflows { margin-top: 120px; width: 100%; display: flex; flex-direction: column; gap: 48px; }
.wf-header { display: flex; flex-direction: column; gap: 16px; width: 731px; max-width: 100%; }
.wf-screen { margin: 0; width: 100%; display: flex; flex-direction: column; gap: 20px; }
.wf-screen .ba-head { border-bottom-color: var(--rule); }
.wf-frame { position: relative; width: 100%; }
.wf-frame img { display: block; width: 100%; height: auto; }   /* original ratio, no crop */
.wf-frame::after { content: ""; position: absolute; inset: 0; border: 1px solid var(--rule); pointer-events: none; }
/* Screen header: title, then (Results only) its supporting paragraph 16 px below; numbered points start 40 px lower */
.wf-screen-head { display: flex; flex-direction: column; gap: 16px; }
.case-workflows .wf-intro { width: 731px; max-width: 100%; }
.wf-screen + .wf-screen { margin-top: 48px; }                         /* 48 + section gap 48 = 96 px: a clear new section */
/* Results: numbered points as a plain vertical list under the paragraph; matching numbered markers on the screenshot.
   No connector lines: the shared number is the only link. */
.wf-points { list-style: none; margin: 8px 0 0; padding: 0; width: 731px; max-width: 100%; display: flex; flex-direction: column; gap: 16px; }   /* paragraph → list: 16 + 8 = 24 px */
.wf-point { display: flex; align-items: flex-start; gap: 12px; }
.wf-point-num { flex: none; min-width: 10px; font-family: var(--font-body); font-weight: 600; font-size: 16px; line-height: 1.5; color: var(--ink); }   /* plain list numbering, same size as the text */
.case-workflows .wf-point-text { margin: 0; font-family: var(--font-body); font-weight: 400; font-size: 16px; line-height: 1.5; color: var(--ink); }
.wf-screen-head:has(.wf-points) { margin-bottom: 20px; }   /* list → screenshot: 20 + figure gap 20 = 40 px */
.wf-pin { position: absolute; width: 0; height: 0; z-index: 2; }
.wf-pin-dot {
  position: absolute; left: -17px; top: -17px; width: 34px; height: 34px; border-radius: 50%;
  background: var(--cyan); color: var(--canvas); display: grid; place-items: center;   /* solid Signal Cyan, white number */
  font-family: var(--font-body); font-weight: 600; font-size: 15px; line-height: 1;
}
.case-workflows + .ba-track--mobile { margin-top: 120px; }   /* same 120 / 80 px rhythm before the Soft Canvas band */
@media (max-width: 900px) { .case-workflows { margin-top: 80px; gap: 32px; } .wf-screen + .wf-screen { margin-top: 32px; } .case-workflows + .ba-track--mobile { margin-top: 80px; } }

/* Reduced motion: no pinning, no scrub. Each comparison shows its final After state. */
@media (prefers-reduced-motion: reduce) {
  .ba-track--dash, .ba-track--reg, .ba-track--flow, .ba-track--mobile { height: auto; }
  .ba-sticky { position: static; height: auto; padding: 32px 0; }
  .ba-after { clip-path: none; }
  .ba-fill { width: 100%; }
}

@media (max-width: 1320px) {
  .process-row { gap: 64px; }
  .process-context { flex-wrap: wrap; row-gap: 40px; }
  .process-bridge { width: auto; height: auto; padding: 0 24px; align-self: center; }
}
@media (max-width: 1100px) {
  .process-row { flex-direction: column; align-items: flex-start; gap: 40px; }
  .process-stage--existing .process-subtitle, .process-research-col, .process-card--problems, .process-card--questions { flex: none; width: 100%; max-width: 640px; }
  .process-insights { flex-wrap: wrap; }
  .process-insight { flex: 1 1 calc(50% - 12px); }
  .process-context { flex-direction: column; align-items: flex-start; }
  .process-bridge { padding: 0; }
  .process-rail-track { height: 100%; }   /* stacked stages make the section longer than 2086 px: the line has to reach the last dot */
}
@media (max-width: 900px) {
  .case-process, .case-audience { margin-top: 80px; }
  .process-body { gap: 36px; }   /* 20 + 16 px (review) */
  .process-dot { left: -47px; }
  .process-stages { gap: 80px; }
  .process-text, .process-problems li, .process-questions li, .process-checks li { font-size: 18px; }
  .process-problems li { white-space: normal; }
}
@media (max-width: 600px) {
  .process-insight { flex-basis: 100%; min-height: 0; }
  .process-card--problems, .process-card--questions, .process-insight { padding: 24px; }
  .process-shared { padding: 24px; }
  .process-visual--desktop, .process-visual--mobile { width: 100%; }
  .process-visual--desktop .process-wire-slot { align-self: stretch; }
  .process-wire--desktop { width: 100%; height: auto; aspect-ratio: 496 / 500.392; }
}

/* ============== Constraints / My response (Figma 576:1963, 1276 x 968) ============== */
.case-constraints { margin-top: 120px; width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 48px; }   /* header → list: 48 */
.constraints-header { width: 100%; display: flex; flex-direction: column; gap: var(--space-title); }
.constraints-intro { margin: 0; width: 100%; font-family: var(--font-body); font-weight: 400; font-size: 20px; line-height: 1.6; }
.constraints-body { width: 100%; display: flex; flex-direction: column; gap: 24px; }                 /* labels → cards: 24 */
.constraints-labels { width: 1117px; max-width: 100%; display: flex; align-items: center; gap: 46px; padding-left: 24px; }   /* Figma 576:2048 */
.constraints-labels p:not(.ov-label) { margin: 0; font-family: var(--font-display); font-weight: 700; font-size: 32px; line-height: 1.2; letter-spacing: 0; color: var(--ink); white-space: nowrap; }
.constraints-labels p:first-child { flex: none; width: 520px; }
.constraints-list { list-style: none; margin: 0; padding: 0; width: 1111px; max-width: 100%; display: flex; flex-direction: column; gap: 32px; }   /* between cards: 32 */
.constraint-card { background: var(--soft); border: 1px solid var(--cyan); border-radius: 8px; padding: 31px; display: flex; flex-direction: column; gap: 12px; }   /* Figma 577:1832: p 32 incl. the 1 px stroke (Figma strokes take no layout space) */
.constraint-title { margin: 0; width: 382px; max-width: 100%; font-family: var(--font-display); font-weight: 600; font-size: 24px; line-height: 1.25; letter-spacing: 0; color: var(--ink); }
.constraint-row { display: flex; align-items: flex-start; gap: 24px; }
.constraint-col { margin: 0; min-width: 0; font-family: var(--font-body); font-weight: 400; font-size: 20px; line-height: 1.6; }
.constraint-col--constraint { flex: 0 1 476px; }
.constraint-col--constraint .constraint-text { max-width: 471px; }   /* text box 471 inside the 476 column */
.constraint-col--response { flex: 0 1 451px; }
.constraint-text { display: block; }
.constraint-arrow { flex: none; width: 32px; height: 32px; display: block; }   /* Figma 576:2031, top-aligned in the row */
.constraint-arrow svg { display: block; }
/* Isracard (Figma 576:1963, updated): column labels are the shared .ov-label (12 px uppercase, Secondary); card titles use
   Body / SemiBold (Instrument Sans 600, 20 / 1.6); 36 px between cards (review: 60 - 24) */
.case-constraints--isracard .constraints-labels .ov-label { white-space: nowrap; }
.case-constraints--isracard .constraint-title { font-family: var(--font-body); font-weight: 600; font-size: 20px; line-height: 1.6; }
.case-constraints--isracard .constraints-list { gap: 60px; }

@media (max-width: 1200px) {
  /* below the 1111 px card width: columns share the space in the Figma 476 : 451 ratio, labels follow them */
  .constraints-labels, .constraint-row { display: grid; grid-template-columns: minmax(0, 476fr) 32px minmax(0, 451fr); gap: 24px; }
  .constraints-labels { width: 100%; padding: 0 32px; }
  .constraints-labels p:first-child { width: auto; }
  .constraints-labels p:last-child { grid-column: 3; }
  .constraints-labels p { white-space: normal; }
}
@media (max-width: 900px) {
  .case-constraints { margin-top: 80px; }
  .constraints-labels { display: none; }   /* column labels stay available to screen readers inside each card */
  .constraint-card { padding: 23px; }
  .constraint-row { display: flex; flex-direction: column; gap: 12px; }
  .constraint-col--constraint, .constraint-col--response { flex: none; }
  .constraint-arrow { transform: rotate(90deg); }
  .constraints-intro, .constraint-col { font-size: 18px; }
  .case-constraints--isracard .constraint-title { font-size: 18px; }   /* same step as the body text on mobile */
  .case-constraints--isracard .constraints-list { gap: 32px; }
}

@media (max-width: 1200px) {
  .goals { flex-direction: column; gap: 0; padding-right: 0; width: 100%; }
  .goal { width: 100%; max-width: 640px; }
  .goal p { width: auto; }
  .case-h3 { white-space: normal; }
}
@media (max-width: 1520px) {
  .impact-list .impact-diagram { margin-top: 24px; }
}
@media (max-width: 900px) {
  .case-goals, .case-impact { margin-top: 80px; }
  .case-content { padding-bottom: 80px; margin-left: auto; margin-right: auto; }
  .case-h2 { font-size: var(--fs-h2); }
  .case-h3 { font-size: clamp(24px, 6.5vw, 32px); }
  .goal { padding: 19px 0 40px 20px; --goal-cap: 5px; --goal-rule: 60px; }
  .goal::before { left: 0; }
  .goal p, .impact-copy p, .impact-enabled ul { font-size: 18px; }
  .impact-enabled ul { gap: 8px; }
  .impact-body { padding-right: 0; }
  .ov-team-more { font-size: 18px; }
}
/* TwentySix Design goals on phones: lighter type; each goal keeps the desktop Signal Cyan top line (2 px here); spacing from the shared .goal (16 top, 40 bottom) */
@media (max-width: 600px) {
  .case-content--ts .case-goals { gap: 40px; }                       /* H2 → first goal */
  .case-content--ts .case-goals .case-h2 { font-size: 34px; }
  .case-content--ts .goal { gap: 10px; --goal-cap: 4px; --goal-rule: 52px; }
  .case-content--ts .goal::before { width: 2px; }
  .case-content--ts .goal .case-h3 { font-size: 22px; font-weight: 600; }
  .case-content--ts .goal p { font-size: 16px; line-height: 1.5; }
}
@media (max-width: 1320px) {
  .case-h3 { white-space: normal; }            /* long goal / impact titles wrap instead of spilling into the gap */
  .ov-role-list { flex-wrap: wrap; row-gap: 32px; }
}
@media (max-width: 900px) {
  .case-hero { padding-bottom: 72px; }
  .case-stats-inner { flex-direction: column; gap: 32px; padding: 48px 0; }
  .case-stats-label { width: auto; }
  .case-stats-list { flex-direction: column; gap: 28px; height: auto; }
  .case-stat { gap: 0; }
  .case-stat + .case-stat { padding-left: 0; }
  .case-stat-divider { display: none; }
  .case-stat-value { font-size: clamp(44px, 12vw, 64px); }
  .ov-company { padding-top: 80px; }   /* stats → Overview: same 80 px as the other mobile section gaps */
  .ov-title { font-size: var(--fs-h2); }
  .ov-text, .ov-body { font-size: 18px; }
  .ov-row { flex-wrap: wrap; gap: 8px 48px; }
  .ov-role-item { flex-basis: 100%; }
  .ov-body { white-space: normal; }
  .ov-block--platforms .ov-body { white-space: pre; }
  .ov-body .ov-sep { white-space: nowrap; }   /* the word before a "·" and the "·" stay together: a separator never starts a line; desktop keeps the parent's pre spacing */
}

/* ============== Home: Selected work (Figma 345:7824) ==============
   Frame 1920: two "Portfolio / Project Card" blocks 1272 px wide, 60 px apart, 112 px top/bottom.
   Preview geometry is expressed in % of the 760 x 546.13 preview so it scales on smaller screens. */
.work {
  background: var(--canvas);
  padding: clamp(64px, 5.834vw, 112px) clamp(20px, 5.625vw, 108px);
  display: flex; flex-direction: column; align-items: center;
}
.work-list { width: min(1272px, 100%); display: flex; flex-direction: column; gap: 80px; }   /* 80 px between projects (Figma: 60) */
/* Projects page: same cards; the page H1 sits on the card grid, 80 px above the first card (same rhythm as between cards).
   Top padding as on Resume (95 px under the header, 48 on mobile), bottom as on Home. */
.work--page { padding-top: clamp(48px, 4.948vw, 95px); }
.work-card { background: var(--soft); padding: 40px; display: flex; align-items: center; gap: 48px; }   /* Figma: p 40, gap 48 */
.work-preview { position: relative; flex: 0 0 auto; width: min(760px, 64%); aspect-ratio: 760 / 546.133; }
/* card 1: desktop + mobile composition (Figma I345:7827;365:3639) */
/* Figma card 1 is fixed at 548 px high: the layout box is the 468 px desktop screen; the phone sits at
   y 205 and hangs 60.5 px below the screen (20.5 px past the card edge), exactly as in the frame. */
.work-preview--composite { aspect-ratio: 760 / 468; filter: drop-shadow(0 18px 25px rgba(36, 30, 23, .09)); }
.work-desk {
  position: absolute; left: 0; top: 0; width: calc(758 / 760 * 100%); height: 100%;
  background: #fbfbfb; border-radius: 26px; overflow: hidden;       /* mockup surface from Figma */
}
.work-desk img { display: block; width: 100%; height: auto; }
.work-mob {
  position: absolute; left: calc(568 / 760 * 100%); top: calc(205 / 468 * 100%);
  width: calc(148.163 / 760 * 100%); aspect-ratio: 148.163 / 323.49;
  filter: drop-shadow(0 18px 10px rgba(36, 30, 23, .08));
}
.work-mob img { display: block; width: 100%; height: 100%; }
/* card 2: single image (Figma 365:3635) */
.work-preview--image {
  aspect-ratio: 760 / 532;   /* Figma 365:3635: 760 x 532 frame, the 768 x 546 image anchored top-left and clipped */
  background: var(--canvas); border-radius: 26px; overflow: hidden;
  box-shadow: 0 18px 50px 0 rgba(36, 30, 23, .09);
}
/* The export is the 760 x 546 preview frame itself (the 768 px image already clipped by Figma) */
.work-preview--image img { position: absolute; left: 0; top: 0; width: 100%; height: 100%; object-fit: cover; object-position: left top; max-width: none; }
.work-preview .ph-media { position: absolute; inset: 0; border-radius: 0; }

.work-summary { flex: 1 0 0; min-width: 1px; overflow: clip; display: flex; flex-direction: column; align-items: flex-start; gap: 48px; color: var(--ink); }
.work-text { width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 24px; }
.work-heading { display: flex; flex-direction: column; gap: 12px; width: min(386px, 100%); }
.work-title { margin: 0; font-family: var(--font-display); font-weight: 700; font-size: 32px; line-height: 1.2; letter-spacing: 0; }
.work-client { margin: 0; }
.work-client--meta { font-family: var(--font-display); font-weight: 600; font-size: 16px; line-height: 1.4; }      /* Figma Meta/Value, both cards */
.work-body { margin: 0; max-width: none; font-family: var(--font-body); font-weight: 400; font-size: 20px; line-height: 1.6; }
.work-role { display: flex; align-items: flex-start; gap: 4px; white-space: pre; }
.work-role-label { flex: none; font-weight: 600; }   /* natural width: "Role:" + 4 px gap, same in every card */
/* Tags as chips (Figma "Slot" / "chips" 740:2818): 1 px Quiet Rule border, radius 8, 4 / 8 padding, Body/Regular 16 in Secondary, 12 px apart */
.work-chips { margin: 0; padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: 12px; }
.work-chip { border: 1px solid var(--rule); border-radius: 8px; padding: 4px 8px; font-family: var(--font-body); font-weight: 400; font-size: 16px; line-height: 24px; color: var(--secondary); white-space: nowrap; }
.work-cta {
  display: inline-flex; align-items: center; gap: 12px;
  padding: 12px 16px 12px 24px; border-radius: 50px; background: var(--ink); color: var(--canvas); text-decoration: none;
  font-family: var(--font-display); font-weight: 700; font-size: 12px; line-height: 1.2; letter-spacing: 0;
  text-transform: uppercase; white-space: nowrap;
}
.work-cta:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
.work-cta .btn-arrow-svg path { fill: var(--cyan); }       /* Figma: cyan ↗ in the card CTA */
.work-cta-arrow { width: 22px; height: 22px; flex: none; }

@media (max-width: 1100px) {
  .work-card { flex-direction: column; align-items: stretch; gap: 32px; }
  .work-preview { width: 100%; }
  .work-role { white-space: normal; }
}
@media (max-width: 600px) {
  .work-card { padding: 20px; }
  .work-title { font-size: var(--fs-h3-m); }
  .work-body { font-size: 18px; }
  .work-desk, .work-preview--image { border-radius: 16px; }
}

/* ============== Resume page (Figma 541:2194) ==============
   1920 frame: content from x 161 (hero row from x 167, 1528 wide), left column 1111 px,
   right column at x 1459 (lists 336 px wide), both starting at y 332. */
.resume {
  padding: 95px calc(clamp(20px, 6.51vw, 125px) + var(--frame-gutter)) 120px calc(var(--page-x) + var(--frame-gutter));   /* centred 1920 frame above 1920 */
  color: var(--ink);
}
.resume-hero { width: min(1528px, 100%); display: flex; align-items: center; justify-content: space-between; gap: 24px; }
.resume-title, .page-title { margin: 0; font-family: var(--font-body); font-weight: 700; font-size: 64px; line-height: 1.1; letter-spacing: 0; white-space: nowrap; }
/* Download card (replaces the Download resume button, same place in the hero row). Built on .resume-card: white, 1 px Quiet Rule,
   8 px radius, 20 px padding incl. stroke, 336 px = the right column width. Outline icons in Signal Cyan, no plates (1.6 stroke).
   Title = Meta/Value (display 600 16), meta = the period style (display 400 14, Secondary). Hover / focus: a very light cyan tint. */
.resume-download {
  flex: none; width: 336px; max-width: 100%; box-sizing: border-box; padding: 19px; display: flex; align-items: center; gap: 16px;
  background: var(--canvas); border: 1px solid var(--rule); border-radius: var(--radius); color: var(--ink); text-decoration: none;
  transition: background-color 280ms cubic-bezier(0.22, 1, 0.36, 1), border-color 280ms cubic-bezier(0.22, 1, 0.36, 1);
}
.resume-download svg { flex: none; display: block; color: var(--cyan); }
.resume-download-text { flex: 1 0 0; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.resume-download-title { font-family: var(--font-display); font-weight: 600; font-size: 16px; line-height: 1.4; }
.resume-download-meta { font-family: var(--font-display); font-weight: 400; font-size: 14px; line-height: 1.5; color: var(--secondary); }
.resume-download-icon { transition: transform 280ms cubic-bezier(0.22, 1, 0.36, 1); }
.resume-download[href]:is(:hover, :focus-visible) { background: color-mix(in srgb, var(--cyan) 8%, var(--canvas)); border-color: color-mix(in srgb, var(--cyan) 40%, var(--rule)); }
.resume-download[href]:is(:hover, :focus-visible) .resume-download-icon { transform: translateY(2px); }   /* the arrow drifts toward the tray */
.resume-download:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
.resume-download:not([href]) { cursor: default; }
/* Placement: first item of the right column, 32 px above Keywords (one group), same 336 px column edges. The left column spans both rows,
   so Professional Experience keeps its position. One column (<= 1280): the card leads, 32 px above Professional Experience. */
.resume-main > .resume-download { grid-column: 2; grid-row: 1; margin-bottom: 32px; }
.resume-main > .resume-left { grid-column: 1; grid-row: 1 / span 2; }
.resume-main > .resume-right { grid-column: 2; grid-row: 2; }
@media (max-width: 1280px) {
  .resume-main > :is(.resume-download, .resume-left, .resume-right) { grid-column: 1; grid-row: auto; }
  .resume-main > .resume-download { margin-bottom: -48px; }   /* row-gap 80 - 48 = 32, same as above Keywords on desktop */
}
@media (max-width: 720px) { .resume-main > .resume-download { width: 100%; } }   /* phones: same edges as the full-width cards below */
@media (prefers-reduced-motion: reduce) { .resume-download, .resume-download-icon { transition: none; } .resume-download-icon { transform: none !important; } }
/* Contact card (above Resume): the .resume-card itself (white, 1 px Quiet Rule, 8 px radius, 20 px padding, label as KEYWORDS).
   Rows: Signal Cyan outline icon (1.6, no plate, as the Resume card), the value (Body 16 / 24, Ink), a Copy button (Ink icon).
   Desktop: out of flow, 16 px above the Resume card in the right column (it rises into the space beside the page title, so nothing below
   moves). One column (<= 1280): first in the column, 16 px above the Resume card. */
.resume-main { position: relative; }
.resume-main > .resume-contact { position: absolute; grid-column: 2 / 3; grid-row: 1 / 2; left: 0; right: 0; bottom: calc(100% + 16px); width: auto; box-sizing: border-box; }   /* both grid lines explicit: for an out-of-flow item a lone start line ends at the container edge, which made the card too wide on very wide screens; the width is the right column's own */
.resume-card .resume-contact-list { gap: 4px; }
.resume-contact .resume-contact-row { display: flex; align-items: center; gap: 12px; min-height: 40px; }
.resume-contact-icon { flex: none; display: block; color: var(--cyan); }
.resume-contact-value { flex: 1 1 auto; min-width: 0; margin: 0; padding: 4px 0; border: 0; background: none; text-align: left; cursor: copy; color: var(--ink); text-decoration: none;
  font-family: var(--font-body); font-weight: 400; font-size: 16px; line-height: 24px; overflow-wrap: anywhere; border-radius: 4px;
  text-decoration-line: underline; text-decoration-color: transparent; text-underline-offset: 4px; text-decoration-thickness: 1px;
  transition: text-decoration-color 200ms ease; }
.resume-contact-value:focus-visible { text-decoration-color: var(--cyan); }
.resume-contact-copy { flex: none; display: grid; place-items: center; width: 36px; height: 36px; margin: -2px -8px -2px 0; padding: 0; border: 0; border-radius: 8px;
  background: transparent; color: var(--ink); cursor: pointer; transition: background-color 200ms ease, color 200ms ease; }
.resume-contact-copy svg { display: block; }
.resume-contact-copy:focus-visible { background: var(--soft); color: var(--ink); }
@media (hover: hover) and (pointer: fine) { .resume-contact-value:hover { text-decoration-color: var(--cyan); } .resume-contact-copy:hover { background: var(--soft); color: var(--ink); } }   /* no sticky hover after a tap */
.resume-contact :is(.resume-contact-value, .resume-contact-copy):focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
@media (hover: none), (pointer: coarse) { .resume-contact-value { padding: 10px 0; } .resume-contact-value[data-call] { cursor: pointer; } .resume-contact-copy { width: 44px; height: 44px; margin: -4px -12px -4px 0; } .resume-card .resume-contact-list { gap: 0; } }   /* 44 px tap targets */
@media (max-width: 1280px) {
  .resume-main > .resume-contact { position: static; grid-column: 1; grid-row: auto; width: 336px; max-width: 100%; margin-bottom: -64px; }   /* row-gap 80 - 64 = 16 to the Resume card */
}
@media (max-width: 720px) { .resume-main > .resume-contact { width: 100%; } }
/* Toast (site-wide, one element): small Ink pill with a Signal Cyan check, top centre 12 px under the 72 px sticky header (plus the safe area),
   fixed so it stays in view at any scroll; fades and rises 8 px; 2 s. Polite live region. */
.site-toast { position: fixed; left: 50%; top: calc(env(safe-area-inset-top, 0px) + 72px + 12px); z-index: 60; display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 16px 10px 12px; border-radius: 999px; background: var(--ink); color: var(--canvas); box-shadow: 0 4px 32px rgba(38, 38, 73, .18);
  font-family: var(--font-display); font-weight: 500; font-size: 14px; line-height: 1.2; white-space: nowrap; pointer-events: none;
  opacity: 0; transform: translate(-50%, 8px); transition: opacity 200ms ease, transform 260ms cubic-bezier(.22, 1, .36, 1); }
.site-toast.is-on { opacity: 1; transform: translate(-50%, 0); }
.site-toast svg { flex: none; display: block; color: var(--cyan); }
@media (prefers-reduced-motion: reduce) { .site-toast { transition: opacity 150ms linear; transform: translate(-50%, 0); } .resume-contact-value, .resume-contact-copy { transition: none; } }
.resume-main {
  margin-top: 120px;                                                     /* H1 row → PROFESSIONAL EXPERIENCE */
  display: grid; grid-template-columns: minmax(0, 1111px) 336px; column-gap: clamp(40px, 9.74vw, 187px);
  align-items: start;
}
.resume-head { display: flex; align-items: center; gap: 12px; width: 100%; }
.resume-head h2 {
  margin: 0; font-family: var(--font-display); font-weight: 400; font-size: 12px; line-height: 1.2;
  letter-spacing: 1.2px; text-transform: uppercase; white-space: nowrap; color: var(--secondary);
}
/* Section labels without the cyan divider (fewer cyan accents, per review) */
.resume-left { display: flex; flex-direction: column; gap: 48px; }
.resume-section { display: flex; flex-direction: column; gap: 48px; }
.resume-section--exp { gap: 60px; }                                   /* Figma: list at y 74 under the 14 px header */
/* Experience: timeline of light dots on a thin rule, items 38 px in, 48 px apart */
/* Figma: each job is its content + 32 px bottom padding (287 / 315 / 251 px), 60 px between job blocks */
.resume-jobs { position: relative; list-style: none; margin: 0; padding: 0 0 0 38px; display: flex; flex-direction: column; gap: 60px; --tl-top: 10px; }
.resume-job { position: relative; display: flex; align-items: flex-start; gap: 40px; padding-bottom: 32px; }
.resume-job::before {                                   /* dot: 12 px, Quiet Rule */
  content: ""; position: absolute; left: -37px; top: var(--tl-top); width: 12px; height: 12px; border-radius: 10px;
  background: var(--rule); z-index: 1;
  transition: background-color 300ms ease-in-out, transform 300ms ease-in-out;
}
.resume-job::after {                                    /* grey base rule down to the next dot */
  content: ""; position: absolute; left: -32px; top: var(--tl-top); width: 1px; height: calc(100% + 60px); background: var(--rule);
}
.resume-job:last-child::after { height: 55px; }         /* Figma: rule ends 55 px below the last dot */
/* Progress rule: Signal Cyan over the Quiet Rule base, from the first dot down; JS sets its height (--tl-fill) */
.resume-jobs::after {
  content: ""; position: absolute; left: 6px; top: calc(var(--tl-top) + 6px); width: 1px; height: var(--tl-fill, 0px);
  background: var(--cyan); z-index: 0; pointer-events: none;
}
.resume-job.is-active::before { background: var(--cyan); transform: scale(1.3333); }   /* 12 → 16 px, no layout shift */
.resume-halo.tl-halo { transition-duration: 300ms; }
.resume-jobs.no-motion .resume-job::before, .resume-jobs.no-motion .tl-halo { transition: none; }
.resume-halo { --tl-halo-size: 40px; left: -31px; top: calc(var(--tl-top) + 6px); z-index: 0; }   /* active dot is 16 px here: 2.5x, same ratio as The Process (12 px dot, 32 px halo) */   /* centred on the Now dot; current position = main active state */
.resume-period { flex: 0 0 99px; padding-top: 8px; margin: 0; font-family: var(--font-display); font-weight: 400; font-size: 14px; line-height: 1.5; white-space: nowrap; }
.resume-details { flex: 1 0 0; min-width: 1px; display: flex; flex-direction: column; gap: 16px; }
.resume-role { display: flex; flex-direction: column; gap: 4px; }
.resume-role h3 { margin: 0; font-family: var(--font-display); font-weight: 600; font-size: 24px; line-height: 1.25; letter-spacing: 0; }
.resume-org { margin: 0; font-family: var(--font-display); font-size: 14px; }
.resume-org--regular { font-weight: 400; line-height: 1.5; }   /* Freelance, as in Figma */
.resume-org--medium { font-weight: 500; line-height: 1.2; }    /* Isracard, Bank Leumi, as in Figma */
.resume-duties { width: 848px; max-width: 100%; display: flex; flex-direction: column; gap: var(--space-list); }   /* Figma 847 px + 1 px: the last Bank Leumi sentence with semibold phrases is 847.2 px wide and would otherwise wrap */
.resume-duties p { margin: 0; max-width: none; }
.resume-duties p { font-family: var(--font-body); font-weight: 400; font-size: 20px; line-height: 1.6; }
.resume-duties strong { font-weight: 600; }   /* key professional phrases: Semibold, same size / color / line-height */
/* Right column (Figma 544:2474): five cards, 16 px apart. White, 1 px Quiet Rule stroke, 8 px radius, 20 px padding;
   title (existing section label) → list 16 px; items 16 px Regular on a 24 px line, 5 px apart. */
.resume-right { display: flex; flex-direction: column; gap: 16px; }
.resume-card { width: 336px; max-width: 100%; padding: 19px; background: var(--canvas); border: 1px solid var(--rule); border-radius: 8px; display: flex; flex-direction: column; gap: 16px; }   /* p 20 incl. stroke */
.resume-card ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
.resume-card li { font-family: var(--font-body); font-weight: 400; font-size: 16px; line-height: 24px; color: var(--ink); }
.resume-card .resume-edu-list { gap: 16px; }
.resume-card .resume-edu-item { display: flex; flex-direction: column; gap: 4px; }
.resume-edu-item p { margin: 0; max-width: none; }
.resume-edu-period { font-family: var(--font-display); font-weight: 400; font-size: 14px; line-height: 1.5; color: var(--secondary); }
.resume-edu-name { font-family: var(--font-body); font-weight: 400; font-size: 16px; line-height: 24px; color: var(--ink); }

@media (max-width: 1280px) {
  .resume-main { grid-template-columns: minmax(0, 1fr); row-gap: 80px; }
  .resume-right { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; align-items: start; }
  .resume-card { width: auto; }
}
@media (max-width: 720px) {
  .resume { padding-top: 48px; padding-bottom: 80px; }
  .resume-hero { flex-direction: column; align-items: flex-start; gap: 24px; margin-left: 0; width: 100%; }
  .resume-title, .page-title { font-size: clamp(36px, 10vw, 64px); white-space: normal; }
  .resume-main { margin-top: 56px; }
  .resume-job { flex-direction: column; align-items: stretch; gap: 4px; }
  .resume-details { flex: none; width: 100%; }
  .resume-jobs { --tl-top: 4px; }
  .resume-period { flex-basis: auto; padding-top: 0; }
  .resume-duties p { font-size: 18px; }
}

/* ============== Home: About teaser (Figma 345:7829 "About Teaser Section") ==============
   1920: 120 / 160 px top / bottom, 162 px sides; container 1596 px: photo column 462 px, gap 186 px,
   content column 948 px. [data-reveal] marks the two groups for a later scroll reveal (no motion yet). */
.about-teaser {
  background: var(--canvas);
  padding: clamp(64px, 6.25vw, 120px) var(--page-x) clamp(80px, 8.334vw, 160px);
  display: flex; justify-content: center; overflow-x: clip;
}
.about-teaser-inner { width: min(1596px, 100%); display: flex; align-items: center; gap: clamp(48px, 9.6875vw, 186px); }
.about-teaser-photo-col {
  position: relative; flex: 1 0 0; min-width: 320px; max-width: 462px;
}
.about-teaser-photo {
  position: relative; width: 100%; aspect-ratio: 462 / 646.121;
  margin: calc(7.865 / 462 * 100%) 0;                  /* rotated photo's extra height: 661.85 vs 646.12 */
  border: 10px solid var(--canvas); box-shadow: 0 18px 40px 0 rgba(0, 0, 0, .13);   /* same treatment as the hero photos */
  transform: rotate(-2deg); overflow: hidden; background: var(--placeholder);
}
/* the export is already the framed crop (924 x 1292 = 2x of 462 x 646), so it fills the frame as is */
.about-teaser-photo img { position: absolute; inset: 0; width: 100%; height: 100%; max-width: none; object-fit: cover; }
.about-teaser-photo .ph-media { position: absolute; inset: 0; border-radius: 0; }
.about-teaser-label {                                  /* "A little about me" accent on the photo's top-right */
  position: absolute; left: calc(338.21 / 462 * 100%); top: calc(51.32 / 661.851 * 100%);
  width: 148.194px; height: 43.55px; display: flex; align-items: center; justify-content: center; z-index: 1;
}
.about-teaser-label span {
  display: flex; align-items: center; width: 146.048px; height: 27.372px; padding: 8px; overflow: hidden;
  background: var(--cyan); border: 1px solid var(--cyan); transform: rotate(6.43deg);
  font-family: var(--font-display); font-weight: 400; font-size: 12px; line-height: 1.2; letter-spacing: 1.2px;
  text-transform: uppercase; white-space: nowrap; color: var(--ink);
}
.about-teaser-content { flex: 1 0 0; min-width: 480px; display: flex; flex-direction: column; align-items: flex-start; gap: 32px; color: var(--ink); }
.about-teaser-text { width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 48px; }
.about-teaser-title {
  margin: 0; font-family: var(--font-display); font-weight: 700; font-size: clamp(56px, 7.8125vw, 150px); line-height: 1;
  letter-spacing: 0; text-transform: none; color: var(--ink);   /* sentence case, per review comment */
}
.about-teaser-body { width: 100%; display: flex; flex-direction: column; gap: 32px; font-family: var(--font-body); font-weight: 400; font-size: 20px; line-height: 1.6; }
.about-teaser-body p { margin: 0; max-width: 690px; }
.about-teaser-traits { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 12px; white-space: nowrap; }
.about-teaser-traits li { display: inline-flex; align-items: center; gap: 12px; }   /* the "/" sits inside the next item, so it wraps with that word, never alone at a line end */
.about-teaser-traits .sep { color: var(--cyan); }
/* CTA: the existing case-study button (.work-cta) in its outline variant, as in Figma 559:1903 */
.work-cta--outline { background: var(--canvas); color: var(--ink); border: 1px solid var(--cyan); padding: 11px 15px 11px 23px; }  /* inside stroke: same 46 px */
.work-cta--outline .btn-arrow-svg path { fill: var(--ink); }

/* ============== CTA hover: one interaction pattern for every main CTA ==============
   Hero (VIEW PROJECTS, GET IN TOUCH), project cards and About (VIEW CASE STUDY / outline), Resume download.
   Hover / keyboard focus (and hover on a whole project card): Signal Cyan background, Ink text and arrow,
   no scale (keeps text rendering crisp), arrow moves 2 px along the direction it already points (--cta-dx / --cta-dy).
   One motion for every CTA: 380 ms, same easing for background, text colour, arrow fill and arrow transform.
   Only the arrow element is transformed; the button and its text never move.
   Only colours and transforms change, so nothing reflows. */
:is(.hero-btn, .work-cta, .footer-cta) {
  --cta-ease: cubic-bezier(0.22, 1, 0.36, 1); --cta-dur: 380ms; --cta-dx: 2px; --cta-dy: -2px;   /* default arrow ↗ */
  transition: background-color var(--cta-dur) var(--cta-ease), color var(--cta-dur) var(--cta-ease);
}
.hero-btn--primary { --cta-dy: 2px; }                                            /* VIEW PROJECTS arrow ↘ */
:is(.hero-btn-arrow, .work-cta-arrow, .footer-cta-arrow) { transition: transform var(--cta-dur) var(--cta-ease); will-change: transform; }   /* own layer: sub-pixel, no stepping */
:is(.hero-btn, .work-cta) .btn-arrow-svg path { transition: fill var(--cta-dur) var(--cta-ease); }
/* Project cards' VIEW CASE STUDY keeps its original look (hover reverted per review): excluded below */
:is(.hero-btn, .work-cta:not([aria-disabled="true"]):not(.work-card *)):is(:hover, :focus-visible) { background: var(--cyan); color: var(--ink); }
:is(.hero-btn, .work-cta:not([aria-disabled="true"]):not(.work-card *)):is(:hover, :focus-visible) :is(.hero-btn-arrow, .work-cta-arrow) { transform: translate(var(--cta-dx), var(--cta-dy)); }
:is(.hero-btn, .work-cta:not([aria-disabled="true"]):not(.work-card *)):is(:hover, :focus-visible) .btn-arrow-svg path { fill: var(--ink); }
/* Footer GET IN TOUCH is already cyan on Ink: its active state is Canvas, same timing and arrow drift */
.footer-cta:is(:hover, :focus-visible) { background: var(--canvas); }
.footer-cta:is(:hover, :focus-visible) .footer-cta-arrow { transform: translate(var(--cta-dx), var(--cta-dy)); }
@media (prefers-reduced-motion: reduce) {
  :is(.hero-btn, .work-cta), :is(.hero-btn-arrow, .work-cta-arrow, .footer-cta-arrow) { transform: none !important; }   /* colours still change */
}
/* Project card hover: lift + soft shadow. The whole card moves as one object (screens inside stay put);
   its VIEW CASE STUDY goes to the active state without changing size; only the arrow drifts 3 px up-right. */
.work-card {
  --card-ease: cubic-bezier(0.22, 1, 0.36, 1);
  transition: transform 280ms var(--card-ease), box-shadow 280ms var(--card-ease);
  box-shadow: 0 24px 56px -20px rgba(10, 13, 20, 0);
}
.work-card:is(:hover, :has(.work-cta:focus-visible)) {
  transform: translateY(-6px);
  box-shadow: 0 24px 56px -20px rgba(10, 13, 20, .12);
}
.work-card:is(:hover, :has(.work-cta:focus-visible)) .work-cta { background: var(--cyan); color: var(--ink); }
.work-card:is(:hover, :has(.work-cta:focus-visible)) .work-cta-arrow { transform: translate(var(--cta-dx), var(--cta-dy)); }
.work-card:is(:hover, :has(.work-cta:focus-visible)) .work-cta .btn-arrow-svg path { fill: var(--ink); }
@media (hover: none) { .work-card:hover { transform: none; box-shadow: 0 24px 56px -20px rgba(10, 13, 20, 0); } }
@media (prefers-reduced-motion: reduce) {
  .work-card, .work-card:is(:hover, :has(.work-cta:focus-visible)) { transform: none !important; }
}
@media (max-width: 1000px) {
  .about-teaser-inner { flex-direction: column; align-items: flex-start; }
  .about-teaser-photo-col { width: min(462px, 100%); flex: none; min-width: 0; }
  .about-teaser-content { min-width: 0; width: 100%; }
}
@media (max-width: 600px) {
  .about-teaser-text { gap: 32px; }
  .about-teaser-body { font-size: 18px; }
  .about-teaser-traits { white-space: normal; }
  .about-teaser-label { transform: scale(.85); transform-origin: left top; }
}

/* ============== Section header ============== */
.section-head { display: flex; align-items: end; justify-content: space-between; gap: 16px; margin-bottom: 32px; flex-wrap: wrap; }

/* ============== Project cards ============== */
.project-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(16px, 3vw, 32px); }
@media (max-width: 720px) { .project-grid { grid-template-columns: 1fr; } }
.project-card {
  display: grid; gap: 16px; text-decoration: none; color: inherit;
  border-radius: var(--radius);
}
.project-card .ph-media { aspect-ratio: 16 / 10; transition: opacity .15s; }
.project-card:hover .ph-media { opacity: .85; }
.project-card:hover h3 { text-decoration: underline; text-underline-offset: 3px; }
.card-body { display: grid; gap: 6px; }
.card-meta { font-size: 0.875rem; color: var(--text-muted); }

/* ============== Home: About teaser ============== */
/* ============== About page (Figma 691:2184 "About B — Studio journal", 1920 wide) ==============
   Hero and "Outside the screen" are editorial compositions: from 1280 px they reproduce the 1920 frame
   with --u (1 Figma px at 1920, scaled down like the Home hero). Text scales with --tk, which never goes
   below 0.75 (20 px body → 15 px min), so line breaks stay as in Figma. Below 1280 both stack in normal flow. */
.ab-stage-wrap { container-type: inline-size; max-width: 1920px; margin: 0 auto; }
.ab-stage { --u: calc(100cqw / 1920); --tk: max(var(--u), 0.75px); --ck: max(var(--u), 0.857px); position: relative; color: var(--ink); }
.ab-stage > * { position: absolute; margin: 0; }

/* Photo frame (Figma "Personal photograph"): white 10 px inside stroke, optional shadow, tilt.
   The supplied photo is the frame-size crop, so it fills the frame and the border covers its edges, as in Figma. */
.ab-photo {
  left: calc(var(--x) * var(--u)); top: calc(var(--y) * var(--u)); width: calc(var(--fw) * var(--u)); height: calc(var(--fh) * var(--u));
  border: calc(10 * var(--u)) solid var(--canvas); transform: rotate(var(--rot)); overflow: hidden; background: var(--placeholder); z-index: 1;
}
.ab-photo--shadow { box-shadow: 0 calc(16 * var(--u)) calc(38 * var(--u)) 0 rgba(10, 13, 20, .08); }
.ab-photo img { position: absolute; left: calc(-10 * var(--u)); top: calc(-10 * var(--u)); width: calc(100% + 20 * var(--u)); height: calc(100% + 20 * var(--u)); max-width: none; object-fit: cover; }
/* "Long walks. Clear mind.": a slow camera pull-back on first view. Armed (JS): the photo starts 2.2x around a point on the right,
   so only the sea shows; then it eases back to its normal crop. Only the image transforms, inside the frame's overflow: hidden,
   so the frame, border, shadow and neighbours never move. No JS / reduced motion: the photo is simply static. */
.ab-photo--walking.is-armed img { transform: scale(2.2); transform-origin: 92% 50%; }
.ab-photo--walking.is-armed.is-in img { transform: none; transition: transform 2000ms cubic-bezier(0.33, 0, 0.15, 1); }   /* soft start, long gentle settle */
/* Hero portrait: the original layer (516 x 688) sits tilted -4.84° inside the frame, as in Figma; position from Figma 719:2457 */
.ab-photo--portrait img { left: -5.382%; top: -4.252%; width: 119.444%; height: 127.407%; transform: rotate(-4.84deg); }
.ab-note, .ab-caption { font-family: var(--font-display); font-weight: 400; font-size: calc(14 * var(--ck)); line-height: 1.5; color: var(--ink); white-space: nowrap; }

/* 1. Hero: Portrait composition (691:2187, 1920 x 660) */
.ab-hero { height: calc(660 * var(--u)); }
.ab-hero-text { left: calc(162 * var(--u)); top: calc(380 * var(--u)); transform: translateY(-50%); width: calc(549 * var(--tk)); display: flex; flex-direction: column; gap: var(--space-lead); }
.ab-hero-title { margin: 0; font-family: var(--font-body); font-weight: 700; font-size: calc(64 * var(--tk)); line-height: 1.1; letter-spacing: 0; color: var(--ink); }
.ab-hero-intro { margin: 0; max-width: none; font-family: var(--font-body); font-weight: 400; font-size: calc(20 * var(--tk)); line-height: 1.6; color: var(--ink); }
.ab-note { left: calc(1307 * var(--u)); top: calc(329 * var(--u)); font-family: "Caveat", cursive; font-weight: 500; font-size: max(calc(26 * var(--u)), 22px); line-height: 1.25; color: var(--secondary); }   /* shared handwritten note style (as on Contact): 26 px at 1920, never under 22 px when the stage scales down */

/* 2. Design practice / What I bring (719:2461, 1920 x 477): copy column 460 + strengths at x 620 */
.ab-practice { background: var(--canvas); padding: clamp(64px, 8.3334vw, 160px) var(--page-x);   /* review: 160 px above and below (Figma 100) for more air */
  display: flex; justify-content: center; }
.ab-practice-inner { width: min(1596px, 100%); display: flex; align-items: flex-start; gap: clamp(40px, 8.334vw, 160px); color: var(--ink); }
.ab-bring { flex: none; width: 460px; display: flex; flex-direction: column; gap: var(--space-title); }
.ab-bring-head { display: flex; flex-direction: column; gap: var(--space-label); }
.ab-bring-title { margin: 0; font-family: var(--font-display); font-weight: 700; font-size: 48px; line-height: 1.1; letter-spacing: 0; white-space: nowrap; }
.ab-bring-text { margin: 0; max-width: none; font-family: var(--font-body); font-weight: 400; font-size: 20px; line-height: 1.6; }
/* Strengths: wrapping chips, bottom-aligned in a 245 px box like the Figma auto layout (rows at y 61 / 165) */
.ab-strengths { flex: 1 1 0; min-width: 0; max-width: 1026px; min-height: 245px; list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; align-content: flex-end; gap: 24px; }
.ab-strength { padding: 23px; background: var(--soft); border: 1px solid var(--cyan); border-radius: 8px; font-family: var(--font-body); font-weight: 400; font-size: 20px; line-height: 1.6; white-space: nowrap; }   /* p 24 incl. stroke */

/* 4. Outside the screen (697:3107, 1920 x 934, Soft Canvas) */
.ab-outside-wrap { background: var(--soft); box-shadow: 0 0 0 100vmax var(--soft); clip-path: inset(0 -100vmax); }   /* full-bleed band, same technique as .case-beyond */
.ab-outside { height: calc(952 * var(--u)); }   /* Figma 934 + 18: ~107 px from the lowest photo to the footer */
.ab-intro { left: calc(162 * var(--u)); top: calc(100 * var(--u)); width: calc(490 * var(--tk)); display: flex; flex-direction: column; gap: var(--space-label); }
.ab-intro .ov-label { font-size: calc(12 * var(--ck)); letter-spacing: calc(1.2 * var(--ck)); }
.ab-story { display: flex; flex-direction: column; gap: var(--space-title); }
.ab-story-title { margin: 0; font-family: var(--font-display); font-weight: 700; font-size: calc(48 * var(--tk)); line-height: 1.1; letter-spacing: 0; color: var(--ink); }
.ab-story-text { margin: 0; width: calc(416 * var(--tk)); max-width: none; font-family: var(--font-body); font-weight: 400; font-size: calc(20 * var(--tk)); line-height: 1.6; color: var(--ink); }
.ab-caption { left: calc(var(--x) * var(--u)); top: calc(var(--y) * var(--u)); z-index: 2;
  font-family: "Caveat", cursive; font-weight: 500; font-size: max(calc(24 * var(--u)), 22px); line-height: 1.25; color: var(--secondary); }   /* shared handwritten style (About note, Contact); 500 is the only Caveat weight loaded */
/* left-hand caption ("Long walks"): x is its right edge (468 = the Caveat line end at 1920), so a larger caption at 1280-1440 grows away from the photo, not into it */
.ab-caption--end { transform: translateX(-100%); }
.ab-caption--lifted { filter: drop-shadow(0 calc(16 * var(--u)) calc(19 * var(--u)) rgba(10, 13, 20, .08)); }   /* Figma: shadow on the "New places" label */
.ab-arrow { left: calc(var(--x) * var(--u)); top: calc(var(--y) * var(--u)); width: calc(var(--w) * var(--u)); height: auto; overflow: visible; z-index: 2; }

/* Tablet & mobile: same content and order, stacked; the collage becomes a vertical editorial sequence */
@media (max-width: 1279px) {
  .ab-stage { --u: 1px; --tk: 1px; --ck: 1px; height: auto !important; padding: 56px var(--page-x); display: flex; flex-direction: column; gap: 40px; }
  .ab-stage > * { position: static; }
  .ab-hero { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 420px); column-gap: 48px; row-gap: 32px; align-items: center; }
  .ab-hero-text { transform: none; width: auto; grid-column: 1; grid-row: 1 / span 2; }
  .ab-hero-title { font-size: clamp(40px, 6vw, 64px); }
  .ab-hero .ab-photo { grid-column: 2; grid-row: 1; }
  .ab-note { grid-column: 2; grid-row: 2; white-space: normal; }
  .ab-photo { position: relative !important; left: 0; top: 0; width: 100%; max-width: calc(var(--fw) * 1px); height: auto; aspect-ratio: var(--fw) / var(--fh); }
  .ab-intro { width: auto; max-width: 560px; }
  .ab-story-title { font-size: var(--fs-h2); }
  .ab-story-text { width: auto; font-size: 18px; }
  .ab-outside { display: grid; grid-template-columns: minmax(0, 1fr); row-gap: 16px; align-items: start; padding-bottom: 96px; }   /* collage → footer */
  .ab-outside .ab-photo { margin-top: 24px; }
  .ab-outside .is-alt { justify-self: end; }
  .ab-caption.is-alt { text-align: right; }
  .ab-outside .ab-photo, .ab-caption { order: var(--o); }   /* stacked: same order as the text (cooking, walks, travel, flowers) */
  .ab-caption { white-space: normal; }
  .ab-caption--end { transform: none; }
  .ab-arrow { display: none; }
  .ab-practice-inner { flex-direction: column; gap: 40px; }
  .ab-bring { width: 100%; max-width: 560px; }
  .ab-bring-title { font-size: var(--fs-h2); }
  .ab-bring-text br { display: none; }
  .ab-strengths { flex: none; width: 100%; max-width: none; min-height: 0; align-content: flex-start; gap: 16px; }
}
@media (max-width: 700px) {
  .ab-hero { grid-template-columns: minmax(0, 1fr); }
  .ab-hero-text, .ab-hero .ab-photo, .ab-note { grid-column: 1; grid-row: auto; }
  .ab-hero .ab-photo { max-width: 420px; }
  .ab-hero-intro, .ab-bring-text { font-size: 18px; }
  .ab-strength { padding: 15px 19px; font-size: 18px; white-space: normal; }
  .ab-outside .ab-photo--flowers { justify-self: center; }   /* mobile: flowers photo centred; size, tilt and caption unchanged */
}

/* ============== Inner pages ============== */
.page-head { padding: var(--section-y) 0 32px; display: grid; gap: 16px; }
.page-body { padding-bottom: var(--section-y); display: grid; gap: 32px; }
.ph-block {
  border: 1px dashed var(--border); border-radius: var(--radius);
  padding: 24px; display: grid; gap: 8px;
}
.ph-block h3 { font-size: 1rem; }

/* ============== Footer (Figma 345:7857 "Portfolio footer") ============== */
.site-footer {
  background: var(--ink); color: var(--canvas);
  padding: 48px calc(clamp(20px, 8.021vw, 154px) + var(--frame-gutter)) 48px calc(clamp(20px, 8.229vw, 158px) + var(--frame-gutter));   /* 1920 frame: 158 / 154; centred frame above 1920 */
}
.site-footer a:focus-visible, .site-footer button:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px; }
.footer-label {
  margin: 0; font-family: var(--font-display); font-weight: 400; font-size: 12px; line-height: 1.2;
  letter-spacing: 1.2px; text-transform: uppercase; color: var(--canvas); white-space: nowrap;
}
.footer-main { display: flex; flex-direction: column; gap: 80px; }
.footer-invite { display: flex; flex-direction: column; align-items: flex-start; gap: 40px; padding-top: 38px; }
.footer-title {
  margin: 0; max-width: none; font-family: var(--font-body); font-weight: 700; font-size: 64px; line-height: 1.1;
  letter-spacing: 0; color: var(--soft);
}
.footer-cta {
  display: inline-flex; align-items: center; gap: 12px;
  padding: 15px 23px; border: 1px solid var(--cyan); border-radius: 150px;   /* Figma 16 / 24 with an inside stroke */
  background: var(--cyan); color: var(--ink); text-decoration: none;
  font-family: var(--font-body); font-weight: 700; font-size: 16px; line-height: normal; letter-spacing: 1.6px;
  white-space: nowrap;
}
.footer-cta-arrow { width: 20px; height: 23px; display: grid; place-items: center; flex: none; }   /* Figma arrow box 20 x 23 */
.footer-base { display: flex; flex-direction: column; justify-content: space-between; height: 82px; }
.footer-rule { height: 1px; border: 0; margin: 0; background: var(--rule); opacity: .3; }   /* same divider as the stats block */
.footer-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; }
.footer-links { list-style: none; margin: 0; padding: 0; min-height: 42px; display: flex; align-items: center; flex-wrap: wrap; gap: 8px 36px; }
.footer-links a {
  font-family: var(--font-display); font-weight: 700; font-size: 16px; line-height: 1.2; letter-spacing: 0;
  color: var(--canvas); text-decoration: none; white-space: nowrap; transition: color .15s;
}
.footer-links a[href]:hover { color: var(--cyan); }
.footer-credit {
  margin: 0; max-width: none; font-family: var(--font-display); font-weight: 400; font-size: 14px; line-height: 1.5;
  color: var(--canvas); white-space: nowrap; min-height: 42px; display: flex; align-items: center;
}
@media (max-width: 1200px) {
  .footer-base { height: auto; gap: 24px; }
  .footer-row { flex-direction: column; gap: 16px; }
  .footer-credit { min-height: 0; }
}
@media (max-width: 720px) {
  .footer-main { gap: 56px; }
  .footer-invite { gap: 32px; padding-top: 24px; }
  .footer-title { font-size: clamp(36px, 10vw, 64px); }
  .footer-links { flex-direction: column; align-items: flex-start; gap: 16px; }
  .footer-credit { white-space: normal; }
}

/* ============== Contact page ==============
   Shared system: label → H1 16, H1 → text 24 (--space-lead), text → buttons 40 (32 mobile), buttons 16 apart.
   95 / 48 px under the header (as Resume / Projects), 120 / 80 px to the footer. Content on the page grid (--page-x). */
.contact { position: relative; padding: clamp(48px, 4.948vw, 95px) var(--page-x) clamp(80px, 6.25vw, 120px); color: var(--ink);
  display: grid; grid-template-columns: minmax(0, 1fr); align-content: center; flex: 1 0 auto; }
/* Vertical balance: when the page is shorter than the viewport, the free height is shared above and below the content
   (paddings unchanged) instead of piling up under the button; the footer stays at the viewport bottom. */
#main:has(> .contact) { display: flex; flex-direction: column; }
.contact-main { display: flex; flex-direction: column; align-items: flex-start; }
.contact-main .ov-label { margin-bottom: var(--space-label); }
.contact-title { margin: 0 0 var(--space-lead); font-family: var(--font-body); font-weight: 700; font-size: 64px; line-height: 1.1; letter-spacing: 0; color: var(--ink); }
.contact-text { margin: 0 0 40px; max-width: 640px; font-family: var(--font-body); font-weight: 400; font-size: 20px; line-height: 1.6; color: var(--ink); }
.contact-actions { display: flex; flex-wrap: wrap; gap: 16px; }
/* Handwritten note: a standalone decorative element in the right column, not tied to the button.
   Two columns: text (640 = the paragraph's max width) · fluid gap · note (230 = the written phrase incl. its tilt).
   The gap shrinks with the screen: 150 px from 1427 px up, 130 at 1366, 104 at 1280, never under 64.
   It is shown wherever both columns fit: 640 + 64 + 230 = 934 px of content = 1124 px viewport with the page margins
   (--page-x); the query uses 1140 for a safe margin. Narrower (tablet, mobile) the phrase is hidden, as there is no room
   beside the 640 px text. The note sits at the bottom of the row (8 px up): opposite the paragraph's last line and just below.
   Caveat in Secondary, with a thin hand-drawn underline under the last words. */
.contact-note { display: none; position: relative; width: 230px; height: 96px; align-self: end; margin-bottom: 120px; }   /* raised 112 px: opposite the H1 / paragraph junction */
@media (min-width: 1140px) {
  .contact { grid-template-columns: minmax(0, 640px) 230px; column-gap: clamp(64px, calc(30vw - 280px), 150px); justify-content: center; }   /* text · gap · note as one group, centred on the page grid (text stays left-aligned) */
  .contact-note { display: block; }
}
.contact-note-text { position: absolute; left: 0; top: 50%; margin: 0; font-family: "Caveat", cursive; font-weight: 500; font-size: 28px; line-height: 1.15;
  color: var(--secondary); white-space: nowrap; transform: translateY(-50%) rotate(-7deg); transform-origin: left center; }
.contact-note-last { position: relative; display: inline-block; }
.contact-note-last svg { position: absolute; left: 6%; top: calc(100% - 0.18em); width: 90%; height: auto; aspect-ratio: 220 / 32; overflow: visible; }   /* warm brush underline under "great together." only (same vector as the About note) */
/* About note: a short warm pen stroke under the end of the last line (drawn after the text, same reveal as Contact) */
.ab-note-last { position: relative; display: inline-block; }
.ab-note-last svg { position: absolute; left: 66%; top: calc(100% - 0.2em); width: 40%; height: auto; aspect-ratio: 220 / 32; overflow: visible; }   /* supplied vector (warm-handwritten-underline.svg), exact shape, uniform scale */
:is(.ab-note-last, .contact-note-last) path { fill: var(--color-accent-warm); stroke: none; }   /* #D7990F through the token, shared by About and Contact */
/* Reveal: label → H1 → text → buttons → note (existing stackIn: opacity + 14 px rise) */
@media (prefers-reduced-motion: no-preference) {
  .contact [data-reveal] { animation: stackIn 700ms cubic-bezier(0.22, 1, 0.36, 1) both; animation-delay: calc(var(--i) * 110ms + 80ms); }
  .contact.is-font-wait [data-reveal] { animation-play-state: paused; }   /* held at its first frame (delays included) until the fonts are ready: see fontsFor() */
}
@media (max-width: 720px) {
  .contact-title { font-size: clamp(36px, 10.3vw, 64px); }
  .contact-title br { display: none; }   /* the H1 wraps naturally on narrow screens */
  .contact-text { font-size: 18px; margin-bottom: 32px; }
  .contact-actions { flex-direction: column; align-self: stretch; gap: 12px; }
  .contact-actions .work-cta { width: 100%; justify-content: center; }
}
@media (max-width: 600px) { .contact { padding-left: var(--page-x-m); padding-right: var(--page-x-m); } }

/* ============== Handwritten notes: "pen" reveal (About note, Contact note) ==============
   Each line is uncovered left → right by a soft-edged mask (~0.7 em "pen tip"), so a letter appears part by part;
   lines follow one another at an even pen speed (JS sets --d / --delay from line widths, ≈ 2.2 s in total).
   On Contact the underline is drawn afterwards. Once per page view; reduced motion: shown at once (never armed). */
@property --hand-p { syntax: "<length-percentage>"; inherits: false; initial-value: 0%; }
.hand-ln { display: inline-block; white-space: nowrap; }
[data-hand].is-armed .hand-ln {
  --edge: .7em;
  -webkit-mask-image: linear-gradient(90deg, #000 calc(var(--hand-p) - var(--edge)), transparent var(--hand-p));
          mask-image: linear-gradient(90deg, #000 calc(var(--hand-p) - var(--edge)), transparent var(--hand-p));
}
[data-hand].is-writing .hand-ln { animation: handWrite var(--d) cubic-bezier(.45, .05, .55, .95) var(--delay) forwards; }
@keyframes handWrite { from { --hand-p: 0%; } to { --hand-p: calc(100% + var(--edge)); } }
[data-hand].is-armed :is(.contact-note-last, .ab-note-last) svg { clip-path: inset(-4px 100% -4px 0); }
[data-hand].is-writing :is(.contact-note-last, .ab-note-last) svg { animation: handUnderline 500ms cubic-bezier(.3, .1, .3, 1) var(--ul-delay) forwards; }
@keyframes handUnderline { to { clip-path: inset(-4px 0 -4px 0); } }

/* ============== Case study, mobile (≤ 900 px) ============== */
@media (max-width: 900px) {
  /* My role: vertical timeline. One continuous line on the left (each step's segment runs from its dot down to the
     next dot), dot centred on the first text line, label to the right. Same reveal logic: --seg now scales on Y. */
  .ov-role-list { flex-direction: column; row-gap: 0; }
  .ov-role-item { flex: none; width: 100%; flex-direction: row; align-items: stretch; justify-content: flex-start; gap: 16px; padding-bottom: 16px; }
  .ov-role-item:last-child { padding-bottom: 0; }
  .ov-role-mark { flex-direction: column; align-items: center; width: 12px; flex: none; padding-top: 10px; }   /* (32 px line − 12 px dot) / 2 */
  .ov-role-mark { position: relative; }
  .ov-role-mark::after { position: absolute; left: 5.5px; top: 22px; bottom: -26px; width: 1px; height: auto; }   /* dot bottom → next dot top (16 px item gap + 10 px offset) */
  .ov-role-item:last-child .ov-role-mark::after { visibility: hidden; }                                          /* line ends at the last dot */
  .ov-role-list.is-armed .ov-role-mark::after { transform: scaleY(var(--seg, 0)); transform-origin: center top; }
  /* Impact: the "Unified product experience" diagram is desktop-only */
  .impact-list .impact-diagram { display: none; }
}

/* ============== Shared responsive rules (typography & spacing system) ============== */
/* Mobile: one side padding for every main container (header, page sections, footer) */
@media (max-width: 600px) {
  .nav, .work, .about-teaser, .ab-stage, .ab-practice, .resume, .site-footer { padding-left: var(--page-x-m); padding-right: var(--page-x-m); }
  .case-h3 { font-size: var(--fs-h3-m); }
  /* Home: the "A little about me" sticker stays inside the screen */
  .about-teaser-label { left: auto; right: 0; }
}
/* Resume: title and Download button stack before they run out of room (was a 69 px overflow at 768) */
@media (max-width: 900px) {
  .resume-hero { flex-direction: column; align-items: flex-start; gap: 24px; }
  .resume-title { white-space: normal; }
}
@media (prefers-reduced-motion: reduce) { * { transition: none !important; scroll-behavior: auto !important; } }

/* ===== First frame before the scripts run (migration, stage 4) =====
   On the static site the page was rendered by JS, which set the start state of an intro in the same frame.
   Now the HTML arrives first: elements carry data-first-frame, and with motion allowed (html.js, set in <head>
   before the first paint) these rules hold the same start state until the page script takes over (it adds the
   original class and removes the attribute in one step). Values copied from the rules named on each line. */
.js .hero-photos[data-first-frame] { opacity: 0; }   /* .hero-photos.is-pending */
.js .hero-stage[data-first-frame] :is(.hero-title-top, .hero-badge, .hero-bottom) { opacity: 0; }   /* .hero-stage.text-pending */
.js [data-hand][data-first-frame] .hand-ln {   /* [data-hand].is-armed .hand-ln */
  --edge: .7em;
  -webkit-mask-image: linear-gradient(90deg, #000 calc(var(--hand-p) - var(--edge)), transparent var(--hand-p));
          mask-image: linear-gradient(90deg, #000 calc(var(--hand-p) - var(--edge)), transparent var(--hand-p));
}
.js [data-hand][data-first-frame] :is(.contact-note-last, .ab-note-last) svg { clip-path: inset(-4px 100% -4px 0); }   /* [data-hand].is-armed … svg */
.js .ab-photo--walking[data-first-frame] img { transform: scale(2.2); transform-origin: 92% 50%; }   /* .ab-photo--walking.is-armed img */
/* Case studies (stage 5) */
.js .case-visual[data-first-frame] :is(.case-dashboard, .case-mobile) { opacity: 0; }   /* .case-visual.is-pending … */
.js .ov-role-list[data-first-frame] .ov-role-mark::after { transform: scaleX(0); transform-origin: left center; }   /* .ov-role-list.is-armed … */
@media (max-width: 900px) { .js .ov-role-list[data-first-frame] .ov-role-mark::after { transform: scaleY(0); transform-origin: center top; } }
.js .ov-role-list[data-first-frame] .ov-role-mark::before { opacity: 0; transform: scale(.6); }
.js .ov-role-list[data-first-frame] .ov-role-name { opacity: 0; transform: translateY(8px); }
.js .process-bridge[data-first-frame] .process-bridge-line:first-child { transform: translateX(100%); }   /* .process-bridge.is-pending … */
.js .process-bridge[data-first-frame] .process-bridge-line:last-child  { transform: translateX(-100%); }
.js .next-card[data-first-frame] { opacity: 0; transform: translateY(64px); }   /* .next-card.is-armed */
.js .ts-hero-visual[data-first-frame] { opacity: 0; }   /* .ts-hero-visual.is-pull-armed */
.js .case-stats[data-first-frame] .case-stat-num { visibility: hidden; }   /* the count-up shows "0" once its script runs */
/* Without motion the intro patches are never shown (the static site did not render them) */
html:not(.js) .case-anim { display: none; }
/* No scripts at all: the Contact reveal is never held (the static site showed nothing without JS; now the text shows) */
html:not(.js) .contact.is-font-wait [data-reveal] { animation-play-state: running; }
