/* =====================================================================
   OTTO JAKOB — site.css
   Translates the Claude Design mockup (React explorations) into a
   portable stylesheet. Pairs with tokens.css (palette / type / motion).
   No framework — plain HTML5 + a few small vanilla-JS behaviours.
   ===================================================================== */

/* --- Reset --- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }
/* Site-wide page ground is plain white (overrides the warm-paper token from
   tokens.css for the body, header and subnav that reference it). */
:root { --paper-warm: #FFFFFF; }
body {
  background: var(--paper-warm);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
}
img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }

/* The gallery uses a generous gutter aligned to the wordmark / utilities. */
:root { --gutter: 44px; }
@media (max-width: 720px) { :root { --gutter: 20px; } }

/* =====================================================================
   HEADER — wordmark left, sections + utilities right.
   Sticks to the top across the catalogue scroll (the design's
   stickyHeader). The Jewelry subcategory row pins beneath it.
   ===================================================================== */
.site-header {
  position: sticky; top: 0; z-index: 40;
  background: var(--paper-warm);
}
.site-header--noir { position: absolute; left: 0; right: 0; background: transparent; }

/* DESKTOP header: wordmark left; EN/DE + icons at the far right of the masthead;
   the section links (.mainnav, a header child) are absolutely placed on the
   masthead's line just left of the EN/DE + icons; subnav rows below. The
   hamburger is hidden on desktop. */
/* The non-noir header stays sticky (its original behaviour) AND is the
   positioning context for the absolutely-placed section links (sticky elements
   establish a containing block). The noir landing header keeps its own
   `position: absolute`. */
.site-header:not(.site-header--noir) { position: sticky; top: 0; }
/* The masthead holds the wordmark (left) and the EN/DE + icons (right). The
   section nav (.mainnav) is a SEPARATE header child, laid over this row so it
   centres in the gap between the two groups — see .mainnav below. */
.masthead {
  display: flex; align-items: center;
  gap: 24px; padding: 26px var(--gutter) 12px;
}
.navtoggle { display: none; }              /* hamburger: mobile only */
.wordmark {
  order: 0;
  font-family: var(--serif); font-weight: var(--w-reg);
  font-size: 39px; line-height: 1; letter-spacing: 0.05em;
  text-transform: lowercase; color: var(--ink); white-space: nowrap;
}
.site-header--noir .wordmark { color: var(--gold-light); }

/* Section links: laid over the masthead row, filling the band BETWEEN the
   wordmark (left) and the EN/DE + icons (right) and centring within it. Insetting
   the box by each group's width (rather than viewport-centring) means the nav
   sits in the free space and can never overlap either group — even with the
   enlarged wordmark or the longer German labels. */
.mainnav {
  position: absolute; top: 41px;
  /* Symmetric insets so the nav's centre is the viewport centre (matching the
     subnav rows below). The inset clears the WIDER side group (the wordmark) on
     both sides, so neither is overlapped. */
  left: 266px; right: 266px;
  display: flex; align-items: center; justify-content: center;
}
.nav-sections { display: flex; align-items: center; gap: 36px; }
.mainnav a { line-height: 1; }
.nav-sections a {
  font-family: var(--sans); font-weight: var(--w-med);
  font-size: 11.7px; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--ink-soft); padding-bottom: 2px;
  border-bottom: 1px solid transparent; white-space: nowrap;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.nav-sections a:hover { color: var(--ink); }
.nav-sections a.is-active { color: var(--ink); font-weight: var(--w-semi); }
.site-header--noir .nav-sections a { color: rgba(244,241,233,.74); }
.site-header--noir .nav-sections a:hover { color: var(--on-noir); }
.site-header--noir .nav-sections a.is-active { color: var(--on-noir); font-weight: var(--w-semi); }

/* Language switch — pushed to the right end of the masthead (its margin-left
   auto sends it and the icons after it to the far right, leaving the middle band
   for the overlaid section nav). */
