* { margin: 0; padding: 0; box-sizing: border-box; }

/* ═════════════════════════════════════════════
   Design tokens
   Light theme lives in :root, dark theme in html.dark.
   To restyle a theme, only change the values here.
   ═════════════════════════════════════════════ */
:root {
  /* ── Layout ── */
  --radius: 4px;
  --card-radius: 20px;
  /* Card arrows column on the right of the cards */
  --nav-size: 40px;
  --nav-gap: 28px;              /* space between cards and the arrows */
  --nav-spacing: 36px;          /* space between arrow, dots, arrow */

  /* Detail panel (fills the content section) */
  --detail-inset: 24px;         /* gap between panel and section sides */
  --detail-inset-y: 0px;        /* gap at the top and bottom of the section */
  --contact-section-gap: 64px;  /* space between groups on the Contact page */
  --dock-space: 96px;           /* height the mobile/tablet dock takes from the bottom (16px gap + dock) */
  --dock-clear: calc(var(--dock-space) + env(safe-area-inset-bottom));
  --logo-cols: 4;               /* logo wall columns */
  --logo-gap: 12px;
  --ba-scroll-length: 70vh;     /* how much scrolling the before→after wipe takes */
  --ba-sticky-top: 72px;        /* compare frame pins centred, but never above this (Back sits there) */

  /* Layout container width per breakpoint (see "Breakpoints" at the end of this file):
     100vw below 1024px, 1024px on laptops, 1440px on desktops */
  --container: 100vw;
  --container-pad: 16px;

  /* Card fills its half of the container minus room for the arrows, short enough that
     the stack fits vertically (height ≤ ~55vh), capped at 620px. 3:2 ratio. */
  --card-w: min(calc(var(--container) / 2 - var(--container-pad) - 94px), 82vh, 620px);
  --card-h: calc(var(--card-w) * 2 / 3);

  /* ── Font sizes ──
     Content section (Home cards, project details, About, Contact) uses one fixed scale:
     14px base, with 12 / 16 / 20 around it. Every role below points at a step. */
  --fs-xs: 12px;   /* labels, tags, notes, small controls */
  --fs-sm: 14px;   /* base: body text */
  --fs-md: 16px;   /* lead lines, prominent links, form fields */
  --fs-lg: 20px;   /* titles and intros */

  /* Navigator (left side) — outside the content scale */
  --fs-title: 1.8rem;
  --fs-subtitle: 1.05rem;   /* role line under the name */

  /* Home cards */
  --fs-card-title: var(--fs-lg);
  --fs-card-subtitle: var(--fs-sm);
  --fs-hint: var(--fs-xs);

  /* Project details */
  --fs-detail-title: var(--fs-lg);
  --fs-detail-lead: 18px;              /* a step above the body, for the opening paragraph */
  --fs-detail-body: var(--fs-md);      /* 16px: comfortable for long case-study reading */
  --fs-detail-label: var(--fs-xs);
  --fs-detail-link: var(--fs-sm);
  --fs-detail-back: var(--fs-xs);

  /* About */
  --fs-about-bio: var(--fs-md);
  --fs-about-skill: var(--fs-xs);

  /* Contact */
  --fs-contact-intro: var(--fs-md);
  --fs-direct-link: var(--fs-md);
  --fs-tab: var(--fs-sm);
  --fs-field: var(--fs-md);    /* 16px also stops phones zooming in on focus */
  --fs-chip: var(--fs-xs);

  /* Keyboard shortcut keycaps */
  --fs-kbd: var(--fs-xs);

  /* ── Base colors ── */
  --bg: #F6F6F6;
  --text: #111111;
  --muted: #6b6b6b;                   /* 4.9:1 on the page background (WCAG AA) */

  /* ── Navigator icon buttons (liquid glass, see .liquid-glass) ── */
  --nav-radius: 14px;
  --icon: #222222;
  --icon-muted: rgba(0, 0, 0, 0.45);   /* focus outline */

  /* ── Keyboard shortcut hints ── */

  /* ── Contact form ── */
  --field-focus-border: rgba(0, 0, 0, 0.25);
  --focus-ring: rgba(0, 0, 0, 0.06);
  --error: #c0392b;

  /* ── Logo wall ── */
  --logo-filter: grayscale(1);
  --logo-rest: 0.7;             /* logo opacity when not highlighted */
  --logo-shine: rgba(255, 255, 255, 0.55);

  /* ── Direct links (Email / LinkedIn) ── */
  --direct-rest: var(--muted);
  --direct-hover: #000000;
  --icon-on-fill: #ffffff;             /* inner lines of a filled (selected) icon */

  /* ── Liquid glass (shared by every glass surface) ──
     Two recipes, from the reference design:
       panel — calm surface: near-clear tint + 10-layer rim (light + dark inner highlights)
               + soft drop shadow → var(--glass) + var(--glass-panel-shadow)
       pill  — raised control: brighter tint + 7-layer rim → var(--pill) + var(--glass-pill-shadow)
     Light/dark only change the tint and the strength of the light/dark reflections. */
  --glass: rgb(255 255 255 / 0.16);
  --pill: rgb(255 255 255 / 0.45);
  --rim-light: #fff;
  --rim-dark: #000;
  --reflex-light: 1;
  --reflex-dark: 1;
  --glass-saturate: 160%;
  --glass-filter: blur(14px) saturate(var(--glass-saturate));
  --glass-panel-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--rim-light) calc(var(--reflex-light) * 12%), transparent),
    inset 1.8px 3px 0 -2px color-mix(in srgb, var(--rim-light) calc(var(--reflex-light) * 90%), transparent),
    inset -2px -2px 0 -2px color-mix(in srgb, var(--rim-light) calc(var(--reflex-light) * 80%), transparent),
    inset -3px -8px 1px -6px color-mix(in srgb, var(--rim-light) calc(var(--reflex-light) * 60%), transparent),
    inset -0.3px -1px 4px 0 color-mix(in srgb, var(--rim-dark) calc(var(--reflex-dark) * 12%), transparent),
    inset -1.5px 2.5px 0 -2px color-mix(in srgb, var(--rim-dark) calc(var(--reflex-dark) * 20%), transparent),
    inset 0 3px 4px -2px color-mix(in srgb, var(--rim-dark) calc(var(--reflex-dark) * 20%), transparent),
    inset 2px -6.5px 1px -4px color-mix(in srgb, var(--rim-dark) calc(var(--reflex-dark) * 10%), transparent),
    0 1px 5px 0 color-mix(in srgb, var(--rim-dark) calc(var(--reflex-dark) * 10%), transparent),
    0 12px 32px 0 color-mix(in srgb, var(--rim-dark) calc(var(--reflex-dark) * 8%), transparent);
  /* Softer panel for big content surfaces (link and skill tiles, contact fields and tabs, chat,
     lock card): its dark reflections are blurred, so large edges don't show hard crescents.
     Icons, buttons and the project cards keep the crisper recipes above and below. */
  --glass-panel-shadow-soft:
    inset 0 0 0 1px color-mix(in srgb, var(--rim-light) calc(var(--reflex-light) * 12%), transparent),
    inset 1.8px 3px 0 -2px color-mix(in srgb, var(--rim-light) calc(var(--reflex-light) * 90%), transparent),
    inset -2px -2px 0 -2px color-mix(in srgb, var(--rim-light) calc(var(--reflex-light) * 80%), transparent),
    inset -3px -8px 1px -6px color-mix(in srgb, var(--rim-light) calc(var(--reflex-light) * 60%), transparent),
    inset -0.3px -1px 4px 0 color-mix(in srgb, var(--rim-dark) calc(var(--reflex-dark) * 8%), transparent),
    inset -1px 1.5px 3px -1px color-mix(in srgb, var(--rim-dark) calc(var(--reflex-dark) * 7%), transparent),
    inset 0 3px 4px -2px color-mix(in srgb, var(--rim-dark) calc(var(--reflex-dark) * 12%), transparent),
    inset 1px -3px 4px -2px color-mix(in srgb, var(--rim-dark) calc(var(--reflex-dark) * 5%), transparent),
    0 1px 5px 0 color-mix(in srgb, var(--rim-dark) calc(var(--reflex-dark) * 10%), transparent),
    0 12px 32px 0 color-mix(in srgb, var(--rim-dark) calc(var(--reflex-dark) * 8%), transparent);
  --glass-pill-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--rim-light) calc(var(--reflex-light) * 10%), transparent),
    inset 2px 1px 0 -1px color-mix(in srgb, var(--rim-light) calc(var(--reflex-light) * 90%), transparent),
    inset -1.5px -1px 0 -1px color-mix(in srgb, var(--rim-light) calc(var(--reflex-light) * 80%), transparent),
    inset -2px -6px 1px -5px color-mix(in srgb, var(--rim-light) calc(var(--reflex-light) * 60%), transparent),
    inset -1px 2px 3px -1px color-mix(in srgb, var(--rim-dark) calc(var(--reflex-dark) * 20%), transparent),
    inset 0 -4px 1px -2px color-mix(in srgb, var(--rim-dark) calc(var(--reflex-dark) * 10%), transparent),
    0 3px 6px 0 color-mix(in srgb, var(--rim-dark) calc(var(--reflex-dark) * 8%), transparent);

  /* ── Carousel cards ── */
  --card-frame: 8px;                              /* glass rim around the image */
  /* Studio backdrop behind the transparent project mockups (images/hero-1…6) */
  --mockup-bg: linear-gradient(160deg, #ffffff 0%, #eceef2 100%);
  --card-text: #ffffff;
  --card-overlay: rgba(0, 0, 0, 0.55);
  --card-text-shadow: rgba(0, 0, 0, 0.25);

  /* ── Card arrows ── */
  --arrow: rgba(0, 0, 0, 0.35);
  --arrow-hover: #111111;
  --dot: rgba(0, 0, 0, 0.15);
  --dot-active: rgba(0, 0, 0, 0.55);

  /* ── Detail panel ── */
  --detail-motion-bg: var(--glass);  /* only while opening/closing */
  --ba-divider: #ffffff;
  --ba-before-filter: grayscale(1) contrast(0.85) brightness(1.08);  /* demo "old" look */
  --detail-divider: rgba(0, 0, 0, 0.08);
  /* Detail tiles (links, tags, step numbers) reuse the card glass tokens
     with the shared --glass-tile-* edges */
  --chip-text: #333333;
  --back-border: rgba(255, 255, 255, 0.25);

  /* ── Scroll hint ── */
  --hint: rgba(0, 0, 0, 0.56);
  --hint-border: rgba(0, 0, 0, 0.2);
  --hint-dot: rgba(0, 0, 0, 0.35);

  /* ── Theme toggle button ── */
  --toggle-icon: #222222;

  /* ── Hex background (read by js/canvas.js, hex only) ── */
  --canvas-bg: #F6F6F6;
  --hex-base: #FAFAFA;
  --hex-shadow: #D5D8DE;         /* cast shadows and the shaded side of each bevel */
  --hex-highlight: #FFFFFF;      /* the bevel facing the light */
  --hex-shadow-opacity: 0.55;    /* 0–1, how strong the cast shadows are */
}

