/* ============================================
   Design tokens
   ============================================ */
:root {
  --color-bg: #fcfcfc;
  --color-fg: #202020;
  --color-fg-body: #424242;
  --color-fg-muted: #8d8d8d;
  --color-border: #e8e8e8;
  --color-tile-bg: #ebebeb;
  --color-tooltip-bg: #111111;
  --color-tooltip-fg: #fafaf8;
  --color-accent: #3a6ff7;
  --color-focus: #3a6ff7;
  --color-pill-bg: #ffffff;
  --shadow-pill: 0 0 0 1px rgba(0, 0, 0, 0.06), 0 1px 2px -1px rgba(0, 0, 0, 0.06), 0 2px 4px 0 rgba(0, 0, 0, 0.04);

  --accent-pink-fill: rgba(246, 51, 154, 0.1);
  --accent-pink-hover-fill: #fbe8f2;
  --accent-pink-border: #fb64b6;
  --accent-pink-text: #f6339a;

  --container-max: 760px;
  --gutter: 20px;
  --tile-gap: 8px;

  --font-sans: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-serif-italic: "Libre Baskerville", Georgia, serif;
  --tracking-tight: -0.15px;

  --radius-tile: 0px;
  --radius-pill: 9999px;

  --motion-fast: 150ms;
  --motion-base: 250ms;
  --motion-slow: 400ms;
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);

  color-scheme: light;
}

@font-face {
  font-family: "Geist";
  src: url("https://cdn.jsdelivr.net/npm/geist@1/dist/fonts/geist-sans/Geist-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

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

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

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-fg);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: var(--tracking-tight);
  -webkit-font-smoothing: antialiased;
  transition: background-color var(--motion-base) var(--ease-standard), color var(--motion-base) var(--ease-standard);
}

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

a {
  color: inherit;
}

button {
  font: inherit;
  color: inherit;
}

:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: 2px;
}

.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;
}

.container {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: 16px;
}

.container-wide {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
  width: 100%;
}

/* ============================================
   Site nav (pill, shared across pages)
   ============================================ */
.site-nav {
  height: 64px;
  display: flex;
  align-items: center;
  justify-content: center;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: 24px;
  width: 100%;
  /* Only the pill visually sticks — this row has no background of its own,
     so it's made sticky (instead of the pill alone) to keep it pinned for
     the whole scroll, not just the height of this 64px row. */
  position: sticky;
  top: 0;
  z-index: 200;
  pointer-events: none;
}