.langswitch { order: 2; margin-left: auto; display: inline-flex; align-items: center; gap: 6px; }
.langswitch a {
  font-family: var(--sans); font-weight: var(--w-med);
  font-size: 11.7px; letter-spacing: 0.18em; text-transform: uppercase;
  /* Non-current language is faded so the bold, near-black active one stands out
     clearly — the two-letter labels need a wider contrast than longer nav words
     to read as an obvious selection. */
  color: var(--ink-faint); padding-bottom: 2px;
  border-bottom: 1px solid transparent;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.langswitch__sep { font-family: var(--sans); font-size: 11.7px; color: var(--ink-faint); }
.langswitch a.is-current { color: var(--ink); font-weight: var(--w-semi); }
.site-header--noir .langswitch a { color: rgba(244,241,233,.45); }
.site-header--noir .langswitch__sep { color: rgba(244,241,233,.4); }
.site-header--noir .langswitch a.is-current {
  color: var(--on-noir); font-weight: var(--w-semi);
}

.utilities {
  order: 3; display: flex; align-items: center; gap: 18px; color: var(--ink);
}
.site-header--noir .utilities { color: var(--on-noir); }
.utilities a { display: inline-flex; opacity: .9; transition: opacity var(--dur) var(--ease); }
.utilities a:hover { opacity: 1; }

/* Subcategory rows — centred under the masthead. All layers use the same font
   size as the section links (9px) and an equal vertical gap between each row. */
.subnav {
  display: flex; align-items: center; justify-content: center;
  gap: 32px; flex-wrap: wrap;
  padding: 8px var(--gutter) 0;          /* equal gap above each subnav row */
  background: var(--paper-warm);
}
.subnav a {
  font-family: var(--sans); font-weight: var(--w-med);
  font-size: 11.7px; line-height: 1; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-mute); padding-bottom: 2px;
  border-bottom: 1px solid transparent; white-space: nowrap;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.subnav a:hover { color: var(--ink); }
.subnav a.is-active { color: var(--ink); font-weight: var(--w-semi); }
/* Line 2 (first subnav) is pulled up so it sits at the exact vertical midpoint
   between line 1 (the absolutely-placed section links) and line 3. */
.mainnav + .subnav { padding-top: 0; margin-top: -10px; }

/* Third menu line — same size + gap as the second (only the colour differs). */
.subnav--third { gap: 28px; padding-top: 11px; }
.subnav--third a { font-size: 11.7px; letter-spacing: 0.18em; color: var(--ink-faint); }
.subnav--third a:hover { color: var(--ink-mute); }
.subnav--third a.is-active { color: var(--ink); font-weight: var(--w-semi); }

/* =====================================================================
   MANIFESTO 1980 — an imaginary widescreen (9:4) frame, scan left + the
   typed list (multi-column) right, keeping the unified master look.
   ===================================================================== */
.manifesto {
  display: flex; justify-content: center;
  padding: 36px var(--gutter) 48px;
}
.manifesto__frame {
  width: 100%; aspect-ratio: 9 / 4; max-height: calc(100vh - 200px);
  display: grid; grid-template-columns: 0.72fr 1.5fr;
  border: 1px solid var(--line); overflow: hidden;
}
.manifesto__scan {
  position: relative; overflow: hidden; background: var(--paper);
  display: flex; align-items: center; justify-content: flex-start;
}
/* show the whole sheet (never crop the list), pulled to the left edge with
   minimal margin so it doesn't float in empty space. */
.manifesto__scan img {
  width: 100%; height: 100%; object-fit: contain; object-position: left center;
  display: block; padding: clamp(8px, 1.6vh, 16px);
}
.manifesto__placeholder { color: var(--ink-faint); }

.manifesto__typed {
  padding: clamp(20px, 3vh, 40px) clamp(20px, 2.5vw, 40px);
  overflow: hidden; display: flex; align-items: center;
}
/* Three balanced columns across the typed area. CSS multi-columns keep each
   column independent, so long phrases wrap inside their own column and never
   collide with or get clipped by the next one, at any width. */
.manifesto__list {
  margin: 0; padding: 0; list-style: none; width: 100%;
  column-count: 3; column-gap: clamp(20px, 3vw, 44px); column-fill: balance;
  font-family: var(--sans); font-weight: var(--w-reg);
  font-size: clamp(9px, 0.9vw, 12px); line-height: 1.65;
  color: var(--ink-soft);
}
.manifesto__list li { break-inside: avoid; }
/* clickable motifs (gold underline grows on hover); empty motifs are quiet. */
.manifesto__list a {
  color: var(--ink-soft); text-decoration: none;
  background-image: linear-gradient(var(--gold-deep), var(--gold-deep));
  background-size: 0% 1px; background-position: 0 100%; background-repeat: no-repeat;
  transition: background-size var(--dur) var(--ease), color var(--dur) var(--ease);
}
.manifesto__list a:hover { color: var(--ink); background-size: 100% 1px; }
.manifesto__list a.is-active { color: var(--ink); background-size: 100% 1px; }
.manifesto__empty { color: var(--ink-faint); }
@media (max-width: 720px) {
  .manifesto__frame { aspect-ratio: auto; grid-template-columns: 1fr; max-height: none; }
  .manifesto__scan { aspect-ratio: 4 / 3; border-right: 0; border-bottom: 1px solid var(--line); }
  .manifesto__list { columns: 2; }
}

/* the motif gallery follows the composition; reuses the catalogue feed.
   scroll-margin-top makes the #manifesto-gallery anchor land just below the
   sticky header when a motif is opened. */
.manifesto-gallery { padding-top: 8px; scroll-margin-top: 130px; }
.manifesto-gallery__title {
  font-family: var(--serif); font-weight: var(--w-reg);
  font-size: var(--fs-h2); line-height: var(--lh-tight);
  letter-spacing: var(--track-tight); color: var(--ink);
  padding: 24px var(--gutter) 0;
}
.manifesto-gallery__empty { padding: 24px var(--gutter); color: var(--ink-mute); }

/* =====================================================================
   CONTACT — the master-slide treatment, true to its proportions: a full
   9:4 framed stage (a 200% stand-in) over a two-column caption carrying the
   atelier details. Stage + caption fit one screen, no scrolling.
   ===================================================================== */
.contact-master {
  display: flex; flex-direction: column; align-items: stretch;
  padding: 28px var(--gutter) 28px; gap: 28px;
}
/* identical stage proportions to .master__stage (9:4, capped to viewport). */
.contact-master__stage {
  position: relative; width: 100%; aspect-ratio: 9 / 4;
  max-height: calc(100vh - 220px);
  border: 1px solid var(--line); overflow: hidden;
  /* image cropped to fill the 9:4 frame (no zoom), centred. */
  background-repeat: no-repeat; background-position: center center;
  background-size: cover;
}

/* two-column caption: note + email + phone (right) | address (left) */
.contact-master__caption {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 24px var(--s-8); align-items: start;
}
.contact__col { margin: 0; }
.contact__col--main { text-align: right; }
.contact__col--address { text-align: left; }
@media (max-width: 720px) {
  .contact-master__caption { grid-template-columns: 1fr; gap: 24px; }
  .contact__col { text-align: center; }
}

/* One uniform line style everywhere (the jewelry-category-nav font: sans,
   tracked caps) — same font and size in both columns, rows aligned. */
.contact__lines {
  margin: 0; font-family: var(--sans); font-weight: var(--w-med);
  font-size: var(--fs-sm); letter-spacing: var(--track-nav); text-transform: uppercase;
  line-height: 2; color: var(--ink-soft);
}
.contact__lines .contact__note { color: var(--ink-mute); }
.contact__lines a {
  color: var(--ink); text-decoration: none; text-transform: none;
  letter-spacing: 0.02em;
  background-image: linear-gradient(var(--gold-deep), var(--gold-deep));
  background-size: 0% 1px; background-position: 0 100%; background-repeat: no-repeat;
  transition: background-size var(--dur) var(--ease);
}
.contact__lines a:hover { background-size: 100% 1px; }

/* =====================================================================
   PRESS — a column of master-style slabs, scrolled top to bottom. Each
   article is a framed scan (sized to its own proportions, capped to the
   viewport) or a paper plate carrying the title when there is no image.
   ===================================================================== */
.press {
  display: flex; flex-direction: column; gap: 56px;
  padding: 36px var(--gutter) 64px; align-items: center;
}
.press__item {
  display: flex; flex-direction: column; align-items: center;
  width: 100%; color: inherit; text-decoration: none;
}

/* image scans: the frame hugs the scan, which keeps its own aspect ratio and
   is capped to a comfortable height so portrait magazine pages aren't tiny. */
.press__img {
  display: block; max-width: 100%; max-height: 78vh; width: auto; height: auto;
  background: var(--paper); border: 1px solid var(--line);
  transition: border-color .2s var(--ease);
}
.press__item:hover .press__img { border-color: var(--line-strong); }

/* paper plate (no image) keeps the wide framed stage with the title. */
.press__stage {
  position: relative; width: 100%; aspect-ratio: 9 / 4;
  max-height: calc(100vh - 220px);
  background: var(--paper); overflow: hidden;
}
.press__stage::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  border: 1px solid var(--line);
}