html.dark {
  /* ── Base colors ── */
  --bg: #1F1F1F;
  --text: #f2f2f2;
  --muted: #8a8a8a;

  /* ── Navigator icon buttons ── */
  --icon: #f2f2f2;
  --icon-muted: rgba(255, 255, 255, 0.5);
  --field-focus-border: rgba(255, 255, 255, 0.35);
  --focus-ring: rgba(255, 255, 255, 0.08);
  --error: #ff7a6e;
  --logo-filter: grayscale(1) invert(1) brightness(1.1);   /* grey marks turn light on dark */
  --logo-rest: 0.7;
  --logo-shine: rgba(255, 255, 255, 0.08);
  --direct-hover: #ffffff;
  --icon-on-fill: #1f1f1f;

  /* ── Liquid glass: fainter tint, softer light rim, deeper dark rim ── */
  --glass: rgb(255 255 255 / 0.05);
  --pill: rgb(255 255 255 / 0.12);
  --reflex-light: 0.35;
  --reflex-dark: 2;

  /* ── Card arrows ── */
  --arrow: rgba(255, 255, 255, 0.4);
  --arrow-hover: #f2f2f2;
  --dot: rgba(255, 255, 255, 0.18);
  --dot-active: rgba(255, 255, 255, 0.65);

  /* ── Detail panel ── */
  --detail-motion-bg: var(--glass);
  --mockup-bg: linear-gradient(160deg, #2c2e33 0%, #18191c 100%);
  --detail-divider: rgba(255, 255, 255, 0.1);
  --chip-text: #dddddd;
  --back-border: rgba(255, 255, 255, 0.18);

  /* ── Scroll hint ── */
  --hint: rgba(255, 255, 255, 0.5);
  --hint-border: rgba(255, 255, 255, 0.3);
  --hint-dot: rgba(255, 255, 255, 0.5);

  /* ── Theme toggle button ── */
  --toggle-icon: #eeeeee;

  /* ── Hex background ── */
  --canvas-bg: #1F1F1F;
  --hex-base: #1E1E1E;
  --hex-shadow: #000000;
  --hex-highlight: #2F2F2F;
  --hex-shadow-opacity: 0.8;
}

html, body {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  touch-action: manipulation;   /* no double-tap zoom on the carousel; pinch-zoom still works */
  font-family: 'Inter', sans-serif;
  background: var(--bg);
  color: var(--text);
}

.page {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  width: 100%;                          /* tablet / mobile: fluid (see Breakpoints) */
  height: 100vh;
  margin: 0 auto;
  padding: 0 var(--container-pad);
  overflow: hidden;
  z-index: 1;
}

/* ───────── Navigator ───────── */
.navigator {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  z-index: 1;
  height: 100vh;
  width: 100%;
}

.navigator-inner {
  display: flex;
  flex-direction: column;
  gap: 42px;
  align-items: flex-start;
  text-align: left;
}

.title-block h1 {
  font-size: var(--fs-title);
  line-height: 1;
  font-weight: 600;
  letter-spacing: -0.04em;
  margin-bottom: 6px;
}

.title-role {
  font-size: var(--fs-subtitle);
  line-height: 1;
  font-weight: 300;
  color: var(--muted);
  letter-spacing: -0.04em;
}

/* One-line pitch: what Sunom does, in plain words */
.title-pitch {
  max-width: 24em;
  margin-top: 18px;
  font-size: var(--fs-sm);
  line-height: 1.6;
  color: var(--muted);
}

.nav-actions {
  display: flex;
  gap: 14px;
  margin-top: 12px;
}

.icon-btn {
  width: 50px;
  height: 50px;
  border-radius: var(--nav-radius);
  display: grid;
  place-items: center;
  cursor: pointer;
  color: var(--icon);
  transition: transform 0.3s ease;
  position: relative;
  z-index: 1;
}

/* Liquid glass — same recipe as the carousel cards, with a finer, lighter border */
.liquid-glass {
  background: var(--pill);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
  border: 0;
  box-shadow: var(--glass-pill-shadow);
}

.liquid-glass:hover {
  transform: translateY(-3px);
}

/* All navigator icons are raised glass pills */
.icon-btn.liquid-glass {
  background: var(--pill);
  box-shadow: var(--glass-pill-shadow);
}

.liquid-glass svg {
  position: relative;
  z-index: 1;
  width: 20px;
  height: 20px;
  stroke: currentColor;
  fill: transparent;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: fill 0.25s ease;
}

/* Selected item: the icon fills in — the only active indicator */
.icon-btn.is-active svg { fill: currentColor; }
.icon-btn.is-active svg .icon-detail { stroke: var(--icon-on-fill); }

.icon-btn:focus-visible {
  outline: 2px solid var(--icon-muted);
  outline-offset: 3px;
}

/* Name label under each navigator icon, on hover or keyboard focus (desktop only).
   It steps aside while the Shift keycaps are showing, which use the same spot. */
@media (hover: hover) and (min-width: 1024px) {
  .icon-btn::after {
    content: attr(data-label);
    position: absolute;
    top: calc(100% + 10px);
    left: 50%;
    padding: 5px 10px;
    border-radius: 999px;
    font-size: var(--fs-xs);
    font-weight: 500;
    line-height: 1.2;
    white-space: nowrap;
    color: var(--text);
    background: var(--pill);
    backdrop-filter: var(--glass-filter);
    -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
    box-shadow: var(--glass-pill-shadow);
    pointer-events: none;
    opacity: 0;
    transform: translate(-50%, -4px);
    transition: opacity 0.18s ease, transform 0.25s ease;
  }
  .icon-btn:is(:hover, :focus-visible)::after {
    opacity: 1;
    transform: translate(-50%, 0);
    transition-delay: 0.25s;   /* a short pause, so a passing pointer doesn't flash labels */
  }
  .show-key-hints .icon-btn::after { opacity: 0; transition-delay: 0s; }
}

/* ───────── Content ───────── */
.content {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  z-index: 1;
  height: 100vh;
  width: 100%;
}

.content-inner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--nav-gap);
  position: relative;
  width: 100%;
  height: 100%;
  transition: opacity 0.4s ease;
}

