/* GENERATED by build.js from src/styles/. Edit the source, not this file. */

/* ==========================================================================
   Tokens
   The design system's raw values. Everything else refers to these, so a
   change here moves the whole site. The /design-system/ page renders them.
   ========================================================================== */
:root {
  /* Colour */
  --bg: #f6f6f6;            /* page and panel background */
  --surface: #ffffff;       /* raised controls (close button, card fallback) */
  --panel: #fbfbfb;         /* project panel (case-study card) background */
  --ink: #212121;           /* primary text */
  --ink-dim: #444444;       /* body copy in case studies, labels */
  --ink-faint: #707070;     /* fine print, helper labels */
  --line: rgba(0, 0, 0, 0.06);         /* separators */
  --underline: rgba(47, 47, 47, 0.2);  /* resting link underline */
  --card-border: rgba(0, 0, 0, 0.06);
  --scrim: rgba(0, 0, 0, 0.1);         /* frosted wash behind the project overlay */
  --skeleton: rgba(0, 0, 0, 0.05);           /* loading placeholder fill */
  --skeleton-shine: rgba(255, 255, 255, 0.6); /* highlight sweeping across it */

  /* Hero gradient defaults (the colour themes live with the aurora in home.css) */
  --sky: #dbf5ff;
  --violet: 147 156 254;    /* rgb triplets, for alpha mixing; also the focus ring */
  --cyan: 168 226 255;

  /* Type */
  --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --size-sm: 14px;   --leading-sm: 20px;   /* fine print */
  --size-md: 16px;   --leading-md: 24px;   /* body, UI */
  --size-lg: 20px;   --leading-lg: 32px;   /* case-study subheads */
  --size-xl: 32px;   --leading-xl: 44px;   /* case-study section titles */
  --size-2xl: 48px;  --leading-2xl: 64px;  /* page titles */
  --weight: 500;                           /* Inter Medium: the site default */
  --weight-regular: 400;                   /* Inter Regular: case-study body, captions, fine print, "Copied" */

  /* Layout */
  --gutter: 24px;           /* minimum side margin */
  --measure: 800px;         /* reading column */
  --panel-width: 996px;     /* project card (overlay and project pages) */
  --stack: 64px;            /* vertical rhythm between blocks */

  /* Shape & depth */
  --radius-card: 24px;
  --radius-panel: 56px;
  --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.04), 0 2px 6px rgba(0, 0, 0, 0.03);
  --shadow-card-hover: 0 2px 8px rgba(0, 0, 0, 0.04), 0 8px 28px rgba(0, 0, 0, 0.05);
  --shadow-panel: 0 0 0 1px rgba(0, 0, 0, 0.04), 0 12px 48px rgba(0, 0, 0, 0.08);

  /* Motion */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-inout: cubic-bezier(0.65, 0, 0.35, 1);
}

@media (max-width: 640px) {
  :root {
    --stack: 48px;
    --radius-panel: 32px;
    --size-xl: 26px;  --leading-xl: 36px;
    --size-2xl: 36px; --leading-2xl: 44px;
  }
}


/* ==========================================================================
   Base
   Reset, page defaults, and the small primitives used everywhere.
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--size-md);
  line-height: var(--leading-md);
  font-weight: var(--weight);
}

h1, h2, h3, p, ul, dl, dd, figure { margin: 0; padding: 0; }
h1, h2, h3 { font-weight: var(--weight); }
ul { list-style: none; }
img { display: block; max-width: 100%; }
a { color: inherit; }
button { font: inherit; color: inherit; }

:focus-visible { outline: 2px solid rgb(var(--violet)); outline-offset: 3px; border-radius: 4px; }

/* Text link: faint underline that darkens on hover (mouse only; on touch a tap would leave it stuck) */
.link {
  text-decoration: underline;
  text-decoration-color: var(--underline);
  text-decoration-thickness: from-font;
  text-underline-position: from-font;
  transition: text-decoration-color 250ms ease;
}
.link:focus-visible { text-decoration-color: var(--ink); }
@media (hover: hover) and (pointer: fine) {
  .link:hover { text-decoration-color: var(--ink); }
}

