/* =========================================================================
   screenschatz.com — Tilo Erwin
   Light editorial theme. Off-white ground, ink text, ONE coral accent.
   Big type is the imagery. Mobile-first, fluid type via clamp().
   Rebuilt from Figma "TIlo_Upate" (node 17:87).
   ========================================================================= */

/* ---- Accessibility utility ---- */
/* Keeps a heading in the DOM/a11y tree for structure and SEO without
   showing it — used where the visual design has no room for a section
   title but the semantic outline still needs one (How I work, Experience). */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---- Tokens ---- */
:root {
  --bg:         #fdfdfd;   /* page ground (off-white)          */
  --ink:        #33332d;   /* body text / logos                */
  --surface:    #f0efe8;   /* Cases card                       */
  --accent:     #ff5640;   /* coral — greeting, contact, dots  */
  --deepl-blue: #0f2b46;   /* language badge                   */
  --sc-muted:   #b6c2c4;   /* muted grey — foundations badge   */
  --line:       #000;      /* pill borders / hairlines         */
  --white:      #fff;

  --maxw: 1300px;
  --pad: clamp(1.25rem, 5vw, 4rem);
  --section-y: clamp(4.5rem, 11vw, 10rem);
  --gap: clamp(2.5rem, 6vw, 6rem);

  /* Fluid type — Figma desktop value is the clamp max */
  /* Greeting scales with viewport width AND height (svh ceiling keeps it
     filling the viewport without overflowing; JS sizes the reserve box to
     the tallest greeting so there's no wasted line and no reflow). */
  --fs-greeting:  clamp(3.5rem, min(18vw, 26svh), 18rem);
  --fs-contact:   clamp(2.75rem, 11vw, 150px);
  --fs-statement: clamp(1.5rem, 1rem + 2.2vw, 2.375rem);  /* 38px */
  --fs-lg:        clamp(1.25rem, 1rem + 1.2vw, 1.75rem);  /* 28px */
  --fs-sm:        clamp(1rem, .9rem + .35vw, 1.125rem);   /* 18px */
  --fs-pill:      clamp(1.05rem, 1rem + .7vw, 1.5rem);    /* 24px */

  --ease: cubic-bezier(.2, .7, .2, 1);
  --ease-out: cubic-bezier(.23, 1, .32, 1);   /* strong ease-out — modal enter/exit */

  --rotate-ms: 3600ms;   /* greeting refresh cycle — drives the badge ring */
  --case-ms:   6000ms;   /* per-case display time — JS overrides from CASE_MS */
}

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

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

body {
  background: var(--bg);
  color: var(--ink);
  font-family: 'ApfelGrotezk', -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
  font-weight: 400;
  font-size: var(--fs-lg);
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }

/* ---- Layout utilities ---- */
.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--pad);
}
.section { padding-block: var(--section-y); }
.section--tight { padding-block: clamp(3rem, 7vw, 6rem); }

/* Modest left indent on large screens, echoing the Figma composition */
.indent { padding-inline-start: clamp(0px, 6vw, 120px); }

/* =========================================================================
   Brand bar + floating nav
   ========================================================================= */
.brandbar {                  /* overlays the top so the hero fills the viewport;
                                scrolls away with the page (absolute, not fixed) */
  position: absolute;
  top: 16px;
  left: 0;
  right: 0;
  display: flex;
  justify-content: center;
  z-index: 40;
  pointer-events: none;
}
.brandbar__name {
  font-weight: 700;
  font-size: .8125rem;        /* 13px */
  letter-spacing: .12em;
  color: var(--accent);
  text-align: center;
}
.nav {                       /* fixed pill — stays at the top across the page */
  position: fixed;
  top: 38px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 50;
  width: fit-content;
  display: flex;
  gap: clamp(1.25rem, 3vw, 2.75rem);
  align-items: center;
  padding: clamp(.75rem, 1.5vw, 1.5rem) clamp(1.25rem, 3vw, 2.25rem);
  background: rgba(253, 253, 253, .62);
  backdrop-filter: blur(27px);
  -webkit-backdrop-filter: blur(27px);
  border-radius: 18px;
  box-shadow: none;          /* shadow appears once scrolling starts (.is-stuck) */
  transition: box-shadow .25s var(--ease), background .25s var(--ease);
}
/* On scroll: keep the frosted base, add an 8% black tint + shadow */
.nav.is-stuck {
  background: linear-gradient(rgba(0, 0, 0, .08), rgba(0, 0, 0, .08)), rgba(253, 253, 253, .62);
  box-shadow: 0 4px 12px rgba(0, 0, 0, .12);
}
.nav a {
  font-size: clamp(1.05rem, 1rem + .7vw, 1.75rem);
  color: var(--ink);
  transition: color .25s var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .nav a:hover { color: var(--accent); }
}

/* =========================================================================
   Hero — rotating greeting + portrait + language badge
   ========================================================================= */
.hero {
  position: relative;
  min-height: 100svh;               /* fixed viewport height — no jump on reload */
  display: grid;
  place-items: center;
  padding-block: clamp(2rem, 5vw, 4rem);
}
.hero__inner {
  position: relative;
  width: 100%;
  max-width: min(1500px, 92vw);     /* wide, so long greetings wrap less */
  margin-inline: auto;
}
/* Reserve room so changing language never reflows. JS refines min-height to
   the exact tallest greeting; this 3-line value is the pre-JS default. */
.hero__greeting-box {
  font-size: var(--fs-greeting);
  min-height: calc(1em * .9 * 3);
  display: grid;
  place-items: center;
}
.hero__greeting {
  font-size: 1em;
  /* Latin uses ApfelGrotezk; Hangul falls through to Noto Sans KR (700) */
  font-family: 'ApfelGrotezk', 'Noto Sans KR', sans-serif;
  font-weight: 700;                 /* Fett */
  line-height: .9;
  color: var(--accent);
  text-align: center;
  text-wrap: balance;
  word-break: break-word;
}

/* Per-character typographic reveal, replayed on every greeting change.
   Default state is visible; the animation reveals FROM hidden (fill: both),
   so text can never get stuck invisible if the animation doesn't run. */