/* Paper plate (no image) — gallery wall-text: label, big serif title, cue. */
.press__plate {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 22px;
  text-align: center; padding: var(--s-7);
}
.press__label { color: var(--ink-faint); }
.press__title {
  margin: 0; font-family: var(--serif); font-weight: var(--w-reg);
  font-size: clamp(1.75rem, 4vw, 3rem); line-height: var(--lh-tight);
  letter-spacing: var(--track-tight); color: var(--ink);
  max-width: 22ch;
}
.press__cue { color: var(--ink-mute); transition: color var(--dur) var(--ease); }
.press__item:hover .press__cue { color: var(--ink); }
.press__item:hover .press__stage::after { border-color: var(--line-strong); }

/* caption beneath an image-bearing article */
.press__caption { margin-top: 24px; }
.press__title--below { font-size: clamp(1.5rem, 3vw, 2.25rem); }
.press__caption .press__cue { display: inline-block; margin-top: 12px; }

/* =====================================================================
   SEARCH — the catalogue search. Field front-and-centre; results render
   below in the same gallery feed as the categories.
   ===================================================================== */
.search {
  display: flex; flex-direction: column; align-items: center;
  text-align: center; padding: 64px var(--gutter) 8px;
}
/* Empty state: lift the field into the centre of the viewport. */
.search--empty {
  justify-content: center;
  min-height: calc(100vh - 180px); padding-bottom: 64px;
}
.search__form { width: 100%; max-width: 680px; }
.search__field {
  display: flex; align-items: center; gap: 14px;
  border-bottom: 1px solid var(--ink);
  padding-bottom: 12px;
}
.search__glyph { color: var(--ink-mute); flex: none; }
.search__input {
  flex: 1; border: none; outline: none; background: transparent;
  font-family: var(--serif); font-weight: var(--w-reg);
  font-size: clamp(1.5rem, 3.5vw, 2.25rem); line-height: 1.1;
  color: var(--ink); padding: 0; min-width: 0;
}
.search__input::placeholder { color: var(--ink-faint); }
.search__exit {
  flex: none; display: inline-flex; align-items: center;
  color: var(--ink-mute); padding: 6px 2px; line-height: 0;
  transition: color var(--dur) var(--ease);
}
.search__exit:hover { color: var(--ink); }
.search__submit {
  flex: none; border: none; background: none; cursor: pointer;
  color: var(--ink-mute); padding: 6px 2px;
  transition: color var(--dur) var(--ease);
}
.search__submit:hover { color: var(--ink); }
.search__count {
  margin-top: 28px; color: var(--ink-mute);
}
.search__count .search__for { color: var(--ink-faint); }

/* =====================================================================
   LANDING — "The Plate": full-bleed noir hero, one featured piece.
   ===================================================================== */
