/* andelse studio — shared stylesheet */

/* Self-hosted from /fonts. One variable file covers the whole 300–900 axis, so
   every weight Figma uses (Regular 400, Medium 500, SemiBold 600, Bold 700) is
   a real instance rather than a synthesised one. */
@font-face {
  font-family: 'Darker Grotesque';
  src: url('../../fonts/DarkerGrotesque-Variable.woff2') format('woff2'),
       url('../../fonts/DarkerGrotesque-VariableFont_wght.ttf') format('truetype');
  font-weight: 300 900;
  font-style: normal;
  font-display: swap;
}

/* Tobias VF — the accent italic, used only for the "[about]" nav link.
   Shipped as the unconverted .ttf on purpose: this is the TRIAL cut, and its
   licence forbids modifying or reassembling the file, which is what a WOFF2
   conversion or a subset would be. See the note in CLAUDE.md before deploying. */
@font-face {
  font-family: 'Tobias VF-TRIAL';
  src: url('../../fonts/TobiasVF-TRIAL.ttf') format('truetype');
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}

:root {
  --bg: #f2f2f2;
  --text: #303030;
  --accent: #0000ff;       /* the archive's opening statement only */
  --ph-light: #e8e8e6;
  --ph-mid: #dcdad5;
  --ph-dark: #262626;

  --gap: clamp(1rem, 1.2vw, 1.5rem);
  --edge: clamp(1.25rem, 3vw, 3rem);
  --fs-base: clamp(1.1375rem, 1.0375rem + 0.4vw, 1.3375rem);
  --fs-label: clamp(1.0875rem, 0.9875rem + 0.3vw, 1.2875rem);
  --logo-w: clamp(10rem, 8rem + 9vw, 17rem);
  --logo-w-sm: clamp(5.5rem, 4.5rem + 3.6vw, 8rem);
  --fs-hero-nav: clamp(1.15rem, 1rem + 0.7vw, 1.65rem);
  --fs-tagline: clamp(1.3rem, 1.1rem + 1.3vw, 2.3rem);
  --fs-heading: clamp(1.4rem, 1.2rem + 1.2vw, 2.1rem);

  /* site nav + landing — extracted via Figma Dev Mode from "andelse website spec"
     (1440x900 reference frames: landing_default, main nav / nav sticky components,
     work_selected work, work_extended archive, studio).
     Each clamp's preferred value is Xpx/1440*100vw so the exact Figma
     pixel value is hit at the 1440px reference width (the clamp max). */
  --land-edge-x: clamp(2rem, 3.6806vw, 3.3125rem);          /* 53px @1440 — header logo left inset, all pages */
  --land-nav-right: clamp(1rem, 1.3194vw, 1.1875rem);       /* 19px @1440 — nav-sticky right inset, all pages */
  --land-top-offset: clamp(1rem, 1.5972vw, 1.4375rem);      /* 23px @1440 — nav-sticky top offset, all pages */
  --land-logo-top: clamp(1rem, 1.5972vw, 1.4375rem);        /* 23px @1440 — header logo top offset, all pages */
  --land-logo-w: clamp(5rem, 8.1924vw, 7.3732rem);          /* 117.971px @1440 — hero mark, natural ratio */
  --land-logo-h: clamp(2.1063rem, 3.4513vw, 3.1062rem);     /* 49.6992px @1440 — hero mark, natural ratio */
  --land-logo-sm-w: clamp(12rem, 18.1944vw, 16.375rem);     /* 262px @1440 — compact mark, subpages + landing stage 2 */
  --land-nav-fs: clamp(1.025rem, 1.389vw, 1.25rem);         /* 20px @1440 — work / studio */
  --land-sub-fs: clamp(0.925rem, 1.2501vw, 1.125rem);       /* 18px @1440 — selected work / extended archive */
  --land-about-fs: clamp(0.925rem, 1.1807vw, 1.0625rem);    /* 17px @1440 — italic accent "[about]" link */
  --land-tag-fs: clamp(0.975rem, 1.3196vw, 1.1875rem);      /* 19px @1440 — hero tagline */
  --land-tag-fs-corner: clamp(1.025rem, 1.389vw, 1.25rem);  /* 20px @1440 — scrolled tagline */
  --land-tag-right: clamp(1rem, 2.1528vw, 1.9375rem);       /* 31px @1440 */
  --land-tag-bottom: clamp(0.75rem, 1.7361vw, 1.5625rem);   /* 25px @1440 */
  --land-top-right: clamp(0.75rem, 1.0417vw, 0.9375rem);    /* 15px @1440 — "scroll to top" right inset */
  --land-top-bottom: clamp(0.5rem, 0.6944vw, 0.625rem);     /* 10px @1440 — "scroll to top" bottom inset */

  /* one Figma pixel of the 1440-wide reference frame — subpage compositions are
     coordinate-based, so every position/size below is written as its literal
     Figma px value multiplied by this unit */
  --fig: calc(100vw / 1440);
  --page-fs: clamp(1rem, calc(var(--fig) * 18), 1.6172rem);       /* 18px @1440 */
  --page-fs-sm: clamp(0.9375rem, calc(var(--fig) * 16), 1.4375rem); /* 16px @1440 — project captions */
  --pr-fs: clamp(0.9375rem, calc(var(--fig) * 17), 1.5273rem);     /* 17px @1440 — projects index */
  --pr-soon-fs: clamp(0.7169rem, calc(var(--fig) * 13), 1.1680rem); /* 13px @1440 — the italic note */
  --page-lh: 0.8;                                                  /* 12px leading on 15px text */

  /* motion */
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --t-stage: 0.55s;
  --t-hover: 0.28s;
  --lift: 8px;
}

