/* Redesign — Final Files / OE Edit
   Shared content grid from Desktop Master (1045 wide):
   98 | 20 | 217 | 20 | 335 | 20 | 335
   Title column starts at x=355 — Earthling / bio / Creative Technology / footer */

/* ABC Diatype (licensed). Package has Regular + Bold — body Medium (500) maps to Regular. */
@font-face {
  font-family: "Diatype";
  src: url("../fonts/ABCDiatype-Regular.otf") format("opentype");
  font-weight: 400 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Diatype";
  src: url("../fonts/ABCDiatype-RegularItalic.otf") format("opentype");
  font-weight: 400 500;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "Diatype";
  src: url("../fonts/ABCDiatype-Bold.otf") format("opentype");
  font-weight: 600 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Diatype";
  src: url("../fonts/ABCDiatype-BoldItalic.otf") format("opentype");
  font-weight: 600 700;
  font-style: italic;
  font-display: swap;
}

:root {
  --oe-text: #3c3636;
  --oe-bg: #ffffff;
  --oe-muted: #e6e6e6;
  --oe-rule: #3c3636;

  --oe-font: "Diatype", "Helvetica Neue", Helvetica, "Arial Unicode MS", sans-serif;
  --oe-size: 11px;
  --oe-leading: 14px;
  --oe-tracking: -0.11px;
  --oe-size-mobile: 19px;
  --oe-leading-mobile: 24px;

  --oe-pad: 20px;
  --oe-content: 1045px;
  --oe-max: 1440px;
  --oe-glyph: 24px;

  /* Exact Figma track fractions of 1045 */
  --oe-c1: calc(98 / 1045 * 100%);
  --oe-c2: calc(217 / 1045 * 100%);
  --oe-c3: calc(335 / 1045 * 100%);
  --oe-c4: calc(335 / 1045 * 100%);
  --oe-g: calc(20 / 1045 * 100%);

  --oe-motion-duration: 560ms;
  --oe-motion-ease: cubic-bezier(0.16, 1, 0.3, 1);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: auto;
}

body.oe {
  margin: 0;
  padding: 0;
  background: var(--oe-bg);
  color: var(--oe-text);
  font-family: var(--oe-font);
  font-size: var(--oe-size);
  line-height: var(--oe-leading);
  letter-spacing: var(--oe-tracking);
  font-weight: 500;
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

body.oe a {
  color: inherit;
  text-decoration: none;
}

body.oe button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  cursor: pointer;
  text-align: left;
  letter-spacing: inherit;
}

.oe-page {
  width: 100%;
  max-width: var(--oe-max);
  margin: 0; /* left-aligned — don’t recenter when the window grows */
  padding: var(--oe-pad);
  padding-bottom: var(--oe-pad);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  /* visible so rules can span past max-width; body still clips x-scroll */
  overflow-x: visible;
  overflow-anchor: none;
}

/*
  ONE shared content grid for index / about / services / footer.
  Percent tracks + gaps always sum to 100% of the same 1045 max width.
*/
.oe-grid {
  display: grid;
  grid-template-columns: var(--oe-c1) var(--oe-c2) var(--oe-c3) var(--oe-c4);
  column-gap: var(--oe-g);
  width: 100%;
  max-width: min(100%, var(--oe-content));
  align-items: start;
}

/* —— Index list —— */
.oe-index {
  position: relative;
  width: 100%;
  max-width: none; /* full page width so media / rules can bleed right */
  overflow-anchor: none;
}

.oe-entry {
  position: relative;
  overflow-anchor: none;
}

.oe-row {
  min-height: var(--oe-leading);
  color: var(--oe-text);
  transition: color var(--oe-motion-duration) var(--oe-motion-ease);
}

.oe-row__year,
.oe-row__type,
.oe-row__title,
.oe-row__client,
.oe-about__identity,
.oe-about__contact,
.oe-about__bio,
.oe-service__label,
.oe-service__title,
.oe-detail__copy,
.oe-detail__credits {
  min-width: 0;
  overflow-wrap: break-word;
}

.oe-service__desc,
.oe-service__desc-inner {
  min-width: 0;
  overflow-wrap: break-word;
  word-break: normal;
  hyphens: none;
}

/* Glyph sits outside the 1045 content box (Figma ~1065+) */
.oe-row__glyph {
  position: absolute;
  top: 0;
  left: min(100%, var(--oe-content));
  margin-left: calc(20 / 1045 * min(100%, var(--oe-content)));
  width: var(--oe-glyph);
  display: flex;
  justify-content: flex-start;
  align-items: flex-start;
  user-select: none;
  pointer-events: none;
  color: var(--oe-text);
  transition: color var(--oe-motion-duration) var(--oe-motion-ease);
}

.oe-row__glyph-symbol {
  font-size: 11px;
  line-height: 14px;
  font-weight: 500;
  font-family: var(--oe-font);
  letter-spacing: var(--oe-tracking);
  color: inherit;
}

.oe-row--interactive {
  scroll-margin-top: 10dvh;
  -webkit-tap-highlight-color: transparent;
}

