/* ==========================================================================
   components.css — Styles for reusable components (header, footer, card…)
   Always reference var(--token); never hard-code colours or fonts.
   ========================================================================== */

/* ---------- Site header (overlay; scrolls with the page) ---------- */
.site-header {
  position: absolute;
  inset: 0 0 auto 0;
  z-index: 100;
  height: var(--header-height);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding-inline: var(--space-md);
}

.site-header__title {
  display: none; /* hidden unless the page opts in via data-show-title */
  flex-direction: column;
  line-height: 1;
}

/* Pages opt in by adding data-show-title to the header include slot. */
[data-show-title] .site-header__title {
  display: flex;
}

.site-header__title:hover {
  text-decoration: none;
}

.site-header__name {
  font-family: var(--font-display);
  font-size: 2rem; /* 32px */
}

.site-header__subtitle {
  margin-top: 0.25em;
  font-weight: var(--font-weight-medium);
  font-style: italic;
  font-size: var(--text-note-size);
  line-height: var(--text-note-lh);
}

/* Collapse the subtitle line when the page didn't set one, so the title
   block can show the name on its own. */
.site-header__subtitle:empty {
  display: none;
}

.site-nav {
  display: flex;
  gap: var(--space-sm);
  margin-left: auto; /* keep nav right-aligned even when the title is hidden */
  font-weight: var(--font-weight-medium);
  font-size: var(--text-paragraph-size);
}

.site-header a {
  text-decoration: none;
  color: var(--color-text);
}

/* Light header text (cream) for pages whose content sits behind the header —
   a hero or full-bleed banner. Opt in with data-header-light on the include
   slot. The shadow keeps it legible over imagery. */
[data-header-light] .site-header {
  color: var(--brand-background);
}

[data-header-light] .site-header a {
  color: var(--brand-background);
}

/* Active page in the nav (set by main.js) */
.site-nav a[aria-current="page"] {
  text-decoration: none;
}

/* ---------- Site footer ---------- */
.site-footer {
  background: var(--color-bg);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  padding-block: var(--space-md);
  padding-inline: var(--space-lg);
}

.site-footer__inner {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-md);
  padding-top: var(--space-md); /* gap below the divider line */
  border-top: 1px solid var(--brand-main-1);
  color: var(--brand-main-1);
}

.site-footer__name {
  font-family: var(--font-display);
  font-size: var(--text-subhead-size);
  color: var(--brand-main-1);
}

.site-footer__email {
  font-weight: var(--font-weight-medium);
  font-size: var(--text-paragraph-size);
  line-height: var(--text-paragraph-lh);
  color: var(--brand-main-1);
}

.site-footer a:hover {
  color: var(--brand-main-2);
  text-decoration: none;
}

@media (max-width: 768px) {
  .site-footer {
    padding-inline: var(--space-sm);
  }

  .site-footer__inner {
    flex-direction: column-reverse;
    gap: var(--space-sm);
  }
}

/* ---------- Card ---------- */
.card {
  display: block;
  padding: var(--space-md);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text);
}

.card:hover {
  border-color: var(--color-primary);
  text-decoration: none;
}

.card h3 {
  margin-bottom: var(--space-xs);
}

.card p {
  margin: 0;
  color: var(--color-muted);
}

/* Grid for laying out cards */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--space-md);
}

/* ---------- Hero ---------- */
.hero {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  min-height: 90vh;
  margin-top: calc(-1 * var(--header-height)); /* sit behind the fixed header */
  padding: var(--space-lg) var(--space-md) var(--space-lg);
  background-image: url("/assets/img/qt-notext.jpg");
  background-size: cover;
  background-position: center;
  overflow: hidden;
  color: var(--brand-background);
}

/* Fade the bottom of the hero into the page background. */
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(115, 40, 167, 0.5) 30%, var(--color-bg) 100%);
  pointer-events: none;
}

.hero > * {
  position: relative;
  z-index: 1;
  margin: 0;
}

.hero__eyebrow {
  font-weight: var(--font-weight-medium);
  font-size: var(--text-subhead-size);
  text-transform: uppercase;
}

.hero__name {
  font-family: var(--font-display);
  font-weight: var(--font-weight-normal);
  font-size: clamp(2.5rem, 9vw, 76px);
  line-height: 1;
  margin-block: 0.15em;
}

