/* Mosaik — Vienna Secession.
 *
 * The Secession is geometric and rectilinear where French Art Nouveau is
 * curvilinear: squares, thin rules, wide letterspacing, restraint. That suits a
 * photographic index, because the aesthetic and the layout requirement are the
 * same shape — a grid.
 *
 * Ivory-led rather than the darker Klimt register: Biedermeier is a large part of
 * this collection and it is light, blonde and quiet. Gold is an accent, not a
 * ground.
 *
 * The collection spans Biedermeier, Secession, Art Deco and Art Nouveau, so this
 * is house identity — not a claim that every object is Secession.
 */

:root {
  --paper:      #f4f1ea;
  --paper-deep: #ebe6dc;
  --ink:        #14120f;
  --ink-soft:   #4a453c;
  --ink-faint:  #8c8477;
  --gold:       #b08d3f;
  --gold-bright:#c9a227;
  --rule:       #14120f;

  --measure: 34rem;
  --gap: clamp(1.25rem, 3vw, 2.5rem);
  --page: clamp(1.25rem, 5vw, 5rem);

  --font-display: "Poiret One", "Optima", "Palatino", Georgia, serif;
  --font-body: "EB Garamond", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  --font-label: "Josefin Sans", "Futura", "Avenir Next", system-ui, sans-serif;

  --tracking-wide: 0.18em;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: clamp(1rem, 0.95rem + 0.2vw, 1.125rem);
  line-height: 1.65;
  text-rendering: optimizeLegibility;
}

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

a { color: inherit; }

.skip {
  position: absolute; left: -9999px;
  background: var(--ink); color: var(--paper);
  padding: 0.75rem 1rem;
}
.skip:focus { left: 1rem; top: 1rem; z-index: 10; }

/* ---------------------------------------------------------------- rules */

.rule {
  height: 1px;
  background: var(--rule);
  opacity: 0.85;
}
/* The Secession double rule: two hairlines with air between them. */
.rule--double {
  height: 4px;
  background:
    linear-gradient(var(--rule), var(--rule)) top / 100% 1px no-repeat,
    linear-gradient(var(--rule), var(--rule)) bottom / 100% 1px no-repeat;
  background-color: transparent;
}

/* ------------------------------------------------------------- masthead */

.masthead {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: clamp(1.5rem, 4vw, 3rem) var(--page) 1.25rem;
  border-bottom: 1px solid var(--rule);
}

.masthead__mark { color: var(--gold); flex: none; text-decoration: none; }

.masthead__title {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 1.2rem + 2vw, 2.6rem);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  text-decoration: none;
  line-height: 1;
}

.masthead__subtitle {
  margin: 0.4rem 0 0;
  font-family: var(--font-label);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* ------------------------------------------------------------------ hero */

/* The showcase piece. One photograph at reading width, captioned in the same
   label voice as the rest of the page; the whole thing is a single link. */
.hero { padding: clamp(2rem, 6vw, 4rem) var(--page) 0; }

.hero__link {
  display: block;
  max-width: 64rem;
  margin: 0 auto;
  text-decoration: none;
  color: inherit;
}

.figure--hero img { width: 100%; height: auto; }

.hero__caption {
  display: block;
  padding-top: 1rem;
  text-align: center;
}

.hero__number {
  display: block;
  font-family: var(--font-label);
  font-size: 0.72rem;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--gold);
}

.hero__title {
  display: block;
  margin-top: 0.35rem;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.5rem, 1rem + 2.2vw, 2.4rem);
  letter-spacing: 0.08em;
}

.hero__link:hover .hero__title,
.hero__link:focus-visible .hero__title { color: var(--gold); }

/* ----------------------------------------------------------------- intro */

.intro { padding: clamp(2rem, 6vw, 4rem) var(--page) 0; }

.intro__heading {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.8rem, 1.2rem + 3vw, 3.2rem);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin: 1.25rem 0 0.5rem;
}

.intro__lede {
  max-width: var(--measure);
  margin: 0 0 0.75rem;
  color: var(--ink-soft);
}

.intro__count {
  font-family: var(--font-label);
  font-size: 0.72rem;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0;
}

/* ------------------------------------------------------------------ grid */