/*
  Desktop cursors — − by default everywhere; + / ↗ only on index expand / link.
  JS repaints these from a live glyph’s computed font (1 CSS px = 1 bitmap px).
*/
body.oe:not(.is-mobile) {
  --oe-cursor-minus: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2214%22%20viewBox%3D%220%200%2024%2014%22%3E%3Ctext%20x%3D%220%22%20y%3D%2211%22%20font-family%3D%22Diatype%2C%20Helvetica%20Neue%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-size%3D%2211%22%20font-weight%3D%22500%22%20fill%3D%22%233c3636%22%3E%E2%88%92%3C%2Ftext%3E%3C%2Fsvg%3E")
    4 7,
    default;
  --oe-cursor-plus: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2214%22%20viewBox%3D%220%200%2024%2014%22%3E%3Ctext%20x%3D%220%22%20y%3D%2211%22%20font-family%3D%22Diatype%2C%20Helvetica%20Neue%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-size%3D%2211%22%20font-weight%3D%22500%22%20fill%3D%22%233c3636%22%3E%2B%3C%2Ftext%3E%3C%2Fsvg%3E")
    4 7,
    pointer;
  --oe-cursor-link: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2214%22%20viewBox%3D%220%200%2024%2014%22%3E%3Ctext%20x%3D%220%22%20y%3D%2211%22%20font-family%3D%22Diatype%2C%20Helvetica%20Neue%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-size%3D%2211%22%20font-weight%3D%22500%22%20fill%3D%22%233c3636%22%3E%E2%86%97%3C%2Ftext%3E%3C%2Fsvg%3E")
    4 7,
    pointer;

  cursor: var(--oe-cursor-minus);
}

body.oe:not(.is-mobile) a,
body.oe:not(.is-mobile) button,
body.oe:not(.is-mobile) .oe-row--interactive,
body.oe:not(.is-mobile) .oe-service__title,
body.oe:not(.is-mobile) .oe-detail__hit,
body.oe:not(.is-mobile) .oe-detail__close,
body.oe:not(.is-mobile) .oe-detail__av-btn,
body.oe:not(.is-mobile) .oe-detail__media.is-nav-gutter-next {
  cursor: var(--oe-cursor-minus);
}

body.oe:not(.is-mobile) .oe-entry[data-action="expand"]:not(.is-open),
body.oe:not(.is-mobile) .oe-entry[data-action="expand"]:not(.is-open) .oe-row,
body.oe:not(.is-mobile) .oe-entry[data-action="expand"]:not(.is-open) .oe-row--interactive {
  cursor: var(--oe-cursor-plus);
}

body.oe:not(.is-mobile) .oe-entry[data-action="expand"].is-open,
body.oe:not(.is-mobile) .oe-entry[data-action="expand"].is-open .oe-row,
body.oe:not(.is-mobile) .oe-entry[data-action="expand"].is-open .oe-row--interactive {
  cursor: var(--oe-cursor-minus);
}

body.oe:not(.is-mobile) .oe-entry[data-action="link"],
body.oe:not(.is-mobile) .oe-entry[data-action="link"] .oe-row,
body.oe:not(.is-mobile) .oe-entry[data-action="link"] .oe-row--interactive {
  cursor: var(--oe-cursor-link);
}

.oe-row--interactive:focus,
.oe-row--interactive:focus-visible,
.oe-row--interactive:active {
  outline: none;
}

/*
  Index hover hierarchy (mirrors Services/Areas) — DESKTOP ONLY.
  Hover a clickable row → it stays dark; siblings mute.
  Does NOT apply when hovering tease rows (preview only, not clickable).
  Mobile: no hover sibling-mute (touch :hover sticks while scrolling).
  Easy to revert if this feels off in review — see docs/DESIGN-NOTE-index-hover-hierarchy.md
*/
body.oe:not(.is-mobile) .oe-index:not(.has-open):has(
    .oe-entry:not(.is-open) .oe-row--interactive:hover
  )
  .oe-entry:not(:has(> .oe-row--interactive:hover))
  .oe-row,
body.oe:not(.is-mobile) .oe-index:not(.has-open):has(
    .oe-entry:not(.is-open) .oe-row--interactive:hover
  )
  .oe-entry:not(:has(> .oe-row--interactive:hover))
  .oe-row__glyph {
  color: var(--oe-muted);
}

body.oe:not(.is-mobile) .oe-entry:not(.is-open) .oe-row--interactive:hover,
body.oe:not(.is-mobile)
  .oe-entry:not(.is-open):has(.oe-row--interactive:hover)
  .oe-row__glyph {
  color: var(--oe-text);
}

/* External / outbound links — mute on hover instead of underline */
body.oe a[href^="http"]:hover,
body.oe a[href^="//"]:hover {
  color: var(--oe-muted);
}

.oe-index.has-open .oe-entry:not(.is-open) .oe-row,
.oe-index.has-open .oe-entry:not(.is-open) .oe-row__glyph {
  color: var(--oe-muted);
}

.oe-index.has-open .oe-entry.is-open .oe-row,
.oe-index.has-open .oe-entry.is-open .oe-row__glyph {
  color: var(--oe-text);
}

.oe-entry.is-open .oe-row__glyph-symbol[data-glyph-open] {
  display: inline;
}

.oe-entry.is-open .oe-row__glyph-symbol[data-glyph-closed] {
  display: none;
}

.oe-entry:not(.is-open) .oe-row__glyph-symbol[data-glyph-open] {
  display: none;
}

/* —— Hover preview —— */
.oe-preview {
  position: fixed;
  top: 0;
  /* Align to the left-pinned page’s right edge (+ pad), not the viewport centre */
  right: max(
    20px,
    calc(var(--oe-layout-width, 100vw) - var(--oe-max) + 20px)
  );
  width: min(301px, 22vw);
  pointer-events: none;
  z-index: 20;
  opacity: 0;
  transition: opacity 120ms ease;
}

.oe-preview.is-visible {
  opacity: 1;
}

.oe-preview img,
.oe-preview video {
  display: block;
  width: 100%;
  height: auto;
  background: var(--oe-bg);
}

/* Author display:block must not override the hidden attribute — otherwise the
   inactive img/video still lays out and covers glyphs below the visible media. */
.oe-preview img[hidden],
.oe-preview video[hidden] {
  display: none !important;
}

body.oe.is-mobile .oe-preview,
.oe-index.has-open .oe-preview {
  display: none !important;
}