/* Separator: fine solid hairline. Zero net height, drawn just above its slot (as in Figma) */
.rule {
  flex-shrink: 0;
  width: 100%;
  height: 1px;
  margin: -1px 0 0;
  border: 0;
  background: var(--line);
}

/* Small section label ("Selected work") */
.label { font-size: var(--size-md); line-height: var(--leading-md); color: var(--ink-dim); }

/* Hidden visually, still read by screen readers */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}


/* ==========================================================================
   Components
   Reusable pieces shared by every page. Each maps to a partial in
   src/partials/ (named in the heading) so markup and styles stay paired.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Brand: logo + name                                     partials/brand.html
   -------------------------------------------------------------------------- */
.brand { display: flex; align-items: center; gap: 16px; }
.brand__logo {
  position: relative;
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 50%;
}
/* The PNG carries a baked shadow, so it overhangs the 40px box (as in Figma) */
.brand__logo img { position: absolute; top: -3.33px; left: -5px; width: 50px; height: 50px; max-width: none; }
.brand__name { white-space: nowrap; }

/* --------------------------------------------------------------------------
   Project card + grid                                     partials/card.html
   -------------------------------------------------------------------------- */
.work__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 48px 32px;
}

.card {
  display: flex;
  flex-direction: column;
  gap: 16px;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
.card__media {
  position: relative;
  display: block;
  height: 360px; /* same on every screen; the image fills it, cropping the sides on narrow cards */
  border-radius: var(--radius-card);
  overflow: hidden;
  box-shadow: var(--shadow-card);
  background: var(--skeleton); /* placeholder until the image covers it, even before JS runs */
  transform: translateZ(0); /* keeps the rounded clip crisp while the image scales */
  transition: transform 500ms var(--ease-out), box-shadow 500ms var(--ease-out);
}
.card__media::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--card-border);
  border-radius: inherit;
  pointer-events: none;
}
.card__media--flush::after { border: 0; }
.card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 700ms var(--ease-out), opacity 300ms ease; /* hover zoom + fade-in after loading */
}
.card__title { text-align: center; }

/* Hover/press flourishes are for mouse users only (on touch, :hover sticks after a tap) */
@media (hover: hover) and (pointer: fine) {
  .card:hover .card__media { transform: translateY(-2px) scale(1.015); box-shadow: var(--shadow-card-hover); }
  .card:hover .card__media img { transform: scale(1.07); }
  .card:active .card__media { transform: scale(0.98); transition-duration: 150ms; }
}

/* --------------------------------------------------------------------------
   Footer: contact links + fine print                    partials/footer.html
   -------------------------------------------------------------------------- */
.footer { display: flex; flex-direction: column; gap: var(--stack); }
.contact { display: flex; flex-direction: column; gap: 16px; }
.contact__links { display: flex; flex-wrap: wrap; gap: 8px 24px; }
.fineprint { font-size: var(--size-sm); line-height: var(--leading-sm); color: var(--ink-faint); font-weight: var(--weight-regular); }
.fineprint__btn { padding: 0; border: 0; background: none; font: inherit; color: inherit; cursor: pointer; }

/* --------------------------------------------------------------------------
   Cookie consent                                  partials/cookie-banner.html
   A small card in the corner, not a wall: the page stays usable. Accept and
   Decline get equal weight. Analytics only loads after Accept (head.html).
   -------------------------------------------------------------------------- */