.hero__greeting .word { display: inline-block; }
.hero__greeting .ch {
  display: inline-block;
  animation: typoIn .55s var(--ease) both;
  animation-delay: calc(var(--i) * 32ms);
}
@keyframes typoIn {
  from { opacity: 0; transform: translateY(.5em); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Safari-on-macOS fallback (js/main.js sets this class): staggering dozens
   of individually-animated .ch spans is disproportionately expensive on
   WebKit's rendering path. Instead of animating each letter, the whole
   greeting is built complete while hidden, then revealed as a single
   fade-in once layout/positioning has settled — same visual "the greeting
   arrives" moment, a single animated element instead of ~20+. */
.hero__greeting-box--fade-whole .hero__greeting .ch {
  animation: none;
  opacity: 1;
  transform: none;
}
.hero__greeting-box--fade-whole .hero__greeting {
  opacity: 0;
  /* Opacity only — no transform. */
  transition: opacity .5s var(--ease);
  /* text-wrap: balance is disabled for this path entirely (falls back to
     normal wrapping): on real Safari this greeting was rendering with words
     scrambled into two interleaved columns on every rotation, reproducing
     even after the transform above was removed — pointing at Safari's
     balance re-calculation itself (run against dynamically-rebuilt
     inline-block .word/.ch spans) rather than at the animation/timing. */
  text-wrap: wrap;
}
.hero__greeting-box--fade-whole .hero__greeting.is-revealed {
  opacity: 1;
  transform: none;
}

/* Context line pinned to the hero's bottom edge — left-aligned, body-text
   color/scale (--fs-lg already maxes at the requested 28px, fluid below
   that on smaller viewports, consistent with the rest of the type scale). */
.hero__note {
  position: absolute;
  left: var(--pad);
  right: var(--pad);
  bottom: clamp(1.25rem, 4vw, 2.5rem);
  max-width: 46ch;
  font-size: var(--fs-lg);
  line-height: 1.35;
  color: var(--ink);
  text-align: left;
}
@media (max-width: 899px) {
  /* The mobile hero's stacked content (greeting + badge + portrait) is
     content-tall, not fixed to the viewport, so a bottom-pinned note can
     run into the portrait on common phone heights. Below 900px the note
     drops back into normal flow, after the portrait, same look otherwise. */
  .hero__note {
    position: static;
    margin: clamp(2rem, 8vw, 3rem) var(--pad) 0;
    max-width: none;
  }
}

/* Portrait overlaps the greeting on large screens */
.hero__portrait {
  width: clamp(120px, 18vw, 223px);
  height: auto;                 /* override the width/height attrs so… */
  aspect-ratio: 1;              /* …aspect-ratio keeps it a circle at any width */
  border-radius: 50%;
  object-fit: cover;
  margin: clamp(1.5rem, 3vw, 2rem) auto 0;
}
.hero__badge {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: fit-content;       /* hug the widest child (icon or label) */
  margin: 14px auto 0;
}
.hero__badge-icon { position: relative; display: block; width: 56px; height: 56px; }
.hero__badge-base { width: 100%; height: 100%; }
.hero__badge--mobile { display: none; }   /* shown on mobile only (see media query) */
/* Progress ring — fills clockwise from the top over one refresh cycle */
.hero__badge-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
  overflow: visible;
}
.hero__badge-ring__progress {
  fill: none;
  stroke: var(--white);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-dasharray: 213.63;          /* 2πr, r = 34 */
  stroke-dashoffset: 213.63;
  animation: ringFill var(--rotate-ms) var(--ease) forwards;  /* eased finish, not static */
}
@keyframes ringFill { to { stroke-dashoffset: 0; } }
.hero__badge-label {
  width: max-content;        /* pill width follows the language name */
  white-space: nowrap;
  display: flex;
  justify-content: center;
  padding: 5px 10px 6px;
  background: var(--deepl-blue);
  border-radius: 4px;
  color: var(--white);
  font-weight: 600;
  font-size: .8125rem;
  letter-spacing: .04em;
  line-height: 1;
  text-transform: uppercase;
}

@media (min-width: 900px) {
  /* Pull portrait + badge up to overlap the greeting, as in Figma.
     This right/bottom placement is the pre-JS / no-JS fallback. */
  .hero__media {
    position: absolute;
    right: clamp(2rem, 10vw, 8rem);
    bottom: -2.5rem;
    margin: 0;
    z-index: 2;
  }
  /* JS anchors the portrait just after the greeting's last word and glides it */
  .hero__media.is-anchored {
    left: var(--media-x);
    top: var(--media-y);
    right: auto;
    bottom: auto;
    transform: translateY(-50%);
    transition: left .6s var(--ease), top .6s var(--ease);
  }
  .hero__portrait { margin: 0; }
}

/* Mobile hero (Figma node 35:805): big text-filling headline (JS fit-to-width),
   then language badge, then a larger portrait — all stacked & centred. */
@media (max-width: 899px) {
  .hero__inner { max-width: 94vw; padding-inline: 0; }   /* near-full width for the headline */
  .hero__greeting-box { width: 100%; }
  .hero__badge--mobile {
    display: flex;
    margin: clamp(1.25rem, 5vw, 2rem) auto 0;
  }
  .hero__portrait {
    width: min(52vw, 189px);
    margin: clamp(1.5rem, 6vw, 2.5rem) auto 0;
  }
}

/* =========================================================================
   Hero custom cursor — blue dot (friction-follow) that rests into a badge.
   Desktop / fine-pointer only; JS toggles .is-cursor-custom + .is-active.
   ========================================================================= */
.hero.is-cursor-custom { cursor: none; }      /* hide native cursor while active */

.hero-cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 60;
  pointer-events: none;
  opacity: 0;
  transform: translate3d(-100px, -100px, 0);  /* parked off-screen until active */
  will-change: transform;
}
.hero-cursor.is-active { opacity: 1; }

/* Both states centre on the cursor point */
.hero-cursor__dot,
.hero-cursor__badge {
  position: absolute;
  top: 0;
  left: 0;
}
.hero-cursor__dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--deepl-blue);              /* the blue dot */
  /* --dot-scale is driven per-frame by JS (grows as it nears the target) */
  transform: translate(-50%, -50%) scale(var(--dot-scale, 1));
  transition: opacity .2s var(--ease);
}
.hero-cursor__badge {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  opacity: 0;
  transform: translate(-50%, -50%) scale(.3);
  transform-origin: center;
  transition: opacity .25s var(--ease), transform .35s var(--ease);
}
.hero-cursor__icon { position: relative; display: block; width: 56px; height: 56px; }
.hero-cursor__icon img { width: 100%; height: 100%; }

