/* n/fāss — design tokens + site chrome
   Accent #C300FB and the near-white ground #FAFAF7 both set by the collective. */

:root {
  /* --- the artifact --- */
  --paper:        #FAFAF7;
  --paper-sunk:   #F0F0EA;
  --paper-line:   #E2E2DA;
  --ink:          #1F1B16;
  --ink-soft:     #6B655C;
  --accent:       #C300FB;
  /* Same purple, one step darker. #C300FB scores 4.26:1 on the near-white, just under the
     4.5:1 minimum for small text, so anything set small in the brand colour uses this. */
  --accent-ink:   #B800EE;
  /* And one step lighter, for brand-coloured small text on the dark Studio chrome,
     where #C300FB only reaches 4.06:1. */
  --accent-lift:  #D34DFF;

  /* --- studio chrome --- */
  --gr-900:       #100F0E;
  --gr-850:       #171614;
  --gr-800:       #1E1D1A;
  --gr-700:       #282722;
  --gr-600:       #34332C;
  --gr-line:      #3D3B33;
  --chr-text:     #EAE5D6;
  --chr-dim:      #A9A392;
  --chr-faint:    #8A8474;

  /* --- type --- */
  --f-mark:  'Archivo Narrow', 'Helvetica Neue', Arial, sans-serif;
  /* The small print: a bold geometric sans in capitals, the way mid-century
     cigarette packs and matchboxes set their labels. League Spartan is the
     Futura family, cut heavy; any Persian or Arabic falls through to Vazirmatn,
     a geometric Persian sans, so both scripts carry the same weight. Only the
     heavy cuts are loaded, so everything set in it lands on 700. Every rule that
     uses this face also sets text-transform: lowercase. */
  --f-ui:    'Fibel Nord', 'League Spartan', 'Vazirmatn', Futura, 'Century Gothic', 'Avenir Next', sans-serif;
  --f-mono:  'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  --f-body:  'Fibel Nord', 'EB Garamond', Georgia, 'Times New Roman', serif;

  /* --- metrics --- */
  --rule: 1px;
  --pad: 1.5rem;
  --mq-h: 64px;      /* logo height in the top bar; chrome.js reads this to size the track */
}

/* Fibel Nord, by Peter Wiegel — free under the SIL Open Font License, so it is
   self-hosted from assets/fonts rather than loaded from a font service. */