.consent {
  position: fixed;
  left: var(--gutter);
  bottom: var(--gutter);
  z-index: 10;
  width: min(360px, 100% - 2 * var(--gutter));
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 20px;
  border-radius: var(--radius-card);
  background: var(--surface);
  box-shadow: var(--shadow-panel);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 300ms var(--ease-out), transform 300ms var(--ease-out);
}
.consent[hidden] { display: none; }
.consent.is-visible { opacity: 1; transform: none; }
.consent__text { font-size: var(--size-sm); line-height: var(--leading-sm); color: var(--ink-dim); }
.consent__actions { display: flex; gap: 8px; }
.consent__btn {
  flex: 1;
  height: 40px;
  padding: 0 16px;
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: 20px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: var(--size-sm);
  cursor: pointer;
  transition: background-color 200ms ease, border-color 200ms ease;
}
.consent__btn--primary { border-color: var(--ink); background: var(--ink); color: var(--surface); }
.consent__btn:focus-visible { outline: 2px solid rgb(var(--violet)); outline-offset: 2px; }
@media (hover: hover) and (pointer: fine) {
  .consent__btn:hover { background: var(--bg); }
  .consent__btn--primary:hover { background: #000; }
}
@media (max-width: 640px) {
  .consent { left: 12px; bottom: 12px; width: calc(100% - 24px); }
}
@media (prefers-reduced-motion: reduce) {
  .consent { transform: none; transition: opacity 150ms linear; }
}

/* Copy to clipboard: a small grey "Copied" label beside the link for a few
   seconds (main.js). Out of flow, so nothing around it shifts. */
.copy-item { position: relative; }
.copied {
  position: absolute;
  left: calc(100% + 8px);
  top: 0;
  white-space: nowrap;
  color: var(--ink-faint);
  font-weight: var(--weight-regular);
  pointer-events: none;
  opacity: 0;
  transform: translateX(-4px);
  filter: blur(2px);
  transition: opacity 200ms ease, transform 200ms ease, filter 200ms ease;
}
.copy.is-copied + .copied {
  opacity: 1;
  transform: none;
  filter: none;
  transition: opacity 250ms var(--ease-out), transform 350ms var(--ease-out), filter 250ms var(--ease-out);
}

/* --------------------------------------------------------------------------
   Project panel: the card a case study sits in. Used inside the overlay
   (home.css positions it) and as the standalone project page.
   -------------------------------------------------------------------------- */
.project__panel {
  position: relative;
  background: var(--panel);
  border-radius: var(--radius-panel);
  box-shadow: var(--shadow-panel);
  overflow: hidden;
  overflow: clip;
}

.project__close {
  position: absolute;
  top: 24px;
  right: 24px;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: 50%;
  background: var(--surface);
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.04));
  cursor: pointer;
  transition: transform 200ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .project__close:hover { transform: rotate(90deg); }
  .project__close:active { transform: rotate(90deg) scale(0.92); }
}

.project__scroll { padding: 48px; outline: none; }

/* --------------------------------------------------------------------------
   Case-study content            partials/project-head.html, src/projects/*.html
   -------------------------------------------------------------------------- */
.project__content { display: flex; flex-direction: column; gap: var(--stack); }

.project__head { display: flex; flex-direction: column; gap: 32px; padding-right: 56px; }
.project__title { font-size: var(--size-2xl); line-height: var(--leading-2xl); }
.project__meta { display: flex; flex-wrap: wrap; gap: 8px 32px; color: var(--ink-dim); }
.project__meta div { display: flex; gap: 0.3em; }
.project__meta dd { margin: 0; }

.project__section { display: flex; flex-direction: column; gap: 16px; color: var(--ink-dim); }
.project__h2 { font-size: var(--size-xl); line-height: var(--leading-xl); color: var(--ink); }
.project__h3 { font-size: var(--size-lg); line-height: var(--leading-lg); color: var(--ink); }
.project__year { color: var(--ink); }
/* Body blocks after the first are a blank line (24px) apart; heading → body stays 16px */
.project__section > :is(p, ul):not(.project__year) + :is(p, ul) { margin-top: 8px; }
.project__list { list-style: disc; padding-left: 24px; }
/* Case-study body copy is Regular; headings and the year stay Medium */
.project__section > :is(p, ul):not(.project__year) { font-weight: var(--weight-regular); }

.project__media {
  position: relative;
  background: var(--skeleton); /* placeholder until the image covers it */
  border-radius: var(--radius-card);
  overflow: hidden;
  aspect-ratio: 4 / 3;
  /* On shorter screens (laptops) the frame gets shorter instead of filling the view;
     it stays full width and the image crops a little less from the sides */
  max-height: clamp(320px, 68vh, 620px);
}
.project__media img { width: 100%; height: 100%; object-fit: cover; }
/* Captioned media (e.g. Old design / New design): label below the frame,
   styled like the previous/next labels */