/* Resting: dot fades, badge scales up (matches .hero__badge-icon size) */
.hero-cursor.is-resting .hero-cursor__dot {
  opacity: 0;
}
.hero-cursor.is-resting .hero-cursor__badge {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

/* =========================================================================
   Statement blocks (About, How I work)
   ========================================================================= */
.statement {
  font-size: var(--fs-statement);
  line-height: 1.2;
  max-width: 35ch;
}
.statement--wide { max-width: 38ch; }

.about-row {
  margin-top: clamp(2.5rem, 5vw, 3.75rem);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(1rem, 2vw, 2rem);
  font-size: var(--fs-lg);
}
.about-row__label { font-weight: 500; }   /* Mittel */
.about-row__body { line-height: 1.4; }

@media (min-width: 760px) {
  .about-row { grid-template-columns: 280px minmax(0, 1fr); gap: clamp(2rem, 5vw, 4rem); }
}

/* How-I-work header: 4/FOUNDATIONS badge + statement */
.how__head {
  display: flex;
  align-items: center;
  gap: clamp(1.5rem, 4vw, 50px);
}
.foundations-badge {
  flex: 0 0 auto;
  width: clamp(120px, 16vw, 192px);
  display: flex;
  flex-direction: column;
  will-change: transform, opacity;   /* scroll-scrubbed entrance (set by JS) */
}
.foundations-badge__num {
  font-weight: 600;                  /* Satt */
  font-size: clamp(5rem, 12vw, 178px);
  line-height: .9;
  color: var(--sc-muted);
  text-align: center;
}
.foundations-badge__label {
  background: var(--sc-muted);
  color: var(--bg);
  font-weight: 600;                  /* Satt */
  font-size: 1.125rem;               /* 18px */
  line-height: .95;
  letter-spacing: .9px;
  text-transform: uppercase;
  text-align: center;
  padding: 6px 0;
}
@media (max-width: 759px) {
  .how__head { flex-direction: column; align-items: flex-start; }
  .section.indent { padding-inline-start: 0; }   /* drop the left indent on mobile for indented sections */
  /* Bigger (≈2×), left-aligned with the section content on mobile */
  .foundations-badge {
    width: 100%;
    align-self: auto;
    transform: none !important;
    opacity: 1 !important;
    margin-bottom: 32px;
  }
  .foundations-badge__num { font-size: clamp(7.5rem, 44vw, 220px); }
  .foundations-badge__label { font-size: 1.0625rem; letter-spacing: .8px; }

  .exp-actions { flex-direction: column; align-items: stretch; padding-inline: var(--pad); }
  .exp-actions .pill { width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .foundations-badge { transform: none !important; opacity: 1 !important; }
}

/* Foundations 2×2 grid */
.foundations {
  margin-top: clamp(2.5rem, 5vw, 3.75rem);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(2rem, 4vw, 3rem) clamp(2rem, 4vw, 3rem);
  font-size: var(--fs-lg);
}
@media (min-width: 760px) {
  .foundations { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.foundation__name { font-weight: 500; margin-bottom: clamp(1rem, 1.75vw, 1.75rem); }
.foundation__desc { line-height: 1.4; }

/* =========================================================================
   Experience list
   ========================================================================= */
.experience { display: flex; flex-direction: column; align-items: stretch; gap: clamp(3rem, 6vw, 6rem); }
.exp-list { width: 100%; display: flex; flex-direction: column; gap: clamp(2.5rem, 5vw, 5rem); }

.exp-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem 2rem;
  align-items: center;
}
/* Figma SVGs use preserveAspectRatio="none" with no intrinsic size,
   so width + height must be set explicitly to match each viewBox ratio. */
.exp-logo { display: flex; align-items: center; min-height: 28px; }
.exp-logo--deepl { gap: 6px; }
.exp-logo--deepl .exp-logo__mark { width: 22px;  height: 28px; }  /* vb 21.84×28   */
.exp-logo--deepl .exp-logo__word { width: 50px;  height: 14px; }  /* vb 50.69×14.17 */
.exp-logo--tby img        { width: 162px; height: 16px; }         /* vb 162×16     */
.exp-logo--metadesign img { width: 124px; height: 23px; }         /* vb 122.28×22.69 */
/* The Accenture PNG is pre-stretched tall; a wide-short box restores its
   true proportions (matches the Figma 167×21 display box). */
.exp-logo--accenture img  { width: 168px; height: 22px; max-width: none; }

.exp-actions { display: flex; justify-content: center; gap: clamp(1rem, 2vw, 1.6rem); flex-wrap: wrap; }

.exp-desc { font-size: var(--fs-lg); line-height: 1.15; }
.exp-meta { font-size: var(--fs-sm); line-height: 1.4; color: var(--ink); }
.exp-meta__role { display: inline; font: inherit; font-weight: 500; margin: 0; }

@media (min-width: 820px) {
  .exp-row {
    grid-template-columns: 181px minmax(0, 1.3fr) 240px;
    gap: 8px clamp(1.5rem, 3vw, 3.25rem);
  }
}

/* =========================================================================
   Pill button
   ========================================================================= */
.pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 14px 24px 16px;
  border: 1px solid var(--line);
  border-radius: 100px;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: var(--fs-pill);
  line-height: 1;
  cursor: pointer;
  white-space: nowrap;
  transition: background .25s var(--ease), color .25s var(--ease);
  will-change: transform;
}
@media (hover: hover) and (pointer: fine) {
  .pill:hover { background: var(--ink); color: var(--bg); }
}

.pill__arrow { margin-left: 8px; }

/* =========================================================================
   Cases card
   ========================================================================= */
/* Wide, viewport-driven container so the Cases card reads big and impressive */
.cases-wrap {
  width: 100%;
  max-width: min(1800px, 94vw);
  margin-inline: auto;
  padding-inline: clamp(1rem, 3vw, 2rem);
}
.cases {
  background: var(--surface);
  border-radius: clamp(20px, 2vw, 32px);
  padding: clamp(2.5rem, 4vw, 4.5rem) clamp(1.5rem, 4vw, 5rem) clamp(3rem, 5vw, 5.5rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(2.5rem, 4vw, 4rem);
}
/* Mobile: the Cases surface runs edge-to-edge (Figma node 11581:149) —
   drop the wrap's max-width/gutter that otherwise centers it with margin,
   and square off the corners since they now sit flush with the screen edge.
   .cases loses its own side padding too, so the card row can bleed all the
   way to the right edge (even on resize); the title/pill/description get
   that inset back directly so they stay readable. The card row keeps only a
   left inset (so card 1 isn't flush left) via padding-inline-start. */
@media (max-width: 759px) {
  :root {
    --case-card-w: 81vw;                              /* also used by .case-card, keeps the math consistent */
    --case-inset: calc((100vw - var(--case-card-w)) / 2);  /* centers card 1 */
  }
  .cases-wrap { max-width: 100%; padding-inline: 0; }
  .cases { border-radius: 0; padding-inline: 0; }
  .cases__title, .case-show, .cases > .pill { padding-inline: var(--case-inset); }
  /* Card 1 is centered by real padding (so it's correct on initial load —
     scroll-padding alone only affects re-snapping after a scroll gesture, not
     the resting position on first paint) plus matching scroll-padding (so a
     swipe back to card 1 re-settles at the same inset instead of flush left).
     align-self: stretch overrides .cases's align-items: center — otherwise the
     parent centers this element by its OUTER (margin) box, and the -20px end
     margin below makes that box asymmetric, shifting the whole row sideways. */
  .case-cards {
    align-self: stretch;
    padding-inline-start: var(--case-inset);
    padding-inline-end: 20px;
    margin-inline-end: -20px;
    scroll-padding-inline-start: var(--case-inset);
  }
}
.cases__title {
  font-size: clamp(2.75rem, 5vw + 1rem, 6rem);
  font-weight: 400;            /* ApfelGrotezk Regular */
  line-height: .95;
  text-align: center;
}

.case-tabs {
  width: 100%;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1rem, 2vw, 1.5rem) clamp(1rem, 3vw, 3.25rem);
}
@media (min-width: 760px) { .case-tabs { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.case-tab {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 25px;
  background: none;
  border: 0;
  font: inherit;
  font-size: var(--fs-sm);
  color: var(--ink);
  text-align: center;
  cursor: pointer;
  padding: 0;
}
.case-tab__title { min-height: 2.8em; }
.case-tab__lock {
  display: inline-block;
  vertical-align: -2px;
  margin-right: .4em;
  opacity: .6;
}
.case-tab[data-locked="true"] { opacity: .55; cursor: not-allowed; }

/* Underline doubles as a timeline. Track = faint ink; on the active tab the
   track is body-text (ink) and a red fill sweeps across over --case-ms. */
.case-tab__line {
  position: relative;
  width: 100%;
  height: 3px;
  border-radius: 3px;
  overflow: hidden;
  background: color-mix(in srgb, var(--ink) 18%, transparent);
  transition: background .25s var(--ease);
}
.case-tab__fill {
  position: absolute;
  inset: 0;
  transform-origin: left center;
  transform: scaleX(0);
  background: var(--accent);          /* the moving timeline */
}
.case-tab[aria-selected="true"] { font-weight: 500; }
.case-tab[aria-selected="true"] .case-tab__line { background: var(--ink); }
.case-tab[aria-selected="true"] .case-tab__fill {
  animation: caseFill var(--case-ms) var(--ease) forwards;  /* match the ring's eased finish */
}
@keyframes caseFill { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* User tapped a tab → auto-play stops; freeze the active bar as a full red mark */
.cases.is-stopped .case-tab[aria-selected="true"] .case-tab__fill {
  animation: none;
  transform: scaleX(1);
}
.case-tab:hover .case-tab__line { background: var(--ink); }

.case-show {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1.5rem, 3vw, 2rem);
}
.case-show__media {
  width: 100%;
  aspect-ratio: 1145 / 613;
  border-radius: 22px;
  overflow: hidden;
  background: #d9d8cf;
}
.case-show__media img,
.case-show__media video { width: 100%; height: 100%; object-fit: cover; display: block; }
.case-show__media [hidden] { display: none; }
.case-show__desc {
  max-width: 700px;
  font-size: var(--fs-sm);
  line-height: 1.5;
}
/* Gentle fade each time the case image / description is swapped (JS restarts it) */
.case-show__media img, .case-show__media video, .case-show__desc { animation: caseFade .4s var(--ease) both; }
@keyframes caseFade { from { opacity: 0; } to { opacity: 1; } }

/* ---- Case image → opens the modal ---- */
.case-show__link {
  display: block;
  width: 100%;
  border-radius: 22px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .2s var(--ease-out);
}
.case-show__link:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 4px;
}
.case-show__link:active { transform: scale(.99); }   /* subtle "press" feedback */
.case-show__media { position: relative; }            /* anchor the hint overlay */
.case-show__media img { transition: transform .5s var(--ease-out); }

/* "View case" hint — only on real hover-capable pointers (no false-positive on touch) */
.case-show__hint {
  position: absolute;
  bottom: 16px; right: 16px;
  display: inline-flex;
  align-items: center;
  gap: .5em;
  padding: .75em 1.4em;
  border-radius: 999px;
  background: color-mix(in srgb, var(--ink) 82%, transparent);
  color: var(--white);
  font-size: var(--fs-sm);
  line-height: 1;
  opacity: 0;
  transform: translateY(6px) scale(.96);
  transition: opacity .2s var(--ease-out), transform .2s var(--ease-out);
  pointer-events: none;
}
@media (hover: hover) and (pointer: fine) {
  .case-show__link:hover .case-show__media img { transform: scale(1.03); }
  .case-show__link:hover .case-show__hint { opacity: 1; transform: translateY(0) scale(1); }
}

/* ---- Mobile case cards (Figma node 11581:149) ----
   Below 760px the tabbed single-viewer swaps for a horizontal, swipeable,
   snap-scroll carousel: one case per slide (media + overlay + title +
   "View case" pill, then its description). The first card sits at the start
   of the (still padded) .cases surface with the next card peeking in from
   the right — it stays inside the rounded card, it does not bleed past it.
   Tapping either opens the same modal as desktop. */
.case-cards { display: none; }
@media (max-width: 759px) {
  .case-tabs, .case-show { display: none; }
  .case-cards {
    width: 100%;
    display: flex;
    gap: 4.76vw;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .case-cards::-webkit-scrollbar { display: none; }
}
.case-card {
  flex: 0 0 var(--case-card-w, 81%);
  width: var(--case-card-w, 81%);
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  gap: 1.1875rem;
}
.case-card__link {
  display: flex;
  flex-direction: column;
  gap: 2.125rem;
  padding: 18px;
  border-radius: 12px;
  overflow: hidden;
  position: relative;
  height: 603px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .2s var(--ease-out);
}
.case-card__link:active { transform: scale(.99); }
.case-card__link:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; }
.case-card__media {
  position: absolute;
  inset: 0;
  background: #8f8f8f;
}
.case-card__media img,
.case-card__media video { width: 100%; height: 100%; object-fit: cover; display: block; }
.case-card__media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--ink) 30%, transparent);
}
.case-card__title {
  position: relative;
  flex: 1 0 0;
  color: #e5e5e5;
  font-size: calc(var(--fs-sm) * 2);
}
.case-card__lock {
  display: inline-block;
  vertical-align: 0.05em;
  margin-right: .3em;
  opacity: .7;
}
.case-card__cta {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10px;
  border-radius: 100px;
  background: var(--ink);
  color: var(--white);
  font-size: var(--fs-sm);
  text-align: center;
}
.case-card__desc { font-size: var(--fs-sm); line-height: 1.5; }

