





/* =====================================================================
   styles.css — shared by every page.

   CONTENTS
     1.  Design tokens      colors, fonts, spacing (edit these first)
     2.  Page transitions   index <-> about <-> case study animations
     3.  Base
     4.  Icons              .icon + one class per glyph
     5.  Face               logo / avatar blink + eye tracking
     6.  Fixed overlay      back-to-top, logo, Work/Playground nav
     7.  Hero               index hero (also the about page card)
     8.  Projects stage     sticky, sideways-scrolling card row
     9.  Project cards      title, divider, case-study button, hover
     10. Device mocks       phone / tablet frames with live prototypes
     11. Playground         tags + photo sliders (also used on about)
     12. About page
     13. Case study page
     14. Case study nav     the "Toast POS ▾" pill + dropdown
     15. Responsive         2000 / 1280 / 1024 / 768px
   ===================================================================== */


/* =====================================================================
   1. Design tokens
   ===================================================================== */

:root {
  /* System UI font: San Francisco (Apple), Segoe UI (Windows), Roboto (Android)… */
  --font-main: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";

  /* Fluid type: interpolates between the 375px and 1440px sizes. */
  --font-fluid-body: clamp(1rem, 0.188vw + 0.956rem, 1.125rem);         /* 16 -> 18px */
  --font-fluid-name-title: clamp(1.125rem, 0.188vw + 1.081rem, 1.25rem); /* 18 -> 20px */
  --font-fluid-h3: clamp(1.5rem, 1.127vw + 1.236rem, 2.25rem);           /* 24 -> 36px */

  /* Colors */
  --color-title: #222222;
  --color-subtitle: #777777;
  --color-role: #777777;
  --color-link: #0062fe;
  --color-card-bg: #f1f1f1;
  --color-divider: #d9d9d9;       /* project card divider, borders */
  --color-line: #e1e1e1;          /* case study rules + stat divider */
  --color-avatar-bg: #d9d9d9;
  --color-device: #0b0b0d;        /* phone / tablet frame */

  /* Navs (index .nav-pill, case study .cs-nav): see-through gray glass,
     with the selected item solid white. */
  --nav-glass-bg: rgba(220, 220, 220, 0.25);
  --nav-glass-blur: blur(12px) saturate(10%);
  --nav-selected-bg: #ffffff;
  --nav-shadow: 0 1px 7px 1px rgba(0, 0, 0, 0.25);
  --nav-pill-width: 255px;        /* index .nav-pill and case study .cs-nav */

  /* Light glass on top of images (about page: photo icon bar) */
  --glass-light-bg: rgba(255, 255, 255, 0.4);
  --glass-light-blur: blur(12px) saturate(140%);

  /* Layout */
  --hero-max-width: 800px;        /* hero card; the about widgets match it */
  --side-margin: 60px;
  --card-gap: 30px;
}

/* Line break shown only on phones (<br class="brM">, see the 768px block) */
.brM {
  display: none;
}


/* =====================================================================
   2. Page transitions
   Elements with the same view-transition-name on two pages morph into
   each other when navigating (Chrome/Edge/Safari 18.2+):
     back-arrow  back-to-top arrow  <->  case study / about back arrow
     top-nav     Work/Playground pill  <->  case study pill
     hero-card   index hero  <->  about page card
   Clicks during a transition are handled by page-transitions.js.
   ===================================================================== */

@view-transition {
  navigation: auto;
}

::view-transition-group(root) {
  animation-duration: 0.45s;
}

::view-transition-group(back-arrow),
::view-transition-group(top-nav) {
  animation-duration: 0.5s;
  animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}


/* =====================================================================
   3. Base
   ===================================================================== */

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

html,
body {
  background: #ffffff;
  color: #000000;
  font-family: var(--font-main);
  -webkit-font-smoothing: antialiased;
  scroll-behavior: smooth;
}

a {
  text-decoration: none;
  color: inherit;
}

img {
  display: block;
}


/* =====================================================================
   4. Icons
   <span class="icon icon--NAME">: the glyph is a CSS mask filled with
   currentColor, so set `color` (or background-color) to recolor it.
   SVGs are inlined as data URIs so they also work from file://.
   ===================================================================== */

.icon {
  display: inline-block;
  background-color: currentColor;
  -webkit-mask: var(--icon) center / contain no-repeat;
  mask: var(--icon) center / contain no-repeat;
}

/* → (About link) */
.icon--right {
  --icon: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath d='M3 8H13M13 8L9 4M13 8L9 12' stroke='%230062fe' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E %3C/svg%3E");
}

/* ↗ (project card case-study button) */
.icon--diagonal {
  --icon: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath d='M7 17L17 7M17 7H8M17 7V16' stroke='%23bdbdbd' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E %3C/svg%3E");
}

/* small filled › (case study nav, rotated to point down) */
.icon--caret {
  --icon: url("data:image/svg+xml,%3Csvg width='6' height='10.1954' viewBox='0 0 6 10.1954' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath d='M0 9.29312L0.902294 10.1954L6 5.09771L0.902294 0L0 0.902294L4.19541 5.09771L0 9.29312Z' fill='black'/%3E %3C/svg%3E");
}


/* =====================================================================
   5. Face (logo + avatar)
   Markup: <svg class="face"> with .face__pupil / .face__socket paired by
   data-eye. shared.js moves the pupils toward the mouse.
   ===================================================================== */

.face__blink {
  transform-box: fill-box;
  transform-origin: center;
  animation: face-blink 3.6s ease-in-out infinite;
}

@keyframes face-blink {
  0%, 90%, 98%, 100% { transform: scaleY(1); }
  92%, 96%           { transform: scaleY(0.05); }
}

.face__pupil {
  transition: transform 0.12s ease-out;
}


/* =====================================================================
   6. Fixed overlay: back-to-top, logo, Work/Playground nav
   Hidden until .is-visible (index: added by script.js once you scroll
   past the hero; other pages: set in the HTML).
   ===================================================================== */

.nav-pill,
.logo,
.back-to-top {
  position: fixed;
  z-index: 50;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity 0.35s ease, transform 0.35s ease, visibility 0.35s;
}