.plate { position: relative; width: 100%; height: 100vh; min-height: 640px;
  background: var(--noir); overflow: hidden; }
.plate__img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; object-position: center;
  padding: clamp(40px, 7vh, 110px) var(--gutter);
}
.plate__scrim {
  position: absolute; inset: 0;
  background: linear-gradient(to bottom,
    rgba(12,11,10,.45) 0%, transparent 24%, transparent 50%, rgba(12,11,10,.82) 100%);
}
.plate__caption {
  position: absolute; left: var(--gutter); bottom: 72px; z-index: 2;
  max-width: 760px; display: block; text-align: left;
}
.plate__caption-row { display: flex; align-items: baseline; gap: 20px; }
.plate__name {
  font-family: var(--antiqua-sc); font-weight: var(--w-reg);
  /* Desktop hero name reduced 30% (mobile keeps the larger size below). */
  font-size: clamp(30.8px, 4.2vw, 51.8px); line-height: 0.98; letter-spacing: 0.005em;
  color: var(--on-noir); padding-bottom: 4px;
  border-bottom: 1px solid transparent; transition: border-color .25s var(--ease);
}
.plate__caption:hover .plate__name { border-bottom-color: var(--gold-light); }
.plate__year {
  font-family: var(--sans); font-weight: var(--w-med); font-size: 12px;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: rgba(244,241,233,.5); font-variant-numeric: tabular-nums;
}

/* =====================================================================
   FEED — the Overview and per-category catalogues.
   A 2-up grid of wide preview frames; the open piece takes its own
   full-width "master" slot spanning both columns.
   ===================================================================== */
.feed {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: 44px 24px; padding: 36px var(--gutter) 64px;
  /* feed.js manages scroll position itself when a master opens; the browser's
     own scroll-anchoring would fight that and cause unpredictable jumps. */
  overflow-anchor: none;
}
@media (max-width: 560px) { .feed { grid-template-columns: 1fr; } }

/* The open master and its hidden siblings span the full feed width. */
.feed__master { grid-column: 1 / -1; }
/* `hidden` must beat the cell's display:flex (the open piece's preview cell). */
.cell[hidden] { display: none; }

/* --- a collapsed preview cell --- */
.cell {
  border: none; background: none; padding: 0; cursor: pointer; text-align: left;
  display: flex; flex-direction: column; gap: 14px; width: 100%;
}
/* Jewelry preview frame — LOCKED to the exact 9:4 (2250:1000) crop the images
   are prepared at. The ratio must never change (no responsive override), and
   the image fills the frame edge-to-edge (object-fit:cover, no padding) so the
   carefully-chosen fragment is shown pixel-exact. Because the source images are
   themselves 9:4, `cover` displays 100% of them with no cropping. */
.cell__frame {
  position: relative; width: 100%; aspect-ratio: 9 / 4; overflow: hidden;
  background: var(--paper);
}
/* Hairline frame as an overlay above the image so the contour stays unbroken
   where the photo reaches the edge. */
.cell__frame::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  border: 1px solid var(--line); transition: border-color .2s var(--ease);
}
.cell__frame--noir { background: var(--noir); }
.cell:hover .cell__frame::after { border-color: var(--ink); }
.cell__img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center;
}
.cell__meta {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
}
.cell__name { font-family: var(--antiqua-sc); font-size: 18px; letter-spacing: 0.01em; color: var(--ink); }
.cell__year {
  font-family: var(--sans); font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

/* =====================================================================
   MASTER — the expanded piece. Ultra-wide 9:4 image, capped to the
   viewport height so the caption always stays on screen; name + year
   left, Enquire on the same line at the right.
   ===================================================================== */
.feed__master { scroll-margin-top: 140px; }
/* The master fills the full feed width — its left/right edges line up with
   the outer edges of the grid above it. Height follows the 9:4 ratio but is
   capped to the viewport so the caption underneath always stays on screen. */
.master { width: 100%; margin: 0 auto; }

/* Master stage — LOCKED to the exact 9:4 (2250:1000) crop, at all times and at
   every viewport. No max-height cap (which would shrink the box on short/wide
   screens) and no responsive override: the ratio is invariant. The image fills
   the frame edge-to-edge (cover, no padding); since the source is 9:4, all of
   it shows with no cropping. */
.master__stage {
  position: relative; width: 100%; aspect-ratio: 9 / 4;
  background: var(--paper); overflow: hidden;
}
/* Multi-image pieces: clicking the stage advances to the next image (matches the
   biography galleries), so hint it with a pointer. */
.master__stage--clickable { cursor: pointer; }
/* Hairline frame drawn as an overlay ABOVE the image, so the contour stays
   unbroken even where the photo reaches the edge of the stage. Sits below the
   close/pager controls (z-index 2). */
.master__stage::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  border: 1px solid var(--line);
}
.master__stage--noir { background: var(--noir); }
.master__shot {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center;
  opacity: 0; transition: opacity .5s cubic-bezier(.4,0,.1,1);
  /* Non-current slides are transparent but still stacked on top in DOM order;
     without this they'd intercept wheel/drag/click meant for the current slide.
     This matters for the scroll slide, whose wheel must reach the window itself
     (an image/video slide is unaffected — clicking anywhere still advances). */
  pointer-events: none;
}
.master__shot.is-current { opacity: 1; pointer-events: auto; }
/* A video slide: a Vimeo iframe injected by feed.js, filling the stage. */
.master__shot--video { padding: 0; }
.master__shot--video iframe {
  position: absolute; inset: 0; width: 100%; height: 100%; border: 0;
  /* Background Vimeo embeds have no controls; let clicks pass through the iframe
     to the stage so clicking a video slide advances like an image (no trap). */
  pointer-events: none;
}
/* A non-current video shot is opacity:0 but still laid out over the whole stage;
   its cross-origin Vimeo iframe then swallows wheel/trackpad events aimed at the
   slide beneath it (a scroll slide stops responding to the trackpad after the
   video has been shown — pointer-events:none doesn't govern wheel routing to a
   cross-origin iframe). Drop the iframe from layout while the video isn't current
   so it can't intercept; it returns when the video slide is shown again. */