.nav-pill {
  background: var(--color-pill-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2px;
  border-radius: var(--radius-pill);
  overflow: hidden;
  box-shadow: var(--shadow-pill);
  pointer-events: auto;
  text-decoration: none;
  transition: box-shadow var(--motion-base) var(--ease-standard);
}

.nav-pill:focus-visible {
  outline: 2px solid #202020;
  outline-offset: 2px;
}

.nav-pill__button {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px 6px;
  border-radius: 99px;
  background: transparent;
  transition: background-color 150ms ease;
}

.nav-pill:hover .nav-pill__button,
.nav-pill:active .nav-pill__button {
  background: #f0f0f0;
}

/* Icon and label each have two variants stacked in the same grid cell
   (CSS Grid overlap), crossfaded via opacity when [data-view] changes —
   the pill itself never moves, only these two contents fade into each
   other over ~150ms. */
.nav-pill__icon-slot {
  display: grid;
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

.nav-pill__icon {
  grid-area: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 150ms ease;
}

.nav-pill__icon img {
  width: 14px;
  height: 14px;
}

.nav-pill__label-slot {
  display: grid;
}

.nav-pill__label {
  grid-area: 1 / 1;
  font-size: 14px;
  line-height: 16px;
  letter-spacing: -0.1504px;
  color: var(--color-fg);
  white-space: nowrap;
  opacity: 0;
  transition: opacity 150ms ease;
}

body[data-view="work"] .nav-pill__icon--plus,
body[data-view="work"] .nav-pill__label--about {
  opacity: 1;
}

body[data-view="about"] .nav-pill__icon--minus,
body[data-view="about"] .nav-pill__label--back {
  opacity: 1;
}

/* ============================================
   Work intro
   ============================================ */
.work-intro {
  padding-top: 24px;
  padding-bottom: 40px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.work-intro__greeting {
  padding-top: 20px;
  width: 100%;
}

.work-intro__hello,
.work-intro__tagline {
  margin: 0;
  font-size: 18px;
  line-height: 1.2;
  letter-spacing: var(--tracking-tight);
}

.work-intro__hello {
  color: var(--color-fg);
}

.work-intro__tagline {
  color: var(--color-fg-muted);
  margin-top: 4px;
}

.work-intro__tagline em {
  font-family: var(--font-serif-italic);
  font-style: italic;
  color: var(--color-fg-muted);
}

.work-intro__gap {
  position: relative;
  width: 100%;
}

.work-intro__gap--24 {
  padding-top: 24px;
}

.work-intro__gap--40 {
  padding-top: 40px;
}

/* Redline spacing indicators: decorative, shown on hover/focus of "design experiments" */
.work-intro__redline {
  position: absolute;
  top: 0;
  left: 0;
  width: 24px;
  height: 24px;
  background: var(--accent-pink-fill);
  border-left: 1px solid var(--accent-pink-border);
  border-right: 1px solid var(--accent-pink-border);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--motion-fast) var(--ease-standard);
}

.work-intro__redline--40 {
  height: 40px;
}

.work-intro__redline span {
  position: absolute;
  left: 27px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 8px;
  line-height: 1;
  color: var(--accent-pink-text);
  white-space: nowrap;
}

.work-intro.is-hovering-experiments .work-intro__redline {
  opacity: 1;
}

@media (hover: none) {
  .work-intro__redline {
    display: none;
  }
}

.work-intro__clients {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
}

.work-intro__row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
  font-size: 16px;
  line-height: 24px;
  letter-spacing: var(--tracking-tight);
}

.muted {
  color: var(--color-fg-muted);
}

.body-strong {
  color: var(--color-fg-body);
}

.work-intro__mostly {
  margin: 0;
  font-size: 16px;
  line-height: 24px;
  letter-spacing: var(--tracking-tight);
}

/* Dribbble badge + link */
.work-intro__dribbble {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  text-decoration: none;
}

.dribbble-badge {
  position: relative;
  width: 26px;
  height: 26px;
  display: inline-flex;
  flex-shrink: 0;
}

.dribbble-badge__back {
  position: absolute;
  inset: 0;
  background: #ebebeb;
  border-radius: 6px;
  box-shadow:
    0 0.4px 0.4px -0.2px rgba(0, 0, 0, 0.06),
    0 1px 1px -0.5px rgba(0, 0, 0, 0.06),
    0 2px 2px -1px rgba(0, 0, 0, 0.06),
    0 4px 4px -2px rgba(0, 0, 0, 0.06),
    0 9px 9px -4px rgba(0, 0, 0, 0.06);
}

.dribbble-badge__front {
  position: absolute;
  inset: 0;
  background: #ffa9eb;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  transform: rotate(8deg);
  box-shadow: 0 16px 32px -4px rgba(12, 12, 13, 0.1), 0 4px 4px -4px rgba(12, 12, 13, 0.05);
  transition: transform var(--motion-base) var(--ease-standard);
}

.dribbble-badge__front img {
  width: 17px;
  height: 17px;
}

.work-intro__dribbble-label {
  color: var(--color-fg-body);
  font-size: 16px;
  line-height: 24px;
  letter-spacing: var(--tracking-tight);
  text-decoration: underline;
  text-underline-offset: 1px;
  transition: color var(--motion-fast) var(--ease-standard);
}

/* Assumption: subtle hover — badge rotates a bit further and the underline darkens. */
.work-intro__dribbble:hover .dribbble-badge__front,
.work-intro__dribbble:focus-visible .dribbble-badge__front {
  transform: rotate(14deg);
}

.work-intro__dribbble:hover .work-intro__dribbble-label,
.work-intro__dribbble:focus-visible .work-intro__dribbble-label {
  color: var(--color-fg);
}

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

/* "design experiments" hover box with corner handles */
.work-intro__experiments {
  position: relative;
  display: inline-block;
  width: 145px;
  height: 24px;
  text-decoration: none;
  background: transparent;
  border: 0.5px solid transparent;
  transition: background-color var(--motion-fast) var(--ease-standard), border-color var(--motion-fast) var(--ease-standard);
  outline: none;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}

.work-intro__experiments-label {
  position: absolute;
  left: 1.75px;
  top: -0.25px;
  font-size: 16px;
  line-height: 24px;
  letter-spacing: var(--tracking-tight);
  color: var(--color-fg-body);
  text-decoration: underline;
  white-space: nowrap;
}

.work-intro__experiments-handle {
  position: absolute;
  width: 4px;
  height: 4px;
  background: var(--accent-pink-hover-fill);
  border: 0.5px solid var(--accent-pink-border);
  opacity: 0;
  transition: opacity var(--motion-fast) var(--ease-standard);
}

.work-intro__experiments-handle--tl { top: -2.25px; left: -2.25px; }
.work-intro__experiments-handle--tr { top: -2.25px; right: -2.25px; }
.work-intro__experiments-handle--br { bottom: -2.25px; right: -2.25px; }
.work-intro__experiments-handle--bl { bottom: -2.25px; left: -2.25px; }

@media (hover: hover) and (pointer: fine) {
  .work-intro__experiments:hover {
    background: var(--accent-pink-hover-fill);
    border-color: var(--accent-pink-border);
  }

  .work-intro__experiments:hover .work-intro__experiments-handle {
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .work-intro__experiments,
  .work-intro__experiments-handle,
  .work-intro__redline {
    transition: none;
  }
}

/* Get in touch button */
.btn-book {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 64px;
  height: 40px;
  padding: 8px 16px;
  border-radius: var(--radius-pill);
  color: #ffffff;
  font-size: 16px;
  line-height: 24px;
  letter-spacing: var(--tracking-tight);
  text-decoration: none;
  background-image: linear-gradient(130.25deg, #2a2729 39.4%, #121112 61.4%);
  box-shadow:
    0 1.5px 2px rgba(0, 0, 0, 0.1),
    0 0 0 1px #4d474b,
    inset 0 0 1px 1px rgba(255, 255, 255, 0.06);
  transition: transform var(--motion-fast) var(--ease-standard);
}

.btn-book:hover {
  transform: scale(1.02);
}

/* ============================================
   Work grid (masonry, two columns)
   ============================================ */
.work-grid-section {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 32px;
  padding-top: 60px;
  padding-bottom: 24px;
}

.work-grid {
  display: flex;
  gap: var(--tile-gap);
  width: 100%;
}

.work-grid__col {
  display: flex;
  flex-direction: column;
  gap: var(--tile-gap);
  flex: 1 1 0;
  min-width: 0;
}

.work-grid[data-grid-state="pending"] {
  visibility: hidden;
}

/* Page-load reveal cascade (Work grid only). Base state is the "before";
   .is-revealed is the "after" — JS sets a per-tile transition-delay then
   toggles this class (see js/main.js). Only opacity/transform, so this
   never affects layout (no CLS). */
.work-tile {
  position: relative;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  overflow: hidden;
  cursor: default;
  display: flex;
  opacity: 0;
  transform: translate3d(0, 14px, 0) scale(0.985);
  will-change: opacity, transform;
}

.work-tile.is-revealed {
  opacity: 1;
  transform: none;
  transition: opacity 500ms ease-out, transform 700ms cubic-bezier(0.22, 1, 0.36, 1);
}

.work-tile__fill {
  background: var(--color-tile-bg);
  width: 100%;
  height: 100%;
  transition: background-color var(--motion-base) var(--ease-standard);
}

.work-tile__media {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* Poster/video sit over the gray frame and fade in on load instead of
   popping in, whether that happens during the reveal or later. The video
   only crossfades in once .is-ready is added (first decoded frame — see
   main.js), never just because it has a src, so there's no flash of a
   blank frame before the real image is painted. */
.work-tile__poster,
.work-tile__video {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 200ms ease-out;
}

.work-tile__poster.is-loaded {
  opacity: 1;
}

.work-tile__video.is-ready {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .work-tile {
    transform: none;
  }
  .work-tile.is-revealed {
    transition: opacity 150ms ease-out;
  }
}

.pill-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 64px;
  padding: 4px 12px;
  background: var(--color-pill-bg);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-pill);
  font-size: 12px;
  line-height: 16px;
  letter-spacing: var(--tracking-tight);
  color: var(--color-fg);
  text-decoration: none;
  transition: background-color var(--motion-base) var(--ease-standard);
}

/* Tooltip (kept from earlier spec; design doesn't contradict it) */
.tile-tooltip {
  position: fixed;
  top: 0;
  left: 0;
  pointer-events: none;
  background: #ffffff;
  color: #202020;
  font-family: "Geist", system-ui, sans-serif;
  font-size: 12px;
  font-weight: 400;
  line-height: 16px;
  letter-spacing: -0.1504px;
  padding: 4px 8px;
  border-radius: 9999px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.06), 0 1px 2px -1px rgba(0, 0, 0, 0.06), 0 2px 4px rgba(0, 0, 0, 0.04);
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  opacity: 0;
  /* Position is set every frame via `transform: translate3d(...)` in main.js
     (offset ~12px right/below the cursor dot so they never overlap) and is
     never transitioned — only `scale` (the pop-in effect) and `opacity` are,
     since they're independent CSS properties from `transform`. */
  transform-origin: top left;
  scale: 0.92;
  transition: opacity var(--motion-fast) var(--ease-standard), scale var(--motion-fast) var(--ease-standard);
  z-index: 100;
  will-change: transform, scale, opacity;
}

.tile-tooltip.is-visible {
  opacity: 1;
  scale: 1;
}

/* ============================================
   Footer (Work page, new design)
   ============================================ */
.site-footer {
  padding-block: 32px;
}

.site-footer__row {
  border-top: 1px dashed var(--color-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 60px;
  flex-shrink: 0;
  padding-block: 16px;
}

.site-footer__copy {
  font-size: 12px;
  line-height: 16px;
  letter-spacing: var(--tracking-tight);
  color: var(--color-fg-muted);
  margin: 0;
}

.site-footer__links {
  display: flex;
  gap: 20px;
}

.site-footer__links a {
  font-size: 12px;
  line-height: 16px;
  letter-spacing: var(--tracking-tight);
  color: var(--color-fg-muted);
  text-decoration: underline;
  text-decoration-color: currentColor;
  transition: color 150ms ease;
}

.site-footer__links a:hover,
.site-footer__links a:focus-visible {
  color: var(--color-fg);
}

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

/* ============================================
   About page
   ============================================ */
.about-content {
  padding-top: 24px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* Wraps the audio pill + heading: 20px top padding, 12px gap between them. */
.about-hero-group {
  padding-top: 20px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  width: 100%;
}

.about-heading {
  margin: 0;
  font-size: 18px;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: var(--tracking-tight);
  color: var(--color-fg);
  width: 100%;
}

.about-heading em {
  font-family: var(--font-serif-italic);
  font-style: italic;
}

.about-block {
  margin-top: 24px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
}

.about-label {
  margin: 0;
  font-size: 16px;
  line-height: 24px;
  letter-spacing: var(--tracking-tight);
  color: var(--color-fg-muted);
}

.about-text {
  margin: 0;
  font-size: 16px;
  line-height: 24px;
  letter-spacing: var(--tracking-tight);
  color: var(--color-fg-body);
  text-wrap: pretty;
}

.about-text a {
  color: inherit;
  text-decoration: underline;
  text-underline-position: from-font;
}

/* Intro audio pill (node 90:9893): fixed 54x25 so toggling play/stop never
   shifts layout. The outer <button> is the pill itself (bg/border/radius);
   an inner row supplies the icon+label gap. */
.audio-pill {
  width: 54px;
  height: 25px;
  box-sizing: border-box;
  padding: 4px;
  display: flex;
  align-items: center;
  background: #fcfcfc;
  border: 1px solid var(--color-border);
  border-radius: 9999px;
  overflow: hidden;
  cursor: pointer;
}

.audio-pill:focus-visible {
  outline: 2px solid #202020;
  outline-offset: 2px;
}

.audio-pill__inner {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 2px 4px 2px 2px;
  border-radius: 99px;
}

.audio-pill__icon {
  width: 10px;
  height: 10px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-fg);
}

.audio-pill__icon img {
  width: 10px;
  height: 10px;
}

.audio-pill__label {
  width: 24px;
  height: 11px;
  font-size: 12px;
  line-height: 1;
  letter-spacing: -0.1504px;
  color: var(--color-fg);
  text-transform: lowercase;
}

/* Text-to-speech karaoke highlight. Idle (no .is-tts-active on the
   ancestor): words use their normal inherited color — zero extra CSS
   needed. While active: every spoken word starts dimmed and returns to
   its normal color (via `color: inherit`, so it automatically matches
   whichever context it's in — heading vs. paragraph) the instant the
   audio reaches it. */
.tts-word {
  transition: color 120ms ease;
}

.is-tts-active .tts-word {
  color: var(--color-fg-muted);
}

.is-tts-active .tts-word.is-spoken {
  color: inherit;
}

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

/* "Everything your product needs, done properly!" services row */
.about-block--services {
  gap: 20px;
}

/* App block: label -> Tomatron row is 8px (was incorrectly sharing the
   services block's 20px). */
.about-block--app {
  gap: 8px;
}

/* Figma now puts a full 1px border on every card. Implemented without any
   per-card border or negative-margin collapsing (which can throw equal
   widths off by a pixel): the row container supplies all 4 outer lines
   (top/bottom read as one continuous line across the whole row, since the
   container's height already matches the stretched cards exactly) and
   each non-first card supplies just its own left edge for the 2 inner
   dividers. Every line ends up exactly 1px, and because box-sizing:
   border-box is in effect (global reset) a border never changes a flex
   item's computed width, so the three cards stay exactly equal. */
.services {
  display: flex;
  width: 100%;
  border: 1px solid var(--color-border);
}

.service-card {
  flex: 1 1 0;
  min-width: 0;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
}

.service-card + .service-card {
  border-left: 1px solid var(--color-border);
}

.service-card__media {
  height: 120px;
  width: 100%;
  padding-bottom: 8px;
}

.service-card__title {
  margin: 0;
  padding: 0 12px;
  font-size: 14px;
  line-height: 20px;
  letter-spacing: -0.4395px;
  color: var(--color-fg);
}

.service-card__desc {
  margin: 0;
  padding: 4px 12px 12px;
  font-size: 12px;
  line-height: 16px;
  letter-spacing: -0.1504px;
  color: var(--color-fg-muted);
}

/* "App" row (Tomatron) */
.app-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding-block: 12px;
  text-decoration: none;
  color: inherit;
  /* Transparent by default so the border reserves its 1px of space the
     whole time — becoming visible on hover/focus never shifts the row. */
  border-bottom: 1px solid transparent;
  transition: border-color 150ms ease;
}

.app-row:focus-visible {
  outline: 2px solid #202020;
  outline-offset: 2px;
  border-radius: 8px;
  border-bottom-color: var(--color-border);
}

@media (hover: hover) {
  .app-row:hover {
    border-bottom-color: var(--color-border);
  }
}

.app-row__icon {
  position: relative;
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  /* Matches the icon artwork's own rounded corners (measured ~27px at the
     PNG's native 3x/120px size, i.e. ~9px at 1x) — without this, both the
     outer box-shadow and the inset highlight were drawn as a square behind
     the rounded icon (box-shadow, inset included, always conforms to the
     element's own border-radius). */
  border-radius: 9px;
  overflow: hidden;
  box-shadow:
    0 7.734px 4.609px rgba(0, 0, 0, 0.05),
    0 3.438px 3.438px rgba(0, 0, 0, 0.09),
    0 0.859px 1.875px rgba(0, 0, 0, 0.1),
    0 0 0.078px rgba(0, 0, 0, 0.1),
    inset -0.313px 0.313px 0.313px rgba(255, 255, 255, 0.3),
    inset 0.313px -0.313px 0.313px rgba(0, 0, 0, 0.12);
}

.app-row__icon img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.app-row__text {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.app-row__name {
  font-size: 16px;
  line-height: 24px;
  letter-spacing: var(--tracking-tight);
  color: var(--color-fg-body);
}

.app-row__meta {
  font-size: 12px;
  line-height: 16px;
  letter-spacing: -0.1504px;
  color: var(--color-fg-muted);
}

.app-row__arrow {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  color: var(--color-fg-muted);
  transition: color 150ms ease;
}

.app-row__arrow svg {
  display: block;
  width: 16px;
  height: 16px;
}

.app-row:focus-visible .app-row__arrow {
  color: var(--color-fg-body);
}

@media (hover: hover) {
  .app-row:hover .app-row__arrow {
    color: var(--color-fg-body);
  }
}

/* ============================================
   Chips (physics-driven, About footer)
   ============================================ */
.chips-viewport {
  position: relative;
  width: 100%;
  flex: 1;
  min-height: 160px;
  overflow: hidden;
  /* Chips aren't draggable, but a touch can still act as the repel source
     (see main.js) — pan-y keeps vertical page scroll working over the box. */
  touch-action: pan-y;
}

.chips-stage {
  position: absolute;
  top: 0;
  left: 0;
  width: 720px;
  height: 200px;
  transform-origin: top left;
}

.chip {
  position: absolute;
  top: 0;
  left: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 8px 16px;
  border-radius: 139px;
  font-size: 16px;
  line-height: 24px;
  letter-spacing: -0.024px;
  color: #424242;
  white-space: nowrap;
  text-decoration: none;
  /* Not interactive: the cursor repels chips without ever touching them
     (see the repel field in main.js), so there's nothing here to click,
     drag, or select. */
  pointer-events: none;
  cursor: default;
  user-select: none;
  -webkit-user-drag: none;
  will-change: transform;
  /* Hidden from first paint — unpositioned chips would otherwise sit
     stacked at the top-left (0,0) and be visible during the transition
     overlay, before the physics engine (or the static layout) has placed
     them. main.js adds .is-positioned right after the first real position
     is computed. */
  opacity: 0;
  visibility: hidden;
}

.chip.is-positioned {
  opacity: 1;
  visibility: visible;
}

.chip--lime {
  background: #e6e99a;
}

.chip--lilac {
  background: #e6e0ec;
}

.chip--neutral {
  background: #f3f5f4;
}

.chip--icon {
  width: 40px;
  height: 40px;
  padding: 8px;
  border-radius: 50%;
}

.chip--icon img {
  width: 24px;
  height: 24px;
  display: block;
}

/* ============================================
   Mobile
   ============================================ */
@media (max-width: 560px) {
  .site-nav {
    padding-inline: 16px;
  }

  .work-intro,
  .work-grid-section,
  .site-footer,
  .about-content {
    padding-inline: 16px;
  }

  .work-grid {
    flex-direction: column;
  }

  /* Stacked: keeps the full outer border on all 4 sides (same as desktop);
     only the dividers between cards rotate from vertical to horizontal. */
  .services {
    flex-direction: column;
  }

  .service-card + .service-card {
    border-left: none;
    border-top: 1px solid var(--color-border);
  }

  .site-footer__row {
    flex-direction: column;
    align-items: flex-start;
    height: auto;
    gap: 12px;
  }
}

/* ============================================
   Custom cursor dot (desktop only, see main.js)
   ============================================ */
.cursor-dot {
  position: fixed;
  top: 0;
  left: 0;
  width: 10px;
  height: 10px;
  margin: -5px 0 0 -5px;
  border-radius: 999px;
  background: #161616;
  pointer-events: none;
  opacity: 0;
  z-index: 2147483647;
  will-change: transform;
  contain: layout paint style;
  backface-visibility: hidden;
  transition: opacity 160ms;
}

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

@media (hover: hover) and (pointer: fine) {
  html[data-cursor="dot"],
  html[data-cursor="dot"] * {
    cursor: none !important;
  }
}

/* ============================================
   Reduced motion
   ============================================ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================
   Page transition overlay (Work <-> About), driven by the Web Animations
   API in main.js — see switchView(). Sits above page content, below the
   menu pill and the cursor dot.
   ============================================ */
.page-transition {
  position: fixed;
  inset: 0;
  z-index: 150;
  pointer-events: none;
  opacity: 0;
  background: rgba(252, 252, 252, 0.55);
  backdrop-filter: blur(22px) saturate(1.6);
  -webkit-backdrop-filter: blur(22px) saturate(1.6);
}

/* ============================================
   View panels (single document, two views)
   ============================================ */
.view-panel {
  opacity: 1;
}

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

/* Programmatic focus targets after a view switch (not reachable via Tab,
   tabindex="-1") — no visible ring needed for them. */
.view-panel:focus,
.work-intro__hello:focus,
.about-heading:focus {
  outline: none;
}

body[data-view="work"] .chips-viewport {
  display: none;
}

/* About view pins the footer to the bottom of the viewport; Work scrolls
   normally (this only applies while data-view="about" is set on body). */
body[data-view="about"] {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

body[data-view="about"] main {
  flex: 0 0 auto;
  display: flex;
}

/* Footer (chips + divider + copyright) absorbs the leftover vertical space
   so the About page lands on exactly 100dvh when content is short, and
   grows/scrolls normally when content is taller than the viewport. */
body[data-view="about"] .site-footer {
  flex: 1 0 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.about-panel {
  flex: 1;
  display: flex;
  justify-content: center;
  width: 100%;
}


/* Service card media: 120x120 artwork centered in the slot. Poster is the
   resting still; the video (hover-driven loop) crossfades over it. */
.service-card__media {
  box-sizing: content-box;
  display: flex;
  justify-content: center;
  align-items: flex-start;
}
.service-card__frame {
  position: relative;
  width: 120px;
  height: 120px;
  flex: none;
  background: #fcfcfc;
  overflow: hidden;
}
.service-card__poster,
.service-card__video {
  position: absolute;
  inset: 0;
  width: 120px;
  height: 120px;
  object-fit: cover;
  object-position: center;
  display: block;
  pointer-events: none;
}
.service-card__video {
  opacity: 0;
  transition: opacity 120ms ease;
}
.service-card.is-playing .service-card__video {
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .service-card__video { display: none; }
}
