/* 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: 13px;
  --oe-leading: 17px;
  --oe-tracking: -0.13px;
  --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: var(--oe-size);
  line-height: var(--oe-leading);
  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);
}

/*
  Media − cursor can’t use mix-blend on a CSS cursor URL. Hide the system
  cursor and draw a difference-blended glyph (same treatment as Prev/Next).
*/
body.oe:not(.is-touch) .oe-detail__media,
body.oe:not(.is-touch) .oe-detail__media *,
body.oe:not(.is-touch) .oe-detail__media.is-nav-gutter-next {
  cursor: none !important;
}

.oe-media-cursor {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 10000;
  margin: 0;
  padding: 0;
  pointer-events: none;
  opacity: 0;
  color: #fff;
  mix-blend-mode: difference;
  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;
  will-change: transform;
  transition: opacity 120ms ease;
}

.oe-media-cursor.is-on {
  opacity: 1;
}

/* Inside :fullscreen the cursor must live in the FS element (body children are hidden) */
body.oe .oe-detail__media:fullscreen .oe-media-cursor,
body.oe .oe-detail__media:-webkit-full-screen .oe-media-cursor,
body.oe .oe-detail__media.is-oe-fs .oe-media-cursor {
  z-index: 20;
}

.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-touch) .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-touch) .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-touch) .oe-entry:not(.is-open) .oe-row--interactive:hover,
body.oe:not(.is-touch)
  .oe-entry:not(.is-open):has(.oe-row--interactive:hover)
  .oe-row__glyph {
  color: var(--oe-text);
}

/* Outbound links: mute only while pressed (or desktop hover).
   iOS keeps :hover stuck after tap — never rely on :hover for touch feedback. */
body.oe a[href^="http"],
body.oe a[href^="//"] {
  -webkit-tap-highlight-color: transparent;
  color: inherit;
  transition: color var(--oe-motion-duration) var(--oe-motion-ease);
}

body.oe a[href^="http"]:focus,
body.oe a[href^="//"]:focus {
  outline: none;
  color: inherit;
}

/* Finger / mouse down only — releases the moment the press ends */
body.oe a[href^="http"]:active,
body.oe a[href^="//"]:active,
body.oe a[href^="http"].is-oe-pressed,
body.oe a[href^="//"].is-oe-pressed {
  color: var(--oe-muted);
}

/* Desktop hover mute (fine pointer, not touch class) */
@media (hover: hover) and (pointer: fine) {
  body.oe:not(.is-touch) a[href^="http"]:hover,
  body.oe:not(.is-touch) a[href^="//"]:hover {
    color: var(--oe-muted);
  }
}

/* Kill sticky :hover mute on any touch / coarse pointer device */
@media (hover: none), (pointer: coarse) {
  body.oe a[href^="http"]:hover:not(:active):not(.is-oe-pressed),
  body.oe a[href^="//"]:hover:not(:active):not(.is-oe-pressed) {
    color: inherit;
  }
}

body.oe.is-touch a[href^="http"]:hover:not(:active):not(.is-oe-pressed),
body.oe.is-touch a[href^="//"]:hover:not(:active):not(.is-oe-pressed) {
  color: inherit;
}

.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,
body.oe.is-tablet .oe-preview,
body.oe.is-touch .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 meta row to the tallest column; media sits flush under that bottom */
.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 the tallest meta column; next project row 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;
}

/* Touch: allow vertical page scroll; horizontal swipe handled in JS for gallery nav */
body.oe.is-touch .oe-detail__media-stage {
  touch-action: pan-y;
}

/* Sits above slides so iOS video can’t steal taps/swipes (pointer-events:none on
   <video> is ignored while playing). Below AV chrome (z-index 5). */
body.oe.is-touch .oe-detail__gesture {
  position: absolute;
  inset: 0;
  z-index: 4;
  touch-action: pan-y;
  -webkit-user-select: none;
  user-select: none;
  background: transparent;
}

body.oe.is-touch .oe-detail__media.is-oe-fs .oe-detail__gesture {
  /* Fullscreen: claim the gesture so horizontal swipes aren’t lost to scroll */
  touch-action: none;
}

.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: var(--oe-leading);
  height: var(--oe-leading);
  margin: 0;
  padding: 0;
  font-size: var(--oe-size);
  line-height: var(--oe-leading);
  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 the stage canvas (below letterbox mattes).
  Horizontally: hug pillarboxed footage (verticals); otherwise the stage /
  client column when it fits. Lives outside the stage so portraits don’t clip.
  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;
  /* Default 0 = stage left edge. Never use full-grid fractions here — this
     box lives inside the media column, so a 355/1045 spacer parks Unmute
     under the credits track until JS sets --oe-av-left. */
  grid-template-columns:
    var(--oe-av-left, 0px)
    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.
   .is-oe-fs = touch simulated FS (our Close / Unmute, no Safari chrome X) */