/* =========================================================================
   Case modal (layer)
   Centered dialog: transform-origin stays center (modals are exempt from the
   origin-aware popover rule). Enters from scale(.95)+opacity — never scale(0).
   Only transform/opacity animate (GPU). Exit is faster than enter.
   ========================================================================= */
.modal {
  position: fixed;
  inset: 0;
  z-index: 200;
  --modal-accent: var(--accent);   /* JS overrides from the case link's href */
  --modal-bg: #f8f8f8;             /* JS overrides per case from cases[].bg */
  --modal-detail-bg: #ededed;      /* JS overrides per case from cases[].detailBg */
}
.modal[hidden] { display: none; }

.modal__backdrop {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--ink) 58%, transparent);
  opacity: 0;
  transition: opacity .26s var(--ease-out);
}

/* Full-bleed panel — also the scroll container for long content */
.modal__panel {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  background: var(--modal-bg);
  /* enter state */
  opacity: 0;
  transform: scale(.95);
  transform-origin: center;
  transition: opacity .26s var(--ease-out), transform .26s var(--ease-out);
}

/* Readable measure, centered; the panel scrolls when this overflows.
   1650px = 1100px + 50%, widened so the case-detail media grids get more
   room on large screens. */
.modal__inner {
  width: 100%;
  max-width: 1650px;
  margin: 0 auto;
  padding: clamp(3.5rem, 7vw, 6rem) var(--pad) clamp(3rem, 8vw, 7rem);
}

