/* ==========================================================
   MARTIN TIGHE — PORTFOLIO
   Technical / spec-sheet aesthetic, kept deliberately sparse:
   clean white ground, one neon accent, generous negative space.
   ========================================================== */

:root {
  --bg: #ffffff;
  --bg-panel: #f6f6f6;
  --ink: #0d0d0d;
  --ink-soft: #6e6e6e;
  --ink-faint: #b3b3b3;
  --line: #e4e4e4;
  --accent: #4443f5;
  --accent-ink: #ffffff;
  --footer-bg: #4443f5;
  --footer-ink: #ffffff;

  --font-mono: "IBM Plex Mono", "SFMono-Regular", Menlo, Consolas, monospace;

  --nav-h: 64px;
  --container-max: 1320px;
  --gutter: clamp(20px, 5vw, 64px);
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

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

/* ---------- Nav ---------- */

.site-nav {
  position: sticky;
  top: 0;
  z-index: 50;
  border-bottom: 1px solid var(--accent);
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(10px);
}

.nav-inner {
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 var(--gutter);
  height: var(--nav-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.site-nav .brand {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-weight: 500;
}

.site-nav .brand span {
  color: var(--ink-soft);
  font-weight: 400;
}

.site-nav .nav-links {
  display: flex;
  gap: clamp(16px, 3vw, 28px);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.site-nav .nav-links a {
  position: relative;
}

.site-nav .nav-links a::before {
  content: "[";
  margin-right: 1px;
  opacity: 0;
  transition: opacity 0.15s ease;
}

.site-nav .nav-links a::after {
  content: "]";
  margin-left: 1px;
  opacity: 0;
  transition: opacity 0.15s ease;
}

.site-nav .nav-links a:hover::before,
.site-nav .nav-links a:hover::after,
.site-nav .nav-links a.active::before,
.site-nav .nav-links a.active::after {
  opacity: 1;
}

/* ---------- Layout shell ---------- */

.page {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
}

/* ---------- Home / hover list ---------- */

.showcase {
  --showcase-pt: clamp(64px, 12vh, 140px);
  position: relative;
  flex: 1;
  display: grid;
  grid-template-columns: minmax(300px, 460px) 1fr;
  gap: clamp(48px, 9vw, 140px);
  padding-top: calc(var(--showcase-pt) + 30px);
  padding-bottom: clamp(64px, 12vh, 140px);
}

.showcase-flourish {
  position: absolute;
  top: var(--showcase-pt);
  left: var(--gutter);
  width: 22px;
  height: auto;
  opacity: 0.8;
}

.campaign-list {
  list-style: none;
  margin: 0;
  padding: 0;
  align-self: start;
}

.campaign-list a {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 5px 2px;
  overflow: hidden;
  transition: padding-left 0.25s var(--ease);
}

.campaign-list a:hover,
.campaign-list a:focus-visible,
.campaign-list a.is-active {
  padding-left: 8px;
}

.campaign-list .title {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.01em;
  font-weight: 400;
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: font-weight 0.15s ease, color 0.15s ease;
}

.campaign-list a:hover .title,
.campaign-list a.is-active .title {
  font-weight: 600;
}

.campaign-list .meta {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-faint);
  white-space: nowrap;
  flex: 0 0 auto;
  transition: opacity 0.15s ease;
}

.campaign-list .chip {
  position: absolute;
  right: 2px;
  top: 50%;
  transform: translateY(-50%) translateX(-4px);
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-ink);
  background: var(--accent);
  padding: 2px 6px;
  border-radius: 2px;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.campaign-list a:hover .chip,
.campaign-list a.is-active .chip {
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}

.campaign-list a:hover .meta,
.campaign-list a.is-active .meta {
  opacity: 0;
}

/* Preview panel — its height is set in JS to match the campaign
   list's own height exactly, so it stays in sync however many
   campaigns there are. The frame's width is also set in JS, from
   whichever image is currently showing, so every image keeps its
   own true aspect ratio instead of being cropped/stretched to a
   fixed box. object-fit: contain below is just a safety net. */

.preview-panel {
  position: sticky;
  top: calc(var(--nav-h) + 56px);
  width: 100%;
  overflow: hidden;
  background: transparent;
}

.preview-frame {
  position: relative;
  width: 100%;
  height: 100%;
  margin-left: auto;
}

.preview-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0;
  transition: opacity 1.1s var(--ease);
}

.preview-img.is-visible {
  opacity: 1;
}

/* Mobile card grid (replaces hover list + panel below breakpoint) */

.campaign-grid {
  display: none;
}

/* ---------- Opening animation (homepage only) ----------
   js/intro.js decides up front (once per browser session, and never for
   prefers-reduced-motion) whether this plays. When it does, js/intro-run.js
   fades a huge centred smiley in, then shrinks/moves it into the exact
   spot .showcase-flourish already occupies while the real page fades in
   underneath. Scoped to body.home so it can't affect about/case-study. */

body.home .site-nav,
body.home main.page,
body.home .site-footer {
  opacity: 0;
  pointer-events: none;
}

body.home .site-nav.is-revealed,
body.home main.page.is-revealed,
body.home .site-footer.is-revealed {
  opacity: 1;
  pointer-events: auto;
  transition: opacity 0.55s var(--ease);
}

body.home.no-intro .site-nav,
body.home.no-intro main.page,
body.home.no-intro .site-footer {
  opacity: 1;
  pointer-events: auto;
}

.intro-overlay {
  position: fixed;
  inset: 0;
  z-index: 999;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #ffffff;
  transition: background-color 0.55s var(--ease);
}

.intro-overlay.is-fading {
  background-color: rgba(255, 255, 255, 0);
}

.intro-smiley {
  width: min(64vw, 460px);
  height: auto;
  opacity: 0;
  transition:
    opacity 1.6s var(--ease),
    transform 1s cubic-bezier(0.65, 0, 0.2, 1);
  will-change: transform, opacity;
}

.intro-smiley.is-visible {
  opacity: 1;
}

.intro-smiley.is-visible {
  opacity: 1;
}

/* ---------- About page ----------
   Same small mono type scale and left-aligned, no-dividers layout
   as the homepage list and case-study pages — no centered column. */

.about-page {
  flex: 1;
  padding-top: clamp(56px, 11vh, 130px);
  padding-bottom: clamp(64px, 12vh, 140px);
}

.about-page .kicker {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 24px;
}

.about-page .kicker::before {
  content: "[ ";
}

.about-page .kicker::after {
  content: " ]";
}

.about-page p {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.9;
  color: var(--ink-soft);
  max-width: 480px;
  margin: 0 0 20px;
}

.about-page .fact-list {
  max-width: 480px;
  margin-top: clamp(32px, 6vh, 56px);
  margin-left: 0;
  margin-right: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px 32px;
}

.about-page .fact-list dt {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 5px;
}

.about-page .fact-list dd {
  margin: 0;
  font-size: 10px;
  font-family: var(--font-mono);
  color: var(--ink-soft);
}

/* ---------- Case study page ----------
   Deliberately minimal: a content frame (image/video, still a
   placeholder until real creative is dropped in) and small, sparse
   copy underneath it — same type scale as the homepage list. Loads
   of negative space, no rules/dividers. */

.case-page {
  flex: 1;
  padding-top: clamp(56px, 11vh, 130px);
  padding-bottom: clamp(64px, 12vh, 140px);
}

.case-page .back-link,
.about-page .back-link {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: clamp(48px, 9vh, 100px);
}

.case-page .back-link:hover,
.about-page .back-link:hover {
  color: var(--ink);
}

.case-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: var(--bg-panel);
  overflow: hidden;
  margin-bottom: clamp(36px, 6vh, 64px);
}

.case-frame img,
.case-frame video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  background: #000;
}