body.oe .oe-detail__media:fullscreen,
body.oe .oe-detail__media:-webkit-full-screen,
body.oe .oe-detail__media.is-oe-fs {
  width: 100%;
  height: 100%;
  max-width: none;
  background: #000;
  cursor: none;
  display: block;
  align-items: stretch;
}

/*
  Mobile reveal uses translateZ(0) which makes position:fixed relative to that
  box — FS overlay would only cover the project panel (looks “frozen”). Drop it
  while simulated FS is open so in-place video FS can cover the viewport without
  reparenting (reparenting reloads the decoder).
*/
html.oe-fs-active body.oe.is-mobile .oe-detail__reveal {
  transform: none !important;
}

html.oe-fs-active body.oe.is-mobile .oe-detail__stage:has(.oe-detail__media.is-oe-fs) {
  display: block !important;
}

body.oe .oe-detail__media.is-oe-fs {
  position: fixed !important;
  inset: 0 !important;
  left: 0 !important;
  top: 0 !important;
  right: 0 !important;
  bottom: 0 !important;
  z-index: 9999 !important;
  width: 100vw !important;
  width: 100dvw !important;
  height: 100vh !important;
  height: 100dvh !important;
  max-width: none !important;
  margin: 0 !important;
  padding: 0 !important;
  order: 0 !important;
  align-self: stretch !important;
  box-sizing: border-box;
  background: #000 !important;
  display: block !important;
}

/* Beat later mobile full-bleed width/margin rules */
body.oe.is-mobile .oe-detail__media.is-oe-fs,
body.oe.is-tablet .oe-detail__media.is-oe-fs {
  position: fixed !important;
  inset: 0 !important;
  width: 100vw !important;
  width: 100dvw !important;
  height: 100vh !important;
  height: 100dvh !important;
  max-width: none !important;
  margin: 0 !important;
  order: 0 !important;
  /* Don’t inherit blown-up mobile vw type while landscape in FS */
  font-size: 14px;
  line-height: 18px;
  letter-spacing: -0.14px;
}

body.oe.is-mobile .oe-detail__media.is-oe-fs .oe-detail__media-stage,
body.oe.is-tablet .oe-detail__media.is-oe-fs .oe-detail__media-stage {
  --oe-media-max-h: 100dvh;
  --oe-media-max-w: 100dvw;
  width: 100% !important;
  height: 100% !important;
  max-width: none !important;
  max-height: none !important;
  aspect-ratio: auto !important;
  margin: 0 !important;
}

body.oe.is-mobile .oe-detail__media.is-oe-fs .oe-detail__av-btn,
body.oe.is-tablet .oe-detail__media.is-oe-fs .oe-detail__av-btn {
  font-size: 14px;
  line-height: 18px;
  letter-spacing: -0.14px;
}

body.oe.is-mobile .oe-detail__media.is-oe-fs img:not(.oe-detail__frame-blur),
body.oe.is-mobile .oe-detail__media.is-oe-fs video,
body.oe.is-mobile .oe-detail__media.is-oe-fs iframe[data-oe-vimeo],
body.oe.is-tablet .oe-detail__media.is-oe-fs img:not(.oe-detail__frame-blur),
body.oe.is-tablet .oe-detail__media.is-oe-fs video,
body.oe.is-tablet .oe-detail__media.is-oe-fs iframe[data-oe-vimeo] {
  object-fit: contain !important;
  object-position: center !important;
  width: 100% !important;
  height: 100% !important;
  inset: 0 !important;
  left: 0 !important;
  top: 0 !important;
}

body.oe .oe-detail__media:fullscreen.is-av-chrome,
body.oe .oe-detail__media:-webkit-full-screen.is-av-chrome,
body.oe .oe-detail__media.is-oe-fs.is-av-chrome {
  /* Keep system cursor hidden — difference glyph follows the pointer instead */
  cursor: none;
}

body.oe .oe-detail__media:fullscreen .oe-detail__media-stage,
body.oe .oe-detail__media:-webkit-full-screen .oe-detail__media-stage,
body.oe .oe-detail__media.is-oe-fs .oe-detail__media-stage {
  --oe-media-max-h: 100vh;
  --oe-media-max-h: 100dvh;
  --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,
body.oe .oe-detail__media.is-oe-fs .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],
body.oe .oe-detail__media.is-oe-fs img:not(.oe-detail__frame-blur),
body.oe .oe-detail__media.is-oe-fs video,
body.oe .oe-detail__media.is-oe-fs 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,
body.oe .oe-detail__media.is-oe-fs .oe-detail__hit,
body.oe .oe-detail__media.is-oe-fs .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,
body.oe .oe-detail__media.is-oe-fs .oe-detail__av {
  padding: 0 0 max(20px, env(safe-area-inset-bottom, 0px))
    max(20px, env(safe-area-inset-left, 0px));
  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;
}