.content.is-detail-open .content-inner {
  opacity: 0;
  pointer-events: none;
}

/* Home ⇄ About / Contact fade is animated with GSAP (js/index.js → showView) */
.content.is-panel-view .content-inner {
  pointer-events: none;
}

/* ───────── 3D Vertical Carousel ───────── */
.carousel-wrapper {
  position: relative;
  width: var(--card-w);
  flex-shrink: 0;
  height: calc(var(--card-h) * 1.33);
  perspective: 1200px;
  perspective-origin: 50% 45%;
}

.carousel {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Liquid glass card: a frosted glass slab with the image set inside it.
   No drop shadow — depth comes from the rim highlights and the sheen. */
.card {
  position: absolute;
  width: var(--card-w);
  height: var(--card-h);
  border-radius: var(--card-radius);
  overflow: hidden;
  backface-visibility: hidden;
  will-change: transform, opacity;
  background: var(--glass);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
  border: 0;
  box-shadow: var(--glass-panel-shadow);
  transition: border-color 0.4s ease;
}

.card { color: inherit; text-decoration: none; -webkit-user-drag: none; }   /* cards are links */
.card:focus { outline: none; }
.card:focus-visible { outline: 2px solid var(--text); outline-offset: 4px; }

.card .card-image,
.card .card-overlay {
  position: absolute;
  inset: var(--card-frame);
  width: calc(100% - var(--card-frame) * 2);
  height: calc(100% - var(--card-frame) * 2);
  border-radius: calc(var(--card-radius) - var(--card-frame));
  pointer-events: none;
}

.card .card-image {
  object-fit: contain;          /* show the whole device mockup */
  background: var(--mockup-bg);
  will-change: transform;
}

.card .card-overlay {
  background: linear-gradient(180deg,
          transparent 40%,
          var(--card-overlay) 100%);
}

/* Caption: plain type on the photo, same voice as the name block
   (bold tight title over a light subtitle) — no box */
.card .card-content,
.detail-hero figcaption {
  position: absolute;
  left: calc(var(--card-frame) + 22px);
  right: calc(var(--card-frame) + 22px);
  bottom: calc(var(--card-frame) + 20px);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  color: var(--card-text);
  text-shadow: 0 1px 10px var(--card-text-shadow);
  pointer-events: none;
  z-index: 2;
}

.card .card-title {
  font-size: var(--fs-card-title);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.04em;
}

.card .card-subtitle {
  font-size: var(--fs-card-subtitle);
  font-weight: 300;
  letter-spacing: -0.02em;
  opacity: 0.85;
  margin-top: 6px;
}

/* Small arrow hinting the card opens */
.card-arrow {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  opacity: 0.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 0.3s ease, opacity 0.3s ease;
}

.card.is-center:hover .card-arrow {
  opacity: 1;
  transform: translate(3px, -3px);
}

.card.is-center { cursor: pointer; }

/* Only the active card shows its image and text;
   the cards behind it are empty liquid glass */
.card .card-image,
.card .card-overlay,
.card .card-content {
  transition: opacity 0.5s ease;
}

.card:not(.is-center) .card-image,
.card:not(.is-center) .card-overlay,
.card:not(.is-center) .card-content {
  opacity: 0;
}

/* ───────── Card arrows ─────────
   Plain chevrons: clickable, but styled as icons, not buttons */
.carousel-nav {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--nav-spacing);
  flex-shrink: 0;
  position: relative;
  z-index: 200;               /* above the cards (their z-index goes up to 100) */
}

.nav-arrow {
  position: relative;
  width: var(--nav-size);
  height: var(--nav-size);
  display: grid;
  place-items: center;
  padding: 0;
  border: none;
  background: none;
  color: var(--arrow);
  cursor: pointer;
  transition: color 0.25s ease, transform 0.25s ease;
}

.nav-arrow svg {
  width: 26px;
  height: 26px;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.nav-arrow:hover { color: var(--arrow-hover); }
#navPrev:hover   { transform: translateY(-3px); }
#navNext:hover   { transform: translateY(3px); }

.nav-dots {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.nav-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--dot);
}

.nav-dot.is-active {
  background: var(--dot-active);
}

.nav-arrow:focus-visible {
  outline: 1px solid var(--arrow);
  outline-offset: 2px;
  border-radius: 6px;
}

/* ───────── Project detail panel ─────────
   Fills the content section; only its inside scrolls */
.detail {
  position: absolute;
  inset: var(--detail-inset-y) var(--detail-inset);
  z-index: 300;
  border-radius: var(--card-radius);
  overflow: hidden;
  background: transparent;          /* content sits directly on the page */
  transition: background-color 0.35s ease;
}

/* While growing out of / shrinking into the card, show the card's tint
   so the motion stays visible */
.detail.is-moving {
  background: var(--detail-motion-bg);
}

.detail[hidden] { display: none; }

/* Scrolls by wheel / touch / keys, but no visible scrollbar */
.detail-scroll {
  height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
}

.detail-scroll::-webkit-scrollbar { display: none; }

/* Once scrolled, text fades out under the Back pill instead of running into it */
.detail-scroll.is-scrolled {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 72px);
  mask-image: linear-gradient(to bottom, transparent 0, #000 72px);
}

/* Liquid glass: link / skill cards are panels, tags and step numbers are raised pills */
.detail-stat {
  background: var(--glass);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
  box-shadow: var(--glass-panel-shadow-soft);
}

.detail-tag,
.detail-steps li::before {
  background: var(--pill);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
  box-shadow: var(--glass-pill-shadow);
}

.detail-body {
  padding: var(--card-frame) var(--card-frame) 48px;
}

.detail-back {
  position: absolute;
  top: calc(var(--card-frame) + 14px);
  left: calc(var(--card-frame) + 14px);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 8px 14px 8px 8px;
  border-radius: 999px;
  border: 0;
  background: var(--pill);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
  box-shadow: var(--glass-pill-shadow);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-detail-back);
  font-weight: 500;
  cursor: pointer;
  transition: transform 0.25s ease;
}

.detail-back:hover { transform: translateX(-3px); }

.detail-back:focus { outline: none; }
.detail-back:focus-visible {
  outline: 2px solid var(--back-border);
  outline-offset: 2px;
}

.detail-back svg {
  width: 18px;
  height: 18px;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Hero image with the same glass caption as the card */
.detail-hero {
  position: relative;
  margin: 0;
  aspect-ratio: 16 / 10;
  border-radius: calc(var(--card-radius) - var(--card-frame));
  overflow: hidden;
}

.detail-hero img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: var(--mockup-bg);
}

/* Same gradient as the card so the caption stays readable */
.detail-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 40%, var(--card-overlay) 100%);
  pointer-events: none;
}

.detail-hero figcaption {
  left: 26px;
  right: 26px;
  bottom: 24px;
}

.detail-hero h2 {
  font-size: var(--fs-detail-title);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.04em;
}

.detail-hero figcaption p {
  font-size: var(--fs-detail-lead);
  font-weight: 300;
  letter-spacing: -0.02em;
  opacity: 0.85;
  margin-top: 8px;
}

.detail-content {
  display: flex;
  flex-direction: column;
  gap: 36px;
  padding: 32px clamp(12px, 4%, 36px) 0;
}

.detail-meta {
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* Role · Client · Year, equal columns */
  gap: 16px;
  padding-bottom: 28px;
  border-bottom: 1px solid var(--detail-divider);
}