.case-info {
  max-width: 560px;
  margin: 0 0 clamp(48px, 9vh, 100px);
}

.case-title {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.01em;
  margin: 0 0 8px;
}

.case-meta {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 24px;
}

.case-summary {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.9;
  color: var(--ink-soft);
  max-width: 58ch;
  margin: 0 0 24px;
}

.credits-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 5px;
  font-family: var(--font-mono);
}

.credits-list li {
  font-size: 9px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* A "justified" gallery: rows of images at a shared height, each kept
   at its own true aspect ratio (portrait, landscape, whatever) rather
   than force-cropped to a uniform tile — so nothing in the shot (a
   competitor's signage, in Co-op's case) gets cropped away. Each row
   fills the full width edge-to-edge; case-study.js works out each
   image's height once it loads and sets it as that image's share of
   the row via flex-grow — see setupJustifiedGalleries() there. Until
   that runs, images sit at a fixed fallback height so the page doesn't
   jump around badly. */

.case-gallery {
  display: flex;
  flex-direction: column;
  gap: clamp(10px, 1.6vw, 20px);
  margin-bottom: clamp(48px, 9vh, 100px);
}

.gallery-row {
  display: flex;
  gap: clamp(10px, 1.6vw, 20px);
}

.gallery-row img,
.gallery-row video {
  display: block;
  width: 100%;
  height: clamp(160px, 26vw, 300px);
  object-fit: cover;
  background: var(--bg-panel);
  flex: 1 1 0;
  min-width: 0;
}

.gallery-row video {
  background: #000;
}

.gallery-row img.is-justified,
.gallery-row video.is-justified {
  height: auto;
  object-fit: unset;
  flex-basis: 0;
}

@media (max-width: 720px) {
  .gallery-row {
    flex-direction: column;
  }
  .gallery-row img.is-justified,
  .gallery-row video.is-justified {
    width: 100%;
    height: auto;
    flex-grow: 0 !important;
  }
}

/* ---------- Case study page: mosaic layout ----------
   For campaigns with a portrait-shaped film alongside a set of stills
   (Diamond Heist, PP Trackies): the video sits as a tall panel beside a
   2x2 grid of photos, matching that grid's height exactly — one neat
   block instead of a hero frame + separate gallery. If the gallery has
   an odd number of images the leftover runs as a full-width strip
   underneath the whole block, rather than stretching the video panel
   to an awkward height to accommodate it. */

.case-mosaic {
  margin-bottom: clamp(48px, 9vh, 100px);
}

.mosaic-row {
  display: flex;
  align-items: stretch;
  gap: clamp(10px, 1.6vw, 20px);
}

.mosaic-video {
  flex: 0 0 34%;
  background: var(--bg-panel);
  overflow: hidden;
}

.mosaic-video video {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  background: #000;
}

.mosaic-grid {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-auto-rows: 1fr;
  gap: clamp(10px, 1.6vw, 20px);
}

.mosaic-grid img {
  width: 100%;
  height: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  display: block;
  background: var(--bg-panel);
}

.case-mosaic .mosaic-wide {
  margin-top: clamp(10px, 1.6vw, 20px);
}

.case-mosaic .mosaic-wide img {
  width: 100%;
  aspect-ratio: 21 / 9;
  object-fit: cover;
  display: block;
  background: var(--bg-panel);
}

/* ---------- Case study page: editorial layout ----------
   Wraps an "editorial" campaign's hand-arranged pieces (rows built by
   buildEditorial(), a mosaic block built by buildMosaic(), or both in
   sequence — e.g. PP Trackies: a hero row, then a mosaic block, then a
   closing row). Spacing BETWEEN pieces is set here, at the same tight
   value used for the gap *within* each piece (a gallery row, or the
   video/grid gap in a mosaic row), so a hero image or closing image
   sits close to the grid rather than getting the larger end-of-section
   margin each piece carries on its own elsewhere on the page. */

.case-editorial {
  display: flex;
  flex-direction: column;
  gap: clamp(10px, 1.6vw, 20px);
  margin-bottom: clamp(48px, 9vh, 100px);
}

.case-editorial .case-gallery,
.case-editorial .case-mosaic {
  margin-bottom: 0;
}

@media (max-width: 720px) {
  .mosaic-row {
    flex-direction: column;
  }
  .mosaic-video {
    flex-basis: auto;
  }
  /* No fixed aspect-ratio box here (that was letterboxing a film whose
     shape doesn't match it) — the film just sizes itself from its own
     true proportions, same idea as everywhere else on the page. */
  .mosaic-video video {
    height: auto;
  }
}

/* ---------- Case study page: stack layout ----------
   A straight scrolling column of equal-width images, one after another
   — for a campaign that's a run of ads rather than a hero + gallery
   (e.g. Yorkshire Gold). Each image keeps its own natural proportions,
   never cropped. */

.case-stack {
  display: grid;
  gap: clamp(16px, 2.4vh, 32px);
  margin-bottom: clamp(48px, 9vh, 100px);
}

.case-stack img {
  width: 100%;
  height: auto;
  display: block;
  background: var(--bg-panel);
}


/* ---------- Footer ---------- */

.site-footer {
  background: var(--footer-bg);
  color: var(--footer-ink);
}

.footer-inner {
  max-width: var(--container-max);
  margin: 0 auto;
  padding: clamp(28px, 5vh, 44px) var(--gutter);
}

.footer-email {
  display: inline-block;
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.05em;
  line-height: 1.4;
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s ease;
}

.footer-email:hover {
  border-color: var(--ink);
}

.footer-bottom {
  margin-top: 6px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: rgba(13, 13, 13, 0.5);
}

/* ---------- Responsive ---------- */

@media (max-width: 900px) {
  .site-nav .brand span {
    display: none;
  }

  .showcase {
    grid-template-columns: 1fr;
    padding-top: clamp(32px, 8vh, 56px);
  }

  .preview-panel {
    display: none;
  }

  .campaign-list {
    display: none;
  }

  .campaign-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
    border-top: 1px solid var(--line);
    padding-top: 18px;
  }

  .campaign-grid a {
    display: block;
  }

  .campaign-grid .thumb {
    position: relative;
    aspect-ratio: 4 / 3;
    border-radius: 0;
    overflow: hidden;
    background: var(--bg-panel);
    margin-bottom: 7px;
    border: 1px solid var(--line);
  }

  .campaign-grid .thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .campaign-grid .title {
    font-family: var(--font-mono);
    font-size: 12px;
    line-height: 1.3;
  }

  .campaign-grid .meta {
    font-family: var(--font-mono);
    font-size: 9px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-faint);
  }

  .about-page .fact-list {
    grid-template-columns: 1fr;
  }

  .footer-row {
    flex-direction: column;
    align-items: flex-start;
  }

  .footer-bottom {
    flex-direction: column;
  }
}

@media (max-width: 540px) {
  .campaign-grid {
    grid-template-columns: 1fr;
  }

  .site-nav .brand {
    font-size: 10px;
  }

  .site-nav .nav-links {
    gap: 14px;
  }
}