/*
  Touch (phone + iPad): both Previous + Next sit in their column positions,
  vertically centered on the visible footage. Shown with media chrome on tap,
  then fade with is-av-chrome (same timer as Unmute / Fullscreen).
*/
body.oe.is-touch .oe-detail__nav-label--prev,
body.oe.is-touch .oe-detail__nav-label--next {
  top: calc(var(--oe-nav-box-top, 0px) + var(--oe-nav-box-h, 100%) / 2);
  opacity: 0;
}

body.oe.is-touch
  .oe-detail__media.has-gallery-nav.is-av-chrome
  .oe-detail__media-stage:not(.is-loading)
  .oe-detail__nav-label--prev,
body.oe.is-touch
  .oe-detail__media.has-gallery-nav.is-av-chrome
  .oe-detail__media-stage:not(.is-loading)
  .oe-detail__nav-label--next {
  opacity: 1;
}

/* —— 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-label p,
.oe-about__bio p {
  margin: 0;
  line-height: var(--oe-leading);
}

/* Phone trial only — desktop / tablet stay label-free */
.oe-about__bio-label {
  display: none;
}

.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);
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  user-select: none;
}

.oe-service__title:focus,
.oe-service__title:focus-visible,
.oe-service__title:active {
  outline: none;
  background: transparent;
  color: inherit;
  -webkit-tap-highlight-color: transparent;
}

/* 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: var(--oe-leading);
}

body.oe:not(.is-mobile) .oe-rights {
  margin-top: auto;
  padding-top: var(--oe-leading);
}

.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 ";
}

/*
  Tablet (iPad etc.) — desktop grid, type nudged up from desktop 13/17
  (~15/19) for reading distance; still well below phone 19/24.
*/
body.oe.is-tablet {
  --oe-size: 15px;
  --oe-leading: 19px;
  --oe-tracking: -0.15px;
  --oe-pad: 24px;
  --oe-glyph: 28px;

  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  font-size: var(--oe-size);
  line-height: var(--oe-leading);
  letter-spacing: var(--oe-tracking);
  font-weight: 500;
}

body.oe.is-tablet .oe-row__glyph-symbol,
body.oe.is-tablet .oe-detail__nav-label {
  font-size: var(--oe-size);
  line-height: var(--oe-leading);
}

/* Touch hits sized to the visible footage box (not the full stage matte).
   Portrait: Next sits on the image’s right edge — stage-right 22% misses it. */
body.oe.is-touch .oe-detail__hit {
  top: var(--oe-nav-box-top, 0px);
  bottom: auto;
  height: var(--oe-nav-box-h, 100%);
  z-index: 4;
}

body.oe.is-touch .oe-detail__hit--prev {
  left: var(--oe-nav-box-left, 0px);
  width: calc(var(--oe-nav-box-w, 100%) * 0.35);
}

body.oe.is-touch .oe-detail__hit--next {
  left: calc(var(--oe-nav-box-left, 0px) + var(--oe-nav-box-w, 100%) * 0.65);
  right: 0;
  width: auto;
}

/* When chrome is up, tapping the Previous / Next words themselves navigates */
body.oe.is-touch
  .oe-detail__media.has-gallery-nav.is-av-chrome
  .oe-detail__nav-label {
  pointer-events: auto;
}

/* Tablet: no desktop title-row spacers; meta height still follows tallest column */
body.oe.is-tablet .oe-detail__copy > .oe-detail__spacer,
body.oe.is-tablet .oe-detail__credits > .oe-detail__spacer {
  display: none;
}

body.oe.is-tablet .oe-detail__meta {
  /* Same as desktop: row height = max(copy, credits); media butts under that */
  align-items: stretch;
}

body.oe.is-tablet .oe-detail__copy {
  display: flex;
  flex-direction: column;
  min-height: 100%;
}

body.oe.is-tablet .oe-page {
  width: min(100%, var(--oe-max));
}

body.oe.is-tablet .oe-grid {
  max-width: min(100%, var(--oe-content));
}