.project__figure { display: flex; flex-direction: column; gap: 24px; }
.project__caption {
  text-align: center;
  color: var(--ink-faint);
  font-size: var(--size-sm);
  line-height: var(--leading-sm);
  font-weight: var(--weight-regular);
}
/* Videos sit on a solid stage colour taken from the original case study */
.project__media--video { position: relative; background: var(--media-bg, #1c2123); }
.project__media--video video { display: block; width: 100%; height: 100%; object-fit: cover; }
/* Whole recording visible, centred on the stage */
.project__media--video.is-contain video { position: absolute; inset: 1% 0; height: 98%; object-fit: contain; }

/* --------------------------------------------------------------------------
   Loading                                             partials/skeleton.html
   Shimmer used by placeholders. On a fast connection none of this shows:
   media only gets .is-loading if it isn't already cached, and the shimmer
   waits 150ms before fading in, so quick loads just fade the image in.
   -------------------------------------------------------------------------- */
@keyframes skeleton-shimmer {
  from { background-position: 150% 0; }
  to   { background-position: -50% 0; }
}
@keyframes skeleton-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.shimmer {
  background-color: var(--skeleton);
  background-image: linear-gradient(100deg, transparent 20%, var(--skeleton-shine) 50%, transparent 80%);
  background-size: 200% 100%;
  animation: skeleton-shimmer 1.4s linear infinite;
}

/* Images and videos still on their way (class added by main.js) */
.project__media img,
.project__media video { transition: opacity 300ms ease; } /* card images: see .card__media img */
.card__media.is-loading,
.project__media.is-loading { background: var(--skeleton); }
.is-loading > img,
.is-loading > video { opacity: 0; }
.card__media.is-loading::before,
.project__media.is-loading::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background-image: linear-gradient(100deg, transparent 20%, var(--skeleton-shine) 50%, transparent 80%);
  background-size: 200% 100%;
  opacity: 0;
  animation: skeleton-shimmer 1.4s linear infinite, skeleton-in 250ms ease 150ms forwards;
}

/* Project skeleton: shown in the overlay while a case study is still loading */
.skeleton { display: flex; flex-direction: column; gap: var(--stack); }
.skeleton__group { display: flex; flex-direction: column; gap: 16px; }
.skeleton__line { height: 14px; margin-block: 5px; border-radius: 7px; }
.skeleton__line--meta { width: 45%; }
.skeleton__line--heading { height: 28px; width: 55%; border-radius: 10px; }
.skeleton__line--short { width: 62%; }
.skeleton__block { aspect-ratio: 4 / 3; max-height: clamp(320px, 68vh, 620px); border-radius: var(--radius-card); }

/* Previous / next                                     partials/project-more.html */
.project__more li { display: flex; flex-direction: column; gap: 24px; }
.project__more-label { text-align: center; color: var(--ink-faint); }

/* --------------------------------------------------------------------------
   Phones
   -------------------------------------------------------------------------- */
@media (max-width: 640px) {
  .work__grid { grid-template-columns: minmax(0, 1fr); gap: 40px; }
  .project__scroll { padding: 32px 24px 48px; }
  .project__close { top: 16px; right: 16px; width: 44px; height: 44px; }
  .project__head { gap: 20px; }
}

@media (prefers-reduced-motion: reduce) {
  .card__media, .card__media img, .project__close { transition: none; }
  .shimmer, .is-loading::before { animation: none; background-image: none; }
  .card__media.is-loading::before, .project__media.is-loading::before { content: none; }
  .copied, .copy.is-copied + .copied { transform: none; filter: none; transition: opacity 150ms linear; }
}


/* ==========================================================================
   Home page: layout, hero gradient, and the project overlay
   ========================================================================== */
.page {
  position: relative;
  width: min(var(--measure), 100% - 2 * var(--gutter));
  margin-inline: auto;
  padding-block: 64px 32px;
  display: flex;
  flex-direction: column;
  gap: var(--stack);
}
.intro { display: flex; flex-direction: column; gap: 24px; }
.work { display: flex; flex-direction: column; gap: var(--stack); }

/* --------------------------------------------------------------------------
   Aurora: animated hero gradient
   Sky → bg linear (Figma) toned down by --sky-amt, plus two colour fields
   drifting over it. Fields fade out well before the 480px edge so a drifting
   blob can never be clipped into a hard line.

   Colour themes: the three colours are registered properties, so the browser
   can blend between them. main.js switches data-theme every 10s; each theme
   takes its colours from one of the projects. Browsers without @property
   just switch without the blend.
   -------------------------------------------------------------------------- */
@property --aurora-sky { syntax: "<color>"; inherits: true; initial-value: #dbf5ff; }
@property --aurora-a   { syntax: "<color>"; inherits: true; initial-value: rgb(147 156 254); }
@property --aurora-b   { syntax: "<color>"; inherits: true; initial-value: rgb(168 226 255); }

.aurora {
  --sky-amt: 0.6; /* 1 = Figma strength */
  /* StudySmarter (default, the Figma colours) */
  --aurora-sky: #dbf5ff;
  --aurora-a: rgb(147 156 254);
  --aurora-b: rgb(168 226 255);
  transition:
    --aurora-sky 3s var(--ease-inout),
    --aurora-a 3s var(--ease-inout),
    --aurora-b 3s var(--ease-inout);
  position: absolute;
  inset: 0 0 auto 0;
  height: 480px;
  overflow: hidden;
  pointer-events: none;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--aurora-sky) calc(var(--sky-amt) * 100%), var(--bg)) 0%,
    color-mix(in srgb, var(--aurora-sky) calc(var(--sky-amt) * 40%), var(--bg)) 60%,
    color-mix(in srgb, var(--aurora-sky) calc(var(--sky-amt) * 17%), var(--bg)) 80%,
    color-mix(in srgb, var(--aurora-sky) calc(var(--sky-amt) * 5%), var(--bg)) 92%,
    var(--bg) 100%);
}
.aurora[data-theme="bumble"] {
  --aurora-sky: #efebff;
  --aurora-a: rgb(176 156 246);  /* softened Badoo purple, similar weight to the StudySmarter periwinkle */
  --aurora-b: rgb(246 196 230);
}
.aurora[data-theme="macropinch"] {
  --aurora-sky: #d8f0f8;
  --aurora-a: rgb(110 180 220);
  --aurora-b: rgb(150 230 210);
}
.aurora__fields {
  position: absolute;
  inset: 0;
  --fade: linear-gradient(180deg,
    #000 0%, #000 40%,
    rgb(0 0 0 / 0.75) 55%,
    rgb(0 0 0 / 0.42) 70%,
    rgb(0 0 0 / 0.16) 84%,
    rgb(0 0 0 / 0.04) 94%,
    transparent 100%);
  -webkit-mask-image: var(--fade);
          mask-image: var(--fade);
}
.aurora__blob {
  position: absolute;
  border-radius: 50%;
  will-change: transform;
  animation: var(--anim) var(--dur) var(--ease-inout) infinite alternate;
}
/* Main field: Figma radial, centre (259.5, -16.5), semi-axes 617 × 300 at 40.3° */
.aurora__blob--1 {
  width: 1235px; height: 600px;
  left: calc(259.5px - 617.5px); top: calc(-16.5px - 300px);
  background: radial-gradient(closest-side, color-mix(in srgb, var(--aurora-a) 40%, transparent), transparent);
  transform: rotate(40.3deg);
  --anim: drift-violet; --dur: 14s;
}
/* Second field: extra, not in Figma */
.aurora__blob--2 {
  width: 1000px; height: 560px;
  right: -360px; top: -320px;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--aurora-b) 42%, transparent), transparent);
  transform: rotate(-20deg);
  --anim: drift-cyan; --dur: 17s;
}
@keyframes drift-violet {
  0%   { transform: translate3d(0, 0, 0) rotate(40.3deg) scale(1); }
  33%  { transform: translate3d(320px, -30px, 0) rotate(58deg) scale(1.1); }
  66%  { transform: translate3d(140px, 50px, 0) rotate(26deg) scale(0.9); }
  100% { transform: translate3d(-120px, -20px, 0) rotate(50deg) scale(1.06); }
}
@keyframes drift-cyan {
  0%   { transform: translate3d(0, 0, 0) rotate(-20deg) scale(1); }
  50%  { transform: translate3d(-420px, 40px, 0) rotate(2deg) scale(1.12); }
  100% { transform: translate3d(-180px, -30px, 0) rotate(-34deg) scale(0.9); }
}