.nav-pill.is-visible,
.logo.is-visible,
.back-to-top.is-visible {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

/* Set for a frame by script.js when returning from a case study: no
   fade, so the overlay is already visible in the page transition. */
.is-restoring .nav-pill,
.is-restoring .logo,
.is-restoring .back-to-top {
  transition: none !important;
}

/* ---- Back-to-top / back button ---- */

.back-to-top {
  top: 30px;
  left: 40px;
  width: 60px;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: #000;
  color: #fff;
  cursor: pointer;
  overflow: hidden;
}

/* Shimmer: a light band sweeps across on hover. */
.back-to-top::before {
  content: '';
  position: absolute;
  top: 0;
  left: -75%;
  width: 50%;
  height: 100%;
  background: linear-gradient(115deg, transparent, rgba(255, 255, 255, 0.55), transparent);
  transform: skewX(-20deg);
  transition: left 0.6s ease;
  pointer-events: none;
}

.back-to-top:hover::before {
  left: 125%;
}

/* One ↗ arrow glyph, rotated: up on index, left on other pages. The
   page transition animates between the two rotations (90°).
   Inline <svg>, not a CSS mask: masks load late on a fresh page and
   briefly render as a white square. */
.back-to-top__arrow {
  position: relative;
  display: block;
  width: 36px;
  height: 36px;
  view-transition-name: back-arrow;
}

.back-to-top__arrow--up   { transform: rotate(-45deg); }
.back-to-top__arrow--left { transform: rotate(-135deg); }

/* ---- Logo ---- */

.logo {
  top: 30px;
  right: 40px;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: var(--color-avatar-bg);
}

/* The face is clipped to a circle here (not with overflow on .logo),
   so the hover bubble below can show outside the circle. */
.logo svg {
  display: block;
  width: 100%;
  height: 100%;
  clip-path: circle(50%);
}

/* Hover bubble under the logo: text from data-tip, right-aligned so it
   stays on screen, tail pointing up at the logo. */
.logo::after,
.logo::before {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  translate: 0 -4px;
  transition: opacity 0.18s ease, translate 0.18s ease;
}

.logo::after {
  content: attr(data-tip);
  top: calc(100% + 12px);
  right: 0;
  padding: 7px 12px;
  border-radius: 12px;
  background: #ffffff;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.15);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.3;
  color: #000;
  white-space: nowrap;
}

/* Tail: centered under the 60px logo */
.logo::before {
  content: '';
  top: calc(100% + 5px);
  right: 23px;
  z-index: 1;
  width: 14px;
  height: 8px;
  background: #ffffff;
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
}

.logo:hover::after,
.logo:hover::before,
.logo:focus-visible::after,
.logo:focus-visible::before {
  opacity: 1;
  translate: 0 0;
}

/* ---- Work / Playground nav ---- */

.nav-pill {
  view-transition-name: top-nav;
  top: 30px;
  left: 50%;
  transform: translateX(-50%) translateY(-8px);
  width: var(--nav-pill-width);
  padding: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 100px;
  background: var(--nav-glass-bg);
  -webkit-backdrop-filter: var(--nav-glass-blur);
  backdrop-filter: var(--nav-glass-blur);
  box-shadow: var(--nav-shadow);
  overflow: hidden;
}

.nav-pill.is-visible {
  transform: translateX(-50%) translateY(0);
}

.nav-pill__item {
  /* Buttons share the pill's width, so the gap to the pill edge is the
     same 10px on every side at any pill width. */
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 10px 20px;
  border: none;
  border-radius: 100px;
  background: none;
  font: inherit;
  font-size: 1.1rem;
  line-height: normal;
  color: #000;
  white-space: nowrap;
  cursor: pointer;
}

/* The white "selected" pill: one element (.nav-pill__indicator, added by
   script.js) that slides under the active item, resizing to fit, and
   fades out while nothing is selected (.is-idle). Items sit above it. */
.nav-pill__item,
.nav-pill .nav-logo {
  position: relative;
  z-index: 1;
}

.nav-pill__indicator {
  position: absolute;
  z-index: 0;
  border-radius: 100px;
  background: var(--nav-selected-bg);
  /* ease-out: starts quickly and settles — also keeps it moving smoothly
     while the dot's growth nudges the target every frame */
  transition: left 0.45s cubic-bezier(0.22, 1, 0.36, 1), width 0.45s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.3s ease, transform 0.3s ease;
}

.nav-pill__indicator.no-anim {
  transition: none;
}

.nav-pill.is-idle .nav-pill__indicator {
  opacity: 0;
  transform: scale(0.9);
}

/* Green "you are here" dot (also used by the case study nav). It grows in
   (and the label slides over) instead of popping in. */
.nav-dot {
  display: inline-block;
  flex: none;
  width: 0;
  height: 7px;
  margin-right: -10px; /* cancels the item's gap while hidden */
  border-radius: 50%;
  background: #26ff00;
  opacity: 0;
  transform: scale(0);
  transition: width 0.3s ease, margin 0.3s ease, opacity 0.3s ease, transform 0.3s ease;
}

.nav-pill__item.is-active .nav-dot {
  width: 7px;
  margin-right: 0;
  opacity: 1;
  transform: scale(1);
}

.nav-pill.is-idle .nav-dot {
  width: 0;
  margin-right: -10px;
  opacity: 0;
  transform: scale(0);
}

/* Over a mostly dark background (shared.js "Nav contrast"), text on the
   glass turns white; the item on the white pill stays black. */
.nav-pill__item,
.cs-nav__menu a {
  transition: color 0.3s ease, background 0.15s ease;
}

.nav-pill.is-on-dark .nav-pill__item {
  color: #fff;
}

.nav-pill.is-on-dark:not(.is-idle) .nav-pill__item.is-active,
.cs-nav__menu.is-on-dark a:hover,
.cs-nav__menu.is-on-dark a:focus-visible {
  color: #000;
}

.cs-nav__menu.is-on-dark a {
  color: #fff;
}

/* Small logo at the left end of the nav (index + case studies) —
   tablet and smaller only; see the 1024px block. */
.nav-logo {
  display: none;
}


/* =====================================================================
   7. Hero (index) — also the bordered card on the about page
   ===================================================================== */

.hero {
  max-width: var(--hero-max-width);
  margin: 2.5rem auto 3.5rem;
  padding: 2.5rem var(--side-margin) 3rem;
}

.hero-card {
  view-transition-name: hero-card;
}

.hero__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 24px;
}