.detail-meta dt,
.detail-section h3,
.detail-next small {
  font-size: var(--fs-detail-label);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

.detail-meta dt { margin-bottom: 6px; }

.detail-meta dd {
  font-size: var(--fs-detail-body);
  font-weight: 500;
}

.detail-lead {
  font-size: var(--fs-detail-lead);
  line-height: 1.6;
}

.detail-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.detail-tag {
  font-size: var(--fs-detail-label);
  padding: 6px 12px;
  border-radius: 999px;
  color: var(--chip-text);
}

.detail-section h3 { margin-bottom: 12px; }

.detail-section p,
.detail-section li {
  font-size: var(--fs-detail-body);
  line-height: 1.7;
}

.detail-steps {
  list-style: none;
  display: grid;
  gap: 14px;
  counter-reset: step;
}

.detail-steps li {
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: 12px;
  counter-increment: step;
}

.detail-steps li::before {
  content: counter(step);
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  color: var(--chip-text);
  font-size: var(--fs-detail-label);
  font-weight: 600;
}

.detail-steps strong { font-weight: 600; }

/* ───────── About view ─────────
   Replaces the carousel when the Profile icon is selected.
   Reuses the detail styles (scroll, meta, sections, tags). */
.about {
  position: absolute;
  inset: var(--detail-inset-y) var(--detail-inset);
  z-index: 250;
}

.about[hidden] { display: none; }

.about-body {
  padding-top: 56px;
  padding-bottom: 56px;
}

.about-eyebrow {
  font-size: var(--fs-detail-label);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 14px;
}

.about-bio {
  font-size: var(--fs-about-bio);
  font-weight: 400;
  line-height: 1.55;
  letter-spacing: -0.015em;
}

.about-timeline {
  list-style: none;
}

.about-timeline li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 0;
  border-bottom: 1px solid var(--detail-divider);
}

.about-timeline li:first-child { padding-top: 0; }

.about-timeline strong {
  display: block;
  color: var(--text);
  font-size: var(--fs-detail-body);
  font-weight: 600;
  margin-bottom: 2px;
}

.about-timeline span {
  font-size: var(--fs-detail-body);
  color: var(--muted);
}