.hero__subtitle {
  font-weight: var(--font-weight-medium);
  font-size: var(--text-emphasis-size);
  line-height: var(--text-emphasis-lh);
}

/* ---------- Project highlights ---------- */
.highlights {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-lg);
  padding: var(--space-lg) var(--space-md);
  /* Contain the reveal's horizontal slide without creating a scroll container
     (clip, unlike hidden, keeps the view() timeline referencing the page). */
  overflow-x: clip;
}

.project-highlight {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  width: 100%;
  max-width: 1000px;
}

/* Alternate the image to the opposite side on every other highlight. */
.highlights > *:nth-child(even) .project-highlight {
  flex-direction: row-reverse;
}

.project-highlight__media {
  flex: 0 0 400px;
  width: 400px;
  aspect-ratio: 1;
  border-radius: var(--radius-md);
  overflow: hidden;
}

.project-highlight__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.project-highlight__media:hover {
  text-decoration: none;
}

.project-highlight__body {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.project-highlight__heading {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.project-highlight__role {
  margin: 0;
  font-weight: var(--font-weight-medium);
  font-size: var(--text-subhead-size);
  text-transform: uppercase;
  color: var(--brand-main-1);
}

.project-highlight__title {
  margin: 0;
  font-size: var(--text-h2-size);
  font-weight: var(--font-weight-bold);
  line-height: 1.2;
  color: var(--color-text);
}

.project-highlight__text {
  margin: 0;
  font-size: var(--text-paragraph-size);
  line-height: var(--text-paragraph-lh);
  color: var(--color-text);
}

.project-highlight__badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
}

.badge {
  padding: var(--space-xs);
  border-radius: var(--radius-md);
  background: var(--brand-main-0);
  color: var(--brand-main-2);
  font-size: var(--text-note-size);
  font-weight: var(--font-weight-medium);
  line-height: 1;
  text-transform: uppercase;
}

.project-highlight__cta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  align-self: flex-start;
  padding-block: var(--space-xs);
  color: var(--brand-main-2);
  font-weight: var(--font-weight-medium);
  font-size: var(--text-subhead-size);
  text-transform: uppercase;
}

.project-highlight__cta:hover {
  color: var(--color-primary-hover);
  text-decoration: none;
}

/* Stack image above text on narrow screens. */
@media (max-width: 768px) {
  .project-highlight,
  .highlights > *:nth-child(even) .project-highlight {
    flex-direction: column;
    align-items: stretch;
  }

  .project-highlight__media {
    flex-basis: auto;
    width: 100%;
    max-width: 400px;
  }
}

/* Scroll-driven reveal: the text slides in from its outer edge and fades in as
   it rises to the viewport centre, then stays in place once scrolled past.
   Uses a view() timeline so it tracks scroll position (and reverses on the way
   in) for free. 0% = entering at the bottom, 50% = centred, 100% = leaving the
   top; holding the centred state from 50%–100% keeps it put after it's passed.
   Gated on @supports so unsupported browsers just show the text normally. */
@keyframes highlight-reveal {
  0% { opacity: 0; transform: translateX(4rem); }
  50% { opacity: 1; transform: translateX(0); }
  100% { opacity: 1; transform: translateX(0); }
}

/* Mirror image for the alternating (image-right) rows. */
@keyframes highlight-reveal-mirror {
  0% { opacity: 0; transform: translateX(-4rem); }
  50% { opacity: 1; transform: translateX(0); }
  100% { opacity: 1; transform: translateX(0); }
}

/* The image mirrors the text's slide — same motion from the opposite edge,
   no opacity change — so the two converge into place together. */
@keyframes highlight-reveal-media {
  0% { transform: translateX(-4rem); }
  50% { transform: translateX(0); }
  100% { transform: translateX(0); }
}

@keyframes highlight-reveal-media-mirror {
  0% { transform: translateX(4rem); }
  50% { transform: translateX(0); }
  100% { transform: translateX(0); }
}

@supports (animation-timeline: view()) {
  .project-highlight__body {
    animation: highlight-reveal linear both;
    animation-timeline: view();
  }

  .project-highlight__media {
    animation: highlight-reveal-media linear both;
    animation-timeline: view();
  }

  .highlights > *:nth-child(even) .project-highlight__body {
    animation-name: highlight-reveal-mirror;
  }

  .highlights > *:nth-child(even) .project-highlight__media {
    animation-name: highlight-reveal-media-mirror;
  }
}