@font-face {
  font-family: 'Fibel Nord';
  src: url('../fonts/fibel-nord.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Fibel Nord';
  src: url('../fonts/fibel-nord-bold.woff') format('woff');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

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

/* --- the site cursor: a rifle scope, hot spot dead centre ---
   A plain scope everywhere; over anything that can be clicked, the red dot
   appears, so it reads as "on target". Both override the browser's own pointers,
   which is why these carry !important. Studio (html.tool) keeps normal pointers
   for precise dragging. */
html:not(.tool),
html:not(.tool) *,
html:not(.tool) *::before,
html:not(.tool) *::after {
  cursor: url('../img/scope-40.png') 20 20, crosshair !important;
  cursor: -webkit-image-set(url('../img/scope-40.png') 1x, url('../img/scope-80.png') 2x) 20 20, crosshair !important;
  cursor: image-set(url('../img/scope-40.png') 1x, url('../img/scope-80.png') 2x) 20 20, crosshair !important;
}
html:not(.tool) :is(a[href], button, summary, select, label[for], [role="button"], [tabindex]:not([tabindex="-1"]),
                    input[type="submit"], input[type="button"], input[type="checkbox"], input[type="radio"],
                    .vw-trigger, .intro, .mq-link),
html:not(.tool) :is(a[href], button, [role="button"], .vw-trigger, .mq-link) * {
  cursor: url('../img/scope-dot-40.png') 20 20, pointer !important;
  cursor: -webkit-image-set(url('../img/scope-dot-40.png') 1x, url('../img/scope-dot-80.png') 2x) 20 20, pointer !important;
  cursor: image-set(url('../img/scope-dot-40.png') 1x, url('../img/scope-dot-80.png') 2x) 20 20, pointer !important;
}

/* --- everything in lower case ---
   Except what someone composed or types themselves: article blocks keep the case
   they were written in, and form fields show what was typed. */
html:not(.tool) body { text-transform: lowercase; }
html:not(.tool) .nf-canvas,
html:not(.tool) .nf-prose,
html:not(.tool) input,
html:not(.tool) textarea { text-transform: none; }

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--f-body);
  font-size: 1.0625rem;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* --- the wordmark, set as live text pending the real file --- */
.wordmark {
  font-family: var(--f-mark);
  font-style: italic;
  font-weight: 600;
  color: var(--accent);
  letter-spacing: -0.02em;
  text-decoration: none;
  display: inline-block;
  line-height: 1;
}

/* --- top bar: the rotating logo marquee -------------------------------------
   Two identical halves sliding exactly -50%, so the second half lands where the
   first began and the loop never shows a seam.

   Two things this depends on, both easy to get wrong:
   1. Spacing is a cell margin, not a flex `gap`. With `gap`, half the track is a
      half-gap short of one repeat and the loop ticks once per cycle.
   2. One half must be at least as wide as the viewport, or the track runs out and
      leaves a gap before looping. chrome.js works the count out from the screen
      width rather than fixing it, and sets the duration to hold a constant speed. */
.mq {
  position: relative;
  width: 100%;
  overflow: hidden;
  background: var(--paper);
  border-bottom: var(--rule) solid var(--paper-line);
}
.mq-link {
  display: block;
  text-decoration: none;
  cursor: pointer;
}
.mq-track {
  display: inline-flex;
  align-items: center;
  padding: 1rem 0;
  animation: nf-scroll 30s linear infinite;  /* duration overridden by chrome.js */
  will-change: transform;
}
@keyframes nf-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
.mq-cell { flex: 0 0 auto; height: var(--mq-h); margin-right: 32px; }
.mq-cell img {
  display: block;
  height: var(--mq-h);
  width: auto;
  object-fit: contain;
  /* the logo file is a JPG on white; multiply drops its ground onto the page */
  mix-blend-mode: multiply;
}
/* readable stand-in until the logo file is in place */
.mq-cell .mq-text {
  font-family: var(--f-mark);
  font-style: italic;
  font-weight: 600;
  font-size: 2.6rem;
  line-height: var(--mq-h);
  color: var(--accent);
  letter-spacing: -0.02em;
  white-space: nowrap;
}
/* pausing on hover also makes the bar easier to click */
.mq:hover .mq-track,
.mq:focus-within .mq-track { animation-play-state: paused; }

@media (prefers-reduced-motion: reduce) {
  .mq-track { animation: none; }
}
@media (max-width: 640px) {
  :root { --mq-h: 44px; }
  .mq-cell { margin-right: 22px; }
  .mq-cell .mq-text { font-size: 1.8rem; }
}

/* --- footer: nav moved to the bottom, centred --- */
.foot {
  border-top: var(--rule) solid var(--paper-line);
  margin-top: 5rem;
}
.foot-nav {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 2.25rem;
  padding: 3rem var(--pad) 0;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 0.72rem;
  letter-spacing: 0.2em;
}
.foot-nav a {
  text-decoration: none;
  color: var(--ink-soft);
  padding-bottom: 0.25rem;
  border-bottom: 1px solid transparent;
  transition: color 160ms ease, border-color 160ms ease;
}
.foot-nav a:hover,
.foot-nav a[aria-current='page'] {
  color: var(--accent-ink);        /* small text, so the AA-safe shade */
  border-bottom-color: var(--accent);
}
.foot-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  text-align: center;
  padding: 2.5rem var(--pad) 3.5rem;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  color: var(--ink-soft);
}

.wrap { max-width: 1080px; margin: 0 auto; padding: 0 var(--pad); }

/* the name is set in the wordmark face, like the logo bar — Fibel Nord has no ā,
   so in the body face the macron would come from a different font */
.foot-mark span {
  font-family: var(--f-mark);
  font-style: italic;
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: -0.01em;
  color: var(--accent-ink);
}

/* the barcode beside the name; multiply drops its white ground onto the paper */
.foot-code {
  display: block;
  width: auto;
  height: 22px;
  mix-blend-mode: multiply;
}

/* placeholder used until the homepage plan lands */
.stub {
  max-width: 46ch;
  margin: 5rem auto;
  padding: 0 var(--pad);
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 0.78rem;
  line-height: 1.9;
  color: var(--ink-soft);
}
.stub b { color: var(--ink); font-weight: 400; }

/* --- homepage ---------------------------------------------------------------
   Built from nfass_homepage_concept.html: one centred 4:5 hero with its caption
   below, then a two-column `recent work` band. Hairline frames, small lowercase
   type, a lot of air. The accent appears exactly once, as the short vertical bar
   bleeding off the hero's left edge — so keep it the only loud thing here. */

.home { max-width: 900px; margin: 0 auto; padding: 0 2.5rem; }

.home-hero {
  padding: 5rem 0 4rem;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.home-figure {
  position: relative;      /* the accent bar hangs off this, not the frame */
  width: 320px;
  max-width: 100%;
  margin: 0;
}
.home-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 5;
  background: var(--paper-sunk);
  border: 0.5px solid var(--paper-line);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}
.home-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 600ms cubic-bezier(0.2, 0, 0, 1);
}
a:hover > .home-frame img { transform: scale(1.03); }

/* The featured piece has no frame at all — it sits on the paper and casts a
   shadow. drop-shadow, not box-shadow, so the shadow follows the artwork's own
   silhouette (cut-outs, transparent corners) instead of drawing a box round it.
   Two layers: a tight contact shadow and a long soft one, which is what makes it
   read as a printed sheet lying on the page rather than a card hovering over it.
   The empty placeholder keeps the old well so the page still has a shape. */