.about-timeline time {
  flex-shrink: 0;
  font-size: var(--fs-detail-label);
  letter-spacing: 0.04em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* Core competencies: liquid glass cards (glass from .detail-stat), icon on top, name at the bottom */
.about-skills {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}

.about-skill {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 28px;
  min-height: 120px;
  color: var(--text);
  transition: transform 0.25s ease;
}

/* Same hover lift as the Website / LinkedIn / Google link cards */
.about-skill:hover { transform: translateY(-2px); }

.about-skill-name {
  position: relative;
  z-index: 1;
  font-size: var(--fs-about-skill);
  font-weight: 500;
  line-height: 1.3;
}

/* Useful links: same link cards as the project details (.detail-stat.detail-link) */
.about-social {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}

/* ───────── Contact view ─────────
   Same panel as About (.about); form fields and chips use the glass tile edges */
.contact-form {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.contact-label {
  display: block;
  font-size: var(--fs-detail-label);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
}

/* Tabs: glass track with a solid pill that slides under the selected tab
   (--tab-index is set in js/index.js → selectContactTab) */
.contact-tabs {
  --tab-index: 0;
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  padding: 4px;
  margin-bottom: 24px;
  border-radius: 999px;
  background: var(--glass);
  backdrop-filter: var(--glass-refract, var(--glass-filter));
  -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
  border: 0;
  box-shadow: var(--glass-panel-shadow-soft);
}

.contact-tabs-pill {
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 4px;
  width: calc((100% - 8px) / 3);
  border-radius: 999px;
  background: var(--pill);
  box-shadow: var(--glass-pill-shadow);
  transform: translateX(calc(var(--tab-index) * 100%));
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

.contact-tab {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 12px;
  border: none;
  border-radius: 999px;
  background: none;
  font: inherit;
  font-size: var(--fs-tab);
  font-weight: 500;
  white-space: nowrap;
  color: var(--text);
  cursor: pointer;
  transition: color 0.3s ease;
}

.contact-tab svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.contact-tab.is-active { color: var(--text); }

.contact-tab:focus-visible {
  outline: 2px solid var(--muted);
  outline-offset: 2px;
}

.contact-panel[hidden] { display: none; }

.contact-panel-intro {
  font-size: var(--fs-detail-body);
  line-height: 1.6;
  color: var(--muted);
  margin-bottom: 16px;
}

.contact-handle {
  font-weight: 600;
  color: var(--text);
}

/* Calendly inline embed, framed like the gallery images */
.contact-calendly {
  position: relative;
  height: 700px;
  border-radius: 14px;
  overflow: hidden;
  background: var(--glass);
  border: 0;
}

.contact-calendly iframe {
  position: relative;
  z-index: 1;
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

.contact-calendly-loading {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: var(--fs-chip);
  color: var(--muted);
}

.contact-fallback {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 12px;
  font-size: var(--fs-chip);
  font-weight: 500;
  color: var(--muted);
  text-decoration: none;
  transition: color 0.25s ease;
}

.contact-fallback svg {
  width: 14px;
  height: 14px;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.contact-fallback:hover { color: var(--text); }

/* WhatsApp tab: QR code + intro side by side, message form below */
.whatsapp-intro {
  display: flex;
  align-items: flex-start;   /* text starts level with the top of the QR card */
  gap: 20px;
  margin-bottom: 20px;
}

.whatsapp-intro .contact-panel-intro { margin-bottom: 0; }

.whatsapp-qr { flex-shrink: 0; }

.whatsapp-qr {
  margin: 0;
  padding: 12px;
  border-radius: 16px;
  text-align: center;
  background: var(--glass);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
  border: 0;
  box-shadow: var(--glass-panel-shadow-soft);
}

.whatsapp-qr img {
  display: block;
  width: 152px;
  height: 152px;
  border-radius: 10px;   /* also trims the dark corners of the screenshot */
}

.whatsapp-qr figcaption {
  margin-top: 10px;
  font-size: var(--fs-chip);
  color: var(--muted);
}

.contact-field input,
.contact-field textarea {
  display: block;
  width: 100%;
  padding: 14px 16px;
  border-radius: 12px;
  font: inherit;
  font-size: var(--fs-field);
  color: var(--text);
  background: var(--glass);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
  border: 0;
  box-shadow: var(--glass-panel-shadow-soft);
  outline: none;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.contact-field textarea {
  min-height: 140px;
  resize: vertical;
  line-height: 1.55;
}

.contact-field ::placeholder { color: var(--muted); }

.contact-field input:focus,
.contact-field textarea:focus {
  border-color: var(--field-focus-border);
  box-shadow: var(--glass-panel-shadow-soft), 0 0 0 4px var(--focus-ring);
}

.contact-field .is-invalid { border-color: var(--error); }

.contact-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
}

/* Primary action: solid pill so it stands out from the glass */
.contact-submit {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 22px;
  border: none;
  border-radius: 999px;
  font: inherit;
  font-size: var(--fs-field);
  font-weight: 500;
  color: var(--bg);
  background: var(--text);
  cursor: pointer;
  transition: transform 0.25s ease;
}

.contact-submit svg {
  width: 18px;
  height: 18px;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 0.25s ease;
}

.contact-submit:hover { transform: translateY(-2px); }
.contact-submit:hover svg { transform: translateX(3px); }

.contact-submit:focus-visible {
  outline: 2px solid var(--muted);
  outline-offset: 3px;
}

.contact-status {
  font-size: var(--fs-chip);
  color: var(--muted);
}

.contact-status.is-error { color: var(--error); }

/* Contact page rhythm: clear groups (intro · get in touch · brands · direct links)
   separated by generous space, so each one reads on its own */
.contact .about-body {
  gap: var(--contact-section-gap);
  padding-bottom: 88px;
}

.contact .detail-section h3 { margin-bottom: 18px; }
.contact .about-intro .about-bio {
  max-width: 34em;   /* comfortable line length */
  font-size: var(--fs-contact-intro);
  line-height: 1.7;
}
.contact .contact-tabs { margin-bottom: 28px; }
.contact .contact-form { gap: 22px; }
.contact .contact-panel-intro { margin-bottom: 20px; }
.contact .contact-actions { margin-top: 4px; }

/* ───── "Trusted by": logo wall ─────
   Every logo at once, sitting straight on the page (no cards). Logos are grey wordmarks in a 500×500 canvas;
   the image is cropped to its middle band so the mark fills the tile. Three motion layers
   (js/index.js → logoWall): entrance bloom from the centre, a light sweep across the tiles,
   and a cursor "flashlight" that brightens nearby logos via --glow (0–1). */
.logo-wall {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;   /* a short last row sits centred */
  gap: var(--logo-gap);
}

.logo-tile {
  --glow: 0;
  position: relative;
  flex: 0 0 calc((100% - var(--logo-gap) * (var(--logo-cols) - 1)) / var(--logo-cols));
  aspect-ratio: 1.7 / 1;
  display: grid;
  place-items: center;
  padding: 10px 14px;
  border-radius: 14px;
  transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}

.logo-tile img {
  display: block;
  width: 100%;
  height: auto;              /* let aspect-ratio win over the height="500" attribute */
  aspect-ratio: 2.6 / 1;     /* keeps the band y≈154–346 of the 500px canvas: all the artwork */
  object-fit: cover;
  filter: var(--logo-filter);
  opacity: calc(var(--logo-rest) + (1 - var(--logo-rest)) * var(--glow));
  transition: opacity 0.3s ease;
  user-select: none;
  -webkit-user-drag: none;
}

.logo-tile:hover { transform: translateY(-3px); }
.logo-tile:hover img { opacity: 1; }

/* Light sweep: a soft diagonal shine. It crosses the whole wall once, right after the
   reveal (.is-shining, delayed per tile by --d so it travels diagonally), and after that
   only on the tile under the cursor. It sits exactly over the logo and is masked to the
   logo's shape (--logo, set in js/index.js), so only the mark itself catches the light. */
.logo-tile:not(.logo-tile--cta)::before {
  content: '';
  position: absolute;
  left: 14px;
  right: 14px;
  top: 50%;
  aspect-ratio: 2.6 / 1;     /* same box and crop as the img */
  translate: 0 -50%;
  background: linear-gradient(115deg, transparent 40%, var(--logo-shine) 50%, transparent 60%) no-repeat;
  background-size: 300% 100%;
  background-position: 100% 0;   /* shine parked off to the left */
  -webkit-mask: var(--logo) center / cover no-repeat;
  mask: var(--logo) center / cover no-repeat;
  pointer-events: none;
}

.logo-wall.is-shining .logo-tile:not(.logo-tile--cta)::before {
  animation: logo-sweep 1.1s ease-in-out both;
  animation-delay: calc(var(--d, 0) * 90ms);
}

.logo-wall:not(.is-shining) .logo-tile:not(.logo-tile--cta):hover::before {
  animation: logo-sweep 0.9s ease-in-out;
}

@keyframes logo-sweep {
  from { background-position: 100% 0; }
  to   { background-position: 0% 0; }
}

/* Invite tile: dashed outline, no glass */
.logo-tile--cta {
  padding: 0;
  background: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: 1px dashed var(--field-focus-border);
  box-shadow: none;
}

.logo-tile--cta .brand-cta {
  width: 100%;
  height: 100%;
  justify-content: center;
  margin: 0;
}

/* The invite as a plain text-style button (used inside the dashed tile) */
.brand-cta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  font-size: var(--fs-chip);
  font-weight: 500;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.25s ease;
}

.brand-cta svg {
  width: 14px;
  height: 14px;
  stroke-linecap: round;
  transition: transform 0.25s ease;
}

.brand-cta:hover { color: var(--text); }
.brand-cta:hover svg { transform: rotate(90deg); }

.brand-cta:focus-visible {
  outline: 2px solid var(--muted);
  outline-offset: 3px;
  border-radius: 10px;
}

@media (prefers-reduced-motion: reduce) {
  .logo-tile::before { display: none; }
}

/* ───── Direct links: big text links instead of cards ─────
   Hover: letters roll up one after another (each letter is a 2-line stack, see js/index.js),
   an underline draws in, and the arrow flies out top-right as a new one slides in. */
.direct-links {
  list-style: none;
  border-top: 1px solid var(--detail-divider);
}

.direct-links li { border-bottom: 1px solid var(--detail-divider); }

.direct-link {
  display: grid;
  grid-template-columns: 96px 1fr auto;
  align-items: center;
  gap: 16px;
  padding: 22px 0;
  color: var(--direct-rest);          /* soft at rest… */
  text-decoration: none;
  transition: color 0.35s ease;
}

.direct-link:hover,
.direct-link:focus-visible { color: var(--direct-hover); }   /* …pure black (white in dark) on hover */

.direct-label {
  font-size: var(--fs-detail-label);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  transition: color 0.3s ease;
}

.direct-text {
  position: relative;
  justify-self: start;
  font-size: var(--fs-direct-link);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.03em;
  white-space: nowrap;
}

/* Underline: draws in from the left, leaves to the right */
.direct-text::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -6px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

/* One letter: a clipped window over a 2-line stack (the letter, then its copy) */
.roll-char {
  display: inline-block;
  height: 1.15em;
  overflow: hidden;
  vertical-align: top;
}

.roll-char > span {
  display: block;
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
  transition-delay: calc(var(--i) * 16ms);
}

.roll-char > span::after {
  content: attr(data-char);
  display: block;
}

.direct-arrow {
  position: relative;
  width: 22px;
  height: 22px;
  overflow: hidden;
}

.direct-arrow svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

.direct-arrow svg + svg { transform: translate(-100%, 100%); }

.direct-link:hover .direct-label,
.direct-link:focus-visible .direct-label { color: var(--direct-hover); }

.direct-link:hover .direct-text::after,
.direct-link:focus-visible .direct-text::after {
  transform: scaleX(1);
  transform-origin: left;
}

.direct-link:hover .roll-char > span,
.direct-link:focus-visible .roll-char > span { transform: translateY(-50%); }

.direct-link:hover .direct-arrow svg:first-child,
.direct-link:focus-visible .direct-arrow svg:first-child { transform: translate(100%, -100%); }

.direct-link:hover .direct-arrow svg + svg,
.direct-link:focus-visible .direct-arrow svg + svg { transform: translate(0, 0); }

.direct-link:focus-visible { outline: none; }

@media (prefers-reduced-motion: reduce) {
  .roll-char > span,
  .direct-arrow svg { transition: none; }
  .direct-link:hover .roll-char > span,
  .direct-link:focus-visible .roll-char > span { transform: none; }
}

/* ───────── Ask AI view ─────────
   Same panel as About/Contact. The message box is pinned to the bottom of the panel;
   the conversation scrolls behind a soft fade. */
.chat-body { padding-bottom: 150px; }   /* room for the pinned message box */

.chat::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 130px;
  background: linear-gradient(to bottom, transparent, var(--bg) 70%);
  pointer-events: none;
  z-index: 1;
}

.chat-log {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.chat-log:empty { display: none; }

.chat-msg {
  max-width: 85%;
  padding: 12px 16px;
  border-radius: 18px;
  font-size: var(--fs-sm);
  line-height: 1.6;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Visitor: solid bubble on the right (same "selected" fill as elsewhere) */
.chat-msg--user {
  align-self: flex-end;
  color: var(--bg);
  background: var(--text);
  border-bottom-right-radius: 6px;
}

/* Assistant: liquid glass bubble on the left */
.chat-msg--bot {
  align-self: flex-start;
  color: var(--text);
  background: var(--glass);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
  border: 0;
  box-shadow: var(--glass-panel-shadow-soft);
  border-bottom-left-radius: 6px;
}

.chat-msg--bot a {
  color: var(--text);
  font-weight: 500;
  text-underline-offset: 2px;
}

/* Action cards under an AI reply (email, meeting, WhatsApp, Contact) */
.chat-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  max-width: 85%;
  margin-top: -4px;   /* sit close to their reply */
}

.chat-action {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  border-radius: 12px;
  font: inherit;
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--text);
  text-decoration: none;
  background: var(--pill);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
  border: 0;
  box-shadow: var(--glass-pill-shadow);
  cursor: pointer;
  transition: transform 0.25s ease;
}

.chat-action-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.chat-action-arrow {
  width: 12px;
  height: 12px;
  color: var(--muted);
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 0.25s ease, color 0.25s ease;
}

.chat-action:hover { transform: translateY(-2px); }
.chat-action:hover .chat-action-arrow { color: var(--text); transform: translate(2px, -2px); }

.chat-action:focus-visible {
  outline: 2px solid var(--muted);
  outline-offset: 2px;
}

/* Typing indicator: three dots */
.chat-typing {
  display: inline-flex;
  gap: 5px;
  padding: 4px 0;
}

.chat-typing span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.35;
  animation: chat-typing 1.2s ease-in-out infinite;
}

.chat-typing span:nth-child(2) { animation-delay: 0.15s; }
.chat-typing span:nth-child(3) { animation-delay: 0.3s; }

@keyframes chat-typing {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.35; }
  30%           { transform: translateY(-4px); opacity: 0.9; }
}

/* Starter questions */
.chat-suggestions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.chat-suggestions[hidden] { display: none; }

.chat-chip {
  padding: 8px 14px;
  border-radius: 999px;
  font: inherit;
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--text);
  background: var(--pill);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
  border: 0;
  box-shadow: var(--glass-pill-shadow);
  cursor: pointer;
  transition: transform 0.2s ease;
}

.chat-chip:hover { transform: translateY(-1px); }

.chat-chip:focus-visible {
  outline: 2px solid var(--muted);
  outline-offset: 2px;
}