@media (prefers-reduced-motion: reduce) {
  .project-highlight__body,
  .project-highlight__media {
    animation: none;
  }
}

/* ---------- Project banner (work page) ---------- */
.projects {
  display: flex;
  flex-direction: column;
}

/* First banner sits behind the fixed header, like the hero. */
.projects > :first-child {
  margin-top: calc(-1 * var(--header-height));
}

/* Scroll-snap the work page (html has class="snap") so each full-height
   banner locks into place, with a smooth glide between them. */
html.snap {
  scroll-snap-type: y mandatory;
  scroll-behavior: smooth;
}

html.snap .project {
  scroll-snap-align: start;
}

/* On the work page the footer overlays the bottom of the last banner as a
   solid background-colour band, rather than being its own section. Taking it
   out of flow anchors it to the page bottom (= the last banner's bottom). */
html.snap body {
  position: relative;
}

html.snap .site-footer {
  position: absolute;
  inset: auto 0 0 0;
  z-index: 50;
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  color: var(--brand-background);
}

/* Over the banner the whole footer is cream (name, email, divider). */
html.snap .site-footer__inner {
  border-top-color: var(--brand-background);
  color: var(--brand-background);
}

html.snap .site-footer__name,
html.snap .site-footer__email,
html.snap .site-footer a:hover {
  color: var(--brand-background);
}

/* Don't force smooth motion on users who'd rather not have it. */
@media (prefers-reduced-motion: reduce) {
  html.snap {
    scroll-behavior: auto;
  }
}

.project {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  min-height: 100dvh; /* fill the viewport; dvh accounts for mobile browser UI */
  padding: var(--space-lg) var(--space-md);
  overflow: hidden;
  color: var(--brand-background);
  text-align: center;
  text-shadow: 0 0 8px rgba(0, 0, 0, 0.25);
}

/* Background image and colour overlay are set per-instance via custom
   properties on the element's style attribute. Shared with .project-header. */
.project::before,
.project::after,
.project-header::before,
.project-header::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.project::before,
.project-header::before {
  background-image: var(--project-image);
  background-size: cover;
  background-position: center;
}

.project::after,
.project-header::after {
  background: var(--project-overlay, transparent);
}

.project__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-lg);
  width: 100%;
  max-width: 540px;
}

.project__name {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-subhead-size);
}

.project__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-lg);
  width: 100%;
}

.project__meta {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  text-align: left;
}

.project__meta dt {
  font-family: var(--font-display);
  font-size: var(--text-subhead-size);
}

.project__meta dd {
  margin: 0;
  font-weight: var(--font-weight-medium);
  font-size: var(--text-paragraph-size);
  line-height: var(--text-paragraph-lh);
}

.project__logo {
  flex-shrink: 0;
  width: auto;
  max-width: 223px;
  max-height: 200px;
  object-fit: contain;
  opacity: 0.8;
}

.project__links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-lg);
}

.project__button {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  padding-block: var(--space-xs);
  color: var(--brand-background);
  font-weight: var(--font-weight-medium);
  font-size: var(--text-subhead-size);
  text-transform: uppercase;
}

.project__button:hover {
  color: var(--brand-background);
  text-decoration: underline;
}

@media (max-width: 768px) {
  .project__row {
    flex-direction: column-reverse;
    align-items: flex-start;
    gap: var(--space-md);
  }

  .project__links {
    flex-direction: column;
    align-items: center;
    gap: var(--space-xs);
  }

  .project__logo {
    max-width: 100px;
  }
}

/* ---------- Project header (case-study top) ---------- */
.project-header {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  padding: calc(var(--header-height) + var(--space-lg)) var(--space-md) var(--space-lg);
  color: var(--brand-background);
  text-shadow: 0 0 8px rgba(0, 0, 0, 0.25);
}

/* ---------- Case study (project detail) ---------- */
.case {
  background: var(--brand-main-0);
}

/* First element (the project header) sits behind the fixed site header. */
.case > :first-child {
  margin-top: calc(-1 * var(--header-height));
}