.grid {
  list-style: none;
  margin: clamp(2rem, 5vw, 3.5rem) 0 0;
  padding: 0 var(--page) clamp(3rem, 8vw, 6rem);
  display: grid;
  gap: var(--gap);
  grid-template-columns: repeat(auto-fill, minmax(min(17rem, 100%), 1fr));
}

.tile {
  display: block;
  text-decoration: none;
  color: inherit;
}

/* The plate: object floating on paper inside a square-in-square frame.
 * Furniture is tall — a square CROP decapitates chairs — so the image is
 * CONTAINED on a ground rather than cropped. That is also exactly the
 * Ver Sacrum catalogue look. */
.tile__plate {
  display: block;
  position: relative;
  aspect-ratio: 1 / 1;
  background: var(--paper-deep);
  border: 1px solid var(--rule);
  padding: 0.85rem;
}
.tile__plate::after {
  content: "";
  position: absolute; inset: 0.4rem;
  border: 1px solid var(--rule);
  opacity: 0.28;
  pointer-events: none;
}

.tile__plate .figure { height: 100%; }
.tile__plate img { width: 100%; height: 100%; object-fit: contain; }

.tile__empty { display: block; height: 100%; }

.tile__caption { display: block; padding-top: 0.85rem; }

.tile__number {
  display: block;
  font-family: var(--font-label);
  font-size: 0.62rem;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.2rem;
}

.tile__title {
  display: block;
  font-family: var(--font-display);
  font-size: 1.15rem;
  letter-spacing: 0.05em;
}

.tile__meta {
  display: block;
  margin-top: 0.2rem;
  font-family: var(--font-label);
  font-size: 0.68rem;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--ink-faint);
}

.tile:hover .tile__plate,
.tile:focus-visible .tile__plate { border-color: var(--gold); }
.tile:hover .tile__title,
.tile:focus-visible .tile__title { color: var(--gold); }

/* ------------------------------------------------------------------ item */

.item { padding: 0 var(--page) clamp(3rem, 8vw, 6rem); }

.crumbs {
  padding: 1.25rem 0 0;
  font-family: var(--font-label);
  font-size: 0.68rem;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}
.crumbs a { color: var(--ink-faint); text-decoration: none; }
.crumbs a:hover { color: var(--gold); }

.item__head { padding-top: clamp(1.5rem, 4vw, 2.5rem); }

.item__number {
  margin: 1.1rem 0 0;
  font-family: var(--font-label);
  font-size: 0.72rem;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--gold);
}
.item__number + .item__title { margin-top: 0.25rem; }

.item__title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.8rem, 1.2rem + 3vw, 3rem);
  letter-spacing: 0.08em;
  margin: 1.1rem 0 0;
}

/* --------------------------------------------------------------- gallery */

/* The images section is a fixed-height block so clicking a thumbnail never
 * moves the page. Height is keyed to the HERO's orientation, decided by the
 * generator and emitted as a data attribute — so the box is the right shape
 * before any script runs.
 *
 * The trade: a portrait photograph shown in a landscape stage sits letterboxed.
 * That is deliberate. A stage that resized to each photograph would jump on
 * every click, and predictability is worth more than filling the box. */
.gallery {
  --stage-h: clamp(20rem, 52vh, 34rem);
  margin: clamp(1.5rem, 4vw, 2.75rem) 0 0;
  display: grid;
  gap: clamp(0.75rem, 2vw, 1.25rem);
  grid-template-columns: 1fr;
}
.gallery[data-hero-orientation="portrait"] { --stage-h: clamp(24rem, 68vh, 46rem); }

@media (min-width: 48rem) {
  .gallery { grid-template-columns: minmax(0, 1fr) 13rem; }
}

.gallery__stage {
  background: var(--paper-deep);
  border: 1px solid var(--rule);
  padding: clamp(0.85rem, 2vw, 1.75rem);
  height: var(--stage-h);
  /* Without this the image escapes the stage and paints over the catalogue
   * text below it. Containment is the whole job of this element. */
  overflow: hidden;
  display: grid;
  grid-template: 1fr / 1fr;
}

/* Every shot occupies the same cell, so switching never reflows anything. */
.gallery__stage .shot {
  grid-area: 1 / 1;
  margin: 0;
  /* Grid and flex children default to min-height/min-width: auto, which means
   * "never shrink below your content". A 6240px photograph then blows the box
   * open. These two lines are what actually constrain the image. */
  min-width: 0;
  min-height: 0;
  display: none;
}