.hero__identity {
  display: flex;
  align-items: center;
  gap: 20px;
  margin-right: 3rem;
}

.avatar {
  display: block;
  width: 70px;
  height: 70px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--color-avatar-bg);
}

/* Home hero avatar links to the about page */
.avatar-link {
  display: block;
  flex-shrink: 0;
  border-radius: 50%;
  transition: transform 0.2s ease;
}

.hero__name-title {
  font-size: var(--font-fluid-name-title);
  font-weight: 600;
  letter-spacing: -0.4px;
  line-height: normal;
  color: #000;
}

.hero__name-sub {
  font-size: var(--font-fluid-body);
  font-weight: 400;
  line-height: normal;
  color: var(--color-role);
}

.hero__links {
  display: flex;
  gap: 10px;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 10px 20px;
  border: 1px solid #000000;
  border-radius: 100px;
  font-size: var(--font-fluid-body);
  letter-spacing: -0.36px;
  white-space: nowrap;
}

.btn--outline {
  background: #ffffff;
  color: #000000;
}

.btn--solid {
  background: #000000;
  color: #ffffff;
}

.hero__bio {
  margin-top: 36px;
  font-size: var(--font-fluid-body);
  letter-spacing: -0.36px;
  line-height: 1.5;
  color: #000000;
}

.hero__bio p + p {
  margin-top: 20px;
}

.hero__bio strong,
.about-card__bio strong {
  font-weight: 700;
}

.hero__bio strong.semibold,
.about-card__bio strong.semibold {
  font-weight: 600;
}

.hero__about-link {
  margin-top: 20px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--font-fluid-body);
  letter-spacing: -0.36px;
  color: var(--color-link);
}

.hero__about-link .icon {
  width: 16px;
  height: 16px;
}


/* =====================================================================
   8. Projects stage (index)
   .projects-scroll          tall wrapper = the scroll distance
     .projects-viewport      sticks mid-screen (top set by script.js)
       .horizontal-track     slides sideways (transform set by script.js)
   ===================================================================== */

.projects-scroll {
  position: relative;
  height: calc(100vh + 1400px); /* +1400px = room for the sideways slide */
}

.projects-viewport {
  position: sticky;
  top: 0;
  z-index: 1;
  height: min(750px, 78vh);
  overflow: hidden;
}

.horizontal-track {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: stretch;
  gap: var(--card-gap);
  padding-left: var(--side-margin);
  transform: translate3d(0, 0, 0);
  will-change: transform;
}

/* All cards fit on screen (script.js adds .is-fit): no sideways scroll,
   the row is centered and the section is just one screen tall. */
.projects-scroll.is-fit {
  height: 100vh;
}

.projects-scroll.is-fit .horizontal-track {
  justify-content: center;
  padding-right: var(--side-margin);
}

.projects-scroll.is-fit .horizontal-track__end-spacer {
  display: none;
}

/* Trailing margin as a real flex item (right padding is ignored on an
   overflowing flex container). Width minus the gap before it. */
.horizontal-track__end-spacer {
  flex-shrink: 0;
  width: max(0px, calc(var(--side-margin) - var(--card-gap)));
}

/* Only the active tab (data-tab = work | playground) is shown. */
.projects-scroll[data-tab] {
  display: none;
}

.projects-scroll[data-tab].is-active {
  display: block;
}


/* =====================================================================
   9. Project cards
   ===================================================================== */

.project-card {
  position: relative;
  flex-shrink: 0;
  background: var(--color-card-bg);
  border-radius: 20px;
  transition: background 0.2s ease;
}

.project-card--lg {
  width: 750px;
  height: 750px;
}

.project-card--sm {
  width: 450px;
  height: 750px;
}

/* In the stage, cards fill the viewport's height. */
.horizontal-track .project-card--lg,
.horizontal-track .project-card--sm {
  height: 100%;
}

.project-card__title {
  position: absolute;
  top: 30px;
  left: 30px;
}

.project-card--lg .project-card__title { width: 690px; }
.project-card--sm .project-card__title { width: 390px; }

.project-card__title h3 {
  font-size: var(--font-fluid-h3);
  font-weight: 600;
  letter-spacing: -1.08px;
  line-height: normal;
  color: var(--color-title);
  transition: color 0.2s ease;
}

/* Subtitle and "View Case Study" sit in the same grid cell and
   cross-fade on hover. */
.project-card__subtitle {
  display: grid;
  margin-top: 4px;
}

.project-card__subtitle p {
  grid-area: 1 / 1;
  font-size: var(--font-fluid-body);
  font-weight: 400;
  letter-spacing: -0.54px;
  line-height: normal;
  transition: opacity 0.2s ease;
  color: var(--color-subtitle);
}

/* Divider under the title */
.project-card__title::after {
  content: '';
  position: absolute;
  top: 100px;
  left: 0;
  width: 100%;
  height: 1px;
  background: var(--color-divider);
  transition: background-color 0.2s ease;
}

/* ↗ case-study button (top-right) */
.project-card__case-study {
  position: absolute;
  top: 30px;
  right: 30px;
  width: 80px;
  height: 80px;
  border: 4px solid var(--color-divider);
  border-radius: 50%;
  background: #ffffff;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease;
}

.project-card__case-study .icon {
  position: absolute;
  top: 50%;
  right: 10px; /* + the 4px border = centered */
  width: 50px;
  height: 50px;
  transform: translateY(-50%);
  background-color: #bdbdbd;
  transition: background-color 0.2s ease;
}

/* Hover: only the button itself turns black (white arrow). */
.project-card__case-study:hover {
  background: #000000;
  border-color: #000000;
}

.project-card__case-study:hover .icon {
  background-color: #ffffff;
}

/* "View case study" bubble (text from data-tip) under the button,
   right-aligned with it, tail pointing up at its center. Same look as
   the logo bubble. */
.project-card__case-study[data-tip] {
  z-index: 2; /* above the device mock below it */
}

.project-card__case-study[data-tip]::after,
.project-card__case-study[data-tip]::before {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  translate: 0 -4px;
  transition: opacity 0.18s ease, translate 0.18s ease;
}