/* --------------------------------------------------------------------------
   Project overlay (<dialog>). The case study is fetched from its own page
   and dropped into the panel; motion is driven from main.js.
   -------------------------------------------------------------------------- */
/* Page scroll is locked while open; padding stands in for the removed
   scrollbar so nothing shifts (width measured in JS) */
html.is-locked { overflow: hidden; }
html.is-locked body { padding-right: var(--scrollbar-w, 0px); }
html.is-locked .aurora { right: var(--scrollbar-w, 0px); }

.project {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ink); /* <dialog> UA styles reset colour to black */
  overflow: hidden;
  overflow: clip; /* not even focus can scroll it (iOS scrolls hidden overflow to reveal focus) */
}
.project::backdrop { background: transparent; }

.project__scrim {
  position: absolute;
  inset: 0;
  background: var(--scrim);
  -webkit-backdrop-filter: blur(24px) saturate(1.8);
          backdrop-filter: blur(24px) saturate(1.8);
  opacity: 0;
  transition: opacity 250ms var(--ease-out);
}
.project.is-open .project__scrim { opacity: 1; }
.project.is-closing .project__scrim { transition: opacity 160ms cubic-bezier(0.4, 0, 1, 1); } /* = CLOSE_MS */

.project .project__panel {
  position: absolute;
  top: 48px;
  bottom: 48px;
  left: 0;
  right: 0;
  margin-inline: auto;
  width: min(var(--panel-width), 100% - 2 * var(--gutter));
}
.project .project__scroll {
  position: relative;
  height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  overflow-anchor: none; /* lazy images loading above must not shift the view */
}