/* ## Which shot is showing
 *
 * Driven by `:target` first, so the gallery works with NO JavaScript at all —
 * a thumbnail is an anchor to `#photo-3`, and CSS alone swaps the stage. An
 * earlier version emitted `hidden` on the non-first shots, which made that
 * claim false: without script you saw one photograph and eight dead links.
 *
 * Once <mosaik-gallery> upgrades, its `.is-current` class takes over (higher
 * specificity) so that history, keyboard and prefetch behave. */
.gallery__stage .shot:first-child { display: flex; }
.gallery__stage:has(.shot:target) .shot:first-child { display: none; }
.gallery__stage .shot:target { display: flex; }

.gallery[data-enhanced] .gallery__stage .shot { display: none; }
.gallery[data-enhanced] .gallery__stage .shot.is-current { display: flex; }

.gallery__stage .shot {
  align-items: center;
  justify-content: center;
}

/* `display: contents` dissolves the two presentational wrappers so the <img>
 * becomes a direct flex child of .shot.
 *
 * This matters: a percentage max-height resolves against the parent's height,
 * and a flex item that is centred rather than stretched has an AUTO height.
 * Chaining `max-height: 100%` through .figure and <picture> is therefore
 * circular and silently ignored — which is the bug that let a 6240px photograph
 * paint over the catalogue text. Removing the boxes removes the ambiguity: the
 * image is measured against .shot, whose height is definite. */
.gallery__stage .shot .figure,
.gallery__stage .shot picture { display: contents; }

/* max-* with auto dimensions is the containment that actually holds: the image
 * keeps its own aspect ratio and can never exceed the frame in either axis.
 * `width/height: 100%` would stretch it and `object-fit` alone would not stop
 * the element itself from overflowing. */
.gallery__stage .shot img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* Three narrow columns, matching the stage height and scrolling past it. */
.gallery__rail {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(4rem, 1fr));
  gap: 0.4rem;
  align-content: start;
}
@media (min-width: 48rem) {
  .gallery__rail {
    grid-template-columns: repeat(3, 1fr);
    height: var(--stage-h);
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--ink-faint) transparent;
    /* Hairline edges rather than a gradient fade: the Secession answer to
     * "there is more below" is a rule, not a vignette. */
    border-top: 1px solid color-mix(in srgb, var(--rule) 30%, transparent);
    border-bottom: 1px solid color-mix(in srgb, var(--rule) 30%, transparent);
    padding: 0.4rem 0.3rem 0.4rem 0;
  }
}

.thumb {
  display: block;
  position: relative;
  aspect-ratio: 1 / 1;
  background: var(--paper-deep);
  border: 1px solid color-mix(in srgb, var(--rule) 45%, transparent);
  padding: 0.2rem;
}
.thumb img { width: 100%; height: 100%; object-fit: contain; }

.thumb:hover,
.thumb:focus-visible { border-color: var(--gold); }

/* The current thumbnail carries the square-in-square mark, so the selected
 * state reads as a frame rather than only as a colour. */
.thumb[aria-current] { border-color: var(--ink); }
.thumb[aria-current]::after {
  content: "";
  position: absolute; inset: 0.25rem;
  border: 1px solid var(--gold);
  pointer-events: none;
}

.item__body {
  display: grid;
  gap: clamp(1.75rem, 4vw, 3rem);
  margin-top: clamp(2rem, 5vw, 3rem);
  grid-template-columns: 1fr;
}
@media (min-width: 60rem) {
  .item__body { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); }
}

.prose { max-width: var(--measure); }
.prose p { margin: 0 0 1rem; }
.prose p:first-of-type::first-line { letter-spacing: 0.02em; }

.section-heading {
  font-family: var(--font-label);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 0.9rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--rule);
}

.facts__list { margin: 0; }

.facts__row {
  display: grid;
  grid-template-columns: 8.5rem 1fr;
  gap: 0.75rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid color-mix(in srgb, var(--rule) 18%, transparent);
}
.facts__row dt {
  font-family: var(--font-label);
  font-size: 0.66rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  padding-top: 0.22rem;
}
.facts__row dd { margin: 0; }

.prose--aside { max-width: var(--measure); }