/* Message box: glass pill pinned to the bottom */
.chat-composer {
  position: absolute;
  left: clamp(12px, 4%, 36px);    /* same side padding as the content column (.detail-content) */
  right: clamp(12px, 4%, 36px);
  bottom: 20px;
  z-index: 2;
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 6px 6px 6px 18px;
  border-radius: 26px;
  background: var(--glass);
  backdrop-filter: var(--glass-refract, var(--glass-filter));
  -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
  border: 0;
  box-shadow: var(--glass-panel-shadow-soft);
}

.chat-composer textarea {
  flex: 1;
  min-height: 40px;
  max-height: 120px;
  padding: 9px 0;
  border: none;
  outline: none;
  resize: none;
  background: none;
  font: inherit;
  font-size: var(--fs-md);   /* 16px: no zoom-on-focus on phones */
  line-height: 1.4;
  color: var(--text);
}

.chat-composer textarea::placeholder { color: var(--muted); }

.chat-send {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border: none;
  border-radius: 50%;
  color: var(--bg);
  background: var(--text);
  cursor: pointer;
  transition: transform 0.2s ease, opacity 0.2s ease;
}

.chat-send svg {
  width: 18px;
  height: 18px;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.chat-send:hover:not(:disabled) { transform: translateY(-1px); }
.chat-send:disabled { opacity: 0.35; cursor: default; }

.chat-send:focus-visible {
  outline: 2px solid var(--muted);
  outline-offset: 2px;
}

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

/* ───── Before & after (scroll-driven) ───── */
.ba-track {
  position: relative;
}

/* Scroll room for the wipe. Must be a real element (not padding):
   a sticky element can only travel inside its parent's content box */
.ba-spacer {
  height: var(--ba-scroll-length);
}

.ba-sticky {
  position: sticky;
  top: var(--ba-sticky-top);
}

.ba-frame {
  --ba: 0;
  position: relative;
  margin: 0;
  aspect-ratio: 16 / 10;
  border-radius: calc(var(--card-radius) - var(--card-frame));
  overflow: hidden;
}

.ba-frame img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;        /* fill the frame edge to edge */
  background: var(--mockup-bg);   /* behind transparent mockups, so the frame always reads as a box */
  display: block;
}

.ba-before { filter: var(--ba-before-filter); }

/* "After" wipes in from the left as --ba goes 0 → 1 */
.ba-after {
  clip-path: inset(0 calc((1 - var(--ba)) * 100%) 0 0);
}

.ba-divider {
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(var(--ba) * 100%);
  width: 2px;
  margin-left: -1px;
  background: var(--ba-divider);
  box-shadow: 0 0 12px var(--card-text-shadow);
  opacity: calc(min(var(--ba), 1 - var(--ba)) * 20);  /* hidden at the very start and end */
}

.detail-stats {
  display: grid;
  grid-auto-flow: column;    /* the tiles share the width, however many links a project has */
  grid-auto-columns: 1fr;
  gap: 12px;
}

.detail-stat {
  position: relative;
  padding: 18px;
  border-radius: 14px;
  overflow: hidden;
}

/* Link tiles: icon at the top, label + arrow at the bottom */
.detail-link {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 28px;
  min-height: 120px;
  color: var(--text);
  text-decoration: none;
  transition: transform 0.25s ease;
}

.detail-link:hover { transform: translateY(-2px); }

.detail-link-icon {
  width: 26px;
  height: 26px;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.detail-link-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: var(--fs-detail-link);
  font-weight: 500;
}

.detail-link-arrow {
  width: 16px;
  height: 16px;
  color: var(--muted);
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 0.25s ease, color 0.25s ease;
}

.detail-link:hover .detail-link-arrow {
  color: var(--text);
  transform: translate(2px, -2px);
}

.detail-link:focus-visible {
  outline: 2px solid var(--muted);
  outline-offset: 2px;
}

/* Compact link tiles on project pages (the About page keeps the larger ones) */
#detail .detail-stats { gap: 10px; }
#detail .detail-link {
  padding: 12px 14px;
  gap: 14px;
  min-height: 0;
  border-radius: 12px;
}
#detail .detail-link-icon { width: 20px; height: 20px; }
#detail .detail-link-label { font-size: var(--fs-xs); }
#detail .detail-link-arrow { width: 14px; height: 14px; }

/* Gallery images stack one after another, full width */
.detail-gallery {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
}

/* Frame clips the image so it can zoom inside (GSAP reveal + hover) */
.detail-gallery-item {
  aspect-ratio: 4 / 3;
  border-radius: 12px;
  overflow: hidden;
}

.detail-gallery-item img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: var(--mockup-bg);
  will-change: transform;
}

.detail-next {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 24px 0 0;
  border: none;
  border-top: 1px solid var(--detail-divider);
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  text-decoration: none;   /* it's a link to the next project's page */
  cursor: pointer;
}
.detail-next:focus-visible { outline: 2px solid var(--text); outline-offset: 4px; border-radius: 4px; }

.detail-next strong {
  display: block;
  font-size: var(--fs-detail-lead);
  font-weight: 600;
  margin-top: 4px;
}

.detail-next svg {
  width: 22px;
  height: 22px;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 0.25s ease;
}

.detail-next:hover svg { transform: translateX(4px); }

/* ───── Locked project (under NDA) ─────
   A liquid-glass card in place of the case study: lock badge, password, a way to ask for access */
.lock-glyph {   /* small lock before "Locked" on the card and in the hero */
  width: 0.95em;
  height: 0.95em;
  margin-right: 0.35em;
  vertical-align: -0.12em;
}

.detail-content--locked { padding-inline: 0; }   /* lock card lines up with the cover image */

.lock-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: clamp(28px, 6%, 44px) clamp(20px, 6%, 44px);
  border-radius: 24px;
  background: var(--glass);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
  box-shadow: var(--glass-panel-shadow-soft);
}

.lock-badge {
  display: grid;
  place-items: center;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  margin-bottom: 20px;
  color: var(--text);
  background: var(--pill);
  box-shadow: var(--glass-pill-shadow);
}
.lock-badge svg { width: 26px; height: 26px; overflow: visible; }
.lock-shackle { transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); }
.lock-card:has(.lock-field:focus-within) .lock-shackle { transform: translateY(-1.2px); }   /* a little nudge while typing */
.lock-card.is-open .lock-shackle { transform: translate(4px, -3px) rotate(18deg); }

.lock-eyebrow {
  font-size: var(--fs-detail-label);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin-bottom: 10px;
}

.lock-title {
  font-size: clamp(22px, 2.2vw, 28px);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.2;
  margin-bottom: 12px;
}

.lock-text {
  max-width: 34em;
  font-size: var(--fs-detail-body);
  line-height: 1.7;
  color: var(--muted);
  margin-bottom: 28px;
}

.lock-form {
  display: flex;
  gap: 10px;
  width: 100%;
  max-width: 420px;
}

.lock-field {
  position: relative;
  flex: 1;
  min-width: 0;
}