.case__section {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-lg);
  padding: var(--space-lg) var(--space-md);
  background: var(--color-bg);
}

.case__intro,
.case__split,
.case__stats {
  display: flex;
  gap: var(--space-lg);
  width: 100%;
  max-width: 900px;
}

.case__intro,
.case__split {
  align-items: flex-start;
}

.case__split {
  justify-content: space-between;
}

/* Left column of the intro (title / subtitle / note) */
.case__intro-heading {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.case__title {
  margin: 0;
  font-size: var(--text-h2-size);
  font-weight: var(--font-weight-bold);
  line-height: 1.2;
  color: var(--color-text);
}

.case__subtitle {
  margin: 0;
  font-weight: var(--font-weight-medium);
  font-size: var(--text-subhead-size);
  text-transform: uppercase;
  color: var(--color-text);
}

.case__note {
  margin: 0;
  font-weight: var(--font-weight-medium);
  font-style: italic;
  font-size: var(--text-note-size);
  line-height: var(--text-note-lh);
  color: var(--color-text);
}

/* Section heading on the left of a split row */
.case__heading {
  flex-shrink: 0;
  margin: 0;
  font-size: var(--text-h2-size);
  font-weight: var(--font-weight-bold);
  line-height: 1.2;
  color: var(--color-text);
}

/* Body copy column (shared by intro and split sections) */
.case__body {
  flex: 0 1 500px;
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.case__body p {
  margin: 0;
  font-size: var(--text-paragraph-size);
  line-height: var(--text-paragraph-lh);
  color: var(--color-text);
}

.case__body .lead {
  font-weight: var(--font-weight-bold);
}

/* Stats row */
.case__stats {
  justify-content: space-between;
}

.case__stat {
  display: flex;
  flex-direction: column;
}

.case__stat-label {
  margin: 0;
  font-weight: var(--font-weight-medium);
  font-size: var(--text-subhead-size);
  text-transform: uppercase;
  color: var(--brand-main-2);
}

.case__stat-value {
  margin: 0;
  font-size: var(--text-h2-size);
  font-weight: var(--font-weight-bold);
  color: var(--color-text);
}

/* Stats rise into place as the row scrolls into view, staggered left→right.
   The stagger comes from offsetting each stat's scroll range a little later
   (scroll timelines have no time delays), then they hold once revealed. */
@keyframes stat-rise {
  from { opacity: 0; transform: translateY(2rem); }
  to { opacity: 1; transform: translateY(0); }
}

@supports (animation-timeline: view()) {
  .case__stat {
    animation: stat-rise linear both;
    animation-timeline: view();
    animation-range: cover 8% cover 30%;
  }

  .case__stat:nth-child(2) {
    animation-range: cover 16% cover 38%;
  }

  .case__stat:nth-child(3) {
    animation-range: cover 24% cover 46%;
  }
}

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

/* Retailer band */
.case__band {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-lg) var(--space-md);
  background: var(--brand-main-1);
  color: var(--brand-background);
  text-align: center;
}

.case__band-title {
  margin: 0;
  font-weight: var(--font-weight-medium);
  font-size: var(--text-paragraph-size);
}

.coming-soon {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-xs) var(--space-md);
  background: var(--brand-contrast-0);
  text-align: center;
}

.coming-soon-title {
  margin: 0;
  font-weight: var(--font-weight-medium);
  font-size: var(--text-subhead-size);
  text-transform: uppercase;
  color: var(--brand-contrast-2);
}

/* Purple accent variant (e.g. the "coming soon" band) */
.case__band--accent {
  background: var(--brand-contrast-0);
  color: var(--brand-contrast-3);
}

.case__retailers {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-md);
  width: 100%;
  max-width: 688px;
}

.case__retailers img {
  opacity: 0.65;
}

.case__retailer {
  font-family: var(--font-display);
  font-size: var(--text-subhead-size);
  text-transform: uppercase;
  opacity: 0.85;
}

/* Full-bleed and contained case images */
.case__media {
  display: flex;
  gap: 4em;
  justify-content: center;
  background: var(--brand-main-0);
  margin: 0;
}

.case__media img {
  display: block;
  width: 100%;
}

.case__media--contained {
  padding: var(--space-lg) var(--space-xs);
}

.case__media--contained img {
  max-width: 900px;
}