.home-figure > a { display: block; text-decoration: none; color: inherit; }
.home-figure .home-frame:has(img) {
  background: none;
  border: 0;
  overflow: visible;
}
.home-figure .home-frame img {
  filter: drop-shadow(0 2px 3px rgba(31, 27, 22, 0.24))
          drop-shadow(0 26px 40px rgba(31, 27, 22, 0.32));
  transition: transform 600ms cubic-bezier(0.2, 0, 0, 1), filter 600ms cubic-bezier(0.2, 0, 0, 1);
}
.home-figure a:hover > .home-frame img {
  filter: drop-shadow(0 3px 5px rgba(31, 27, 22, 0.22))
          drop-shadow(0 38px 54px rgba(31, 27, 22, 0.36));
}

/* the single accent mark — drawn in only while the featured piece is hovered */
.home-mark {
  position: absolute;
  left: -2px;
  top: 24px;
  width: 2px;
  height: 0;
  background: var(--accent);
  transition: height 420ms cubic-bezier(0.2, 0, 0, 1);
}
.home-figure:hover .home-mark,
.home-figure:focus-within .home-mark { height: 36px; }

.home-cap {
  margin: 1.25rem 0 0;
  font-family: var(--f-body);
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink-soft);
  text-align: center;
}

.home-recent { padding: 0 0 5rem; }
.home-label {
  margin: 0 0 1.5rem;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
}
.home-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 64px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.home-item { margin: 0; }
.home-item > a { display: block; text-decoration: none; color: inherit; }
.home-item .home-cap {
  margin-top: 10px;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 12px;
  text-align: left;
}
.home-item > a:hover .home-cap { color: var(--accent-ink); }

.frame-empty {
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 10px;
  letter-spacing: 0.18em;
  color: var(--ink-soft);
  opacity: 0.55;
}

@media (max-width: 700px) {
  .home { padding: 0 1.5rem; }
  .home-hero { padding: 3.5rem 0 3rem; }
  .home-grid { grid-template-columns: minmax(0, 1fr); gap: 3rem; }
  .home-recent { padding-bottom: 3.5rem; }
}

/* --- journal -----------------------------------------------------------------
   Deliberately not a grid. Entries alternate side and interlock vertically, so
   reading down the page feels composed rather than tabulated. Two things recur
   and hold it together: the notation-style index number, and the accent bar from
   the homepage hero — which here arrives on hover, marking where you are.

   Numbers are assigned oldest-first, so an entry keeps its number for good. */

.j-head {
  max-width: 1000px;
  margin: 0 auto;
  padding: 3.5rem 2.5rem 1rem;
  display: flex;
  align-items: baseline;
  gap: 0.9rem;
}
.j-head h1 {
  margin: 0;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.3em;
  color: var(--ink);
}
.j-count {
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  color: var(--accent-ink);
}

.j-index {
  max-width: 1000px;
  margin: 0 auto 6rem;
  padding: 0 2.5rem;
  list-style: none;
}
.j-entry { margin: 0; }
.j-entry + .j-entry { margin-top: 7rem; }

.j-entry > a {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 2.5rem;
  align-items: center;
  text-decoration: none;
  color: inherit;
}
/* odd: image left, words right. even: the reverse, dropped down to interlock. */
.j-entry:nth-child(odd)  .j-media { grid-column: 1 / 8; }
.j-entry:nth-child(odd)  .j-meta  { grid-column: 8 / 13; }
.j-entry:nth-child(even) .j-media { grid-column: 6 / 13; grid-row: 1; }
.j-entry:nth-child(even) .j-meta  { grid-column: 1 / 6;  grid-row: 1; }
.j-entry:nth-child(even) { padding-top: 4rem; }

.j-media { position: relative; }
.j-frame {
  overflow: hidden;
  border: 0.5px solid var(--paper-line);
  background: var(--paper-sunk);
}
.j-frame img {
  display: block;
  width: 100%;
  height: auto;
  transition: transform 700ms cubic-bezier(0.2, 0, 0, 1);
}
.j-entry a:hover .j-frame img { transform: scale(1.02); }

/* the signature mark, arriving rather than sitting there */
.j-bar {
  position: absolute;
  left: -2px;
  top: 24px;
  width: 2px;
  height: 0;
  background: var(--accent);
  transition: height 420ms cubic-bezier(0.2, 0, 0, 1);
}
.j-entry a:hover .j-bar,
.j-entry a:focus-visible .j-bar { height: 36px; }