.lock-field input {
  width: 100%;
  height: 50px;
  padding: 0 48px 0 20px;
  border: 1px solid transparent;
  border-radius: 999px;
  font: inherit;
  font-size: var(--fs-field);
  color: var(--text);
  background: var(--glass);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
  box-shadow: var(--glass-panel-shadow-soft);
  outline: none;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.lock-field input::placeholder { color: var(--muted); }
.lock-field input:focus {
  border-color: var(--field-focus-border);
  box-shadow: var(--glass-panel-shadow-soft), 0 0 0 4px var(--focus-ring);
}
.lock-field input[aria-invalid="true"] { border-color: var(--error); }

.lock-peek {   /* show / hide the password */
  position: absolute;
  top: 50%;
  right: 8px;
  translate: 0 -50%;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.2s ease;
}
.lock-peek:hover { color: var(--text); }
.lock-peek:focus-visible { outline: 2px solid var(--text); outline-offset: 1px; }
.lock-peek svg { width: 18px; height: 18px; }
.lock-peek-slash { transition: opacity 0.2s ease; }
.lock-peek[aria-pressed="true"] .lock-peek-slash { opacity: 0; }

.lock-submit {   /* solid pill, like the contact form's Send */
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 50px;
  padding: 0 22px;
  border: none;
  border-radius: 999px;
  font: inherit;
  font-size: var(--fs-field);
  font-weight: 500;
  color: var(--bg);
  background: var(--text);
  cursor: pointer;
  transition: transform 0.25s ease;
}
.lock-submit svg { width: 18px; height: 18px; transition: transform 0.25s ease; }
.lock-submit:hover svg { transform: translateX(3px); }
.lock-submit:active { transform: scale(0.96); }
.lock-submit:focus-visible { outline: 2px solid var(--text); outline-offset: 3px; }

.lock-error {
  min-height: 1.6em;   /* reserve the line so the card doesn't jump */
  margin-top: 10px;
  font-size: var(--fs-xs);
  color: var(--error);
}

.lock-card.is-wrong { animation: lock-shake 0.45s cubic-bezier(0.36, 0.07, 0.19, 0.97); }
@keyframes lock-shake {
  20%, 60% { transform: translateX(-6px); }
  40%, 80% { transform: translateX(6px); }
}

.lock-help {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  width: 100%;
  margin-top: 14px;
  padding-top: 24px;
  border-top: 1px solid var(--detail-divider);
  font-size: var(--fs-sm);
  color: var(--muted);
}

.lock-request {   /* glass pill */
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 11px 18px;
  border-radius: 999px;
  color: var(--text);
  font-weight: 500;
  text-decoration: none;
  background: var(--pill);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
  box-shadow: var(--glass-pill-shadow);
  transition: transform 0.2s ease;
}
.lock-request:hover { transform: translateY(-2px); }
.lock-request:active { transform: scale(0.96); }
.lock-request:focus-visible { outline: 2px solid var(--text); outline-offset: 3px; }
.lock-request svg { width: 18px; height: 18px; }

.lock-email {
  font-size: var(--fs-xs);
  user-select: all;   /* one click selects it, for people without a mail app */
}

@media (max-width: 479.98px) {
  .lock-form { flex-direction: column; }
  .lock-submit { justify-content: center; }
}

@media (prefers-reduced-motion: reduce) {
  .lock-card.is-wrong { animation: none; }
  .lock-shackle { transition: none; }
}

/* Scroll hint */
.scroll-hint {
  position: absolute;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  color: var(--hint);
  font-size: var(--fs-hint);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  z-index: 2;
  transition: opacity 0.6s ease;
  pointer-events: none;
}

.scroll-hint .mouse-icon {
  width: 22px;
  height: 34px;
  border: 2px solid var(--hint-border);
  border-radius: 12px;
  position: relative;
  animation: float-hint 2.4s ease-in-out infinite;
}

.scroll-hint .mouse-icon::after {
  content: '';
  position: absolute;
  top: 7px;
  left: 50%;
  transform: translateX(-50%);
  width: 3px;
  height: 6px;
  background: var(--hint-dot);
  border-radius: 3px;
  animation: scroll-dot 2s ease-in-out infinite;
}

.scroll-hint.hidden {
  opacity: 0;
  transform: translateX(-50%) translateY(12px);
}

@keyframes float-hint {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-5px); }
}

@keyframes scroll-dot {
  0%, 100% { opacity: 1; transform: translateX(-50%) translateY(0); }
  50%      { opacity: 0.3; transform: translateX(-50%) translateY(10px); }
}

/* ───────── Keyboard shortcut hints (hold Shift) ─────────
   Each control gets a small glass keycap (added in js/index.js → addKeyHint) */