/* —— Inline project detail (accordion reveal top → down) —— */
.oe-detail {
  display: grid;
  grid-template-rows: 0fr;
  width: 100%;
  max-width: none;
  transition: grid-template-rows var(--oe-motion-duration) var(--oe-motion-ease);
  overflow-anchor: none;
}

.oe-entry.is-open .oe-detail {
  grid-template-rows: 1fr;
}

/* Up/down (or click) project switch: snap accordion; scroll snaps in JS too */
.oe-index.is-swapping .oe-detail,
.oe-index.is-swapping .oe-detail__meta {
  transition: none !important;
}

.oe-index.is-swapping .oe-detail__meta,
.oe-index.is-swapping .oe-entry.is-open .oe-detail__meta {
  opacity: 1;
  transition: none !important;
}

.oe-index.is-swapping,
.oe-index.is-swapping .oe-entry,
.oe-index.is-swapping .oe-detail {
  overflow-anchor: none;
}

.oe-detail__reveal {
  overflow: hidden;
  min-height: 0;
  padding-bottom: 0;
}

.oe-entry.is-open .oe-detail__reveal {
  padding-bottom: 0;
}

/* Stretch copy/credits; media sits flush under whichever column is taller */
.oe-detail__meta {
  margin-bottom: 0;
  max-width: min(100%, var(--oe-content));
  opacity: 0;
  transition: opacity calc(var(--oe-motion-duration) * 0.75) ease;
  align-items: stretch;
  padding-bottom: 0;
}

.oe-entry.is-open .oe-detail__meta {
  opacity: 1;
  transition: opacity calc(var(--oe-motion-duration) * 0.85) ease 90ms;
}

.oe-detail__copy {
  display: flex;
  flex-direction: column;
  min-height: 100%;
}

@media (prefers-reduced-motion: reduce) {
  .oe-detail,
  .oe-detail__media-stage,
  .oe-detail__meta {
    transition: none;
  }

  .oe-detail__meta,
  .oe-entry.is-open .oe-detail__meta {
    opacity: 1;
  }
}

.oe-detail__close {
  display: block;
  width: 100%;
  -webkit-tap-highlight-color: transparent;
}

.oe-detail__close:focus,
.oe-detail__close:focus-visible,
.oe-detail__close:active {
  outline: none;
  background: transparent;
}

.oe-detail__copy p,
.oe-detail__credits p,
.oe-detail__credits li {
  margin: 0;
  line-height: var(--oe-leading);
}

.oe-detail__copy .oe-detail__spacer,
.oe-detail__credits .oe-detail__spacer {
  height: var(--oe-leading);
}

.oe-detail__credits ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Trial: role | name as two columns within the credits track (Figma-style) */
.oe-detail__credits li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  column-gap: var(--oe-g);
  align-items: start;
}

.oe-detail__credit-role,
.oe-detail__credit-name {
  min-width: 0;
}

.oe-detail__credit-role {
  display: flex;
  flex-direction: column;
}

.oe-detail__credit-role-line {
  display: block;
  line-height: var(--oe-leading);
}

.oe-detail__tech {
  margin: 0;
}

.oe-detail__tech .oe-detail__credit-name {
  display: flex;
  flex-direction: column;
}

.oe-detail__tech-item {
  display: block;
  line-height: var(--oe-leading);
}

/*
  Figma 186:3275 — Close [x] at image top, in year+type columns (335).
  Media flush under copy; next project row sits flush under media.
*/
.oe-detail__stage {
  display: grid;
  grid-template-columns:
    calc((98 + 20 + 217) / 1045 * min(100%, var(--oe-content)))
    minmax(0, 1fr);
  column-gap: calc(20 / 1045 * min(100%, var(--oe-content)));
  align-items: start;
  justify-items: start;
  width: 100%;
}

.oe-detail__close-col {
  min-width: 0;
}

.oe-detail__close-fallback {
  max-width: min(100%, var(--oe-content));
  padding-top: var(--oe-leading);
}

.oe-detail__media {
  position: relative;
  margin-left: 0;
  width: 100%;
  max-width: none;
  min-width: 0;
  justify-self: stretch; /* column still full-width for gutter / AV */
  background: transparent;
  user-select: none;
  /* Stage is narrower than this column — always pin it left, never center */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.oe-detail__media-stage {
  position: relative;
  /*
    16:9 hero. Width capped so height ≤ --oe-media-max-h (no separate
    max-height — that + aspect-ratio was centering the shrunk box).
  */
  --oe-media-max-h: min(49vh, 33.6rem);
  --oe-ar: 1.7777778;
  --oe-media-ar: 16 / 9;
  --oe-frame-zoom: 1;
  --oe-frame-focus: left top;
  width: min(100%, calc(var(--oe-media-max-h) * var(--oe-ar)));
  max-width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  margin: 0;
  margin-right: auto;
  justify-self: start;
  align-self: flex-start;
  background: var(--oe-bg);
  line-height: 0;
  overflow: hidden;
  transform-origin: top left;
  -webkit-tap-highlight-color: transparent;
  transition: none;
  container-type: inline-size;
  container-name: oe-media;
}

.oe-detail__media-stage[data-frame-bg="black"],
.oe-detail__media-stage[data-frame-fit="matte-black"] {
  background: #000;
}

.oe-detail__media-stage[data-frame-bg="white"],
.oe-detail__media-stage[data-frame-fit="matte-white"] {
  background: #fff;
}

.oe-detail__media-stage[data-frame-bg="blur"],
.oe-detail__media-stage[data-frame-fit="blur"] {
  background: #111;
}

.oe-detail__media-stage[data-frame-bg="custom"] {
  background: var(--oe-frame-bg, var(--oe-bg));
}

/* Blurred fill behind contain media */
.oe-detail__frame-blur {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--oe-frame-focus, left top);
  filter: blur(28px);
  transform: scale(1.1);
  transform-origin: left top;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  user-select: none;
}