.modal.is-open .modal__backdrop { opacity: 1; }
.modal.is-open .modal__panel { opacity: 1; transform: scale(1); }
/* Exit: snappier than the entrance */
.modal.is-closing .modal__backdrop,
.modal.is-closing .modal__panel { transition-duration: .18s; }

/* Rubber-band close: once the panel is scrolled to its end, further
   wheel/touch input drags it down (via --drag-y, JS-driven) instead of
   scrolling, revealing the real page through the fading backdrop. Below
   the close threshold it snaps back with this same transition; past it,
   JS hands off to the normal closeModal() animation. Placed after the
   .is-open rules above so it wins on source order (same specificity). */
.modal.is-dragging .modal__panel {
  transform: translateY(var(--drag-y, 0px));
  transition: none;   /* 1:1 with input while dragging */
}
.modal.is-snapping-back .modal__panel {
  transform: translateY(0);
  transition: transform .3s var(--ease-out);
}
.modal.is-dragging .modal__backdrop,
.modal.is-snapping-back .modal__backdrop {
  opacity: var(--drag-backdrop-opacity, 1);
}
.modal.is-snapping-back .modal__backdrop { transition: opacity .3s var(--ease-out); }

/* ---- Intro (title + lead description) ---- */
.modal__intro {
  display: flex;
  flex-direction: column;
  gap: clamp(1.25rem, 2.5vw, 1.75rem);
  margin-bottom: clamp(2.5rem, 5vw, 4rem);
}
@media (min-width: 760px) {
  .modal__intro { flex-direction: row; flex-wrap: wrap; gap: clamp(2rem, 5vw, 5rem); align-items: flex-start; }
}
/* A case-level .modal-detail__timeline-wrap is appended as a third flex child
   of .modal__intro (title | desc | timeline) — force it onto its own
   full-width row underneath rather than squeezing into the row's remaining
   space. */
.modal__intro > .modal-detail__timeline-wrap { flex-basis: 100%; margin-top: 0; }
.modal__title {
  font-weight: 700;
  font-size: var(--fs-statement);
  line-height: 1.1;
  flex: 0 0 auto;
}
@media (min-width: 760px) { .modal__title { max-width: 340px; } }
.modal__desc {
  max-width: 700px;
  font-size: var(--fs-lg);
  line-height: 1.5;
  flex: 1 1 auto;
}
.modal__desc p + p { margin-top: 1em; }
.modal__desc strong { display: inline-block; margin-top: 1em; }
.modal__desc ul {
  list-style: disc;   /* global reset (ul { list-style: none }) strips this by default */
  padding-left: 1.25em;
  margin-top: .5em;
  display: flex;
  flex-direction: column;
  gap: .35em;
}
.modal__desc ul li::marker { color: var(--modal-accent); }
/* The Automotive IT Monitoring case (the only one with a case-level process
   timeline in its intro) uses a neutral marker instead of the case accent —
   its dark panels below read as a monochrome system, not an accented one. */
.modal__intro:has(.modal-detail__timeline-wrap) .modal__desc ul li::marker {
  color: color-mix(in srgb, var(--ink) 55%, transparent);
}
/* Same case: intro copy runs 18px mobile → 24px desktop (its own scale,
   distinct from --fs-lg which the other 3 cases still use). */
.modal__intro:has(.modal-detail__timeline-wrap) .modal__desc {
  font-size: clamp(1.125rem, 1rem + .6vw, 1.5rem);
}

/* ---- Detail sections — one per sub-case, each its own rounded panel ---- */
.modal__details {
  display: flex;
  flex-direction: column;
  gap: clamp(2rem, 4vw, 3rem);
}
.modal-detail {
  background: var(--modal-detail-bg);
  border-radius: 24px;
  padding: clamp(1.75rem, 4vw, 2.25rem) clamp(1.25rem, 3vw, 3rem) clamp(2.5rem, 5vw, 4rem);
}
.modal-detail__eyebrow {
  font-weight: 700;
  font-size: var(--fs-sm);
  text-align: center;
  text-transform: uppercase;
  letter-spacing: .06em;
  margin-bottom: .75em;
}
.modal-detail__heading {
  font-weight: 700;
  font-size: clamp(1.5rem, 1.1rem + 1.6vw, 2.25rem);
  text-align: center;
  margin-bottom: clamp(1.75rem, 3.5vw, 2.5rem);
}

.modal-detail__body {
  display: flex;
  flex-direction: column;
  gap: clamp(2rem, 4vw, 3rem);
}
@media (min-width: 900px) {
  /* DOM order already puts media first (or last) per mediaFirst in JS —
     row keeps that order left-to-right; media-first needs no reversal. */
  .modal-detail__body { flex-direction: row; align-items: flex-start; }
}