.j-num {
  display: block;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 11px;
  letter-spacing: 0.18em;
  color: var(--accent-ink);
  margin-bottom: 0.7rem;
}
.j-date {
  display: block;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 11px;
  letter-spacing: 0.14em;
  color: var(--ink-soft);
  margin-bottom: 0.9rem;
}
.j-title {
  margin: 0;
  font-family: 'Fibel Nord', var(--f-body);
  font-weight: 700;
  font-size: clamp(1.5rem, 2.6vw, 2.15rem);
  line-height: 1.12;
  letter-spacing: -0.015em;
  transition: color 180ms ease;
}
.j-entry a:hover .j-title { color: var(--accent-ink); }
.j-cap {
  margin: 0.9rem 0 0;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 12px;
  line-height: 1.85;
  color: var(--ink-soft);
  max-width: 40ch;
}
.j-nocover {
  aspect-ratio: 4 / 5;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 10px;
  letter-spacing: 0.18em;
  color: var(--ink-soft);
  opacity: 0.55;
}

@media (max-width: 760px) {
  .j-head  { padding: 2.5rem 1.5rem 0.5rem; }
  .j-index { padding: 0 1.5rem; }
  .j-entry > a { grid-template-columns: minmax(0, 1fr); gap: 1.25rem; }
  .j-entry:nth-child(odd)  .j-media,
  .j-entry:nth-child(even) .j-media { grid-column: 1; grid-row: 1; }
  .j-entry:nth-child(odd)  .j-meta,
  .j-entry:nth-child(even) .j-meta  { grid-column: 1; grid-row: 2; }
  .j-entry:nth-child(even) { padding-top: 0; }
  .j-entry + .j-entry { margin-top: 4rem; }
  /* on a phone the bar has no room to bleed, so bring it inside */
  .j-bar { left: 0; height: 36px; }
}

/* --- plates -----------------------------------------------------------------
   One image with a caption underneath. Work is a grid of these; the Journal is
   the same unit with a title and date added, wrapped in a link. Keeping them one
   component is what makes the two pages read as siblings. */

.page-head {
  max-width: 900px;
  margin: 0 auto;
  padding: 3.5rem 2.5rem 2rem;
}
.page-head h1 {
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.3em;
  color: var(--ink-soft);
  margin: 0;
}

.plates {
  max-width: 900px;
  margin: 0 auto 2rem;
  padding: 0 2.5rem;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 64px;                      /* the reference's grid gap */
  list-style: none;
}
.plate { margin: 0; }
.plate > a { display: block; text-decoration: none; color: inherit; }

.plate-img {
  width: 100%;
  overflow: hidden;
  background: var(--paper-sunk);
  border: 0.5px solid var(--paper-line);   /* hairline frame, as in the reference */
}
.plate-img img {
  display: block;
  width: 100%;
  height: auto;
  transition: transform 600ms cubic-bezier(0.2, 0, 0, 1);
}
.plate > a:hover .plate-img img { transform: scale(1.03); }
/* A real piece drops the well and hairline and casts a shadow instead, so cut-outs
   and transparent corners show the paper rather than a grey box. The empty
   placeholder keeps its well. */
.plate-img:has(img) {
  background: none;
  border: 0;
  overflow: visible;
}
.plate-img:has(img) img {
  filter: drop-shadow(0 2px 3px rgba(31, 27, 22, 0.24))
          drop-shadow(0 26px 40px rgba(31, 27, 22, 0.32));
  transition: transform 600ms cubic-bezier(0.2, 0, 0, 1), filter 600ms cubic-bezier(0.2, 0, 0, 1);
}
.plate-img.vw-trigger:hover img {
  filter: drop-shadow(0 3px 5px rgba(31, 27, 22, 0.22))
          drop-shadow(0 38px 54px rgba(31, 27, 22, 0.36));
}
.vw-trigger:hover img { transform: scale(1.02); }

.plate-title {
  margin: 1rem 0 0;
  font-family: 'Fibel Nord', var(--f-body);
  font-weight: 700;
  font-size: 1.4rem;
  line-height: 1.2;
  color: var(--ink);
  transition: color 160ms ease;
}
.plate > a:hover .plate-title { color: var(--accent-ink); }

.plate-date {
  margin-top: 0.55rem;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  color: var(--ink-soft);
}

/* the caption — the thing that sits under every image */
.plate-cap {
  margin-top: 10px;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 12px;
  line-height: 1.8;
  letter-spacing: 0.03em;
  color: var(--ink-soft);
  max-width: 46ch;
}

.plate-missing {
  aspect-ratio: 4 / 3;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  color: var(--ink-soft);
  background: var(--paper-sunk);
}

.page-empty {
  max-width: 900px;
  margin: 0 auto;
  padding: 1rem 2.5rem 4rem;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 0.75rem;
  line-height: 1.9;
  color: var(--ink-soft);
}

@media (max-width: 700px) {
  .plates    { grid-template-columns: minmax(0, 1fr); gap: 3rem; padding: 0 1.5rem; }
  .page-head { padding: 2.5rem 1.5rem 1.5rem; }
  .page-empty { padding: 1rem 1.5rem 3rem; }
}