.oe-detail__media-stage[data-frame-bg="blur"] .oe-detail__frame-blur.is-active,
.oe-detail__media-stage[data-frame-fit="blur"] .oe-detail__frame-blur.is-active {
  opacity: 1;
  visibility: visible;
}

/*
  Desktop only: also stop at the glyph column (title → content right = 690/1045).
  Height comes only from width ÷ 16:9 so the box cannot shrink-and-center.
*/
body.oe:not(.is-mobile) .oe-detail__media-stage {
  --oe-media-max-w: calc(var(--oe-content) * 690 / 1045);
  width: min(100%, var(--oe-media-max-w), calc(var(--oe-media-max-h) * var(--oe-ar)));
  max-width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  margin: 0;
  margin-right: auto;
  align-self: flex-start;
}

.oe-detail__media img:not(.oe-detail__frame-blur),
.oe-detail__media video,
.oe-detail__media iframe[data-oe-vimeo] {
  position: absolute;
  inset: auto;
  left: 0;
  top: 0;
  display: block;
  /* Default: fill height; width/left/top set by layoutSlideInFrame */
  width: auto;
  height: 100%;
  max-width: none;
  object-fit: contain;
  object-position: left top !important;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 180ms ease;
  background: transparent;
  border: 0;
  transform: none;
  transform-origin: left top;
  z-index: 1;
}

/* Cover crop fills the locked frame; optional CMS focus / align */
.oe-detail__media-stage[data-frame-fit="cover"] [data-oe-slide].is-active {
  inset: 0;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--oe-frame-focus, left top) !important;
  transform: scale(var(--oe-frame-zoom, 1));
  transform-origin: var(--oe-frame-focus, left top);
}

/* Vimeo poster — fills the frame until the player is ready */
.oe-detail__media img[data-oe-vimeo-poster].is-active {
  visibility: visible;
  opacity: 1;
  z-index: 0;
}

.oe-detail__media:has(iframe[data-oe-vimeo].is-active.is-loaded)
  img[data-oe-vimeo-poster].is-active {
  opacity: 0;
  visibility: hidden;
}

/* Native video poster shows via the element itself once active */
.oe-detail__media video.is-active:not(.is-loaded)[poster] {
  visibility: visible;
  opacity: 1;
  z-index: 1;
}

/* Kill Chromium’s built-in muted-autoplay / media overlay chrome (inline only) */
.oe-detail__media video::-webkit-media-controls,
.oe-detail__media video::-webkit-media-controls-enclosure,
.oe-detail__media video::-webkit-media-controls-overlay-enclosure,
.oe-detail__media video::-webkit-media-controls-start-playback-button,
.oe-detail__media video::-webkit-media-controls-overlay-play-button,
.oe-detail__media video::-webkit-media-controls-mute-button,
.oe-detail__media video::-webkit-media-controls-toggle-closed-captions-button,
.oe-detail__media video::-webkit-media-controls-volume-slider,
.oe-detail__media video::-webkit-media-controls-fullscreen-button {
  display: none !important;
  opacity: 0 !important;
  width: 0 !important;
  height: 0 !important;
  pointer-events: none !important;
}

.oe-detail__media img.is-active,
.oe-detail__media video.is-active,
.oe-detail__media iframe[data-oe-vimeo].is-active {
  visibility: visible;
  z-index: 1;
}

.oe-detail__media img.is-active.is-loaded {
  opacity: 1;
}

/* Videos / Vimeo: visible only once decoded (matches image behaviour) */
.oe-detail__media video.is-active.is-loaded,
.oe-detail__media iframe[data-oe-vimeo].is-active.is-loaded {
  opacity: 1;
}

.oe-detail__media-stage.is-loading .oe-detail__hit,
.oe-detail__media-stage.is-loading .oe-detail__nav-label {
  opacity: 0 !important;
  pointer-events: none;
}

.oe-detail__media:has(.oe-detail__media-stage.is-loading) .oe-detail__av {
  opacity: 0 !important;
  pointer-events: none;
}

/* Loading + — inner glyph spins so Firefox keeps it centred in the 14×14 box */
.oe-detail__loader {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  margin: 0;
  padding: 0;
  pointer-events: none;
  user-select: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 120ms ease, visibility 120ms ease;
}

.oe-detail__loader-glyph {
  display: block;
  width: 14px;
  height: 14px;
  margin: 0;
  padding: 0;
  font-size: 11px;
  line-height: 14px;
  text-align: center;
  letter-spacing: var(--oe-tracking);
  color: #fff;
  mix-blend-mode: difference;
  transform-origin: 50% 50%;
}

.oe-detail__media-stage.is-loading .oe-detail__loader {
  opacity: 1;
  visibility: visible;
}

.oe-detail__media-stage.is-loading .oe-detail__loader-glyph {
  animation: oe-loader-spin 1s ease infinite;
}

@keyframes oe-loader-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .oe-detail__media-stage.is-loading .oe-detail__loader-glyph {
    animation: none;
  }
}

/*
  Unmute / Fullscreen — bottom of media, left-aligned to the client column.
  Lives in the media column, not the stage, so a narrow (portrait) frame
  cannot clip it. JS drops the row to the frame's bottom-left when the client
  column would push it past the frame's right edge.
  Fullscreen keeps that same screen X. Visible with is-av-chrome.
*/
.oe-detail__av {
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--oe-av-bottom, 0px);
  z-index: 5;
  display: grid;
  grid-template-columns:
    var(--oe-av-left, calc((335 + 20) / 1045 * min(100%, var(--oe-content))))
    minmax(0, 1fr);
  align-items: end;
  margin: 0;
  padding: 0 0 2px;
  border: 0;
  background: none;
  pointer-events: none;
  box-sizing: border-box;
  opacity: 0;
  transition: opacity 120ms ease;
  /*
    Blend on the wrapper, not the labels. position + z-index makes this a
    stacking context, so a mix-blend-mode set on a child would only ever
    blend against this box's transparent interior, never the footage.
  */
  mix-blend-mode: difference;
}