/* Media grid — flexible per-case layout of images/videos over a grid */
.modal-detail__media {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  flex: 1 1 0;
  min-width: 0;
}
.modal-detail__tile {
  position: relative;
  aspect-ratio: 4 / 3;
  background: #939393;
  border-radius: 6px;
  overflow: hidden;
}
.modal-detail__tile img,
.modal-detail__tile video { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Wide tiles span the full 562px container width and size to their own
   media's natural aspect ratio instead of being force-fit into the base
   tile's 4:3 box (which was stretching/cropping every wide image). */
.modal-detail__tile--wide { grid-column: 1 / -1; aspect-ratio: auto; }
.modal-detail__tile--wide img,
.modal-detail__tile--wide video { height: auto; object-fit: contain; }
/* Per-tile natural sizing — set via inline aspect-ratio when a media item
   carries its own width/height in the data (see buildMediaTile). Overrides
   whatever aspect-ratio the size modifier (or the 4:3 default) would apply. */
.modal-detail__tile--natural img,
.modal-detail__tile--natural video { object-fit: contain; }
.modal-detail__tile--16-9 { aspect-ratio: 16 / 9; }
.modal-detail__tile--tall { aspect-ratio: 3 / 4; }
/* Bottom pair (e.g. the two nav-flyout crops) — fixed 220px height, each
   tile takes half the row width (the grid's 1fr 1fr already gives 50%).
   On narrow screens that same 220px against a ~half-column width crops
   these landscape screenshots down to an illegible sliver, so below 620px
   they go full-width, stacked, and switch to `contain` on a light backdrop
   so the whole crop stays visible instead of being zoomed into. */
.modal-detail__tile--fixed-220 { aspect-ratio: auto; height: 220px; }
@media (max-width: 619px) {
  .modal-detail__tile--fixed-220 {
    grid-column: 1 / -1;
    height: auto;
    aspect-ratio: 553 / 442;
    background: #f4f4f2;
  }
  .modal-detail__tile--fixed-220 img,
  .modal-detail__tile--fixed-220 video { object-fit: contain; }
}
/* For UI screenshots with meaningful edges (buttons, labels) where a cover
   crop would cut off content — shows the full image, letterboxed. */
.modal-detail__tile--contain { aspect-ratio: 3 / 4; background: #f4f4f2; }
.modal-detail__tile--contain img,
.modal-detail__tile--contain video { object-fit: contain; }

.modal-detail__copy {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(1.5rem, 3vw, 2.25rem);
}
.modal-detail__block-heading {
  font-weight: 700;
  font-size: clamp(1.05rem, .95rem + .5vw, 1.35rem);
  margin-bottom: .85em;
}
.modal-detail__block-body,
.modal-detail__block ul {
  font-size: clamp(1.05rem, .95rem + .5vw, 1.35rem);
  line-height: 1.5;
}
.modal-detail__block ul {
  list-style: disc;   /* global reset (ul { list-style: none }) strips this by default */
  padding-left: 1.25em;
  display: flex;
  flex-direction: column;
  gap: .5em;
}
.modal-detail__block ul li::marker { color: var(--modal-accent); }

/* Ideas/insights carried forward — full-width row beneath the two columns */
.modal-detail__insights {
  margin-top: clamp(2.5rem, 5vw, 4rem);
}
.modal-detail__insights-title {
  font-weight: 700;
  font-size: var(--fs-sm);
  text-align: center;
  margin-bottom: clamp(1.25rem, 2.5vw, 1.75rem);
}
.modal-detail__insights-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
}
@media (min-width: 700px) {
  .modal-detail__insights-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1050px) {
  .modal-detail__insights-grid { grid-template-columns: repeat(4, 1fr); }
}
.modal-detail__insights-grid p {
  font-size: clamp(1.05rem, .95rem + .5vw, 1.35rem);
  line-height: 1.5;
}

/* ---- Dark-panel theme (per-case opt-in via details[].theme = 'dark') ----
   .modal-detail normally inherits the page's light --ink text color; a dark
   panel needs its own local flip since --modal-detail-bg only controls the
   background, not the text riding on top of it. */
.modal-detail--dark {
  background: #141414;
  color: #f2f2f2;
}
.modal-detail--dark .modal-detail__eyebrow { display: none; }
.modal-detail--dark .modal-detail__heading,
.modal-detail--dark .modal-detail__block-heading,
.modal-detail--dark .modal-detail__timeline-label,
.modal-detail--dark .modal-detail__insights-title {
  color: #f2f2f2;
}
/* Section headings ("The Challenge" etc.): 24px mobile → 36px desktop,
   this case's own scale (other cases keep the shared clamp above). */
.modal-detail--dark .modal-detail__heading {
  font-size: clamp(1.5rem, 1.2rem + 1.2vw, 2.25rem);
}
/* Panel copy (sub-headings, body paragraphs, bullet lists): 18px mobile →
   24px desktop, matching the intro copy scale for this case. The sub-heading
   (e.g. "Understanding the current implementation") reads at the same size
   as its own body text, not the smaller shared --fs-sm. */
.modal-detail--dark .modal-detail__block-heading,
.modal-detail--dark .modal-detail__block-body,
.modal-detail--dark .modal-detail__block ul {
  font-size: clamp(1.125rem, 1rem + .6vw, 1.5rem);
}
.modal-detail--dark .modal-detail__block ul li::marker {
  color: color-mix(in srgb, #f2f2f2 55%, transparent);
}
.modal-detail--dark .modal-detail__block-body,
.modal-detail--dark .modal-detail__block ul,
.modal-detail--dark .modal-detail__timeline-body,
.modal-detail--dark .modal-detail__insights-grid p {
  color: color-mix(in srgb, #f2f2f2 82%, transparent);
}
.modal-detail--dark .modal-detail__tile { background: #262626; }
.modal-detail--dark .modal-detail__timeline-label { background: #f2f2f2; color: #141414; }

/* ---- Process timeline — horizontal stepper (case intro, or a detail panel) ----
   Six stages by default; wraps to 3, then 2, then 1 column as space runs out
   rather than shrinking text below legibility. */
.modal-detail__timeline-title {
  font-weight: 700;
  font-size: clamp(1.5rem, 1.1rem + 1.6vw, 2.25rem);
  text-align: center;
  margin-bottom: clamp(1.5rem, 3vw, 2.25rem);
}
.modal-detail__timeline {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: clamp(1rem, 2vw, 1.5rem);
}
.modal-detail__timeline-wrap { margin-top: clamp(1.75rem, 3.5vw, 2.5rem); }
@media (max-width: 900px) {
  .modal-detail__timeline { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  .modal-detail__timeline { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.modal-detail__timeline-step {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .85em;
  text-align: left;
  padding-left: clamp(1rem, 2vw, 1.5rem);
}
/* Thin divider between columns — sits in the grid gap, skipped before the
   first column of each row (a wrapped row shouldn't inherit a stray line). */
.modal-detail__timeline-step::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 1px;
  background: rgba(255, 255, 255, .3);
}
.modal-detail__timeline-step:first-child::before,
.modal-detail__timeline-step:nth-child(6n + 1)::before { display: none; }
@media (max-width: 900px) {
  .modal-detail__timeline-step:nth-child(3n + 1)::before { display: none; }
  .modal-detail__timeline-step:nth-child(6n + 1)::before { display: block; }
}
@media (max-width: 620px) {
  .modal-detail__timeline-step:nth-child(2n + 1)::before { display: none; }
  .modal-detail__timeline-step:nth-child(3n + 1)::before,
  .modal-detail__timeline-step:nth-child(6n + 1)::before { display: block; }
}
.modal-detail__timeline-label {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 10px 20px;
  border-radius: 100px;
  background: #161616;
  color: #f2f2f2;
  font-weight: 700;
  font-size: var(--fs-sm);
  white-space: nowrap;
}
.modal-detail__timeline-step:nth-child(even) .modal-detail__timeline-label { background: #626363; }
.modal-detail__timeline-body {
  font-size: var(--fs-sm);
  line-height: 1.4;
  color: color-mix(in srgb, var(--ink) 70%, transparent);
}

/* ---- Closing mosaic — plain 4-col × 2-row grid, full-bleed within the
   panel. Item 1: 2 cols × 2 rows. Item 2: 1 col × 1 row. Item 3: 1 col ×
   1 row. Item 4: 2 cols × 1 row. Just boxes — no captions, no overlays. */
/* Overrides the shared --dark panel background — this module sits on the
   modal's own page background (#f8f8f8), not the dark panel color. */
.modal-detail--closing { padding: 0; overflow: hidden; background: #f8f8f8; }
.modal-closing {
  display: grid;
  gap: 20px;
  aspect-ratio: 16 / 9;
  grid-template-rows: repeat(2, minmax(0, 1fr));
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
@media (max-width: 900px) {
  .modal-closing {
    aspect-ratio: auto;
    grid-template-rows: none;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 619px) {
  .modal-closing { grid-template-columns: minmax(0, 1fr); }
}
.modal-closing__tile { position: relative; overflow: hidden; border-radius: 24px; }
.modal-closing__tile img,
.modal-closing__tile video { width: 100%; height: 100%; object-fit: cover; display: block; }
.modal-closing__tile--1 { grid-row: 1 / 3; grid-column: 1 / 3; }
.modal-closing__tile--2 { grid-row: 1; grid-column: 3; }
.modal-closing__tile--3 { grid-row: 1; grid-column: 4; }
.modal-closing__tile--4 { grid-row: 2; grid-column: 3 / 5; }
@media (max-width: 900px) {
  .modal-closing__tile--1,
  .modal-closing__tile--4 { grid-row: auto; grid-column: 1 / -1; }
  .modal-closing__tile--2,
  .modal-closing__tile--3 { grid-row: auto; grid-column: auto; }
}
@media (max-width: 619px) {
  .modal-closing__tile { aspect-ratio: 4 / 3; }
}

/* 3-tile variant (Figma "Case_Detail_Page_Deepl", node 11674:169): one wide
   media tile spanning both rows on the left, two stacked tiles on the right. */
.modal-closing--3 {
  aspect-ratio: auto;
  height: 580px;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr) minmax(0, .8fr);
}
.modal-closing--3 .modal-closing__tile--1 { grid-row: 1 / 3; grid-column: 1 / 3; }
.modal-closing--3 .modal-closing__tile--2 { grid-row: 1; grid-column: 3; }
.modal-closing--3 .modal-closing__tile--3 { grid-row: 2; grid-column: 3; }
@media (max-width: 900px) {
  .modal-closing--3 {
    height: auto;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .modal-closing--3 .modal-closing__tile--1 { grid-row: auto; grid-column: 1 / -1; }
  .modal-closing--3 .modal-closing__tile--2,
  .modal-closing--3 .modal-closing__tile--3 { grid-row: auto; grid-column: auto; }
}
@media (max-width: 619px) {
  .modal-closing--3 { grid-template-columns: minmax(0, 1fr); }
}

/* ---- Contact block — mirrors the page's own .contact section ----
   Same width as the rest of the case content (lives inside .modal__inner,
   no bleed). Vertical padding is --section-y * 1.5 (50% taller than the
   page's own .contact section) so it reads as a bigger closing block. */
.modal__contact {
  padding-block: calc(var(--section-y) * 1.5);
  display: flex;
  flex-direction: column;
  gap: clamp(1.5rem, 3vw, 2rem);
}
@media (min-width: 760px) {
  .modal__contact { flex-direction: row-reverse; align-items: center; justify-content: space-between; gap: clamp(2rem, 4vw, 3rem); }
}
.modal__contact-lead { display: flex; flex-direction: column; gap: clamp(1.25rem, 2.5vw, 1.75rem); align-items: flex-start; }
.modal__contact-headline {
  font-weight: 700;                 /* Satt */
  color: var(--accent);
  font-size: var(--fs-contact);
  line-height: .85;
}
.modal__contact-actions { display: flex; gap: clamp(1rem, 2vw, 1.6rem); flex-wrap: wrap; }
.modal__contact-text { max-width: 400px; font-size: var(--fs-sm); line-height: 1.4; }

/* Content entrance — a short rise+fade cascade down the page as the layer
   opens (intro, then each detail panel, then contact), so the reader's eye
   is drawn top-to-bottom instead of the whole page popping in at once.
   Panel scale/opacity (the layer itself) already animates via .modal.is-open;
   this is a second, independent stagger on the content inside it. */
.modal__intro,
.modal__details > .modal-detail,
.modal__contact {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .5s var(--ease-out), transform .5s var(--ease-out);
  transition-delay: var(--reveal-delay, 0s);
}
.modal.is-open .modal__intro,
.modal.is-open .modal__details > .modal-detail,
.modal.is-open .modal__contact {
  opacity: 1;
  transform: none;
}
.modal.is-open .modal__intro { --reveal-delay: .08s; }
.modal.is-open .modal__details > .modal-detail:nth-child(1) { --reveal-delay: .16s; }
.modal.is-open .modal__details > .modal-detail:nth-child(2) { --reveal-delay: .22s; }
.modal.is-open .modal__details > .modal-detail:nth-child(3) { --reveal-delay: .28s; }
.modal.is-open .modal__contact { --reveal-delay: .3s; }

@media (prefers-reduced-motion: reduce) {
  .modal__intro,
  .modal__details > .modal-detail,
  .modal__contact { opacity: 1; transform: none; transition: none; }
}

/* Fixed to the viewport so it stays reachable while the panel scrolls.
   Same frosted-glass treatment as .nav (rgba white + backdrop-blur) so the
   close control reads as part of the same floating-chrome language. */
.modal__close {
  position: fixed;
  top: clamp(1rem, 2vw, 1.5rem);
  right: clamp(1rem, 2vw, 1.5rem);
  z-index: 2;   /* above .modal__backdrop and .modal__panel (siblings) */
  width: 44px; height: 44px;
  display: grid;
  place-items: center;
  border: none;
  border-radius: 999px;
  background: #33332d;
  backdrop-filter: blur(27px);
  -webkit-backdrop-filter: blur(27px);
  color: var(--white);
  cursor: pointer;
  opacity: 0;
  transition: background .2s var(--ease-out), transform .16s var(--ease-out), box-shadow .25s var(--ease), opacity .26s var(--ease-out);
}
.modal.is-open .modal__close { opacity: 1; }
.modal.is-closing .modal__close { transition-duration: .18s; }
.modal__close:hover { background: color-mix(in srgb, var(--modal-accent) 32%, #33332d); box-shadow: 0 4px 12px rgba(0, 0, 0, .12); }
.modal__close:active { transform: scale(.94); }   /* press feedback */
.modal__close:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* Reduced motion: keep the opacity fade, drop the scale/movement */
@media (prefers-reduced-motion: reduce) {
  .modal__panel { transform: none; }
  .modal.is-open .modal__panel { transform: none; }
  .case-show__media img { transition: none; }
}

/* =========================================================================
   Case pages — standalone, crawlable /cases/<slug>/ documents. Same custom
   properties as .modal (--modal-accent/--modal-bg/--modal-detail-bg), set
   inline per case in the page's own markup instead of via JS, so every
   .modal-detail/.modal__desc/etc. rule above renders identically outside
   the modal. Not a modal: no position/animation/backdrop, just the resting
   visual state.
   ========================================================================= */
.case-page {
  --modal-accent: var(--accent);
  --modal-bg: #f8f8f8;
  --modal-detail-bg: #ededed;
  background: var(--modal-bg);
  min-height: 100dvh;
}
.case-page__inner {
  width: 100%;
  max-width: 1650px;
  margin: 0 auto;
  padding: clamp(3.5rem, 7vw, 6rem) var(--pad) clamp(3rem, 8vw, 7rem);
}
.case-page__back { padding: clamp(1.5rem, 4vw, 2.5rem) var(--pad) 0; }
/* .modal__intro/.modal-detail/.modal__contact default to opacity:0, revealed
   only by .modal.is-open (the in-page layer's entrance animation) — a
   standalone case page has no .modal ancestor to ever add that class, so
   force the resting/visible state directly instead. */
.case-page .modal__intro,
.case-page .modal__details > .modal-detail,
.case-page .modal__contact {
  opacity: 1;
  transform: none;
  transition: none;
}

/* Loading state for the modal while its fetched fragment is in flight —
   brief on a normal connection, visible on a throttled one. */
#modalDetails.is-loading { opacity: .4; pointer-events: none; }

/* =========================================================================
   Contact
   ========================================================================= */
.contact__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(2rem, 4vw, 3rem);
  align-items: center;
}
@media (min-width: 900px) {
  .contact__grid { grid-template-columns: minmax(0, 1fr) 360px; gap: clamp(2rem, 4vw, 2.4rem); }
}
.contact__lead { display: flex; flex-direction: column; align-items: flex-start; gap: clamp(1.75rem, 3vw, 2.7rem); }
@media (min-width: 900px) { .contact__lead { align-items: flex-end; } }

.contact__headline {
  font-weight: 700;                 /* Satt */
  font-size: var(--fs-contact);
  line-height: .85;
  color: var(--accent);
}
@media (min-width: 900px) { .contact__headline { text-align: right; } }

.contact__actions { display: flex; gap: clamp(1rem, 2vw, 1.6rem); flex-wrap: wrap; }
.contact__text { font-size: var(--fs-lg); line-height: 1.2; }

/* =========================================================================
   Footer
   ========================================================================= */
.footer {
  border-top: 1px solid var(--white);
}
.footer__inner {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem 1.5rem;
  justify-content: space-between;
  align-items: center;
  padding-block: clamp(1.5rem, 3vw, 2.5rem);
  font-size: var(--fs-sm);
  color: color-mix(in srgb, var(--ink) 70%, transparent);
}
.footer__inner a:hover { color: var(--accent); }

/* =========================================================================
   Back-to-top button
   ========================================================================= */
.totop {
  position: fixed;
  right: var(--pad);
  bottom: 0px;
  width: 37px;
  height: 42px;
  overflow: hidden;
  z-index: 40;
  opacity: 0;
  visibility: hidden;
  transition: opacity .3s var(--ease), visibility .3s;
}
.totop.is-visible { opacity: 1; visibility: visible; }
.totop__shape {
  position: absolute;
  top: 0;
  left: 0;
  width: 37px;
  height: 55px;
  opacity: .3;
  transition: transform .2s var(--ease);
}
.totop:hover .totop__shape { transform: translateY(-4px); }
.totop__arrow {
  position: absolute;
  top: 14px;
  left: 11px;
  width: 15px;
  height: 31px;
  transition: transform .2s var(--ease);
}
.totop:hover .totop__arrow { transform: translateY(-4px); }
@media (prefers-reduced-motion: reduce) {
  .totop { transition: opacity .01ms, visibility .01ms; }
}

/* =========================================================================
   Motion — scroll reveals (strictly rationed)
   ========================================================================= */
.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
}
.reveal.is-in { opacity: 1; transform: none; }
.reveal[data-delay="1"] { transition-delay: .08s; }
.reveal[data-delay="2"] { transition-delay: .16s; }
.reveal[data-delay="3"] { transition-delay: .24s; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
  .reveal { opacity: 1; transform: none; }
}