.project-card__case-study[data-tip]::after {
  content: attr(data-tip);
  top: calc(100% + 12px);
  right: -4px; /* line up with the button's outer edge (4px border) */
  padding: 7px 12px;
  border-radius: 12px;
  background: #ffffff;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.15);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.3;
  color: #000;
  white-space: nowrap;
}

.project-card__case-study[data-tip]::before {
  content: '';
  top: calc(100% + 5px);
  right: calc(50% - 7px); /* centered under the button */
  z-index: 1;
  width: 14px;
  height: 8px;
  background: #ffffff;
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
}

.project-card__case-study[data-tip]:hover::after,
.project-card__case-study[data-tip]:hover::before,
.project-card__case-study[data-tip]:focus-visible::after,
.project-card__case-study[data-tip]:focus-visible::before {
  opacity: 1;
  translate: 0 0;
}


/* =====================================================================
   10. Device mocks (live prototypes inside cards)
   .iphone-mock  portrait phone — the iframe renders at 375x812 and is
                 scaled to fit by script.js
   .tablet-mock  landscape tablet — the iframe just fills it
   ===================================================================== */

/* Area below the card's divider that centers the device. */
.iphone-mock-wrap {
  container-type: size; /* lets the tablet size itself to fit (cqw/cqh) */
  position: absolute;
  top: 150px;
  right: 0;
  bottom: 30px;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.iphone-mock {
  position: relative;
  height: 100%;
  aspect-ratio: 375 / 812;
  padding: 6px;
  /* Corners scale with the phone (38px at its 241x522 desktop size), so
     it keeps the same shape when it's smaller on tablets and phones. */
  border-radius: 15.8% / 7.3%;
  background: var(--color-device);
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.28);
}

.tablet-mock {
  position: relative;
  width: min(88cqw, 150cqh); /* 88% wide, but never taller than the area (3:2) */
  aspect-ratio: 1440 / 960;
  border-radius: 10px;
  outline: 10px solid var(--color-device);
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.28);
}

/* Fingertip cursor over live prototypes (not over videos). */
.iphone-mock,
.tablet-mock {
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3E%3Ccircle cx='15' cy='15' r='11' fill='%23000000' fill-opacity='0.16' stroke='%23ffffff' stroke-width='2'/%3E%3Ccircle cx='15' cy='15' r='11' fill='none' stroke='%23000000' stroke-opacity='0.35' stroke-width='1'/%3E%3C/svg%3E") 15 15, pointer;
}

.iphone-mock--video {
  cursor: default;
}

/* One-shot shake when the pointer enters the card (script.js). */
.iphone-mock.is-buzzing,
.tablet-mock.is-buzzing {
  animation: device-buzz 0.35s ease-in-out;
}

@keyframes device-buzz {
  0%, 100% { transform: translateX(0); }
  15%, 45% { transform: translateX(-2px) rotate(-1deg); }
  30%, 60% { transform: translateX(2px) rotate(1deg); }
  80%      { transform: translateX(-1px); }
}

.iphone-mock__screen,
.tablet-mock__screen {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.iphone-mock__screen {
  border-radius: 14% / 6.3%; /* 32px at the desktop size */
  background: #ffffff;
}

.tablet-mock__screen {
  border-radius: 10px;
  background: #000000;
}

.iphone-mock__screen iframe {
  position: absolute;
  top: 0;
  left: 0;
  border: 0;
}

.tablet-mock__screen iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Video "prototype" (Koki, Coocup): fills the screen. */
.iphone-mock__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Desktop monitor (SMG): a static screenshot that scrolls top → bottom
   while the card is hovered. Sized like the tablet: as wide as the area
   allows without getting taller than it (display 16:10 + stand ≈ 0.72). */
.desktop-mock {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: min(88cqw, 136cqh);
}

.desktop-mock__display {
  width: 100%;
  aspect-ratio: 16 / 10;
  padding: 10px;
  border-radius: 14px;
  background: var(--color-device);
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.28);
}

.desktop-mock__screen {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: 5px;
  background: #ffffff;
}

.desktop-mock__screen img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0%;
  transition: object-position 0.8s ease;
}

.project-card:hover .desktop-mock__screen img {
  object-position: 50% 100%;
  transition: object-position 7s ease-in-out;
}