.master__shot--video:not(.is-current) iframe { display: none; }

/* A tall scroll slide: the shot IS a vertical scroll window. The pre-cropped
   image already ends at its bottom framing (Magdalena: the tassel tip pinned at
   the chorinea point; Selvans IV: the current main crop), so scrolling bottoms
   out there and reveals more above. feed.js pins it to the bottom when the slide
   becomes current and captures the wheel/drag.
   Image width is --scroll-w of the stage: 100% for frame-width assets (a 2250-
   wide composed crop), or a smaller value baked per piece when the raw image
   must render at true master scale (Magdalena's necklace = 86%). */
.master__shot--scroll {
  padding: 0; background: var(--paper, #fff);
  overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain;
  --scroll-w: 100%;
}
.master__stage--noir .master__shot--scroll { background: var(--noir); }
.master__shot--scroll img {
  display: block; width: var(--scroll-w); margin: 0 auto;
  height: auto; object-fit: initial;   /* override the .master__shot cover rules */
}
/* Magdalena's necklace image is raw (necklace ~ full image width); render it at
   86% of the stage so the necklace lands at true master scale. */
.master__shot--scroll[data-scroll-scale="master"] { --scroll-w: 86%; }
.master__shot--scroll { scrollbar-width: thin; }
.master__shot--scroll::-webkit-scrollbar { width: 9px; }
.master__shot--scroll::-webkit-scrollbar-thumb {
  background: rgba(0,0,0,.28); border-radius: 5px;
}
.master__shot--scroll::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,.45); }
/* On a dark (noir) stage a dark thumb is invisible — use a light thumb instead. */
.master__stage--noir .master__shot--scroll::-webkit-scrollbar-thumb {
  background: rgba(255,255,255,.35);
}
.master__stage--noir .master__shot--scroll::-webkit-scrollbar-thumb:hover {
  background: rgba(255,255,255,.55);
}
/* Firefox: thin scrollbar with a theme-matched thumb (thumb colour, track colour). */
.master__shot--scroll { scrollbar-color: rgba(0,0,0,.35) transparent; }
.master__stage--noir .master__shot--scroll { scrollbar-color: rgba(255,255,255,.4) transparent; }

/* Up-arrow discovery hint for a scroll slide: they open at the bottom and reveal
   more above, but read as a static image otherwise (no persistent scrollbar on
   touch). A small round arrow chip at the RIGHT edge, vertically centred (where
   the scrollbar sits on desktop). A stage-level sibling of the scroll window so
   it doesn't scroll with the image. Shown only while a scroll slide is current
   (feed.js adds .has-scroll-current) and faded out once the viewer scrolls
   (feed.js adds .hint-dismissed). Reads on light and dark/textured backdrops. */
.master__scroll-hint {
  position: absolute; right: 14px; top: 50%; z-index: 2;
  display: none; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%;
  color: #fff; background: rgba(20,20,20,.55);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  pointer-events: none; user-select: none;
  transition: opacity .5s ease; opacity: 1;
  transform: translateY(-50%);
}
/* The arrow is a marker, not a control (clicking anywhere on the image scrolls
   up); it just needs to show while a scroll slide is current and fade on scroll. */
.master__stage.has-scroll-current .master__scroll-hint { display: inline-flex; }
.master__stage.hint-dismissed .master__scroll-hint { opacity: 0; }
.master__scroll-hint-arrow {
  font-size: 16px; line-height: 1;
  animation: hintbob 1.7s ease-in-out infinite;
}
@keyframes hintbob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
@media (prefers-reduced-motion: reduce) {
  .master__scroll-hint-arrow { animation: none; }
}