* { box-sizing: border-box; }

html {
  background: var(--bg);
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: 'Darker Grotesque', sans-serif;
  font-size: var(--fs-base);
  line-height: 1.35;
  text-transform: lowercase;
  -webkit-font-smoothing: antialiased;
  animation: page-in 0.35s var(--ease) both;
}

@keyframes page-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

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

ul { list-style: none; margin: 0; padding: 0; }
p { margin: 0; }
figure { margin: 0; }

.underline {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

/* ---------- landing page (index.html only) ---------- */
/* Calibrated from Figma "andelse website spec" file, 1440px reference frame. */

/* -- stage 0: hero (default, pre-scroll) -- */

.hero {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--edge);
}

/* width is the logo's width, so .hero centres the LOGO on the page; the tagline
   starts at that box's left edge and overflows right (Figma: logo centred at
   720, tagline left edge 652 = logo left edge) */
.hero-content {
  width: var(--land-logo-w);
  opacity: 1;
  transition: opacity var(--t-stage) var(--ease), transform var(--t-stage) var(--ease);
}

body.page-landing.is-scrolled .hero-content {
  opacity: 0;
  transform: translateY(calc(var(--lift) * -1));
  pointer-events: none;
}

.hero-logo {
  display: block;
  width: var(--land-logo-w);
  height: var(--land-logo-h);
  color: var(--text);
}
.hero-logo img { display: block; width: 100%; height: 100%; }

.land-tagline {
  color: var(--text);
  font-family: 'Darker Grotesque', sans-serif;
  font-weight: 700;
  font-size: var(--land-tag-fs);
  letter-spacing: -0.04em;
  white-space: nowrap;
}

.land-tagline .u {
  text-decoration: underline;
  text-underline-offset: 0.1em;
}

.hero-tagline { margin-top: clamp(0.5rem, calc(var(--fig) * 16), 1rem); }

/* -- persistent header: compact logo + work/studio nav --
   shared by landing (stages 2 & 3, scroll-toggled) and every subpage
   (always visible — this is the site's one consistent nav system) */

.land-logo {
  position: fixed;
  left: var(--land-edge-x);
  top: var(--land-logo-top);
  z-index: 60;
  width: var(--land-logo-sm-w);
  color: var(--text);
  opacity: 0;
  pointer-events: none;
  transform: translateY(var(--lift));
  transition: opacity var(--t-stage) var(--ease), transform var(--t-stage) var(--ease),
              width var(--t-stage) var(--ease), left var(--t-stage) var(--ease),
              top var(--t-stage) var(--ease);
}
.land-logo img { display: block; width: 100%; height: auto; }