.desktop-mock__stand {
  width: 14%;
  aspect-ratio: 5 / 3;
  background: linear-gradient(#1c1c20, var(--color-device));
  clip-path: polygon(18% 0, 82% 0, 100% 100%, 0 100%);
}

.desktop-mock__base {
  width: 28%;
  height: 6px;
  border-radius: 6px 6px 2px 2px;
  background: var(--color-device);
}

.iphone-mock__island {
  position: absolute;
  top: 13px;
  left: 50%;
  z-index: 4;
  width: 17%;
  height: 17px;
  transform: translateX(-50%);
  border-radius: 100px;
  background: var(--color-device);
}


/* =====================================================================
   11. Playground (image-slider cards + tags)
   ===================================================================== */

.project-card--pg {
  width: 800px;
  height: 600px;
  overflow: hidden;
}

/* Card + its tags underneath, as one item on the track. */
.playground-item {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 10px;
}

.playground-item__tags {
  font-size: 1.25rem;
  color: #000;
}

.playground-item__tags span {
  color: #666;
}


/* Ascii card: a single iframe filling the card */
.img-slider {
  position: absolute;
  inset: 0;
  background: #eeeeee;
  overflow: hidden;
}

.img-slider iframe {
  width: 100%;
  height: 100%;
  border: 0;
}

/* ---- Photo slider (.photo-widget): about page (icons, Figma "Frame 94")
   and playground cards (dots, .photo-widget--dots). Photos slide by
   every 2s (shared.js); hovering shows the glass nav bar. Sizes are cqw
   (% of the widget's width) so it scales with it. */
.photo-widget {
  container-type: inline-size;
  background: #ffffff;
}

.photo-widget__track {
  display: flex;
  height: 100%;
  touch-action: pan-y; /* vertical swipes scroll the page; horizontal ones swipe photos (shared.js) */
  user-select: none;
  transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

.photo-widget__slide {
  flex: 0 0 100%;
  display: grid;
  place-items: center;
  background: #e2e2e2; /* placeholder, until a photo is added */
  font-size: 12cqw;
  font-weight: 600;
  color: #c7c7c7;
}

.photo-widget__slide img {
  -webkit-user-drag: none;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Icon bar: 80% wide, 15% tall, 6% from the bottom (Figma 800×150 at y 790) */
.photo-widget__nav {
  position: absolute;
  bottom: 6cqw;
  left: 10%;
  width: 80%;
  height: 15cqw;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 11.1% 0 8.1%;
  border-radius: 100px;
  background: var(--glass-light-bg);
  -webkit-backdrop-filter: var(--glass-light-blur);
  backdrop-filter: var(--glass-light-blur);
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.25s ease, transform 0.25s ease;
}

.photo-widget:hover .photo-widget__nav,
.photo-widget:has(:focus-visible) .photo-widget__nav {
  opacity: 1;
  transform: translateY(0);
}

/* Touch screens have no hover: keep the bar visible. */
@media (hover: none) {
  .photo-widget__nav {
    opacity: 1;
    transform: none;
  }

  .photo-widget--dots .photo-widget__nav {
    transform: translateX(-50%);
  }
}

.photo-widget__icon {
  display: grid;
  place-items: center;
  padding: 0;
  border: none;
  background: none;
  color: #666;
  cursor: pointer;
  transition: color 0.15s ease, transform 0.15s ease;
}

.photo-widget__icon:hover {
  transform: scale(1.1);
}

.photo-widget__icon.is-active {
  color: #fff;
}

.photo-widget__icon svg {
  display: block;
  height: 100%;
  width: 100%;
  fill: currentColor;
}

/* Icon sizes from Figma (in a 1000px-wide frame) */
.photo-widget__icon--person { width: 6cqw;   height: 6cqw; }
.photo-widget__icon--plane  { width: 7cqw;   height: 7cqw; }
.photo-widget__icon--heart  { width: 6cqw;   height: 5.5cqw; }
.photo-widget__icon--music  { width: 4.7cqw; height: 7cqw; }

/* ---- Dots variant (playground cards): same glass bar, but just wide
   enough for its dots, centered, and capped in size on the big cards. */
.project-card--pg .photo-widget {
  position: absolute;
  inset: 0;
}

.photo-widget--dots .photo-widget__nav {
  bottom: min(6cqw, 24px);
  left: 50%;
  width: auto;
  height: min(15cqw, 52px);
  justify-content: center;
  gap: 14px;
  padding: 0 22px;
  transform: translate(-50%, 12px);
}

.photo-widget--dots:hover .photo-widget__nav,
.photo-widget--dots:has(:focus-visible) .photo-widget__nav {
  transform: translate(-50%, 0);
}

.photo-widget__dot {
  width: 10px;
  height: 10px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: #666;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.15s ease;
}

.photo-widget__dot:hover {
  transform: scale(1.25);
}

.photo-widget__dot.is-active {
  background: #fff;
}

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


/* =====================================================================
   12. About page
   ===================================================================== */

html:has(.page-about),
.page-about {
  background: #f6f6f6;
  padding-bottom: 4rem;
}

/* About: no Work/Playground nav on desktop (shown again from 1024px down) */
.page-about .nav-pill {
  display: none;
}

.page-about .hero {
  margin: 2.5rem auto 0;
}

.page-about .hero-card {
  background: #fff;
  border-radius: 25px;
}

.about-card__bio {
  margin-top: 36px;
  font-size: var(--font-fluid-body);
  letter-spacing: -0.36px;
  line-height: 1.5;
  color: #000000;
}

.about-card__bio p + p {
  margin-top: 20px;
}

/* "Based in Toronto · 3:42 PM EDT" under the bio */
.about-card__location {
  color: var(--color-subtitle);
  font-variant-numeric: tabular-nums; /* time doesn't shift as it ticks */
}

/* Two widgets, 50 / 50, exactly as wide as the hero card above */
.about-widgets {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 30px;
  max-width: var(--hero-max-width);
  margin: 30px auto 0;
}

.about-widget {
  position: relative;
  min-width: 0;
  aspect-ratio: 1 / 1;
  border-radius: 25px;
  overflow: hidden;
}

/* Toronto map (second widget) — Figma "Frame 93", a 1000×1000 frame.
   Everything is positioned in % of the square and sized in cqw (1cqw =
   1% of the widget's width), so it scales with the widget. */
.about-widget--map {
  container-type: inline-size;
  background: #ffffff;
}

/* Map image: fills the square (cropped to fit) and zooms in slightly
   while the mouse is over the widget, back out when it leaves. */
.toronto-map__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.8s ease, filter 0.8s ease;
}

/* Hover: zoom in and brighten slightly */
.about-widget--map:hover .toronto-map__bg {
  transform: scale(1.15);
  filter: brightness(1.1);
}

.toronto-map__title {
  position: absolute;
  top: 40%;
  left: 50%;
  transform: translateX(-50%);
  font-size: 9cqw;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: normal;
  color: #000;
  pointer-events: none;
}

/* ---- Emoji + speech bubble ----
   <span class="map-emoji" data-tip="…"><span class="map-emoji__glyph">☕️</span></span>
   The glyph swings and scales; the bubble is a separate element
   (.map-bubble, created by about.js) so it stays still
   and inside the widget. */

.map-emoji {
  position: absolute;
  font-size: 15cqw;
  line-height: normal;
  cursor: pointer;
  outline: none;
}

.map-emoji:hover,
.map-emoji:focus {
  z-index: 2;
}

.map-emoji--coffee { top: 30%; left: 75%; }
.map-emoji--guitar { top: 55%; left: 35%; }
.map-emoji--tomato  { top: 10%; left: 40%; }
.map-emoji--eyes   { top: 40%; left: 10%; }

.map-emoji__glyph {
  display: inline-block;
  transform-origin: 50% 10%; /* hangs from near its top */
  transition: transform 0.2s ease;
}

.map-emoji:hover .map-emoji__glyph,
.map-emoji:focus .map-emoji__glyph {
  transform: scale(1.08);
}

/* Hovering the map makes the emoji swing ("dangle"), each a little out
   of step. `rotate` (not `transform`), so it combines with the scale. */
.map-emoji--coffee .map-emoji__glyph { animation-delay: -0.2s; }
.map-emoji--guitar .map-emoji__glyph { animation-delay: -0.5s; }
.map-emoji--tomato .map-emoji__glyph { animation-delay: -0.8s; }
.map-emoji--eyes   .map-emoji__glyph { animation-delay: -1.1s; }

/* Desktop: swing while the mouse is over the map (always on tablets and
   phones, see the 1024px block). Longhands so the delays above stay. */
.about-widget--map:hover .map-emoji__glyph {
  animation-name: emoji-dangle;
  animation-duration: 1.4s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}

@keyframes emoji-dangle {
  0%, 100% { rotate: -6deg; }
  50%      { rotate: 6deg; }
}

/* The bubble: a white caption along the bottom edge of the map, the same
   spot for every emoji (text set by about.js). */
.map-bubble {
  position: absolute;
  bottom: 1.5rem;
  left: 50%;
  z-index: 3;
  width: max-content;
  max-width: calc(100% - 16px);
  padding: 7px 12px;
  border-radius: 50px;
  background: #ffffff;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.3;
  color: #000;
  text-align: center;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, 6px);
  transition: opacity 0.18s ease, transform 0.18s ease;
}

.map-bubble.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
}

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

  .about-widget--map .map-emoji__glyph {
    animation-name: none !important;
  }
}