/* --- about ------------------------------------------------------------------
   A matchbox, built as a solid object in 3D rather than a picture of one. The
   sleeve is six faces — the printed label on top (assets/img/matchbox-label.webp,
   carrying the first line of the couplet), a striker down each long side, the two
   ends left open — and the drawer is an open-topped box with a floor and four
   walls. It lies tilted on the page with a soft shadow beneath it; pressing it
   slides the drawer out of one end, and you look down into it at the matches and
   the slip carrying the reply.

   Geometry is three numbers — width, height, depth (--W, --H, --D) — in cqw, so
   the box is one scalable object. The label photo is 1.55:1 and so is the box.
   On a phone the open box glides left, partly off the screen, so the drawer and
   its slip end up in the middle where they can be read. */

.about {
  overflow-x: clip;            /* the open drawer must never cause sideways scrolling */
  min-height: 72vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 5rem 2rem 3rem;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.mbox {
  --label: #F2E7CF;        /* the paper */
  --kraft: #D6BE93;        /* inside the drawer */
  --wall:  #E6D3AE;
  --move: 1000ms cubic-bezier(0.2, 0, 0, 1);

  /* the box */
  --W: 100cqw;
  --H: 64.5cqw;
  --D: 17cqw;
  /* the drawer, a fraction smaller so it sits inside */
  --Wt: calc(var(--W) * 0.97);
  --Ht: calc(var(--H) * 0.9);
  --Dt: calc(var(--D) * 0.84);
  /* how it lies on the page */
  --rx: 34deg;
  --ry: -18deg;
  --rz: -7deg;

  appearance: none;
  display: block;
  /* open, the box and drawer together are about 1.7x this wide, so it scales with the window */
  width: min(500px, 52vw);
  margin: 1rem 0 2.5rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  cursor: pointer;
  /* pressing and dragging off the box must not pick up the label photo */
  -webkit-user-select: none;
  user-select: none;
  container-type: inline-size;
  perspective: 1500px;
  -webkit-tap-highlight-color: transparent;
}
.mbox:focus-visible { outline: 0; }
.mbox:focus-visible .ms-top { outline: 2px solid var(--accent); outline-offset: 6px; }

.mbox-stage {
  position: relative;
  display: block;
  width: var(--W);
  height: var(--H);
  transform-style: preserve-3d;
  transform: translateX(var(--shift, 0px)) rotateX(var(--rx)) rotateY(var(--ry)) rotateZ(var(--rz));
  transition: transform var(--move);
}
@media (hover: hover) {
  .mbox:hover { --rx: 30deg; --ry: -22deg; }
}
.mbox.is-open {
  --shift: calc(var(--W) * -0.27);
  --rx: 38deg;
  --ry: -12deg;
}

/* every face starts centred on the box and is turned into place */
.ms,
.mt-floor,
.mt-wall,
.mbox-shadow {
  position: absolute;
  left: 50%;
  top: 50%;
  display: block;
}

/* --- the sleeve --- */
.ms { backface-visibility: hidden; -webkit-backface-visibility: hidden; }
.ms-top,
.ms-bottom {
  width: var(--W);
  height: var(--H);
  margin: calc(var(--H) / -2) 0 0 calc(var(--W) / -2);
}
.ms-top    { transform: translateZ(calc(var(--D) / 2)); }
.ms-bottom { transform: rotateY(180deg) translateZ(calc(var(--D) / 2)); background: #E4D6B8; }

.ms-n,
.ms-s {
  width: var(--W);
  height: var(--D);
  margin: calc(var(--D) / -2) 0 0 calc(var(--W) / -2);
}
.ms-n { transform: rotateX(90deg)  translateZ(calc(var(--H) / 2)); }
.ms-s { transform: rotateX(-90deg) translateZ(calc(var(--H) / 2)); }

.ms-e,
.ms-w {
  width: var(--D);
  height: var(--H);
  margin: calc(var(--H) / -2) 0 0 calc(var(--D) / -2);
}
.ms-e { transform: rotateY(90deg)  translateZ(calc(var(--W) / 2)); }
.ms-w { transform: rotateY(-90deg) translateZ(calc(var(--W) / 2)); }

/* the long sides carry the striker; the ends are open */
.ms-n,
.ms-s {
  background-color: #4B2B3C;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='80'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.6' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='80' height='80' filter='url(%23g)' opacity='0.55'/%3E%3C/svg%3E");
  background-blend-mode: overlay;
  /* the label paper wraps over the edges and frames the strip */
  box-shadow: inset 0 0 0 0.9cqw #D9CBAA;
}
.ms-s { filter: brightness(0.82); }      /* turned away from the light */
.ms-e,
.ms-w { display: none; }

/* --- the drawer --- */
.mbox-tray {
  position: absolute;
  left: 50%;
  top: 50%;
  display: block;
  width: 0;
  height: 0;
  transform-style: preserve-3d;
  /* sits on the sleeve's floor */
  transform: translate3d(var(--tx, 0px), var(--ty, 0px), calc((var(--Dt) - var(--D)) / 2));
  transition: transform var(--move);
}
.mbox.is-open .mbox-tray { --tx: calc(var(--W) * 0.6); }
@media (hover: hover) {
  .mbox:not(.is-open):hover .mbox-tray { --tx: calc(var(--W) * 0.06); }
}

.mt-floor {
  width: var(--Wt);
  height: var(--Ht);
  margin: calc(var(--Ht) / -2) 0 0 calc(var(--Wt) / -2);
  transform: translateZ(calc(var(--Dt) / -2));
  font-size: 2.15cqw;
  background: var(--kraft);
  box-shadow: inset 0 0.5em 1.4em rgba(60, 40, 10, 0.3);
}
.mt-wall { background: var(--wall); }
.mt-n,
.mt-s {
  width: var(--Wt);
  height: var(--Dt);
  margin: calc(var(--Dt) / -2) 0 0 calc(var(--Wt) / -2);
}
.mt-n { transform: rotateX(90deg)  translateZ(calc(var(--Ht) / 2)); }
.mt-s { transform: rotateX(-90deg) translateZ(calc(var(--Ht) / 2)); filter: brightness(0.86); }
.mt-e,
.mt-w {
  width: var(--Dt);
  height: var(--Ht);
  margin: calc(var(--Ht) / -2) 0 0 calc(var(--Dt) / -2);
}
.mt-e { transform: rotateY(90deg)  translateZ(calc(var(--Wt) / 2)); filter: brightness(0.92); }
.mt-w { transform: rotateY(-90deg) translateZ(calc(var(--Wt) / 2)); }

/* --- shadows, lying on the page under the box --- */
.mbox-shadow {
  width: var(--W);
  height: var(--H);
  margin: calc(var(--H) / -2) 0 0 calc(var(--W) / -2);
  transform: translate3d(1.5cqw, 2.5cqw, calc(var(--D) / -2 - 2px));
  background: rgba(31, 27, 22, 0.42);
  border-radius: 4%;
  filter: blur(14px);
}
.mbox-shadow-tray {
  width: var(--Wt);
  height: var(--Ht);
  margin: calc(var(--Ht) / -2) 0 0 calc(var(--Wt) / -2);
  transform: translate3d(1.5cqw, 2.5cqw, calc(var(--Dt) / -2 - 2px));
  opacity: 0;
  transition: opacity 600ms ease;
}
.mbox.is-open .mbox-shadow-tray { opacity: 1; }

/* --- the label --- */
.mbox-label,
.label-face {
  -webkit-user-drag: none;
  user-drag: none;
}
.mbox-label {
  object-fit: cover;
  background: #EFE3C8;       /* while the photo loads */
}

/* --- inside the drawer --- */
.mbox-matches {
  position: absolute;
  inset: 1em 1.3em;
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
}
.mbox-matches i {
  position: relative;
  display: block;
  width: 84%;
  height: 0.6em;
  border-radius: 0.1em;
  background: linear-gradient(#F0DDB6, #D2B47E);
  box-shadow: 0 0.12em 0.14em rgba(40, 25, 5, 0.3);
}
/* heads alternate ends, the way a box is actually packed */
.mbox-matches i::after {
  content: '';
  position: absolute;
  top: 50%;
  right: -0.35em;
  width: 1.25em;
  height: 0.9em;
  border-radius: 48% 52% 52% 48%;
  transform: translateY(-50%);
  background: radial-gradient(circle at 35% 35%, #DA75FF, var(--accent) 45%, #5E007A);
}
.mbox-matches i:nth-child(even) { align-self: flex-end; }
.mbox-matches i:nth-child(even)::after { right: auto; left: -0.35em; }

.mbox-slip {
  position: absolute;
  top: 50%;
  right: 5%;
  width: 46%;
  display: block;
  padding: 0.9em 1.2em 1em;
  background: #FBF7EC;
  box-shadow: 0 0.2em 0.6em rgba(40, 25, 5, 0.28);
  transform: translateY(-50%) rotate(2.5deg);
  font-family: var(--f-body);
  font-style: italic;
  font-size: 1.8em;
  line-height: 1.2;
  text-align: left;
  color: var(--ink);
}


/* --- phone: still landscape, but opening pans to the drawer --- */
@media (max-width: 560px) {
  .about { padding: 3.5rem 1rem 2rem; }
  .mbox {
    width: 84vw;
    --rx: 30deg;
    --ry: -16deg;
    --rz: -5deg;
  }
  /* the box slides mostly off the left edge so the drawer lands centre-screen */
  .mbox.is-open {
    --shift: calc(var(--W) * -0.55);
    --rx: 36deg;
    --ry: -10deg;
  }
  /* the slip is the thing being read, so it gets more room at this size */
  .mbox-slip { width: 56%; right: 3%; font-size: 2.3em; }
}

/* --- thanks ---------------------------------------------------------------
   The page after the form is sent: one line, centred, in the site's capitals. */

.thanks {
  min-height: 62vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4rem 1.5rem;
}
.thanks p {
  margin: 0;
  max-width: 34ch;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: clamp(0.8rem, 1.5vw, 0.95rem);
  line-height: 2.1;
  letter-spacing: 0.2em;
  text-align: center;
  color: var(--ink);
}
.thanks a {
  color: var(--accent-ink);
  text-decoration: none;
  border-bottom: 2px solid var(--accent);
}

/* --- contact ----------------------------------------------------------------
   A matchbox label, printed on both sides: Persian on the front, English on the
   back. Hovering (or tabbing to it) turns it over, and the whole label is the
   way to the message form.

   The turn is a real 3D flip — two faces back to back, each hidden when facing
   away — while the label lifts slightly off the page, so it reads as being
   picked up and turned in the hand rather than swapped. On touch screens there is
   no hover, so the label turns over by itself every few seconds instead. */

.contact {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 5rem 2rem 6.5rem;
}
.label {
  display: block;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  width: min(580px, 100%);
  aspect-ratio: 3 / 2;
  perspective: 1600px;
  transition: transform 500ms cubic-bezier(0.2, 0, 0, 1);
}
.label:hover,
.label:focus-visible { transform: translateY(-6px); }
.label:focus-visible { outline: 0; }

.label-flip {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 1000ms cubic-bezier(0.3, 0.1, 0.15, 1);
}
.label:hover .label-flip,
.label:focus-visible .label-flip { transform: rotateY(180deg); }

.label-face {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 1.4% / 2.1%;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  /* box-shadow, not drop-shadow: a filter would flatten the 3D */
  box-shadow:
    0 1px 2px rgba(31, 27, 22, 0.16),
    0 18px 34px -10px rgba(31, 27, 22, 0.3);
  transition: box-shadow 500ms cubic-bezier(0.2, 0, 0, 1);
}
.label-back { transform: rotateY(180deg); }
.label:hover .label-face,
.label:focus-visible .label-face {
  box-shadow:
    0 2px 4px rgba(31, 27, 22, 0.14),
    0 30px 46px -12px rgba(31, 27, 22, 0.32);
}
.label:focus-visible .label-face { outline: 2px solid var(--accent); outline-offset: 6px; }

@media (hover: none) {
  .label-flip { animation: label-turn 9s cubic-bezier(0.3, 0.1, 0.15, 1) 1.5s infinite; }
}
@keyframes label-turn {
  0%, 38%   { transform: rotateY(0deg); }
  50%, 84%  { transform: rotateY(180deg); }
  96%, 100% { transform: rotateY(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .label-flip { animation: none; }
}

/* --- inquiry form ----------------------------------------------------------- */

.form-wrap {
  max-width: 560px;
  margin: 0 auto;
  padding: 4.5rem 2.5rem 6rem;
}
.form-wrap h1 {
  margin: 0 0 2.4rem;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.3em;
  color: var(--ink);
}
.form-intro {
  margin: 0 0 2.5rem;
  max-width: 44ch;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 0.72rem;
  line-height: 1.95;
  color: var(--ink-soft);
}
.field { margin-bottom: 1.6rem; }
.field label {
  display: block;
  margin-bottom: 0.45rem;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 0.58rem;
  letter-spacing: 0.2em;
  color: var(--ink-soft);
}
.field input,
.field textarea {
  width: 100%;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--paper-line);
  padding: 0.55rem 0;
  font-family: var(--f-body);
  font-size: 1.05rem;
  color: var(--ink);
  transition: border-color 200ms ease;
}
.field textarea {
  min-height: 8rem;
  resize: vertical;
  line-height: 1.6;
}
.field input:focus,
.field textarea:focus {
  outline: 0;
  border-bottom-color: var(--accent);
}
.field input::placeholder,
.field textarea::placeholder { color: var(--ink-soft); opacity: 0.55; }

.form-send {
  appearance: none;
  margin-top: 0.7rem;
  padding: 0.85rem 2.2rem;
  background: var(--ink);
  border: 1px solid var(--ink);
  color: var(--paper);
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 0.66rem;
  letter-spacing: 0.24em;
  cursor: pointer;
  transition: background 200ms ease, border-color 200ms ease;
}
.form-send:hover { background: var(--accent); border-color: var(--accent); }

/* honeypot — hidden from people, catches the bots that fill everything in */
.hp { position: absolute; left: -9999px; opacity: 0; height: 0; overflow: hidden; }

.form-note {
  margin-top: 2.5rem;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 0.6rem;
  line-height: 1.9;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
}

@media (max-width: 480px) {
  .contact { padding: 3.5rem 1.25rem 5rem; }
  /* the capitals run wider than the old lowercase, so the four links need tighter spacing to share a line */
  .foot-nav { gap: 1.3rem; letter-spacing: 0.14em; }
}

/* --- enlarged view ----------------------------------------------------------
   view.js moves one frame from the thumbnail to the centre; everything here is
   what happens around that move. The page recedes behind frosted paper, and once
   the piece lands the accent bar draws down its left edge — the homepage hero's
   mark, so an enlarged piece reads as featured. The upload time arrives last and
   quietest: tracked wide, then drawing in to rest. */

.vw-trigger { cursor: zoom-in; }
.vw-lock { overflow: hidden; }

.vw {
  position: fixed;
  inset: 0;
  z-index: 100;
  cursor: zoom-out;
}
.vw-veil {
  position: absolute;
  inset: 0;
  background: rgba(250, 250, 247, 0.9);    /* --paper, held back a touch */
  -webkit-backdrop-filter: blur(14px) saturate(0.85);
  backdrop-filter: blur(14px) saturate(0.85);
  opacity: 0;
  transition: opacity 520ms ease;
}
.vw.is-in .vw-veil { opacity: 1; }
.vw.is-out .vw-veil { opacity: 0; transition-duration: 460ms; }

.vw-frame { position: fixed; }
.vw-frame img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;          /* matches the thumbnail's crop at the start, full piece at the end */
  /* lifted further off the page than the featured thumbnail, so it reads as picked up */
  filter: drop-shadow(0 2px 3px rgba(31, 27, 22, 0.14))
          drop-shadow(0 34px 48px rgba(31, 27, 22, 0.2));
}
.vw-bar {
  position: absolute;
  left: -2px;
  top: 24px;
  width: 2px;
  height: 0;
  background: var(--accent);
  transition: height 420ms cubic-bezier(0.2, 0, 0, 1);
}
.vw.is-landed .vw-bar { height: 36px; }

.vw-words {
  position: fixed;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  padding-top: 14px;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 360ms ease, transform 500ms cubic-bezier(0.2, 0, 0, 1);
}
.vw.is-landed .vw-words {
  opacity: 1;
  transform: none;
  transition-delay: 120ms;
}
.vw-cap {
  margin: 0;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 12px;
  line-height: 1.7;
  letter-spacing: 0.03em;
  color: var(--ink-soft);
}
.vw-time {
  flex: 0 0 auto;
  margin-left: auto;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 10px;
  letter-spacing: 0.42em;
  white-space: pre;            /* keeps the spaces either side of the dot */
  color: var(--ink-soft);
  opacity: 0;
  transition: letter-spacing 1100ms cubic-bezier(0.2, 0, 0, 1), opacity 700ms ease;
}
.vw.is-landed .vw-time {
  letter-spacing: 0.16em;
  opacity: 0.6;
  transition-delay: 300ms;
}

.vw-close {
  position: fixed;
  top: 18px;
  right: 22px;
  appearance: none;
  background: none;
  border: 0;
  padding: 0.5rem;
  font-family: var(--f-ui);
  text-transform: lowercase;
  font-size: 0.62rem;
  letter-spacing: 0.24em;
  color: var(--ink-soft);
  cursor: pointer;
  opacity: 0;
  transition: opacity 400ms ease 200ms, color 160ms ease;
}
.vw.is-in .vw-close { opacity: 1; }
.vw.is-out .vw-close { opacity: 0; transition-delay: 0ms; }
.vw-close:hover { color: var(--accent-ink); }

@media (max-width: 700px) {
  .vw-words { flex-direction: column; gap: 0.2rem; }
  .vw-time { margin-left: 0; }
}

/* shown only when a page is opened straight from the folder (chrome.js) */
.file-warn {
  position: fixed;
  left: 50%;
  bottom: 1rem;
  z-index: 9500;
  transform: translateX(-50%);
  width: min(560px, calc(100% - 2rem));
  padding: 0.9rem 1.1rem;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--f-ui);
  font-size: 0.68rem;
  line-height: 1.7;
  letter-spacing: 0.06em;
  box-shadow: 0 12px 30px -10px rgba(31, 27, 22, 0.45);
}
.file-warn b { color: var(--accent-lift); font-weight: 700; }

/* --- page to page -----------------------------------------------------------
   A white veil over the whole page. Every page arrives under it and it lifts;
   clicking through to another page of the site brings it back down first
   (chrome.js adds .nf-leaving and navigates once it has settled). A pseudo
   element on <html>, so it needs no markup and is there from the first paint.
   It never takes clicks. */

html::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 10000;            /* above the intro and the enlarged view */
  background: #fff;
  pointer-events: none;
  opacity: 0;
  animation: nf-veil-lift 480ms cubic-bezier(0.4, 0, 0.2, 1) both;
}
html.nf-leaving::after {
  animation: nf-veil-drop 260ms cubic-bezier(0.4, 0, 1, 1) forwards;
}
@keyframes nf-veil-lift { from { opacity: 1; } to { opacity: 0; } }
@keyframes nf-veil-drop { from { opacity: 0; } to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