/* The grade leads the condition report; the note explains it. */
.condition__grade {
  font-family: var(--font-label);
  font-size: 0.72rem;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--ink);
}
.condition__grade + p { margin-top: 0.35rem; }

/* --------------------------------------------------------------- figures */

/* Reserve the box before the image loads, so nothing jumps. */
mosaik-figure { display: block; }
mosaik-figure picture { display: block; }
.figure--plate { height: 100%; }

/* --------------------------------------------------------------- enquire */

.enquire { margin-top: clamp(2.5rem, 6vw, 4rem); }
.enquire p {
  margin: 1rem 0 0;
  font-family: var(--font-label);
  font-size: 0.74rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.enquire a { color: var(--gold); text-decoration-color: var(--gold); }
.enquire a:hover { color: var(--gold-bright); }

.footer__note a { color: inherit; text-decoration-color: var(--gold); }
.footer__note a:hover { color: var(--gold); }

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

.footer {
  padding: clamp(2rem, 5vw, 3rem) var(--page) clamp(2.5rem, 6vw, 4rem);
  font-family: var(--font-label);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.footer p { margin: 1rem 0 0; }
.footer__note { color: var(--ink-soft); }

.mark { display: block; margin-top: clamp(1.5rem, 4vw, 2.25rem); }

.mark__link {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  color: var(--ink-faint);
}
.mark__link:hover, .mark__link:focus-visible { color: var(--gold); }

/* Rounded in CSS rather than baked into the PNG, so one square asset serves
 * every size and no alpha channel is carried for something a single
 * declaration does better. 22.5% approximates the iOS squircle closely enough
 * to be indistinguishable at this scale. */
.mark__icon {
  width: 1.75rem; height: 1.75rem;
  border-radius: 22.5%;
  border: 1px solid color-mix(in srgb, var(--rule) 25%, transparent);
}

.mark__words {
  font-family: var(--font-label);
  font-size: 0.66rem;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

@media (prefers-reduced-motion: no-preference) {
  .tile__plate, .tile__title { transition: border-color 160ms ease, color 160ms ease; }
}

/* ------------------------------------------------------------------- zoom */

/* Native <dialog>: Esc, focus trapping, top layer and backdrop for free. */
.zoom {
  width: 100vw;
  max-width: 100vw;
  height: 100dvh;
  max-height: 100dvh;
  padding: 0;
  border: 0;
  background: var(--ink);
  color: var(--paper);
  overflow: hidden;
}
.zoom::backdrop { background: rgb(10 9 8 / 0.92); }

.zoom__stage {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  overflow: hidden;
}

/* Fit-to-screen by default. */
.zoom__image {
  max-width: 100%;
  max-height: 100dvh;
  width: auto;
  height: auto;
  object-fit: contain;
  cursor: zoom-in;
}

/* Magnified: the image renders at its natural size and the stage scrolls.
 * Panning is then ordinary scrolling, which means trackpads, scroll wheels,
 * touch and the keyboard all work without being reimplemented. */
.zoom[data-magnified="true"] .zoom__stage {
  overflow: auto;
  place-items: start;
  cursor: grab;
  scrollbar-width: thin;
}
.zoom[data-magnified="true"] .zoom__image {
  max-width: none;
  max-height: none;
  width: auto;
  height: auto;
  cursor: grab;
}
.zoom[data-dragging="true"] .zoom__stage,
.zoom[data-dragging="true"] .zoom__image { cursor: grabbing; }

.zoom__close {
  position: fixed;
  top: 1rem; right: 1rem;
  z-index: 2;
  width: 2.75rem; height: 2.75rem;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--paper);
  background: rgb(10 9 8 / 0.55);
  border: 1px solid rgb(244 241 234 / 0.35);
  cursor: pointer;
}
.zoom__close:hover, .zoom__close:focus-visible { border-color: var(--gold-bright); }

.zoom__hint {
  position: fixed;
  left: 50%; bottom: 1rem;
  transform: translateX(-50%);
  margin: 0;
  font-family: var(--font-label);
  font-size: 0.62rem;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: rgb(244 241 234 / 0.55);
  pointer-events: none;
}

/* The stage image invites the click that opens the dialog. */
.gallery[data-enhanced] .shot[data-zoom] img { cursor: zoom-in; }

@media (prefers-reduced-motion: no-preference) {
  .zoom__close { transition: border-color 160ms ease; }
}