/* =====================================================================
   13. Case study page (toast-pos.html)
   ===================================================================== */

html:has(.page-case-study),
.page-case-study {
  background: #fdfdfd;
}

.case-study {
  width: min(900px, 100% - 32px);
  margin: 0 auto;
  padding: 6rem 0 8rem;
  font-size: var(--font-fluid-body);
  letter-spacing: -0.02em;
  line-height: 1.5;
}

.case-study p + p {
  margin-top: 1.25em;
}

/* ---- Cover image + tabs ---- */

.case-study__cover {
  width: min(498px, 100%);
  height: auto;
  margin: 0 auto;
}

/* Gray stand-in until a real cover image is added */
.case-study__cover--placeholder {
  display: grid;
  place-items: center;
  aspect-ratio: 498 / 339;
  border-radius: 10px;
  background: var(--color-card-bg);
  font-size: 0.875rem;
  color: var(--color-subtitle);
}

.case-study__cover-tabs {
  display: flex;
  width: fit-content;
  margin: 40px auto 0;
  padding: 5px;
  border-radius: 10px;
  background: var(--color-card-bg);
}

.case-study__cover-tabs button {
  padding: 5px 10px;
  border: none;
  border-radius: 5px;
  background: none;
  font: inherit;
  font-size: 0.875rem;
  line-height: normal;
  color: var(--color-subtitle);
  cursor: pointer;
  transition: background 0.15s ease;
}

.case-study__cover-tabs button.is-active {
  background: #ffffff;
}

/* ---- SMG work gallery (smg.html): category tabs, then a gray panel
   with project tabs, skill chips and the project's screenshot ---- */

.smg-gallery {
  margin-top: 3rem;
}

.smg-gallery__tabs {
  display: flex;
  gap: 10px;
  padding: 10px;
  overflow-x: auto;
  border-radius: 10px;
  background: #f1f1f1;
  scrollbar-width: none;
}

.smg-gallery__tabs button {
  flex: 1 0 0;
  min-width: max-content;
  height: 40px;
  padding: 5px 10px;
  border: none;
  border-radius: 5px;
  background: none;
  font: inherit;
  font-size: 1.125rem;
  line-height: normal;
  color: #666666;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.15s ease;
}

.smg-gallery__tabs button.is-active {
  background: #ffffff;
}

.smg-gallery__panel {
  margin-top: 20px;
  padding: 20px 10px 60px;
  border-radius: 10px;
  background: #f1f1f1;
}

/* Project tabs sit straight on the panel (no second gray box) */
.smg-gallery__tabs--sub {
  padding: 0;
  background: none;
}

.smg-gallery__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 20px;
}

.smg-gallery__chip {
  display: flex;
  flex: 1 1 0;
  min-width: max-content; /* wraps onto a new row instead of overflowing */
  align-items: center;
  justify-content: center;
  height: 40px;
  padding: 5px 10px;
  border-radius: 5px;
  background: #aaaaaa;
  font-size: 1.125rem;
  line-height: normal;
  color: #ffffff;
  white-space: nowrap;
}

.smg-gallery__chip--link {
  background: #000000;
  text-decoration: none;
}

.smg-gallery__chip[hidden] {
  display: none;
}

.smg-gallery__stage {
  position: relative;
  display: flex;
  justify-content: center;
  margin-top: 64px;
}

/* Fixed-size window; tall screenshots scroll inside it. */
.smg-gallery__frame {
  width: min(471px, 100% - 140px);
  height: 892px;
  overflow-y: auto;
  scrollbar-width: thin;
}

.smg-gallery__img {
  display: block;
  width: 100%;
  height: auto;
}

.smg-gallery__arrow {
  position: absolute;
  top: 50%;
  display: grid;
  place-items: center;
  width: 50px;
  height: 50px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: none;
  cursor: pointer;
  transform: translateY(-50%);
  transition: opacity 0.15s ease;
}

.smg-gallery__arrow:hover {
  opacity: 0.7;
}

.smg-gallery__arrow--prev {
  left: 50px;
}

.smg-gallery__arrow--prev img {
  transform: scaleX(-1);
}

.smg-gallery__arrow--next {
  right: 50px;
}

@media (max-width: 768px) {
  .smg-gallery__tabs button,
  .smg-gallery__chip {
    font-size: 0.9375rem;
  }

  /* No sideways scrolling: tabs go two per row. An odd last tab spans
     the full row. */
  .smg-gallery__tabs {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    overflow: visible;
  }

  .smg-gallery__tabs > button:last-child:nth-child(odd) {
    grid-column: 1 / -1;
  }

  .smg-gallery__tabs button {
    min-width: 0;
    height: auto;
    min-height: 40px;
    white-space: normal;
    word-break: keep-all;
  }

  .smg-gallery__frame {
    width: calc(100% - 100px);
    height: 600px;
  }

  .smg-gallery__arrow {
    width: 36px;
    height: 36px;
  }

  .smg-gallery__arrow img {
    width: 36px;
    height: 36px;
  }

  .smg-gallery__arrow--prev { left: 4px; }
  .smg-gallery__arrow--next { right: 4px; }
}

/* ---- Title + intro ---- */

.case-study__intro {
  margin-top: 3rem;
}