.oe-detail__av[hidden] {
  display: none !important;
}

.oe-detail__media.is-av-chrome .oe-detail__av:not([hidden]) {
  opacity: 1;
  pointer-events: auto;
}

/* White Medium labels, same treatment as the Previous / Next labels */
.oe-detail__av-btns {
  grid-column: 2;
  justify-self: start;
  display: flex;
  gap: 12px;
  margin: 0;
  padding: 0;
  color: #fff;
  pointer-events: auto;
  line-height: var(--oe-leading);
}

.oe-detail__av-btn {
  font-family: var(--oe-font);
  font-size: var(--oe-size);
  line-height: var(--oe-leading);
  letter-spacing: var(--oe-tracking);
  font-weight: 500;
  white-space: nowrap;
}

.oe-detail__av-btn:hover {
  opacity: 0.55;
}

/* Fullscreen — media column fills the viewport; stage must beat desktop/mobile caps */
body.oe .oe-detail__media:fullscreen,
body.oe .oe-detail__media:-webkit-full-screen {
  width: 100%;
  height: 100%;
  max-width: none;
  background: #000;
  cursor: none;
  display: block;
  align-items: stretch;
}

body.oe .oe-detail__media:fullscreen.is-av-chrome,
body.oe .oe-detail__media:-webkit-full-screen.is-av-chrome {
  cursor: default;
}

body.oe .oe-detail__media:fullscreen .oe-detail__media-stage,
body.oe .oe-detail__media:-webkit-full-screen .oe-detail__media-stage {
  --oe-media-max-h: 100vh;
  --oe-media-max-w: 100vw;
  width: 100% !important;
  max-width: none !important;
  height: 100% !important;
  max-height: none !important;
  aspect-ratio: auto !important;
  align-self: stretch;
  margin: 0;
  /* Native FS: always black letterbox — never site / blur / custom matte */
  background: #000 !important;
  display: block;
}

/* Site frame blur is for the page stage only */
body.oe .oe-detail__media:fullscreen .oe-detail__frame-blur,
body.oe .oe-detail__media:-webkit-full-screen .oe-detail__frame-blur {
  display: none !important;
  opacity: 0 !important;
  visibility: hidden !important;
}

body.oe .oe-detail__media:fullscreen img:not(.oe-detail__frame-blur),
body.oe .oe-detail__media:fullscreen video,
body.oe .oe-detail__media:fullscreen iframe[data-oe-vimeo],
body.oe .oe-detail__media:-webkit-full-screen img:not(.oe-detail__frame-blur),
body.oe .oe-detail__media:-webkit-full-screen video,
body.oe .oe-detail__media:-webkit-full-screen iframe[data-oe-vimeo] {
  object-fit: contain !important;
  object-position: center !important;
}

/* No gallery prev/next while fullscreen */
body.oe .oe-detail__media:fullscreen .oe-detail__hit,
body.oe .oe-detail__media:fullscreen .oe-detail__nav-label,
body.oe .oe-detail__media:-webkit-full-screen .oe-detail__hit,
body.oe .oe-detail__media:-webkit-full-screen .oe-detail__nav-label {
  display: none !important;
}

body.oe .oe-detail__media:fullscreen .oe-detail__av,
body.oe .oe-detail__media:-webkit-full-screen .oe-detail__av {
  padding: 0 0 20px 20px;
  grid-template-columns: 0 minmax(0, 1fr);
}