.master__close {
  position: absolute; top: 16px; right: 18px; z-index: 3;
  display: flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%; padding: 0;
  border: none; cursor: pointer; line-height: 1; font-size: 16px;
  /* A dark disc behind the ✕ (like .master__scroll-hint) so it stays legible
     over any slide — including a light-backed scroll image on a noir stage,
     where a bare light glyph would vanish against the pale photo. */
  color: #fff; background: rgba(20,20,20,.55);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
}
.master__stage--noir .master__close { color: #fff; }

/* Image navigation overlays the image, in its lower-right corner. */
.master__pager {
  position: absolute; right: 18px; bottom: 16px; z-index: 2;
  display: flex; align-items: center; gap: 16px; color: var(--ink-soft);
}
.master__stage--noir .master__pager { color: var(--on-noir); }
.master__pager button {
  border: none; background: none; cursor: pointer; padding: 2px 4px;
  font-family: var(--serif); font-size: 18px; line-height: 1; color: inherit;
}
.master__count {
  font-family: var(--sans); font-size: 11px; letter-spacing: 0.16em;
  font-variant-numeric: tabular-nums;
}
.master__count .sep { opacity: .5; margin: 0 5px; }

.master__caption { margin-top: 28px; }
.master__caption-row {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 24px;
}
.master__title-group { display: flex; align-items: baseline; gap: 18px; flex-wrap: wrap; }
.master__name {
  margin: 0; font-family: var(--antiqua-sc); font-weight: var(--w-reg);
  font-size: clamp(34px, 4vw, 52px); line-height: 1.0; letter-spacing: 0.01em;
  color: var(--ink);
}
.master__sub {
  font-family: var(--sans); font-size: 12px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.master__enquire {
  font-family: var(--sans); font-weight: var(--w-med); font-size: 11px;
  letter-spacing: 0.2em; text-transform: uppercase; color: var(--on-noir);
  background: var(--ink); padding: 14px 30px; border-radius: var(--r-sm);
  cursor: pointer; white-space: nowrap;
  transition: background-color var(--dur) var(--ease);
}
.master__enquire:hover { background: var(--ink-soft); }
.master__desc {
  margin: 14px 0 0; font-family: var(--antiqua); font-weight: var(--w-reg);
  font-size: 20.8px; line-height: 1.62; color: var(--ink-soft);
  text-wrap: pretty; max-width: 760px;
}

/* =====================================================================
   JS-driven expand/collapse. Without JS, every piece is just a grid
   cell linking to its own page; the master blocks are hidden until JS
   promotes one. (Progressive enhancement.)
   ===================================================================== */
.feed__master[hidden] { display: none; }

/* =====================================================================
   BIOGRAPHY — editorial column with interleaved 9:4 widescreen figures.
   Prose lives in a centred, readable measure; figures break out wider so
   the images dominate, in Otto's preferred widescreen format.
   ===================================================================== */
/* No page title — the masthead subnav already reads "Biography". The lede
   opens the page directly, with a little breathing room below the subnav. */
.bio { padding: clamp(28px, 6vh, 64px) var(--gutter) 96px; }

/* Readable prose measure, centred. */
.bio__col { max-width: 640px; margin: 0 auto; }
.bio__col p {
  font-family: var(--antiqua); font-size: clamp(16px, 1.25vw, 18px);
  line-height: var(--lh-body); color: var(--ink-soft); margin: 0 0 1.15em;
}
.bio__col p:last-child { margin-bottom: 0; }
.bio__col em { font-style: italic; }

/* Opening: portrait beside the large first sentence, the rest of the lede
   flowing beneath the sentence (portrait spans both). */
.bio-open {
  max-width: 1320px; margin: 0 auto clamp(8px, 3vh, 28px);
  display: grid; grid-template-columns: 1.15fr 1fr;
  gap: clamp(28px, 4vw, 64px); align-items: start;
}
.bio-open__portrait { margin: 0; }
.bio-open__portrait img {
  display: block; width: 100%; height: auto;
  border: 1px solid var(--line);
}
.bio-open__text { align-self: center; }
.bio-open__lead {
  margin: 0 0 0.6em; font-family: var(--antiqua); font-weight: var(--w-reg);
  font-size: clamp(26px, 3vw, 40px); line-height: 1.16;
  letter-spacing: -0.012em; color: var(--ink);
}
.bio-open__rest {
  margin: 0; font-family: var(--antiqua);
  font-size: clamp(16px, 1.25vw, 18px); line-height: var(--lh-body);
  color: var(--ink-soft);
}

@media (max-width: 760px) {
  .bio-open { grid-template-columns: 1fr; gap: 22px; }
  .bio-open__portrait { max-width: 320px; }
}

/* Figures break out to a wide measure and breathe vertically. */
.bio-fig {
  max-width: 1180px; margin: clamp(48px, 7vh, 96px) auto;
}
.bio-fig__stage {
  position: relative; width: 100%; aspect-ratio: 9 / 4;
  max-height: calc(100vh - 200px);
  background: var(--paper); overflow: hidden;
}
/* Hairline frame as an overlay above the image (matches .master__stage). */
.bio-fig__stage::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  border: 1px solid var(--line);
}
.bio-fig--gallery .bio-fig__stage { cursor: pointer; }
.bio-fig__shot {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0; transition: opacity .5s cubic-bezier(.4,0,.1,1);
}
.bio-fig__shot.is-current { opacity: 1; }

/* Pager — lower-right of the frame, like the master pager. */
.bio-fig__pager {
  position: absolute; right: 18px; bottom: 16px; z-index: 2;
  display: flex; align-items: center; gap: 16px; color: var(--on-noir);
  mix-blend-mode: difference;
}
.bio-fig__pager button {
  border: none; background: none; cursor: pointer; padding: 2px 4px;
  font-family: var(--serif); font-size: 18px; line-height: 1; color: inherit;
}
.bio-fig__count {
  font-family: var(--sans); font-size: 11px; letter-spacing: 0.16em;
  font-variant-numeric: tabular-nums;
}
.bio-fig__count .sep { opacity: .5; margin: 0 5px; }

.bio-fig__caption {
  margin-top: 14px; font-family: var(--sans); font-size: 12px;
  letter-spacing: 0.04em; color: var(--ink-mute); line-height: 1.5;
}

@media (max-width: 720px) {
  .bio-fig__stage { aspect-ratio: 3 / 2; }
}

/* =====================================================================
   COMPACT HEADER (<=1149px) — a compact top bar with a hamburger that opens a
   full-screen menu overlay. Top bar:  [≡] EN/DE  ——  otto jakob  ——  🔍 ⧉
   Open: the whole header becomes a full-screen overlay showing the section
   links (column 1), plus the category subcategories (column 2) and necklace
   sub-subcategories (column 3) when present — as in the reference.

   The switch happens at 1149px (not 720px) because that is where the one-line
   desktop header stops fitting: the enlarged wordmark + the six section links
   (widest in German) + the EN/DE + icons need ~1108px on one line, so below
   ~1150px we fold the nav into the hamburger rather than cramp or overlap it.
   (Only the HEADER folds here; the page grid/hero keep their own 720px mobile
   breakpoints — a laptop at 1000px gets the hamburger but the desktop grid.)
   ===================================================================== */
@media (max-width: 1149px) {
  /* On compact widths the header itself is not sticky; the TOP BAR is fixed
     (below) so the hamburger is always reachable while the menu + page scroll
     under it. (`:not(.site-header--noir)` matches the desktop rule's specificity
     so this wins inside the query.) */
  .site-header:not(.site-header--noir),
  .site-header { position: static; }

  /* -- Top bar: fixed at the top, always visible -- */
  .masthead {
    /* One-line top bar. Left group (hamburger + EN/DE) and right group (icons)
       flow inline; the wordmark is absolutely centred over the bar so it stays
       in the true middle regardless of the side groups' widths. */
    position: fixed; top: 0; left: 0; right: 0; z-index: 50;
    display: flex; align-items: center; gap: 12px;
    padding: 14px var(--gutter); min-height: 52px;
    background: var(--paper-warm);
  }
  .site-header--noir .masthead { background: transparent; }
  /* The header itself takes no flow space (bar is fixed; menu overlays when
     open). The page content clears the fixed bar via body padding — except on
     the noir landing, where the bar deliberately overlays the hero. */
  .site-header { padding-top: 0; }
  body { padding-top: 52px; }
  body:has(.site-header--noir) { padding-top: 0; }
  .navtoggle {
    order: 0;
    display: inline-flex; align-items: center;
    background: none; border: none; padding: 0; cursor: pointer;
  }
  .navtoggle__bars { display: inline-block; width: 22px; height: 13px; position: relative; }
  .navtoggle__bars span {
    position: absolute; left: 0; width: 100%; height: 1.6px; background: currentColor;
    transition: transform .25s var(--ease), opacity .2s var(--ease);
  }
  .navtoggle__bars span:nth-child(1) { top: 0; }
  .navtoggle__bars span:nth-child(2) { top: 6px; }
  .navtoggle__bars span:nth-child(3) { top: 12px; }
  .navtoggle { color: var(--ink); }
  .site-header--noir .navtoggle { color: var(--on-noir); }

  /* EN/DE — inline, just right of the hamburger. The active language is marked
     by BOLD only (no underline), so the glyphs centre cleanly with the hamburger
     bars, wordmark and icons (a hair of downward nudge lands them on the bar). */
  .langswitch { order: 1; margin: 0; align-items: center; position: relative; top: 1px; }
  .langswitch a { padding-bottom: 0; }
  .langswitch a.is-current { font-weight: var(--w-semi); }

  /* Icons — pushed to the far right of the bar. */
  .utilities { order: 2; margin-left: auto; }

  /* Wordmark — absolutely centred over the bar (true middle of the viewport).
     At the +30% size (31.2px) the word is wide; tighten the tracking on the
     narrow bar so it clears the enlarged EN/DE on the left. Bodoni Antiqua sits
     high in its line box (large font descent), so nudge it down ~4px to land the
     visible letters optically on the hamburger / EN·DE / icons line. */
  .wordmark {
    order: 1; position: absolute; left: 50%; top: 50%;
    transform: translate(-50%, calc(-50% + 1.5px));
    font-size: 31.2px; letter-spacing: 0; text-align: center; white-space: nowrap;
  }

  /* -- The nav: CLOSED by default (hidden). It stays closed across page loads
     and navigation until the user taps the hamburger, which adds `.is-open`. -- */
  .mainnav { display: none; }
  .subnav  { display: none; }

  /* Open (only when `.is-open`): the menu is a grid of columns below the fixed
     top bar. Layout differs by page type:
       • Non-noir (gallery/list pages): the menu sits IN FLOW (static), so it
         pushes the page content down — the first piece stays visible below it.
       • Noir landing (home): the menu OVERLAYS the hero (absolute, anchored at
         the top) and scrolls away with the document, leaving the art unbroken. */
  .site-header.is-open {
    display: grid;
    grid-template-columns: auto auto auto;
    grid-auto-rows: min-content;
    column-gap: 16px; align-content: start;
    /* Non-noir menu is in flow; body's 52px top padding already clears the fixed
       bar, so the menu's own top padding is just breathing room (20px). */
    padding: 20px var(--gutter) var(--gutter);
    background: var(--paper-warm);
  }
  .site-header--noir.is-open {
    position: absolute; top: 52px; left: 0; right: 0; z-index: 45;
    background: var(--noir);
  }

  /* Turn the hamburger into an X when open. */
  .site-header.is-open .navtoggle__bars span:nth-child(1) { top: 6px; transform: rotate(45deg); }
  .site-header.is-open .navtoggle__bars span:nth-child(2) { opacity: 0; }
  .site-header.is-open .navtoggle__bars span:nth-child(3) { top: 6px; transform: rotate(-45deg); }

  /* mainnav is absolutely centred on desktop — reset position AND the centring
     transform/offset so it flows into the grid (column 1) on mobile. */
  .site-header.is-open .mainnav {
    position: static; left: auto; transform: none;
    grid-row: 1; grid-column: 1;
  }
  .site-header.is-open .subnav { grid-row: 1; grid-column: 2; }
  .site-header.is-open .subnav--third { grid-row: 1; grid-column: 3; }

  /* All three columns: identical type size, line-height and row gap so the
     entries align line-to-line, and every column's first line sits at the same
     height (all start on grid row 2 with the same margin-top / padding). */
  .site-header.is-open .mainnav,
  .site-header.is-open .subnav,
  .site-header.is-open .nav-sections {
    display: flex; flex-direction: column; flex-wrap: nowrap;
    align-items: flex-start; justify-content: flex-start; align-content: flex-start;
    gap: 12px; margin-top: 22px; padding: 0; background: none;
  }
  .site-header.is-open .nav-sections { margin-top: 0; }   /* nav-sections is inside .mainnav */

  /* All menu entries share one font size AND line-height so every row aligns
     across the three columns. Only the long compound label ("Manschettenknöpfe")
     may wrap — at its soft-hyphen break, never mid-word — so all three columns
     fit the phone width without horizontal scroll; the smaller font keeps every
     other single-word label on one line. Its own wrapped line gets a touch more
     leading via padding so its two lines don't touch, without changing row rhythm. */
  .site-header.is-open .nav-sections a,
  .site-header.is-open .subnav a {
    font-size: 12.5px; letter-spacing: 0.06em; line-height: 1;
    white-space: nowrap;
  }
  .site-header.is-open .subnav a { white-space: normal; }

  /* Lighter with each layer: sections darkest, subcategories mid, sub-sub
     lightest. Active items are bold (and one step darker) for emphasis. */
  .site-header.is-open .nav-sections a       { color: var(--ink-soft); }
  .site-header.is-open .nav-sections a.is-active { color: var(--ink); font-weight: var(--w-semi); }
  .site-header.is-open .subnav a             { color: var(--ink-mute); }
  .site-header.is-open .subnav a.is-active   { color: var(--ink-soft); font-weight: var(--w-semi); }
  .site-header.is-open .subnav--third a      { color: var(--ink-faint); }
  .site-header.is-open .subnav--third a.is-active { color: var(--ink-mute); font-weight: var(--w-semi); }

  /* On the noir landing the menu overlays a black hero, so the dark ink tones
     above vanish. Use the same warm light palette as the wordmark/utilities,
     fading one step per layer. */
  .site-header--noir.is-open .nav-sections a            { color: var(--on-noir); }
  .site-header--noir.is-open .nav-sections a.is-active  { color: var(--gold-light); font-weight: var(--w-semi); }
  .site-header--noir.is-open .subnav a                  { color: rgba(244,241,233,.72); }
  .site-header--noir.is-open .subnav a.is-active        { color: var(--on-noir); font-weight: var(--w-semi); }
  .site-header--noir.is-open .subnav--third a           { color: rgba(244,241,233,.5); }
  .site-header--noir.is-open .subnav--third a.is-active { color: rgba(244,241,233,.72); font-weight: var(--w-semi); }

}

/* =====================================================================
   BRACELETS — legacy photos read large in the 9:4 frame; shrink each so
   the piece occupies at most ~80% of the frame (both axes), centred, with
   nothing cropped. Scoped to the Bracelets category via the body class.
   ===================================================================== */
.cat-bracelets .cell__img,
.cat-bracelets .master__shot {
  /* Keep the image filling the frame but show the WHOLE piece (contain), then
     uniformly scale it to 80% so the bracelet occupies 80% of the frame on both
     axes, centred. (Percentage padding is width-based and over-shrinks height in
     a wide 9:4 frame, so scale is the clean way.) */
  object-fit: contain;
  padding: 0;
  transform: scale(0.8);
  transform-origin: center;
}

/* A detail flagged left-aligned (e.g. Pangabangan's close-up): keep the 80%
   scale but anchor the image to the LEFT of the stage — its left edge sits at the
   frame's left and the empty space falls on the right. */
.cat-bracelets .master__shot--left {
  object-position: left center;
  transform-origin: left center;
}

/* =====================================================================
   MOBILE LANDING HERO (<=720px) — the featured piece is a wide 9:4 image
   in a tall portrait viewport, so object-fit:contain leaves it small and
   floating. Scale it up ~3x (and drop the big padding) so the starter ring
   reads large. .plate has overflow:hidden, so the widened sides are clipped.
   ===================================================================== */
@media (max-width: 720px) {
  .plate__img {
    padding: 0 0;
    transform: scale(3);
    transform-origin: center;
  }
  /* The hero-name reduction is desktop-only: restore the original size here. */
  .plate__name { font-size: clamp(44px, 6vw, 74px); }
}