/*
  Portrait iPad: glyphs sit in the right pad (outside the content track).
  Do NOT shrink .oe-grid / meta / stage — that made the whole layout look scaled down
  vs landscape even though --oe-size stayed 13px.
*/
@media (orientation: portrait) {
  body.oe.is-tablet .oe-page {
    /* Same left pad as landscape tablet; only right grows for the glyph column */
    padding-right: calc(var(--oe-glyph) + 12px);
  }

  body.oe.is-tablet .oe-row__glyph {
    left: 100%;
    right: auto;
    margin-left: 8px;
  }
}

/*
  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 {
  /*
    Size from the short viewport edge so rotating to landscape doesn’t blow up
    type/pad (100vw becomes the long edge). Page browsing stays “portrait scale”.
  */
  --oe-m-vw: min(100vw, 100vh);
  --oe-m-artboard: 720;
  --oe-m-grid: 680;
  --oe-m-pad: calc(20 / var(--oe-m-artboard) * var(--oe-m-vw));
  --oe-m-size: min(19px, calc(19 / var(--oe-m-artboard) * var(--oe-m-vw)));
  --oe-m-leading: min(24px, calc(24 / var(--oe-m-artboard) * var(--oe-m-vw)));
  --oe-m-track: min(-0.19px, calc(-0.19 / var(--oe-m-artboard) * var(--oe-m-vw)));
  /* Keep shared rules (rights, service line-height, etc.) on mobile scale */
  --oe-size: var(--oe-m-size);
  --oe-leading: var(--oe-m-leading);
  --oe-tracking: var(--oe-m-track);
  --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%;
}

/* Landscape browse: keep the site column at portrait width (FS is exempt) */
@media (orientation: landscape) {
  body.oe.is-mobile:not(:has(.oe-detail__media.is-oe-fs)) .oe-page {
    width: min(100vh, 480px);
    max-width: 100%;
    margin-left: auto;
    margin-right: auto;
  }
}

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;
}

/* Shared touch mute — idle non-tappable rows AND closed rows when something is open */
body.oe.is-mobile,
body.oe.is-tablet {
  /* ~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,
body.oe.is-tablet .oe-entry[data-action="tease"] .oe-row,
body.oe.is-tablet .oe-entry[data-action="none"] .oe-row,
body.oe.is-tablet .oe-index.has-open .oe-entry:not(.is-open) .oe-row,
body.oe.is-tablet .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 touch */
body.oe.is-mobile .oe-row,
body.oe.is-mobile .oe-row__glyph,
body.oe.is-tablet .oe-row,
body.oe.is-tablet .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"]:not(.oe-about__bio-label) {
  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;
}

/* Phone trial: About label sits in the left column beside the bio */
body.oe.is-mobile .oe-about__bio-label {
  display: block;
  grid-column: 1;
  grid-row: 2;
  margin-top: var(--oe-m-leading);
}

/* 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);
}

/* Phone only: hide leftover closed accordion after WebKit tab-switch glitches.
   Desktop / tablet keep the existing collapse animation. */
body.oe.is-mobile .oe-entry:not(.is-open) .oe-detail {
  pointer-events: none;
}

body.oe.is-mobile .oe-entry:not(.is-open) .oe-detail__reveal {
  visibility: hidden;
  transition: visibility 0s linear var(--oe-motion-duration);
}

body.oe.is-mobile .oe-entry.is-open .oe-detail__reveal {
  visibility: visible;
  transition: visibility 0s;
}

body.oe.is-mobile .oe-index.is-swapping .oe-entry:not(.is-open) .oe-detail__reveal {
  transition: none;
}

/* Phone: About → rule → projects → rule → services / areas.
   Desktop / tablet keep the source order (projects first). */
body.oe.is-mobile .oe-about {
  order: 1;
}

body.oe.is-mobile .oe-about + .oe-rule {
  order: 2;
}

body.oe.is-mobile .oe-index {
  order: 3;
}

body.oe.is-mobile .oe-index + .oe-rule {
  order: 4;
}

body.oe.is-mobile .oe-services {
  order: 5;
}

body.oe.is-mobile .oe-areas {
  order: 6;
}

/* Mobile: rules on both sides of the project list.
   Hairline stroke — 1px reads heavy on phone DPR vs desktop. */
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);
  border-top-width: 1px;
  transform: scaleY(0.75);
  transform-origin: center;
  transition: none !important;
}

/* Services / Areas — tap title to reveal description (radio, one open at a time) */

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(32 / 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 use visible-footage hit boxes (see is-touch .oe-detail__hit) */
body.oe.is-mobile .oe-detail__hit {
  z-index: 4;
}

body.oe.is-mobile .oe-detail__av,
body.oe.is-tablet .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,
body.oe.is-tablet .oe-detail__av-btns {
  grid-column: 2;
  justify-self: start;
}