.case-study__title {
  display: flex;
  align-items: center;
  gap: 19px;
  margin-bottom: 1rem;
  font-size: 2.25rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: normal;
  color: #000;
}

strong {
  font-weight: 600;
}

/* ---- Stats (+75% | +37%) ---- */

.case-study__stats {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 80px;
  margin-top: 3rem;
}

.case-study__stat {
  font-size: 1.125rem;
  font-weight: 600;
  white-space: nowrap;
}

.case-study__stat strong {
  margin-right: 0.4em;
  font-size: 1.75rem;
  font-variant-numeric: tabular-nums; /* no jitter while counting */
  letter-spacing: -0.05em;
}

.case-study__stats-divider {
  width: 2px;
  height: 30px;
  background: var(--color-line);
}

/* ---- Sections ---- */

/* .case-study__rule {
  margin-top: 10rem;
  border: none;
  border-top: 2px solid var(--color-line);
} */

.case-study__section {
  margin-top: 8rem;
}

.case-study__section h2 {
  margin-bottom: 0.75rem;
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: normal;
}

/* ---- Key design decisions ---- */

.case-study__section h2 + .case-study__decision {
  margin-top: 1rem;
}

.case-study__decision + .case-study__decision {
  margin-top: 5rem;
}

.case-study__decision h3 {
  display: inline;
  padding: 0 4px;
  margin-left: -4px; /* text stays aligned with the paragraphs; the stroke sticks out */
  font-size: 1.25rem;
  font-weight: 600;
  line-height: normal;
  background: linear-gradient(transparent 45%, var(--color-highlight) 55%, var(--color-highlight) 90%, transparent 90%);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

.case-study__decision h3 + p {
  margin-top: 16px;
}

/* Before / After images */
.case-study__compare {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  margin-top: 2rem;
}

.case-study__shot {
  position: relative;
  aspect-ratio: 340 / 255;
  border-radius: 10px;
  background: var(--color-card-bg);
  overflow: hidden;
}

.case-study__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.case-study__shot figcaption,
.case-study__tag {
  position: absolute;
  bottom: 1rem;
  left: 50%;
  transform: translateX(-50%);
  padding: 5px 10px;
  border-radius: 5px;
  background: #ffffff;
  font-size: 0.875rem;
  color: var(--color-subtitle);
  border: 2px solid #eee;
}

.case-study__video {
  position: relative; /* for .case-study__tag */
  margin-top: 2rem;
  width: 100%;
  border-radius: 10px;
  overflow: hidden;}
  
.case-study__video video {    
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;}

.case-study__video img {    
width: 100%;
}

.case-study__final {
  background: #0f0f10;
  border-radius: 10px;
  overflow: hidden;
}

.case-study__final video {
    width: 50%;
    margin: 0 auto;
    display: block;
    object-fit: cover;
}

.case-study__final img {
  width: 100%;
}

/* ---- Live prototype at the end (padding = room for the 10px frame) ---- */

.case-study__prototype {
  margin-top:3rem;
  padding: 10px;
}

.case-study__prototype .tablet-mock {
  width: 100%;
}

/* Phone prototype / video (Science Day, Koki, Coocup) */
.case-study__prototype--phone {
  display: flex;
  justify-content: center;
  height: 700px;
}


/* =====================================================================
   14. Case study nav (.cs-nav): pill + dropdown of other case studies.
   Same position and size as index's .nav-pill, so it doesn't move
   between pages. Hover opens the menu (CSS); tap toggles .is-open
   (case-study.js).
   ===================================================================== */

.cs-nav {
  position: fixed;
  top: 30px;
  left: 50%;
  z-index: 60;
  width: var(--nav-pill-width);
  transform: translateX(-50%);
}

/* The pill. (view-transition-name lives here, not on .cs-nav, or the
   dropdown's blur couldn't see the page behind it.) */
.cs-nav__current {
  view-transition-name: top-nav;
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  padding: 20px 30px;
  border: none;
  border-radius: 100px;
  background: var(--nav-glass-bg);
  -webkit-backdrop-filter: var(--nav-glass-blur);
  backdrop-filter: var(--nav-glass-blur);
  box-shadow: var(--nav-shadow);
  font: inherit;
  font-size: 1.1rem;
  line-height: normal;
  color: #000;
  cursor: pointer;
}

/* White inner pill (selected item) */
.cs-nav__current::before {
  content: '';
  position: absolute;
  inset: 10px;
  z-index: -1;
  border-radius: 100px;
  background: var(--nav-selected-bg);
}

.cs-nav__current .nav-dot {
  width: 7px;
  margin-right: 0;
  opacity: 1;
  transform: none;
}

.cs-nav__current .icon--caret {
  position: absolute;
  top: 50%;
  right: 30px;
  width: 6px;
  height: 10px;
  margin-top: -5px;
  background-color: #999999;
  transform: rotate(90deg);
}

.cs-nav__menu {
  position: absolute;
  top: calc(100% + 10px);
  /* Same width as the white "current case study" part of the pill
     (inset 10px; on tablets it starts after the nav logo). */
  left: 10px;
  right: 10px;
  padding: 10px;
  list-style: none;
  border-radius: 25px;
  background: var(--nav-glass-bg);
  -webkit-backdrop-filter: var(--nav-glass-blur);
  backdrop-filter: var(--nav-glass-blur);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s;
}

/* Invisible bridge over the 10px gap so hover doesn't drop. */
.cs-nav__menu::before {
  content: '';
  position: absolute;
  top: -10px;
  right: 0;
  left: 0;
  height: 10px;
}

.cs-nav.is-open .cs-nav__menu,
.cs-nav:focus-within .cs-nav__menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

@media (hover: hover) {
  .cs-nav:hover .cs-nav__menu {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
  }
}

.cs-nav__menu a {
  display: block;
  padding: 10px 20px;
  border-radius: 100px;
  font-size: 1rem;
  line-height: normal;
  text-align: center;
  color: #000;
}

.cs-nav__menu a:hover,
.cs-nav__menu a:focus-visible {
  background: var(--nav-selected-bg);
}




/* ---- ≤1280px ---- */
@media (max-width: 1280px) {
  :root {
    --side-margin: 32px;
  }
}


/* ---- ≤1024px (iPad and smaller): cards stack vertically ---- */
@media (max-width: 1024px) {
  :root {
    --side-margin: 28px;
    --card-gap: 20px;
    --nav-pill-width: 299px; /* 255px + the nav logo */
  }

  /* Photo sliders (about + playground): the nav bar is always shown */
  .photo-widget__nav {
    opacity: 1;
    transform: none;
  }

  .photo-widget--dots .photo-widget__nav {
    transform: translateX(-50%);
  }

  /* Overlay: no corner logo / back-to-top (the logo moves into the nav). */
  #logoMark,
  #backToTop {
    display: none;
  }

  /* The Work/Playground nav: at the bottom, and always visible (not
     only once you scroll past the hero). */
  .nav-pill,
  .nav-pill.is-visible {
    top: auto;
    bottom: 25px;
    padding: 5px; /* selected button fills more of the pill */
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(0);
  }

  .nav-pill__item {
    padding: 13px 20px;
    font-size: 1rem;
  }

  /* About: the nav shows here (hidden on desktop) */
  .page-about .nav-pill {
    display: flex;
  }

  .cs-nav {
    top: auto;
    bottom: 25px;
  }

  /* Case study pill at the bottom; its menu opens upward. The white inner
     pill (5px from the edge, after the nav logo) and the menu line up. */
  .cs-nav__current {
    padding: 18px 25px 18px 74px;
    font-size: 1rem;
  }

  .cs-nav__current::before {
    inset: 5px 5px 5px 54px;
  }

  .cs-nav__current .icon--caret {
    right: 25px;
    transform: rotate(-90deg);
  }

  .cs-nav__menu {
    top: auto;
    bottom: calc(100% + 10px);
    left: 54px;
    right: 5px;
  }

  .cs-nav__menu::before {
    top: auto;
    bottom: -10px;
  }

  .cs-nav__menu a {
    padding: 10px 12px;
    white-space: nowrap;
  }

  /* Logo inside the nav, at its left end, as tall as the selected
     button (44px) with the same 5px gap. */
  .nav-logo {
    display: block;
    flex: none;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--color-avatar-bg);
  }

  .nav-logo svg {
    display: block;
    width: 100%;
    height: 100%;
    clip-path: circle(50%);
  }

  .nav-pill .nav-logo {
    margin-right: 5px;
  }

  /* Case study pill: the logo sits over the pill's left end; the white
     inner pill and its text move right to make room. */
  .cs-nav .nav-logo {
    position: absolute;
    top: 50%;
    left: 5px;
    z-index: 1;
    transform: translateY(-50%);
  }

  /* Projects: the sticky sideways row becomes a plain vertical stack
     (iPad and smaller). Must match STACK_QUERY in script.js. */
  .projects-scroll {
    height: auto;
  }

  .projects-viewport {
    position: static;
    height: auto;
    overflow: visible;
  }

  .horizontal-track {
    position: static;
    flex-direction: column;
    padding: 0 var(--side-margin) 6rem;
    transform: none;
  }

  .horizontal-track__end-spacer {
    display: none;
  }

  .horizontal-track .project-card {
    width: 100%;
    height: 560px;
  }

  .horizontal-track .project-card--has-prototype {
    height: 640px;
  }

  /* Playground photos keep their 4:3 shape */
  .horizontal-track .project-card--pg {
    height: auto;
    aspect-ratio: 4 / 3;
  }

  .playground-item__tags {
    margin-bottom: 2rem;
    font-size: 1rem;
  }

  /* Device mockups sit a little higher in the stacked cards */
  .horizontal-track .iphone-mock-wrap {
    transform: translateY(-1rem);
  }

  .project-card--lg .project-card__title,
  .project-card--sm .project-card__title {
    top: 1.75rem;
    left: 1.75rem;
    width: auto;
    margin-right: 8rem;
  }

  .project-card__title::after {
    display: none;
  }

  .horizontal-track .project-card__case-study {
    top: 1.5rem;
    right: 1.5rem;
    width: 4rem;
    height: 4rem;
    border-width: 3px;
  }

  .horizontal-track .project-card__case-study .icon {
    right: 0.55rem;
    width: 2.5rem;
    height: 2.5rem;
  }

  html:has(.page-about),
  .page-about {
    background: none;
  }

  /* No "View case study" bubble on the project card buttons */
  .project-card__case-study[data-tip]::after,
  .project-card__case-study[data-tip]::before {
    display: none;
  }

  /* About map: the emoji swing all the time (bubbles open on tap, about.js) */
  .about-widget--map .map-emoji__glyph {
    animation-name: emoji-dangle;
    animation-duration: 1.4s;
    animation-timing-function: ease-in-out;
    animation-iteration-count: infinite;
  }

  .case-study {
    padding: 1rem 0 8rem;
  }
}