.key-hint {
  --hx: 0;
  --hy: 0;
  position: absolute;
  z-index: 5;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 7px;
  border-radius: 6px;
  font-family: 'Inter', sans-serif;
  font-size: var(--fs-kbd);
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.02em;
  white-space: nowrap;
  color: var(--text);
  background: var(--pill);
  border: 0;
  box-shadow: var(--glass-pill-shadow);
  pointer-events: none;
  opacity: 0;
  transform: translate(var(--hx), var(--hy)) scale(0.85);
  transition: opacity 0.2s ease, transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.show-key-hints .key-hint {
  /* blur only while the hints show: each hidden blur layer still costs Safari and Firefox a frame pass */
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  opacity: 1;
  transform: translate(var(--hx), var(--hy)) scale(1);
}

.key-hint--bottom { top: calc(100% + 8px); left: 50%; --hx: -50%; }
.key-hint--top    { bottom: calc(100% + 8px); left: 50%; --hx: -50%; }
.key-hint--left   { right: calc(100% + 6px); top: 50%; --hy: -50%; }
.key-hint--right  { left: calc(100% + 8px); top: 50%; --hy: -50%; }
.key-hint--inside { top: calc(var(--card-frame) + 14px); right: calc(var(--card-frame) + 14px); }

/* The card hint only shows on the active card */
.show-key-hints .card:not(.is-center) .key-hint { opacity: 0; }

/* ───────── Loading screen ─────────
   A small honeycomb in the canvas colours. The six outer cells lift one after another in a
   clockwise wave (like the canvas cells under the cursor) while the centre cell ticks round a
   sixth of a turn each cycle. When the page is ready (js/index.js adds .is-done) the outer
   cells drift apart, the centre grows, and the screen fades into the page. Pure SVG + CSS. */
.loader {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: grid;
  place-items: center;
  background: var(--canvas-bg);
  transition: opacity 0.5s ease 0.15s, visibility 0s linear 0.65s;
}
.loader.is-done {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.loader-label {   /* read by screen readers only */
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.loader-comb {
  width: 40vmin;              /* 40% of the screen (its shorter side, so it always fits) */
  height: 40vmin;             /* the motion is in SVG units, so it scales along with this */
  overflow: visible;
}
.loader-light { flood-color: var(--hex-highlight); }
.loader-shade { flood-color: var(--hex-shadow); }

.loader-hex {
  fill: var(--hex-base);
  stroke: var(--hex-base);
  stroke-width: 5;            /* same colour as the fill: softly rounded corners */
  stroke-linejoin: round;
  transform-box: fill-box;
  transform-origin: center;
  animation: loader-lift 1.5s cubic-bezier(0.45, 0, 0.2, 1) infinite;
  animation-delay: calc(var(--i, 0) * 0.125s);
  transition: transform 0.55s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.4s ease;
}
.loader-hex--core { animation: loader-tick 1.5s cubic-bezier(0.65, 0, 0.35, 1) infinite; }

@keyframes loader-lift {
  0%, 45%, 100% { transform: none; }
  18% { transform: translateY(-3px) scale(1.08); fill: var(--hex-highlight); }
}
@keyframes loader-tick {
  0%, 55% { transform: rotate(0deg); }
  100% { transform: rotate(60deg); }   /* a hexagon turned 60° looks the same: seamless loop */
}

/* Ready: the comb opens up as the screen fades */
.loader.is-done .loader-hex {
  animation: none;
  opacity: 0;
  transform: translate(calc(var(--ox) * 16px), calc(var(--oy) * 16px)) scale(0.7);
}
.loader.is-done .loader-hex--core { transform: scale(1.5); }

@media (prefers-reduced-motion: reduce) {
  .loader-hex, .loader-hex--core { animation: none; }
}

/* Intro (js/index.js → intro): the name's letters rise out of a mask, one word at a time.
   The padding gives descenders (the "g") room inside the clip without moving the layout. */
.intro-word {
  display: inline-block;
  overflow: hidden;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
  vertical-align: top;
}
.intro-char {
  display: inline-block;
  will-change: transform;
}

/* Phones: link tiles two per row (four in a row get cramped) */
@media (max-width: 599.98px) {
  .detail-stats { grid-auto-flow: row; grid-template-columns: repeat(2, 1fr); }
}

/* Responsive */
/* ═════════════════════════════════════════════
   Breakpoints
   Tablet / mobile: default, below 1024px  → one column, fluid container
   Laptop:  1024px – 1439px                → two columns, 1024px container
   Desktop: 1440px and up                  → two columns, 1440px container
   ═════════════════════════════════════════════ */

/* Laptop: 1024px to 1439px */
@media (min-width: 1024px) {
  :root { --container: 1024px; }
  .page {
    width: 1024px;
    margin: 0 auto;
    padding: 0 16px;
  }
}

/* Laptop only: navigator 35%, content 65% (desktop keeps 50/50) */
@media (min-width: 1024px) and (max-width: 1439.98px) {
  :root {
    /* card fills the 65% content column minus the arrows (40px) + gap (28px) + breathing room */
    --card-w: min(calc((var(--container) - var(--container-pad) * 2) * 0.65 - 94px), 82vh, 620px);
  }
  .page { grid-template-columns: 35% 65%; }
}

/* Desktop: 1440px and up */
@media (min-width: 1440px) {
  :root { --container: 1440px; }
  .page {
    width: 1440px;
    padding: 0 16px;
  }
}

/* Tablet / mobile: below 1024px — single column, navigator above the content */
@media (max-width: 1023.98px) {
  :root {
    --nav-size: 36px;
    --nav-gap: 12px;
    --nav-spacing: 24px;
    /* full width minus the 16px container padding on each side (no arrows on tablet/mobile) */
    --card-w: min(calc(100vw - 32px), 60vh, 620px);
    --card-radius: 16px;
    --card-frame: 6px;
    --detail-inset: 0px;
    --contact-section-gap: 48px;
    --logo-cols: 2;
    --logo-gap: 8px;
  }
  html, body {
    height: 100%;
    overflow: hidden;
  }
  /* Header on top, content fills the rest of the screen — all the way down, under the dock */
  .page {
    grid-template-columns: 1fr;
    grid-template-rows: auto minmax(0, 1fr);
    padding: 24px 16px 0;
    gap: 24px;
    height: 100vh;
    height: 100dvh;
  }
  .navigator {
    height: auto;
    min-height: auto;
  }
  .content {
    height: 100%;
    min-height: 0;
  }

  /* Things that must stay clear of the dock */
  .content-inner { padding-bottom: var(--dock-clear); }   /* carousel centred above the dock */
  .scroll-hint { bottom: calc(var(--dock-clear) + 4px); }
  .detail-body { padding-bottom: calc(var(--dock-clear) + 32px); }
  .about .about-body { padding-bottom: calc(var(--dock-clear) + 40px); }
  .chat .chat-body { padding-bottom: calc(var(--dock-clear) + 150px); }
  .chat::after { height: calc(var(--dock-clear) + 130px); }

  /* Header: name + title top-left */
  .navigator {
    position: static;   /* no own layer, so the fixed dock can sit above the content panels */
    z-index: auto;
    justify-content: flex-start;
    align-items: flex-start;
    min-height: 44px;   /* same height as the theme toggle opposite */
    padding-right: 60px;   /* keep clear of the toggle */
  }
  .navigator-inner { gap: 0; }
  .title-pitch { display: none; }   /* the phone header stays one compact line */

  /* Navigation: a floating liquid glass dock at the bottom */
  .nav-actions {
    position: fixed;
    left: 50%;
    bottom: calc(16px + env(safe-area-inset-bottom));
    z-index: 500;
    transform: translateX(-50%);
    width: 90%;
    justify-content: space-evenly;   /* equal space around every icon */
    margin: 0;
    gap: 0;
    padding: 8px;
    border-radius: 28px;
    background: var(--glass);
    /* plain frosted glass: the lens-rim refraction smeared the page at the dock's left end */
    backdrop-filter: var(--glass-filter);
    -webkit-backdrop-filter: blur(14px) saturate(160%); /* Safari ignores var() here */
    border: 0;
    box-shadow: var(--glass-panel-shadow);
  }
  .nav-actions .icon-btn {
    width: 48px;
    height: 48px;
  }
  .nav-actions .key-hint--bottom {   /* keycaps above the icons: below would be off-screen */
    top: auto;
    bottom: calc(100% + 10px);
  }

  /* Light/dark toggle: top-right corner, level with the name */
  body #theme-toggle {
    top: 24px;
    right: 16px;
    bottom: auto;
    left: auto;
  }
  body #theme-toggle .key-hint--right {
    left: auto;
    right: calc(100% + 8px);
  }

  .carousel-wrapper {
    height: 70vh;
    perspective: 800px;
  }
  .carousel-nav { display: none; }   /* no arrows/dots: swipe (or scroll) to change cards */
  .scroll-hint .mouse-icon { width: 20px; height: 30px; }

  .detail-meta { gap: 10px; }
  .detail-stats { gap: 8px; }
  .detail-stat { padding: 14px; }
  .detail-link { min-height: 96px; gap: 20px; }

  .about-skills { grid-template-columns: repeat(2, 1fr); gap: 8px; }
  .about-skill { min-height: 96px; gap: 20px; }
  .about-social { grid-template-columns: repeat(2, 1fr); gap: 8px; }

  .contact-tab { padding: 10px 6px; gap: 6px; }
  .contact-tab svg { display: none; }   /* labels only, so all three tabs fit */
  .contact-calendly { height: 620px; }
  .whatsapp-qr { display: none; }       /* can't scan your own device's screen; the button opens WhatsApp */
  .direct-link {
    grid-template-columns: 1fr auto;
    gap: 6px 12px;
    padding: 20px 0;
  }
  .direct-label { grid-column: 1 / -1; }

  .chat-composer { left: 12px; right: 12px; bottom: calc(var(--dock-clear) + 4px); }   /* just above the dock */
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* ───────── Without JavaScript ─────────
   Search engines and readers without JS get a plain, readable page (written by tools/build-seo.mjs)
   over the interactive layout, which can't work without scripts. */
.noscript-content {
  position: fixed;
  inset: 0;
  z-index: 10000;
  overflow-y: auto;
  padding: 48px max(24px, calc((100vw - 680px) / 2));
  background: var(--bg);
  color: var(--text);
  font-size: var(--fs-md);
  line-height: 1.7;
}
.noscript-content h1 { font-size: var(--fs-title); line-height: 1.15; margin: 8px 0 6px; }
.noscript-content h2 { font-size: var(--fs-lg); margin: 36px 0 10px; }
.noscript-content h3 { font-size: var(--fs-detail-label); text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); margin: 28px 0 8px; }
.noscript-content p, .noscript-content li { margin-bottom: 10px; }
.noscript-content ol, .noscript-content ul { padding-left: 1.2em; }
.noscript-content img { max-width: 100%; height: auto; margin: 16px 0; border-radius: 12px; }
.noscript-content a { color: var(--text); }

/* ── Phone and tablet header ──
   The name sits over the content instead of in its own row, so every view can use the whole
   screen: it stays put on Home, fades away while a project is open, and scrolls away with the
   About / Ask AI / Contact text (js/index.js moves it with --head-shift). The theme toggle,
   level with the name, does the same. */
@media (max-width: 1023.98px) {
  :root { --head-space: 94px; }   /* screen top to the content below the name; js/index.js measures it */
  .page { padding-top: 0; gap: 0; }
  .navigator { min-height: 0; padding-right: 0; }
  .title-block {
    position: absolute;
    top: 24px;
    left: 16px;
    right: 76px;
    translate: 0 var(--head-shift, 0px);
    transition: opacity 0.35s ease, transform 0.35s ease, visibility 0.35s;
  }
  body #theme-toggle {
    translate: 0 var(--head-shift, 0px);
    transition: transform 0.2s ease, opacity 0.35s ease, visibility 0.35s;
  }
  /* Back to the top of a view: the name slides home instead of jumping */
  html.head-easing .title-block,
  html.head-easing body #theme-toggle {
    transition-property: opacity, transform, visibility, translate;
    transition-duration: 0.35s, 0.35s, 0.35s, 0.45s;
    transition-timing-function: ease, ease, ease, cubic-bezier(0.2, 0.7, 0.2, 1);
  }

  .content-inner { padding-top: var(--head-space); }                   /* Home: cards below the name */
  .about .about-body { padding-top: calc(var(--head-space) + 56px); }  /* panels start where they did */

  /* A project uses the full screen: the name and toggle fade out, and come back on close */
  .detail { top: 12px; }
  .page:has(.content.is-detail-open) .title-block,
  body:has(.content.is-detail-open) #theme-toggle {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
  }
  .page:has(.content.is-detail-open) .title-block { transform: translateY(-10px); }
}

/* Firefox re-blurs every glass layer each time the honeycomb redraws and can't hold 60fps doing it.
   The page behind the glass is nearly always flat colour, where a frosted tint looks the same as a
   blur, so Firefox gets the tint (same rim light) and Chrome and Safari keep the live blur. */
@supports (-moz-appearance: none) {
  .card, .liquid-glass, .nav-actions, html #theme-toggle, html #sketch-toggle { backdrop-filter: none; }
  .card { background: rgb(255 255 255 / 0.3); }
  .liquid-glass, .icon-btn.liquid-glass, html #theme-toggle, html #sketch-toggle { background: rgb(255 255 255 / 0.62); }
  html.dark .card { background: rgb(255 255 255 / 0.09); }
  html.dark .liquid-glass, html.dark .icon-btn.liquid-glass,
  html.dark #theme-toggle, html.dark #sketch-toggle { background: rgb(255 255 255 / 0.17); }
  @media (max-width: 1023.98px) {   /* the phone dock */
    .nav-actions { background: rgb(255 255 255 / 0.62); }
    html.dark .nav-actions { background: rgb(255 255 255 / 0.17); }
  }
}