/* Overlay scrollbar, Apple-style: thin, inset, only visible while scrolling.
   Native bar hidden on fine pointers only; touch keeps the OS overlay bar. */
.project__bar { display: none; }
@media (hover: hover) and (pointer: fine) {
  .project .project__scroll { scrollbar-width: none; }
  .project .project__scroll::-webkit-scrollbar { display: none; }
  .project__bar {
    display: block;
    position: absolute;
    top: 24px;
    bottom: 24px;
    right: 4px;
    width: 14px;
    z-index: 3;
    opacity: 0;
    transition: opacity 400ms var(--ease-out);
  }
  .project__bar[hidden] { display: none; }
  .project__bar.is-active,
  .project__bar:hover,
  .project__bar.is-dragging { opacity: 1; transition-duration: 150ms; }
  .project__thumb {
    position: absolute;
    top: 0;
    right: 3px;
    width: 6px;
    border-radius: 6px;
    background: rgba(0, 0, 0, 0.32);
    will-change: transform;
    transition: width 150ms var(--ease-out), background-color 150ms var(--ease-out);
  }
  .project__bar:hover .project__thumb,
  .project__bar.is-dragging .project__thumb { width: 9px; background: rgba(0, 0, 0, 0.45); }
}

@media (max-width: 640px) {
  .page { padding-block: 48px 32px; }
  .project .project__panel { top: 12px; bottom: 12px; width: calc(100% - 24px); }
  .project__scrim { -webkit-backdrop-filter: blur(12px) saturate(1.8); backdrop-filter: blur(12px) saturate(1.8); } /* lighter on phones */
  .project.is-closing .project__scrim { transition: opacity 280ms cubic-bezier(0.4, 0, 1, 1); } /* = SHEET_CLOSE_MS */
}

@media (prefers-reduced-motion: reduce) {
  .aurora__blob { animation: none; }
  .aurora { transition: none; }
}


/* ==========================================================================
   Standalone project page (/<project>/)
   The same panel as the overlay, sitting in the page instead of floating
   over it: what visitors see when they open a project link directly.
   ========================================================================== */
.project-page {
  width: min(var(--panel-width), 100% - 2 * var(--gutter));
  margin: 48px auto;
  display: flex;
  flex-direction: column;
  gap: var(--stack);
}
.project-page > .footer { padding: 0 48px 16px; }

@media (max-width: 640px) {
  .project-page { width: calc(100% - 24px); margin: 12px auto 48px; }
  .project-page > .footer { padding: 0 24px; }
}