.bro {
  background: radial-gradient(297.51% 50% at 50% 50%, #1A212A 70%, #000 100%);
  width: 100%;
  margin: 0;
  padding: 80px 1em;
}

.bro img {
  border-radius: var(--radius-lg);
  max-width: 400px;
  width: 40%;
}

.bro-full {
  background: radial-gradient(297.51% 50% at 50% 50%, #1A212A 70%, #000 100%);
  margin: 0;
  padding: 0;
}

img.bro-screen {
  height: 500px;
  width: auto;
}

@media (max-width: 768px) {
  .case__intro,
  .case__split  {
    flex-direction: column;
  }

  .case__body {
  flex: 0 1;
  }

  .case__media  {
    flex-direction: column;
    align-items: center;
  }

  .bro img {
    width: 100%;
  }

  .case__retailers {
    grid-template-columns: repeat(2, 1fr);
  }

  .case__stats {
    flex-wrap: wrap;
  }
}

/* ---------- Project nav (prev / next at the foot of a case study) ---------- */
.project-nav {
  background: var(--color-bg);
  padding: var(--space-lg) var(--space-md);
}

.project-nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  width: 100%;
  max-width: 1000px;
  margin-inline: auto;
}

.project-nav__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  color: var(--color-text);
  font-weight: var(--font-weight-medium);
  font-size: var(--text-subhead-size);
  text-transform: uppercase;
}

.project-nav__link:hover {
  color: var(--brand-main-2);
  text-decoration: none;
}

/* ---------- About page ---------- */
.about {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-lg);
  padding: var(--space-lg) var(--space-md);
}

/* Shared text accents on the about page */
.about__eyebrow {
  margin: 0;
  font-weight: var(--font-weight-medium);
  font-size: var(--text-subhead-size);
  text-transform: uppercase;
  color: var(--brand-main-1);
}

.about__display {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--font-weight-normal);
  font-size: var(--text-subhead-size);
  color: var(--color-text);
}

.about__heading {
  margin: 0;
  font-size: var(--text-h2-size);
  font-weight: var(--font-weight-bold);
  line-height: 1.2;
  color: var(--color-text);
}

/* Body copy blocks */
.prose {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.prose p {
  margin: 0;
  font-size: var(--text-paragraph-size);
  line-height: var(--text-paragraph-lh);
  color: var(--color-text);
}

/* Intro: avatar + bio */
.about__intro {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-md);
  width: 100%;
  max-width: 900px;
}

.about__avatar {
  width: 300px;
  height: 300px;
  border-radius: 1000px;
  object-fit: cover;
}

.about__bio {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

/* Approach: image + text */
.about__feature {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  width: 100%;
  max-width: 1000px;
}

.about__feature-img {
  flex: 0 0 394px;
  width: 394px;
  height: 281px;
  border-radius: var(--radius-lg);
  object-fit: cover;
}

.about__feature-body {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

/* Current role + experience columns */
.about__columns {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: var(--space-lg);
  width: 100%;
  max-width: 1000px;
}

.about__role {
  flex: 0 1 600px;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.about__experience {
  flex: 0 0 300px;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.about__jobs {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.about__job-title {
  margin: 0;
  font-size: var(--text-paragraph-size);
  font-weight: var(--font-weight-bold);
  line-height: var(--text-paragraph-lh);
  color: var(--color-text);
}

.about__job-date {
  margin: 0;
  font-size: var(--text-paragraph-size);
  font-weight: var(--font-weight-medium);
  line-height: var(--text-paragraph-lh);
  color: var(--brand-main-2);
}

@media (max-width: 768px) {
  .about__feature {
    flex-direction: column;
    align-items: stretch;
  }

  .about__feature-img {
    flex-basis: auto;
    width: 100%;
    height: auto;
    aspect-ratio: 394 / 281;
  }

  .about__columns {
    flex-direction: column;
  }

  .about__role,
  .about__experience {
    flex-basis: auto;
    width: 100%;
  }
}

/* ---------- Media block (image/video + caption) ---------- */
.media {
  margin-block: var(--space-md);
}

.media img,
.media video {
  border-radius: var(--radius-sm);
  width: 100%;
}

.media__caption {
  margin-top: var(--space-xs);
  color: var(--color-muted);
  font-size: var(--text-sm);
}