.oe-detail__hit {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 50%;
  z-index: 2;
  cursor: pointer;
  border: 0;
  background: transparent;
  padding: 0;
  margin: 0;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  appearance: none;
  -webkit-appearance: none;
  outline: none;
  box-shadow: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.oe-detail__hit:focus,
.oe-detail__hit:focus-visible,
.oe-detail__hit:active {
  outline: none;
  background: transparent;
  box-shadow: none;
}

.oe-detail__hit--prev {
  left: 0;
}

.oe-detail__hit--next {
  right: 0;
}

/* Pointer over the empty media-column gutter (right of a narrow stage) */
.oe-detail__media.is-nav-gutter-next {
  cursor: pointer;
}

.oe-detail__hit[disabled] {
  cursor: default;
}

/*
  Figma 186:3276 / 186:3277 — white Medium labels.
  difference keeps them readable on light or dark pixels.
  Prev: visible media left edge. Next: year-col inset from visible media right.
  Box size comes from JS (--oe-nav-box-*) so labels stay on the image, not the matte.
  Y follows cursor, clamped to the visible media bounds.
*/
.oe-detail__nav-label {
  position: absolute;
  z-index: 3;
  transform: translateY(-50%);
  margin: 0;
  padding: 0;
  color: #fff;
  mix-blend-mode: difference;
  font: inherit;
  font-size: var(--oe-size);
  line-height: var(--oe-leading);
  letter-spacing: var(--oe-tracking);
  font-weight: 500;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 80ms ease;
  text-shadow: none;
}

.oe-detail__nav-label--prev {
  left: var(--oe-nav-box-left, 0px);
  top: var(--oe-nav-y-prev, 50%);
}

.oe-detail__nav-label--next {
  left: var(--oe-nav-next-x, calc(100% - (98 / 1045 * 100%)));
  top: var(--oe-nav-y-next, 50%);
}

/* Narrow visible media: pin Next inside the image’s right edge */
.oe-detail__media-stage.is-nav-box-narrow .oe-detail__nav-label--next {
  left: calc(var(--oe-nav-box-left, 0px) + var(--oe-nav-box-w, 100%) - 10px);
  transform: translate(-100%, -50%);
}

/* Only the active side’s label is visible */
.oe-detail__media-stage.is-nav-prev .oe-detail__nav-label--prev,
.oe-detail__media-stage.is-nav-next .oe-detail__nav-label--next {
  opacity: 1;
}

.oe-detail__media-stage.is-nav-prev .oe-detail__nav-label--prev.is-disabled,
.oe-detail__media-stage.is-nav-next .oe-detail__nav-label--next.is-disabled {
  opacity: 0.35;
}

/* —— About / services —— */
/* Full layout width, same side pad as the page (grows past --oe-max).
   Uses --oe-layout-width (clientWidth via JS) so resize isn’t laggy like 100vw. */
.oe-rule {
  border: 0;
  border-top: 1px solid var(--oe-rule);
  margin: 12px 0;
  width: calc(var(--oe-layout-width, 100%) - 2 * var(--oe-pad));
  max-width: none;
  box-sizing: border-box;
  transition: none !important;
}

.oe-about {
  margin-bottom: 0;
  align-items: baseline;
}

.oe-about__identity p,
.oe-about__contact p,
.oe-about__bio p {
  margin: 0;
  line-height: var(--oe-leading);
}

.oe-about__contact a {
  display: block;
}

.oe-services,
.oe-areas {
  max-width: min(100%, var(--oe-content));
}

/* Desktop Master: Areas starts ~40px below last Services title (2× leading + gap) */
.oe-areas {
  margin-top: calc(var(--oe-leading) * 2);
}

/* Desktop: pin rights to the viewport bottom when the window is taller than the page.
   Never lifts above its natural spot — only gains space when there’s spare height. */
body.oe:not(.is-mobile) .oe-areas {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  width: 100%;
}

.oe-service {
  position: relative;
  align-items: start;
  min-height: var(--oe-leading);
  /* Grow when title wraps (e.g. Software Engineering & Real-Time Systems) */
  height: auto;
}

.oe-service__label {
  color: var(--oe-text);
  line-height: var(--oe-leading);
  transition: color var(--oe-motion-duration) var(--oe-motion-ease);
}

.oe-service__label.is-dot {
  color: transparent;
  user-select: none;
}

.oe-service__title {
  color: var(--oe-text);
  cursor: pointer;
  line-height: var(--oe-leading);
  transition: color var(--oe-motion-duration) var(--oe-motion-ease);
}

/* Hovered title stays dark (active); siblings mute for hierarchy */
body.oe:not(.is-mobile) .oe-services:has(.oe-service__title:hover)
  .oe-service:not(.oe-rights):not(:has(> .oe-service__title:hover))
  .oe-service__title,
body.oe:not(.is-mobile) .oe-areas:has(.oe-service__title:hover)
  .oe-service:not(.oe-rights):not(:has(> .oe-service__title:hover))
  .oe-service__title {
  color: var(--oe-muted);
}

/* Titles mute on hover removed — active title stays full contrast */
body.oe:not(.is-mobile) .oe-service:not(.oe-rights) .oe-service__title:hover {
  color: var(--oe-text);
}

body.oe:not(.is-mobile)
  .oe-service:not(.oe-rights):has(.oe-service__title:hover)
  .oe-service__label:not(.is-dot) {
  color: var(--oe-text);
}

/* Col 4 overlays; wrapping must not open gaps between titles */
.oe-service__desc {
  position: relative;
  height: 0;
  min-height: 0;
  overflow: visible;
  pointer-events: none;
}

.oe-service__desc-inner {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  color: var(--oe-text);
  line-height: var(--oe-leading);
  opacity: 0;
  visibility: hidden;
  z-index: 2;
}

body.oe:not(.is-mobile) .oe-service__title:hover + .oe-service__desc .oe-service__desc-inner {
  opacity: 1;
  visibility: visible;
}

.oe-service__desc-inner.oe-service__tech {
  white-space: pre-line;
}

/*
  Core Technologies: keep the tech list in flow so its height is always
  reserved (rights stay below it), but only show the text on hover/open.
*/
.oe-service--tech .oe-service__desc {
  height: auto;
}

.oe-service--tech .oe-service__desc-inner {
  position: static;
  opacity: 0;
  visibility: hidden;
}

body.oe:not(.is-mobile) .oe-service--tech .oe-service__title:hover + .oe-service__desc .oe-service__desc-inner {
  opacity: 1;
  visibility: visible;
}

/* Rights line: under Areas. Desktop pins to viewport bottom when page is short. */
.oe-rights {
  margin-top: calc(var(--oe-leading) * 2);
}

body.oe:not(.is-mobile) .oe-rights {
  margin-top: auto;
  padding-top: calc(var(--oe-leading) * 2);
}

.oe-rights__reserved,
.oe-rights__copy {
  margin: 0;
  min-width: 0;
  color: var(--oe-text);
  line-height: var(--oe-leading);
  letter-spacing: var(--oe-tracking);
  font-family: var(--oe-font);
  font-size: var(--oe-size);
  font-weight: 500;
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.oe-rights__reserved {
  display: none;
}

.oe-rights__copy {
  grid-column: 3 / -1;
  white-space: nowrap;
}

.oe-rights__copy::before {
  content: "All rights reserved ";
}

/*
  Mobile — Figma Mobile Home 1.1 (720px artboard) as proportional quote.
  Every dimension scales with viewport width so the layout fits any phone on
  load without zoom, pinch, or horizontal scroll. At 720px+ it matches Figma
  at 1:1; below that, type and columns shrink together keeping the same ratios.

  720 frame = 20 pad + 680 grid
  Index:  155 | 20 | 155 | 20 | 155 | 20 | 155
  Services: 155 | 20 | 155 | 20 | 330
*/
body.oe.is-mobile {
  --oe-m-artboard: 720;
  --oe-m-grid: 680;
  --oe-m-pad: calc(20 / var(--oe-m-artboard) * 100vw);
  --oe-m-size: min(19px, calc(19 / var(--oe-m-artboard) * 100vw));
  --oe-m-leading: min(24px, calc(24 / var(--oe-m-artboard) * 100vw));
  --oe-m-track: min(-0.19px, calc(-0.19 / var(--oe-m-artboard) * 100vw));
  --oe-m-col: calc(155 / var(--oe-m-grid) * 100%);
  --oe-m-gap: calc(20 / var(--oe-m-grid) * 100%);
  --oe-m-desc: calc(330 / var(--oe-m-grid) * 100%);

  font-size: var(--oe-m-size);
  line-height: var(--oe-m-leading);
  letter-spacing: var(--oe-m-track);
  overflow-x: hidden;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body.oe.is-mobile .oe-page {
  width: 100%;
  max-width: 100%;
  padding: var(--oe-m-pad);
  padding-bottom: var(--oe-m-pad);
  box-sizing: border-box;
  overflow-x: visible;
}

/* 4-column grid — index + about */
body.oe.is-mobile .oe-grid {
  grid-template-columns: var(--oe-m-col) var(--oe-m-col) var(--oe-m-col) var(--oe-m-col);
  column-gap: var(--oe-m-gap);
  width: 100%;
  max-width: 100%;
}

body.oe.is-mobile .oe-row {
  align-items: start;
}

/* Year + type: Figma overflow-clip — one line */
body.oe.is-mobile .oe-row__year,
body.oe.is-mobile .oe-row__type {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: clip;
}

/* Title + client: wrap at words inside column */
body.oe.is-mobile .oe-row__title,
body.oe.is-mobile .oe-row__client {
  overflow-wrap: break-word;
  word-break: normal;
  hyphens: none;
}

body.oe.is-mobile .oe-row__glyph {
  display: none;
}

/* One shared mobile mute — idle non-tappable rows AND closed rows when something is open */
body.oe.is-mobile {
  /* ~20% lighter than #9a9595 toward white */
  --oe-muted-mobile: #aeaaaa;
}

body.oe.is-mobile .oe-entry[data-action="tease"] .oe-row,
body.oe.is-mobile .oe-entry[data-action="none"] .oe-row,
body.oe.is-mobile .oe-index.has-open .oe-entry:not(.is-open) .oe-row,
body.oe.is-mobile .oe-index.has-open .oe-entry:not(.is-open) .oe-row__glyph {
  color: var(--oe-muted-mobile);
}

/* External links only when the accordion is fully closed */
.oe-index.has-open .oe-entry[data-action="link"],
.oe-index.has-open .oe-entry[data-action="link"] .oe-row,
.oe-index.has-open .oe-entry[data-action="link"] .oe-row--interactive {
  pointer-events: none;
  cursor: var(--oe-cursor-minus, default);
}

/* Snap list colour changes — only the accordion should ease on mobile */
body.oe.is-mobile .oe-row,
body.oe.is-mobile .oe-row__glyph {
  transition: none;
}

body.oe.is-mobile .oe-detail {
  transition: grid-template-rows 480ms var(--oe-motion-ease);
}

body.oe.is-mobile .oe-detail__reveal {
  transform: translateZ(0);
}

/* About — identity col 1; contact + bio span cols 2–4 */
body.oe.is-mobile .oe-about {
  margin-bottom: 0;
  align-items: start;
}

body.oe.is-mobile .oe-about > div[aria-hidden="true"] {
  display: none;
}

body.oe.is-mobile .oe-about__identity {
  grid-column: 1;
  grid-row: 1;
}

body.oe.is-mobile .oe-about__contact {
  grid-column: 2 / -1;
  grid-row: 1;
}

/* Figma: empty 24px line between phone and bio (node 186:7) */
body.oe.is-mobile .oe-about__bio {
  grid-column: 2 / -1;
  grid-row: 2;
  margin-top: var(--oe-m-leading);
}

/* Mobile: one rule only — between index and about; none before services.
   Match the tighter line→copy gap on both sides of the rule. */
body.oe.is-mobile .oe-rule {
  width: calc(var(--oe-layout-width, 100%) - 2 * var(--oe-m-pad));
  max-width: none;
  margin-top: calc(36 / var(--oe-m-artboard) * 100vw);
  margin-bottom: calc(36 / var(--oe-m-artboard) * 100vw);
  transition: none !important;
}

body.oe.is-mobile .oe-about + .oe-rule {
  display: none;
}

/* Services / Areas — tap title to reveal description (radio, one open at a time) */
body.oe.is-mobile .oe-services {
  margin-top: calc(36 / var(--oe-m-artboard) * 100vw);
}

body.oe.is-mobile .oe-services,
body.oe.is-mobile .oe-areas {
  width: 100%;
  max-width: 100%;
}

body.oe.is-mobile .oe-service.oe-grid {
  grid-template-columns: var(--oe-m-col) var(--oe-m-col) var(--oe-m-desc);
  column-gap: var(--oe-m-gap);
  width: 100%;
  max-width: 100%;
  align-items: start;
  min-height: 0;
  height: auto;
  padding: 0;
}

body.oe.is-mobile .oe-service > div[aria-hidden="true"] {
  display: none;
}

body.oe.is-mobile .oe-service__label {
  grid-column: 1;
  overflow: hidden;
}

body.oe.is-mobile .oe-service__label.is-dot {
  color: transparent;
}

body.oe.is-mobile .oe-service__title {
  grid-column: 2;
  cursor: pointer;
  overflow-wrap: break-word;
  word-break: normal;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  user-select: none;
}

body.oe.is-mobile .oe-service__title:focus,
body.oe.is-mobile .oe-service__title:active {
  outline: none;
  background: transparent;
  color: inherit;
}

/* When one service/area is open, mute sibling titles only (section labels stay) */
body.oe.is-mobile .oe-services.has-open .oe-service:not(.is-open):not(.oe-rights) .oe-service__title,
body.oe.is-mobile .oe-areas.has-open .oe-service:not(.is-open):not(.oe-rights) .oe-service__title {
  color: var(--oe-muted-mobile);
}

body.oe.is-mobile .oe-services.has-open .oe-service__label:not(.is-dot),
body.oe.is-mobile .oe-areas.has-open .oe-service__label:not(.is-dot),
body.oe.is-mobile .oe-service.is-open .oe-service__title,
body.oe.is-mobile .oe-service.is-open .oe-service__desc-inner {
  color: var(--oe-text);
}

body.oe.is-mobile .oe-service__label,
body.oe.is-mobile .oe-service__title,
body.oe.is-mobile .oe-service__desc-inner {
  transition: none;
}

body.oe.is-mobile .oe-service__desc {
  grid-column: 3;
  position: static;
  height: 0;
  min-height: 0;
  overflow: hidden;
  pointer-events: none;
}

body.oe.is-mobile .oe-service__desc-inner {
  position: static;
  opacity: 0;
  visibility: hidden;
  overflow-wrap: break-word;
  word-break: normal;
}

body.oe.is-mobile .oe-service.is-open .oe-service__desc {
  height: auto;
  overflow: visible;
  pointer-events: auto;
}

body.oe.is-mobile .oe-service.is-open .oe-service__desc-inner {
  opacity: 1;
  visibility: visible;
}

body.oe.is-mobile .oe-service--tech .oe-service__desc {
  height: 0;
}

body.oe.is-mobile .oe-service--tech.is-open .oe-service__desc {
  height: auto;
}

body.oe.is-mobile .oe-service__desc-inner.oe-service__tech {
  white-space: pre-line;
}

body.oe.is-mobile .oe-areas {
  margin-top: calc(48 / var(--oe-m-artboard) * 100vw);
}

body.oe.is-mobile .oe-rights {
  margin-top: calc(48 / var(--oe-m-artboard) * 100vw);
}

/* Mobile footer — full line from col 2 (same start as previous ©-only line) */
body.oe.is-mobile .oe-rights.oe-grid {
  display: grid;
  grid-template-columns: var(--oe-m-col) var(--oe-m-col) var(--oe-m-col) var(--oe-m-col);
  column-gap: var(--oe-m-gap);
  width: 100%;
}

body.oe.is-mobile .oe-rights > div[aria-hidden="true"] {
  display: none;
}

body.oe.is-mobile .oe-rights__reserved {
  display: none;
}

body.oe.is-mobile .oe-rights__copy {
  grid-column: 2 / -1;
  white-space: nowrap;
}

/* Expanded project — Close → summary|credits (side by side) → media.
   Description spans two mobile columns (--oe-m-desc); credits are role | name
   in the remaining two columns (same pattern as desktop / services). */
body.oe.is-mobile .oe-detail__reveal {
  display: flex;
  flex-direction: column;
}

body.oe.is-mobile .oe-detail__stage {
  display: contents;
}

body.oe.is-mobile .oe-detail__meta {
  display: grid;
  grid-template-columns: var(--oe-m-desc) var(--oe-m-col) var(--oe-m-col);
  column-gap: var(--oe-m-gap);
  width: 100%;
  max-width: 100%;
  align-items: start;
  order: 2;
  padding-bottom: 0;
}

body.oe.is-mobile .oe-detail__meta > div[aria-hidden="true"] {
  display: none;
}

/* Title-row spacers are desktop alignment only */
body.oe.is-mobile .oe-detail__copy > .oe-detail__spacer,
body.oe.is-mobile .oe-detail__credits > .oe-detail__spacer {
  display: none;
}

body.oe.is-mobile .oe-detail__copy {
  display: block;
  grid-column: 1;
  min-height: 0;
}

body.oe.is-mobile .oe-detail__copy > p {
  margin: 0;
}

body.oe.is-mobile .oe-detail__credits {
  grid-column: 2 / -1;
  padding-bottom: 0;
  margin-top: 0;
}

body.oe.is-mobile .oe-detail__credits li {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  column-gap: var(--oe-m-gap);
}

body.oe.is-mobile .oe-detail__close-col,
body.oe.is-mobile .oe-detail__close-fallback {
  order: 1;
  margin: 0 0 var(--oe-m-leading);
}

body.oe.is-mobile .oe-detail__media {
  order: 3;
  margin-top: 0;
  /* Full-bleed past page pad */
  width: calc(100% + 2 * var(--oe-m-pad));
  max-width: none;
  margin-left: calc(-1 * var(--oe-m-pad));
  margin-right: calc(-1 * var(--oe-m-pad));
  align-self: stretch;
  min-width: 0;
}

/*
  Mobile: full-bleed stage. Aspect (→ height) is set once from the widest
  landscape slide in the gallery (capped at 16:9). Every slide shares it.
*/
body.oe.is-mobile .oe-detail__media-stage {
  width: 100%;
  max-width: none;
  height: auto;
  max-height: none;
  aspect-ratio: var(--oe-media-ar, 16 / 9);
  margin: 0;
  align-self: stretch;
}

body.oe.is-mobile .oe-detail__stage {
  margin-top: 0;
  gap: 0;
}

/* Side-edge taps for gallery nav — center free for native video controls */
body.oe.is-mobile .oe-detail__hit {
  width: 25%;
  z-index: 4;
}

body.oe.is-mobile .oe-detail__av {
  /* Same 2-col pin as desktop — --oe-av-left tracks the footage (incl. portraits) */
  grid-template-columns:
    var(--oe-av-left, 0px)
    minmax(0, 1fr);
  padding: 0 0 2px;
  transition: opacity 320ms ease;
}

body.oe.is-mobile .oe-detail__av-btns {
  grid-column: 2;
  justify-self: start;
}