body.page-landing.is-scrolled .land-logo {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

body:not(.page-landing) .land-logo {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

/* Figma `Frame 22`: the header is one row inset 53 either side, the nav
   centred against the logo's 21.79 height. */
body:not(.page-landing) .land-topnav {
  right: calc(var(--fig) * 53);
  top: calc(var(--fig) * 23.89);
}

/* -- stage 1: centered vertical work/studio menu -- */

.land-menu {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translateY(calc(-50% + var(--lift)));
  z-index: 55;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-stage) var(--ease), transform var(--t-stage) var(--ease);
}

/* the stage-2 pieces settle in sequence rather than all at once; the delay is
   only on the incoming state so leaving stays immediate */
body.page-landing.is-scrolled .land-menu {
  opacity: 1;
  transform: translateY(-50%);
  transition-delay: 0.06s;
  pointer-events: auto;
}

.land-menu-group {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* invisible hit-area bridge so hover survives the gap between trigger and
   submenu; padding+negative-margin cancel out so layout is unaffected */
.land-menu-group:not(.land-menu-group--studio) {
  padding-bottom: 40px;
  margin-bottom: -40px;
}

.land-menu-group--studio {
  --studio-bridge: 20px;
  margin-top: 71px;
  /* hover bridge across the 8px gap to "[about]" */
  padding-right: var(--studio-bridge);
}

.land-menu-trigger {
  font-size: var(--land-nav-fs);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 0.15em;
  white-space: nowrap;
}

.land-menu-sub {
  position: absolute;
  left: 0;
  /* just under the trigger, whatever size it is */
  top: calc(var(--land-nav-fs) * 1.35 + 1px);
  opacity: 0;
  transform: translateY(-3px);
  pointer-events: none;
  transition: opacity var(--t-hover) var(--ease), transform var(--t-hover) var(--ease);
}

/* studio's reveal is a single inline link to the right of the trigger,
   not a stack below it */
/* 8px to the right of the trigger's text — the bridge padding is part of the
   group's width, so it has to come back off the 100% anchor */
.land-menu-group--studio .land-menu-sub {
  left: 100%;
  top: 1px;
  margin-left: calc(8px - var(--studio-bridge));
  transform: translateX(-4px);
}

.land-menu-group:hover .land-menu-sub {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.land-menu-sub a {
  display: block;
  line-height: 1;
  font-size: var(--land-sub-fs);
  font-weight: 500;
  white-space: nowrap;
}
.land-menu-sub a:hover { text-decoration: underline; }

/* Figma: Tobias VF-TRIAL Regular Italic, 11px, 22px leading, -0.43px tracking.
   Scoped through the submenu so it outranks the generic 13px `.land-*-sub a`
   rule, which otherwise wins on specificity and forces this link to 13px/500. */
.land-menu-sub .land-about,
.land-topnav-sub .land-about {
  font-family: 'Tobias VF-TRIAL', Georgia, 'Times New Roman', serif;
  font-style: italic;
  font-weight: 400;
  /* the italic sits on a custom `ital` axis running 0–12, so font-style alone
     — which asks for ital 1 — would render all but upright */
  font-variation-settings: 'ital' 12;
  font-size: var(--land-about-fs);
  line-height: 1.8333;
  letter-spacing: -0.0358em;
  white-space: nowrap;
}
.land-about:hover { text-decoration: underline; }

/* -- stage 1: bottom-right corner tagline -- */

.land-tagline--corner {
  position: fixed;
  right: var(--land-tag-right);
  bottom: var(--land-tag-bottom);
  z-index: 55;
  opacity: 0;
  transform: translateY(var(--lift));
  pointer-events: none;
  transition: opacity var(--t-stage) var(--ease), transform var(--t-stage) var(--ease);
}

/* the scrolled tagline is set a point larger than the hero one */
.land-tagline--corner { font-size: var(--land-tag-fs-corner); }

body.page-landing.is-scrolled .land-tagline--corner {
  opacity: 1;
  transform: translateY(0);
  transition-delay: 0.12s;
}

/* -- stage 2 / persistent header: compact top-right nav -- */

.land-topnav {
  position: fixed;
  right: var(--land-nav-right);
  top: var(--land-top-offset);
  z-index: 55;
  display: flex;
  align-items: flex-start;
  gap: clamp(0.875rem, 1.25vw, 1.125rem); /* 18px @1440 */
  opacity: 0;
  transform: translateY(calc(var(--lift) * -1));
  pointer-events: none;
  transition: opacity var(--t-stage) var(--ease), transform var(--t-stage) var(--ease);
}

body:not(.page-landing) .land-topnav {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.land-topnav-group {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  /* hit-area bridge down to the submenu — safe with no negative margin,
     since these are flex-row siblings and don't push each other */
  padding-bottom: 40px;
}

.land-topnav-group--studio {
  align-items: flex-start;
}

.land-topnav-trigger {
  font-size: var(--land-nav-fs);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 0.15em;
  white-space: nowrap;
}

.land-topnav-sub {
  position: absolute;
  right: 0;
  top: calc(var(--land-nav-fs) * 1.35);
  text-align: right;
  opacity: 0;
  transform: translateY(-3px);
  pointer-events: none;
  transition: opacity var(--t-hover) var(--ease), transform var(--t-hover) var(--ease);
}

/* Figma sets this one 3px left of the trigger's own left edge */
.land-topnav-group--studio .land-topnav-sub {
  right: auto;
  left: calc(var(--fig) * -3);
  top: calc(var(--land-nav-fs) * 1.35);
  text-align: left;
}

.land-topnav-group:hover .land-topnav-sub {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.land-topnav-sub a {
  display: block;
  line-height: 1;
  font-size: var(--land-sub-fs);
  font-weight: 500;
  white-space: nowrap;
}
.land-topnav-sub a:hover { text-decoration: underline; }

/* -- the scroll that reveals the menu; the landing ends here -- */

.land-spacer {
  min-height: 100vh;
}

/* ---------- subpages ----------
   All three destination pages are coordinate-based compositions taken from the
   1440x900 Figma frames (work_selected work / work_extended archive / studio).
   Every position and size below is the literal Figma px value x --fig. */

.page-label {
  display: block;
  color: var(--text);
  font-size: var(--page-fs);
  font-weight: 700;
  /* Figma sets these 15px labels in a 20px box */
  line-height: 1.3333;
  text-decoration: underline;
  text-underline-offset: 0.15em;
  white-space: nowrap;
}

/* ---------- projects index (selected work) ----------
   Figma `work_selected work` (306:18): a three-column text list at x 67 / 191 /
   420 from y 190, 19 lines on a 1.2 leading, and one hidden image layer per
   project that fades in while its row is hovered or focused. */

.pr {
  position: relative;
  height: calc(var(--fig) * 1000);
  font-size: var(--pr-fs);
}

/* Tobias VF-TRIAL Regular Italic, 13px, sitting 45px above the list and
   flush with its numbering column. The italic rides a custom `ital` axis
   running 0–12, so font-style alone — which asks for ital 1 — renders upright. */
.pr-soon {
  position: absolute;
  left: calc(var(--fig) * 67);
  top: calc(var(--fig) * 145);
  font-family: 'Tobias VF-TRIAL', Georgia, 'Times New Roman', serif;
  font-style: italic;
  font-weight: 400;
  font-variation-settings: 'ital' 12;
  font-size: var(--pr-soon-fs);
  line-height: 1.2;
  color: var(--text);
  z-index: 2;
}

.pr-list {
  position: absolute;
  left: calc(var(--fig) * 67);
  top: calc(var(--fig) * 190);
  width: calc(var(--fig) * 533);
  z-index: 2;
}

.pr-row {
  position: relative;
  display: grid;
  grid-template-columns: calc(var(--fig) * 124) calc(var(--fig) * 246) auto;
  height: 1.2em;
  line-height: 1.2;
  color: var(--text);
  transform-origin: left center;
  transition: transform var(--t-hover) var(--ease);
}

/* the three blank lines that group the list in the frame */
.pr-row--gap { display: block; }

/* hovered or focused: the row magnifies and thickens, its immediate
   neighbours a little less, and each piece of text takes its own rule.
   Transforms don't reflow, so the list never shifts underneath the pointer. */
.pr-row.is-active { transform: scale(1.08); z-index: 1; }
.pr-row.is-near { transform: scale(1.03); }

.pr-row span {
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.18em;
  /* transparent until hovered, so the rule can fade rather than snap */
  text-decoration-color: transparent;
  transition: text-decoration-color var(--t-hover) var(--ease),
              font-variation-settings var(--t-hover) var(--ease);
}

.pr-row.is-active span { text-decoration-color: var(--text); }

.pr-row.is-active .pr-no,
.pr-row.is-active .pr-kind { font-variation-settings: 'wght' 800; }
.pr-row.is-active .pr-name { font-variation-settings: 'wght' 900; }
.pr-row:focus { outline: none; }
.pr-row:focus-visible { outline: 1px dotted currentColor; outline-offset: 0.2em; }

.pr-row span { white-space: nowrap; }
.pr-no { font-weight: 600; font-variation-settings: 'wght' 600; }
.pr-name { font-weight: 800; font-variation-settings: 'wght' 800; }
.pr-kind { font-weight: 600; font-variation-settings: 'wght' 600; }

/* Each layer is its group's Figma bounding box, so a group of several images
   scales as one piece; the children sit inside it as percentages. */
.pr-img {
  container-type: inline-size;
  position: absolute;
  left: calc(var(--fig) * var(--bx));
  top: calc(var(--fig) * var(--by));
  width: calc(var(--fig) * var(--bw));
  height: calc(var(--fig) * var(--bh));
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s var(--ease);
  z-index: 1;
}

.pr-img.is-on { opacity: 1; }

/* the description sizes against its own layer, so it holds both on the
   --fig canvas and when the layer is scaled up for the phone reveal */
.pr-img > .pr-note,
.pr-img > .pr-credit {
  /* the Figma box becomes a floor rather than a cap: at this size the text
     needs more room than the frame allots it. Scoped through .pr-img so it
     outranks the `.pr-img > *` box rule that follows. */
  height: auto;
  min-height: var(--h);
  color: var(--text);
  text-align: justify;
}

.pr-note {
  font-size: calc(100cqw * 16 / var(--bw));
  font-weight: 600;
  line-height: 0.9;
}

.pr-year,
.pr-credit {
  display: block;
  font-size: calc(100cqw * 15 / var(--bw));
  font-weight: 800;
  line-height: 1;
}

.pr-year { margin-top: 1em; }

.pr-img > * {
  position: absolute;
  left: var(--l, 0);
  top: var(--t, 0);
  width: var(--w, 100%);
  height: var(--h, 100%);
  overflow: hidden;
}

/* a couple of plates are rounded in the frame */
.pr-img > [style*="--r"] { border-radius: calc(var(--fig) * var(--r)); }

/* most fills are plain covers; the cropped ones carry their own offsets */
.pr-img img {
  position: absolute;
  left: var(--il, 0);
  top: var(--it, 0);
  width: var(--iw, 100%);
  height: var(--ih, 100%);
  object-fit: cover;
}

/* ---------- the studio page's background ----------
   The canvas carries the gradient as a CSS background too, so the art is
   there before the shader runs — and stays there if WebGL is missing or the
   visitor asked for reduced motion. */

.st-bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  display: block;
  width: 100%;
  height: 100%;
  background: var(--bg) url('../img/about-bg.webp') center / cover no-repeat;
}

/* The generated gradient runs from #3f3f3f to #efefef, so the page's usual
   #303030 would sit on top of its own value in the dark passages. */
body.page-studio {
  /* white, not #efefef: the gradient's own ceiling is #efefef, so matching it
     leaves the type no headroom against the brightest passages */
  --text: #ffffff;
}

/* the mark is a dark SVG, so it needs inverting rather than recolouring */
body.page-studio .land-logo img { filter: invert(1); }

body.page-studio .st,
body.page-studio .land-logo,
body.page-studio .land-topnav { z-index: 1; }

body.page-studio .land-logo { z-index: 60; }
body.page-studio .land-topnav { z-index: 55; }

/* ---------- extended archive ---------- */

.ea {
  position: relative;
  height: calc(var(--fig) * 6700);
  font-size: var(--page-fs);
}

.ea-opening {
  position: absolute;
  left: calc(var(--fig) * 115);
  top: calc(var(--fig) * 210);
  width: calc(var(--fig) * 342);
  color: var(--accent);
  font-weight: 700;
  line-height: 1.333;
}

.ea-rule {
  position: absolute;
  left: calc(var(--fig) * 111);
  /* centred in the ink gap between the two lines, not on the line-box
     boundary: measured, the glyphs of line 1 end 19.75 below the text top and
     line 2 begins at 28.75, so the stroke's centre belongs at 24.25 --
     1.5156em at this size -- less half its own 2px height */
  top: calc(var(--fig) * 210 + 1.5156 * var(--page-fs) - 1px);
  width: calc(var(--fig) * 349.2);
  height: 2px;
  background: var(--accent);
}

.ea .page-label { position: absolute; }
.ea-at-interior { right: calc(var(--fig) * 118); top: calc(var(--fig) * 356); }
.ea-at-research { left: calc(var(--fig) * 115); top: calc(var(--fig) * 1236); }
.ea-at-teaching { right: calc(var(--fig) * 118); top: calc(var(--fig) * 1236); }
.ea-at-experimental { right: calc(var(--fig) * 118); top: calc(var(--fig) * 1642); }

/* `mardini`: a 2x2 grid of spreads with its caption row 14 beneath */
.ea-set {
  position: absolute;
  left: calc(var(--fig) * 76);
  top: calc(var(--fig) * 460);
  width: calc(var(--fig) * 1288);
  display: flex;
  flex-direction: column;
  gap: calc(var(--fig) * 14);
}

.ea-interiors {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: calc(var(--fig) * 6);
}

.ea-shot {
  position: relative;
  overflow: hidden;
  aspect-ratio: 641 / 321;
  background: var(--ph-light);
}

.ea-cap {
  display: flex;
  align-items: center;
  height: calc(var(--fig) * 22);
  width: calc(var(--fig) * 114);
  font-size: var(--page-fs-sm);
  font-weight: 400;
  line-height: 1.3333;
}

/* sits outside the caption frame in Figma, 83 in from the right edge */
.ea-kind {
  position: absolute;
  right: calc(var(--fig) * 83);
  top: calc(var(--fig) * 1122);
  width: calc(var(--fig) * 114);
  text-align: right;
  font-size: var(--page-fs-sm);
  font-weight: 600;
  line-height: 1.3333;
}

/* the three dotted-underline notes that caption the experimental sections */
.ea-note {
  position: absolute;
  font-size: var(--page-fs);
  font-weight: 700;
  line-height: var(--page-lh);
  text-decoration: underline dotted;
  text-underline-offset: 0.15em;
}

.ea-note--start {
  right: calc(var(--fig) * 111);
  top: calc(var(--fig) * 1681);
  width: calc(var(--fig) * 204);
  height: calc(var(--fig) * 88);
  text-align: right;
}

.ea-note--anything {
  left: calc(var(--fig) * 618);
  top: calc(var(--fig) * 3368);
  width: calc(var(--fig) * 204);
  height: calc(var(--fig) * 51);
}

.ea-note--posters {
  left: calc(var(--fig) * 116);
  top: calc(var(--fig) * 4823);
  width: calc(var(--fig) * 112);
  height: calc(var(--fig) * 24);
}

.ea-note--arabic {
  left: calc(var(--fig) * 1247);
  top: calc(var(--fig) * 5910);
  width: calc(var(--fig) * 112);
  height: calc(var(--fig) * 24);
}

/* `Frame 26`: a centred stack of a three-up row over a free-placed field */
.ea-collage {
  position: absolute;
  left: calc(var(--fig) * 120);
  top: calc(var(--fig) * 1805);
  width: calc(var(--fig) * 1193);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--fig) * 48);
}

.ea-collage-row {
  display: flex;
  align-items: flex-end;
  gap: calc(var(--fig) * 4);
}

.ea-collage-row img {
  display: block;
  width: calc(var(--fig) * var(--w));
  height: calc(var(--fig) * var(--h));
  object-fit: cover;
}

/* the lower field overlaps its own grid tracks in Figma, so each plate keeps
   its literal coordinate rather than being forced into columns */
.ea-collage-field {
  position: relative;
  width: 100%;
  height: calc(var(--fig) * 1119);
}

.ea-collage-field img {
  position: absolute;
  left: calc(var(--fig) * var(--x));
  top: calc(var(--fig) * var(--y));
  width: calc(var(--fig) * var(--w));
  height: calc(var(--fig) * var(--h));
  object-fit: cover;
}

/* `Frame 27`: six poster slots, one of which holds three smaller sheets, so
   each keeps its own literal box rather than sharing a uniform track */
.ea-posters {
  position: absolute;
  left: calc(var(--fig) * 233);
  top: calc(var(--fig) * 4866);
  width: calc(var(--fig) * 973);
  height: calc(var(--fig) * 914.426);
}

.ea-poster,
.ea-poster--set > * {
  position: absolute;
  left: calc(var(--fig) * var(--x));
  top: calc(var(--fig) * var(--y));
  width: calc(var(--fig) * var(--w));
  height: calc(var(--fig) * var(--h));
  overflow: hidden;
  background: var(--ph-light);
}

.ea-poster--set { background: none; }

.ea-poster img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* `Frame 32`: the arabic type studies */
.ea-arabic {
  position: absolute;
  left: calc(var(--fig) * 212);
  top: calc(var(--fig) * 5965);
  width: calc(var(--fig) * 1014);
  height: calc(var(--fig) * 647);
}

.ea-arabic > * {
  position: absolute;
  left: calc(var(--fig) * var(--x));
  top: calc(var(--fig) * var(--y));
  width: calc(var(--fig) * var(--w));
  height: calc(var(--fig) * var(--h));
  overflow: hidden;
  background: var(--ph-light);
}

.ea-arabic img {
  position: absolute;
  left: var(--il, 0);
  top: var(--it, 0);
  width: var(--iw, 100%);
  height: var(--ih, 100%);
  object-fit: cover;
}

/* the loose composition plates below the collage */
.ea-plate {
  position: absolute;
  left: calc(var(--fig) * var(--x));
  top: calc(var(--fig) * var(--y));
  width: calc(var(--fig) * var(--w));
  height: calc(var(--fig) * var(--h));
  overflow: hidden;
  background: var(--ph-light);
}

.ea-plate img,
.ea-plate video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* the dot sits above the video layer */
.ea-plate video { display: block; }

.ea-shot img {
  position: absolute;
  left: 0;
  top: -16.57%;
  width: 100%;
  height: 133.14%;
  object-fit: cover;
}

.ea-block {
  position: absolute;
  top: calc(var(--fig) * 1286);
  width: calc(var(--fig) * 217.6);
  font-weight: 700;
  line-height: var(--page-lh);
}

.ea-research { left: calc(var(--fig) * 115); }
.ea-teaching { right: calc(var(--fig) * 111); text-align: right; }

.ea-block p + p { margin-top: 0.8em; }
.ea-reg { font-weight: 400; }

.ea-thesis {
  text-decoration: underline;
  text-underline-offset: 0.15em;
  text-transform: none;
}

/* the roman-numeral column sits inside the teaching block, 57px in from its
   left edge and 54px down — expressed relatively so it holds at any scale */
.ea-nums {
  position: absolute;
  left: 27.94%;
  top: 3.6em;
  text-align: left;
  font-weight: 700;
}

/* ---------- studio ---------- */

.st {
  position: relative;
  height: calc(var(--fig) * 999);
  font-size: var(--page-fs);
  font-weight: 700;
  line-height: var(--page-lh);
}

/* Figma `Frame 21` (301:78): the three blocks are a single vertical
   auto-layout anchored at 116,210 on a uniform 51px gap */
.st-stack {
  position: absolute;
  left: calc(var(--fig) * 116);
  top: calc(var(--fig) * 210);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: calc(var(--fig) * 51);
}

.st-block p + p { margin-top: 0.8em; }

/* fixed-height frames in Figma, so the trailing space is part of the rhythm */
.st-opening { width: calc(var(--fig) * 424); min-height: calc(var(--fig) * 92); }
.st-services { width: calc(var(--fig) * 138); min-height: calc(var(--fig) * 125); }
.st-background { width: calc(var(--fig) * 167); min-height: calc(var(--fig) * 190); }

/* studio labels sit inside the 12px-leaded text blocks */
.st .page-label { line-height: inherit; margin-bottom: 0.8em; }

.st-brand {
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

/* Figma `contact us at hello@andelse.studio` (431:28): a right-aligned column
   on the same 138x125 box and the same y as `services`, mirrored to the right */
.st-contact {
  position: absolute;
  right: calc(var(--fig) * 117);
  top: calc(var(--fig) * 353);
  width: calc(var(--fig) * 138);
  min-height: calc(var(--fig) * 125);
  text-align: right;
}

.st-contact a:hover,
.st-contact a:focus-visible {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}


/* ---------- pointer dot ----------
   Replaces the system cursor on fine pointers. The fill flips to #d9d9d9
   wherever the backdrop is too dark for #303030 to read against; the test
   itself lives in assets/js/cursor.js. */

.cursor-dot {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 9999;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background-color: #303030;
  opacity: 0;
  pointer-events: none;
  transform: translate3d(-50px, -50px, 0);
  will-change: transform;
  transition: background-color 0.12s linear, opacity 0.12s linear;
}

/* only once the script is running, so a failure leaves the real cursor in place */
body.has-cursor-dot,
body.has-cursor-dot * {
  cursor: none;
}

/* ---------- footer note ---------- */

.site-footer {
  padding: clamp(2rem, 4vw, 3rem) var(--edge);
  font-size: var(--fs-label);
  color: var(--text);
}

/* ---------- responsive ---------- */

/* Below this width the coordinate-based compositions unwind into a single
   column. Type keeps its 15px/12px setting rather than shrinking with the
   viewport, so the pages read the same — they stack rather than scale down. */
@media (max-width: 900px) {
  :root {
    --page-fs: 1.125rem;
    --page-gutter: 1.5rem;
  }

  /* hero: the tagline is nowrap at desktop and far wider than a phone, so here
     it wraps inside a gutter-width box with the logo centred above it */
  .hero { padding-inline: 1.5rem; }
  .hero-content { width: 100%; max-width: 26rem; }
  .hero-logo { width: clamp(5rem, 30vw, 7.375rem); height: auto; margin: 0 auto; }
  .hero-logo img { height: auto; }
  .land-tagline { white-space: normal; }

  /* phone: the hero line sits centred under the logo at a size that keeps
     the logo the dominant element, broken into two balanced lines */
  .hero-tagline {
    font-size: 0.875rem;
    text-align: center;
    text-wrap: balance;
    max-width: 17rem;
    margin-inline: auto;
  }

  /* scrolled corner line: small, so it reads as a caption, not a headline */
  .land-tagline--corner {
    font-size: 0.8125rem;
    max-width: 13rem;
    text-align: right;
    text-wrap: balance;
  }

  /* nav: the compact logo carries the header on a phone, so it gets bigger;
     the work/studio type gets smaller so the logo leads */
  :root {
    --land-nav-fs: 0.9375rem;
    --land-sub-fs: 0.8125rem;
    --land-about-fs: 0.75rem;
  }
  .land-logo { width: clamp(8.5rem, 38vw, 11rem); }
  .land-topnav { gap: 0.75rem; }
  .land-menu-group--studio { margin-top: 2.5rem; }

  /* -- projects index: the list goes full width and the revealed image is
        centred on screen, since the frame coordinates mean nothing at phone
        width. The group keeps its own proportions. -- */
  .pr {
    position: static;
    height: auto;
    min-height: 100vh;
    padding: 6.5rem var(--page-gutter) 4rem;
  }
  .pr-list {
    position: static;
    width: auto;
  }
  .pr-row {
    grid-template-columns: 2.5rem minmax(0, 1fr);
    height: auto;
    line-height: 1.3;
    padding: 0.35rem 0;
  }
  .pr-row--gap { height: 1rem; padding: 0; }
  .pr-row.is-active,
  .pr-row.is-near { transform: none; }
  .pr-row span { white-space: normal; }
  .pr-kind { grid-column: 2; font-size: 0.9375rem; opacity: 0.75; }
  .pr-img {
    position: fixed;
    left: 50%;
    top: 50%;
    width: min(78vw, calc(70vh * var(--bw) / var(--bh)));
    height: auto;
    aspect-ratio: var(--bw) / var(--bh);
    transform: translate(-50%, -50%);
    z-index: 40;
  }

  /* tapped project opens inline, right under its row, and pushes the rest
     of the list down instead of covering it (main.js moves the layer here).
     The composition keeps its proportions; its description comes out below
     as readable text, since inside the composition it would be a few px. */
  .pr-drop {
    display: block;
    padding: 0.75rem 0 1.75rem 2.5rem;
  }
  .pr-drop .pr-img {
    position: relative;
    left: auto;
    top: auto;
    transform: none;
    width: min(100%, calc(55vh * var(--bw) / var(--bh)));
    height: auto;
    aspect-ratio: var(--bw) / var(--bh);
    z-index: auto;
  }
  .pr-drop .pr-img > .pr-note,
  .pr-drop .pr-img > .pr-credit { display: none; }
  .pr-drop-text {
    margin-top: 0.75rem;
    max-width: 22rem;
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.15;
    opacity: 0;
    transition: opacity 0.25s var(--ease);
  }
  .pr-drop-text p + p { margin-top: 0.5em; }
  .pr-drop-text .pr-year {
    margin-top: 0.6em;
    font-size: 0.875rem;
    font-weight: 800;
  }
  .pr-drop.is-on .pr-drop-text { opacity: 1; }

  /* -- extended archive + studio: unwind the canvas -- */
  .ea,
  .st {
    position: static;
    height: auto;
    padding: 6.5rem var(--page-gutter) 4rem;
  }
  .ea > *,
  .st-stack,
  .st-block,
  .st-contact {
    position: static;
    width: auto;
    height: auto;
    inset: auto;
  }
  .st-stack { gap: 3rem; }

  /* the text column must stay a positioned layer: as a plain static block it
     drops beneath the fixed background canvas and the page reads as empty */
  body.page-studio .st { position: relative; z-index: 1; }
  /* every block takes a full row except the motion plates, which pair up.
     Without positioned parents the images inside posters, arabic tiles and
     plates would anchor to the whole page and pile on top of each other. */
  .ea {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    column-gap: 0.5rem;
  }
  .ea > * { flex: 0 0 100%; min-width: 0; }
  .ea-opening {
    max-width: 24rem;
    border-bottom: 2px solid var(--accent);
    padding-bottom: 0.35em;
  }
  .ea-rule { display: none; }
  .ea-set { margin-top: 1.5rem; }
  .ea-interiors {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.5rem;
  }
  .ea-shot { height: auto; aspect-ratio: 641 / 321; }
  .ea-cap { width: auto; }
  .ea-kind { text-align: left; }

  /* the experimental sections unwind into plain stacked grids */
  .ea-note {
    margin-top: 2.5rem;
    text-align: left;
  }
  .ea-collage {
    width: auto;
    gap: 0.5rem;
    align-items: stretch;
    margin-top: 1.5rem;
  }
  .ea-collage-row { flex-wrap: wrap; gap: 0.5rem; }
  .ea-collage-row img {
    width: calc(50% - 0.25rem);
    height: auto;
    aspect-ratio: var(--w) / var(--h);
  }
  .ea-collage-field {
    position: static;
    height: auto;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.5rem;
  }
  .ea-collage-field img {
    position: static;
    width: 100%;
    height: auto;
    aspect-ratio: var(--w) / var(--h);
  }
  .ea-plate {
    position: relative;
    inset: auto;
    flex: 0 0 calc(50% - 0.25rem);
    width: calc(50% - 0.25rem);
    height: auto;
    aspect-ratio: var(--w) / var(--h);
    margin-top: 0.5rem;
  }
  .ea-posters,
  .ea-arabic {
    width: auto;
    height: auto;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.5rem;
    margin-top: 1.5rem;
  }
  .ea-poster,
  .ea-arabic > * {
    position: relative;
    left: auto;
    top: auto;
    width: 100%;
    height: auto;
    aspect-ratio: var(--w) / var(--h);
  }
  .ea-poster--set {
    position: relative;
    /* relative, so the desktop left/top would still shift it */
    inset: auto;
    aspect-ratio: var(--w) / var(--h);
  }
  .ea-poster--set > * {
    position: absolute;
    left: calc(var(--x) / 321.667 * 100%);
    top: calc(var(--y) / 454.713 * 100%);
    width: calc(var(--w) / 321.667 * 100%);
    height: calc(var(--h) / 454.713 * 100%);
  }
  .ea .page-label {
    position: static;
    display: block;
    margin-top: 3rem;
    margin-bottom: 0.8em;
  }
  /* keep the archive's left/right dialogue rather than flattening it */
  .ea-at-interior,
  .ea-at-teaching,
  .ea-at-experimental { text-align: right; }
  .ea-block { position: relative; max-width: 22rem; }
  .ea-teaching { margin-left: auto; }
  .st-contact { margin-top: 3rem; text-align: left; }
}

/* ---------- reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }
}