/* ---- ≤850px: about widgets ---- */
@media (max-width: 850px) {
  .about-widgets {
    gap: 1rem;
    margin: 1rem var(--side-margin) 0;
  }
}

/* ---- ≤768px: phones ---- */
@media (max-width: 768px) {
  .brM {
    display: block;
  }

  /* About widgets stack vertically */
  .about-widgets {
    grid-template-columns: 1fr;
  }

  :root {
    --nav-pill-width: 280px; /* 236px + the nav logo */
    --side-margin: 20px;
    --card-gap: 30px;
  }

  .horizontal-track .project-card--has-prototype {
    height: 560px;
  }

  /* Cards with the (landscape) tablet mockup: shorter, growing with the
     screen width, so there isn't a big gap above and below the tablet
     (~400px tall at 390px wide, up to 560px). */
  .horizontal-track .project-card--has-prototype:has(.tablet-mock),
  .horizontal-track .project-card--has-prototype:has(.desktop-mock) {
    height: clamp(400px, 172px + 58.7vw, 560px);
  }

  .case-study__stats {
    gap: 1rem;
  }

  /* Stats may wrap on narrow screens (long labels would otherwise
     push the page wider than the phone). */
  .case-study__stat {
    flex: 1 1 0;
    font-size: 0.9375rem;
    white-space: normal;
    text-align: center;
  }

  .case-study__stat strong {
    font-size: 1.25rem;
  }

  .case-study__compare {
    grid-template-columns: 1fr;
    gap: 12px;
  }

  .case-study__prototype--phone {
    height: 560px;
  }
}
