/*
 * One stylesheet for the whole site.
 *
 * No framework and no build step: the server serves these files straight off
 * the classpath, so a change to a headline is a change to one file. The palette
 * is warm on purpose -- this sells a keepsake, not a toy, and the blue-grey of
 * a software product makes a $1,800 model of somebody's house look like an app.
 */

:root {
  color-scheme: light dark;

  --paper: #faf7f2;
  --card: #ffffff;

  /* The baseplate the whole site sits on. Not LEGO's blue but the gold from
     the wordmark, held at the same lightness the studs were softened to --
     the plate was already on that hue, and it was only the saturation that
     kept it a neutral cream. The three tones stay close enough together
     that the studs read as texture and never as pattern. */
  --plate: #f7efe0;
  --stud-shadow: #f3e7d0;
  --stud-face: #f9f3e8;
  --stud-top: #fcf8f2;
  --ink: #1b1a17;
  --muted: #6c655b;
  --line: #e5dfd4;
  /* The two inks of the wordmark. Green does the work -- buttons, labels,
     links, the focus ring -- because it carries text at any size. Gold is
     trim only: at 2.3:1 on the plate it cannot hold small type, so it draws
     the baseplate rule under the header and fills, never letters. */
  --accent: #055935;
  --accent-soft: #e7efe9;
  --gold: #c69333;
  --gold-soft: #f7edd7;
  --gold-ink: #7f5d1c;
  --good: #2f6b46;
  --warn: #8a6d1f;

  --radius: 14px;
  --shadow: 0 1px 2px rgba(27, 26, 23, .06), 0 8px 24px rgba(27, 26, 23, .06);
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #14130f;
    --card: #1e1c18;
    --plate: #16140f;
    --stud-shadow: #100f0b;
    --stud-face: #1a1813;
    --stud-top: #1f1c16;
    --ink: #f4efe6;
    --muted: #a9a195;
    --line: #322e28;
    --accent: #5bb389;
    --accent-soft: #14291f;
    --gold: #d9a94f;
    --gold-soft: #2b2415;
    --gold-ink: #e3bd72;
    --good: #7fc79b;
    --warn: #d9b45f;
  }
}

* { box-sizing: border-box; }

/* Hidden means hidden, whatever a class says about how it shows: a button
   is inline-flex and a viewer's picture is a block, and either would
   otherwise stay on screen with the attribute set. */
[hidden] { display: none !important; }

body {
  margin: 0;
  color: var(--ink);
  font: 16px/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;

  /* A LEGO baseplate, drawn in three circles per tile: the shadow the stud
     casts below it, the face, and the crown the light catches on top. Real
     proportions -- a stud is 4.8mm across on an 8mm pitch, so 60% of the
     tile. The tones sit within a few percent of the plate and every circle
     fades out rather than stopping, so the board reads as texture under a
     paragraph and never as pattern competing with it. */
  background-color: var(--plate);
  background-image:
    radial-gradient(circle 11px   at 50% 45%, var(--stud-top) 0 45%, transparent 100%),
    radial-gradient(circle 13.5px at 50% 49%, var(--stud-face) 0 82%, transparent 97%),
    radial-gradient(circle 13.5px at 50% 57%, var(--stud-shadow) 0 62%, transparent 100%);
  background-size: 46px 46px;
}

a { color: inherit; }

.wrap { max-width: 1060px; margin: 0 auto; padding: 0 20px; }

/* ---------- header ---------- */

header.site {
  border-bottom: 2px solid var(--gold);
  background: color-mix(in srgb, var(--plate) 82%, transparent);
  position: sticky; top: 0; z-index: 10;
  backdrop-filter: blur(8px);
}

header.site .wrap {
  display: flex; align-items: center; gap: 24px;
  height: 64px;
}

/* The wordmark is artwork, not type, so it ships as two inked PNGs and the
   page picks one by colour scheme. Height is fixed and width follows, so the
   gold plate under the lettering always lands on the same pixel. */
.brand { display: block; text-decoration: none; line-height: 0; }
.brand img { display: block; height: 37px; width: auto; }
.brand.quiet img { height: 30px; }

/* The line rides with the wordmark, and steps out of the way when the
   header gets tight. */
.lockup { display: flex; align-items: center; gap: 14px; min-width: 0; }
.lockup .line {
  font: italic 14px/1 var(--serif); color: var(--muted); white-space: nowrap;
}
@media (max-width: 1080px) { .lockup .line { display: none; } }

nav.site { margin-left: auto; display: flex; gap: 22px; align-items: center; }
nav.site a { text-decoration: none; color: var(--muted); font-size: 15px; white-space: nowrap; }
nav.site a:hover, nav.site a[aria-current="page"] { color: var(--ink); }

/* ---------- type ---------- */

h1, h2, h3 { font-family: var(--serif); font-weight: 600; line-height: 1.15; margin: 0 0 12px; }
h1 { font-size: clamp(34px, 5vw, 54px); letter-spacing: -.5px; }
h2 { font-size: clamp(25px, 3.2vw, 34px); }
h3 { font-size: 19px; }
p { margin: 0 0 14px; }
.lead { font-size: 19px; color: var(--muted); max-width: 54ch; }
/* The hero's lead as verse: each stanza starts its own line, with a little
   air between them so a line that wraps on a phone still reads as one.
   Every phrase is a .unit, so a line breaks only at a comma or a full stop,
   never at "a / grid" or "built / by your hands", and never leaves "cells."
   alone; balancing then evens the lines out. */
.lead.verse > span { display: block; text-wrap: balance; }
.lead.verse > span + span { margin-top: 12px; }
/* Voxel and heirloom carry the two halves of the name, so in the headline,
   the thumbnails' labels and the zoom they take the wordmark's own inks,
   exactly -- the owner's choice, after the darker text gold read as black.
   The logo's gold is 2.4:1 on the plate, under the 3:1 asked of large
   text, so it is kept to these two words and never used for sentences. */
.hero .vox, .zoom .vox { color: var(--accent); }
.hero .loom, .zoom .loom { color: var(--gold); }
.tagline {
  font: italic 20px/1.3 var(--serif); color: var(--accent);
  margin: -4px 0 16px;
}
.muted { color: var(--muted); }
.small { font-size: 14px; }
section { padding: 64px 0; }
section + section { border-top: 1px solid var(--line); }
.eyebrow {
  text-transform: uppercase; letter-spacing: .12em; font-size: 12px;
  color: var(--accent); font-weight: 600; margin-bottom: 10px;
}

/* ---------- buttons ---------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 12px 20px; border-radius: 999px; border: 1px solid transparent;
  font: 500 15px/1 var(--sans); text-decoration: none; cursor: pointer;
  background: var(--card); color: var(--ink); border-color: var(--line);
}
.btn:hover { border-color: var(--muted); }
.btn.primary { background: var(--accent); color: #fff; border-color: var(--accent); }
.btn.primary:hover { filter: brightness(1.06); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn.small { padding: 8px 14px; font-size: 14px; }
.actions { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 22px; }

/* ---------- cards and grids ---------- */

.card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 22px;
}
.grid { display: grid; gap: 20px; }
.grid.two { grid-template-columns: repeat(2, 1fr); }
.grid.three { grid-template-columns: repeat(3, 1fr); }
.grid.four { grid-template-columns: repeat(4, 1fr); }

.shot {
  width: 100%; aspect-ratio: 7 / 5; object-fit: contain;
  border-radius: 10px; background: var(--paper); display: block;
}

/* A whole card is a link to the design; underlining the title as well just
   makes the card look like a list of links. */
figure.card a { text-decoration: none; }
figure.card h3 a:hover { text-decoration: underline; }

.badge {
  display: inline-block; padding: 3px 10px; border-radius: 999px;
  background: var(--accent-soft); color: var(--accent);
  font-size: 12px; font-weight: 600; letter-spacing: .02em;
}
.badge.grey { background: var(--line); color: var(--muted); }
.badge.gold { background: var(--gold-soft); color: var(--gold-ink); }
.badge.good { background: color-mix(in srgb, var(--good) 15%, transparent); color: var(--good); }

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

.hero { padding: 72px 0 56px; }
/* Pixel, voxel, heirloom as three pictures laid over the top of the
   animation's card. Every frame is framed on the finished model, and the top
   29.5% of all 29 frames is empty -- the still picture too -- so the strip
   sits in that band and never covers the building: at most 27% of the card,
   at any width from 320px up. The cap on its width keeps it inside the band
   where the card is wider than the square picture in it, as on a tablet. */
.showcase { position: relative; }
.journey {
  --gap: 18px;
  position: absolute; z-index: 1; top: 3%; left: 50%; transform: translateX(-50%);
  width: 80%; max-width: 380px;
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gap);
}
.journey li { margin: 0; text-align: center; }
/* The arrow hangs off the picture's frame rather than the list item, so it
   sits level with the middle of the picture, not of picture and label. */
.journey .pic { position: relative; }
.journey li:not(:last-child) .pic::after {
  content: "\2192"; position: absolute; top: 50%; right: calc(-1 * var(--gap));
  width: var(--gap); transform: translateY(-50%);
  color: var(--muted); font-size: 16px; line-height: 1;
}
.hero .journey img {
  aspect-ratio: 3 / 2; object-fit: cover; max-height: none; border-radius: 8px;
}
.journey span {
  display: block; margin-top: 6px;
  font: 600 14px/1.2 var(--sans); color: var(--ink);
}
/* Each thumbnail opens the zoom. There is no hover on a phone, so the
   caption under the card says so as well. */
.journey a { display: block; border-radius: 8px; cursor: zoom-in; }
.journey a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
@media (prefers-reduced-motion: no-preference) {
  .journey a img { transition: transform .15s ease; }
  .journey a:hover img { transform: translateY(-2px); }
}

.zoom {
  border: 0; padding: 12px; border-radius: var(--radius);
  background: var(--paper); color: var(--ink); box-shadow: var(--shadow);
  max-width: 96vw; max-height: 96vh; overflow: auto;
}
.zoom::backdrop { background: rgba(20, 18, 14, .72); }
.zoom img { display: block; height: auto; border-radius: 8px; margin: 0 auto; }
.zoom-close {
  position: absolute; top: 18px; right: 18px; z-index: 1;
  width: 36px; height: 36px; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--line); background: var(--paper); color: var(--ink);
  font-size: 22px; line-height: 1;
}
.zoom-caption { margin: 10px 4px 2px; text-align: center; font-size: 14px; color: var(--muted); }
.zoom-label { font-weight: 600; color: var(--ink); }

/* Under the card, not in it: the strip has 10-25px to spare above the
   building, and a line of text inside would push it onto the roof. */
.journey-note {
  margin: 10px 0 0; text-align: center;
  font-size: 13px; color: var(--muted);
}
/* The headline and the eyebrow over it are each two phrases, and a line
   should never break inside one: "memories live, pixel / to voxel to
   heirloom" splits the chain it is about, "LEGO brick / keepsakes" the thing we
   make. Each phrase moves to the next line whole, and wraps within itself
   only when the screen is too narrow to hold it. "One-of-a-kind" never
   splits at a hyphen. */
.hero h1, .hero .eyebrow { text-wrap: balance; }
.hero .unit { display: inline-block; }
.nowrap { white-space: nowrap; }
@media (min-width: 861px) {
  /* Beside the picture the column is about 510px, and the longer phrase
     needs 12 times the type size -- so 42px is the most that keeps it to
     one line. */
  .hero h1 { font-size: clamp(34px, 3.3vw, 42px); }
}
@media (max-width: 860px) {
  /* On a phone the column is the screen less 40px of gutter, and the usual
     34px floor is too big for either phrase -- "pixel to voxel to heirloom"
     split in two on every iPhone. Here the type is sized to the screen, so
     each phrase keeps to one line: about 27px at 375px wide, 31px at 430. */
  .hero h1 {
    font-size: min(clamp(34px, 5vw, 54px), max(22px, calc((100vw - 40px) / 12.3)));
  }
}
.hero .grid { grid-template-columns: 1.05fr .95fr; align-items: center; gap: 44px; }
.hero picture { display: block; }
.hero img {
  width: 100%; height: auto; max-height: 460px; object-fit: contain;
  background: var(--paper); border-radius: var(--radius);
  box-shadow: var(--shadow); display: block;
}

/* ---------- steps and tiers ---------- */

.step { display: flex; gap: 14px; }
.step .n {
  flex: none; width: 30px; height: 30px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent);
  display: grid; place-items: center; font-weight: 600; font-size: 14px;
}
.tier { display: flex; flex-direction: column; }
.tier .badge { align-self: flex-start; }   /* a flex child would stretch to the card */
.tier .price { font: 600 30px/1 var(--serif); margin: 6px 0 2px; }
.tier ul { margin: 14px 0 0; padding-left: 18px; color: var(--muted); font-size: 15px; }
.tier li { margin-bottom: 6px; }
.tier .spacer { flex: 1; min-height: 12px; }

/* ---------- forms ---------- */

.field { margin-bottom: 16px; }
.field label { display: block; font-size: 14px; font-weight: 500; margin-bottom: 6px; }
.field .hint { font-size: 13px; color: var(--muted); margin-top: 6px; }
input[type=text], input[type=email], input[type=tel], input[type=number], select, textarea {
  width: 100%; padding: 11px 13px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--card); color: var(--ink);
  font: 15px/1.5 var(--sans);
}
textarea { min-height: 120px; resize: vertical; }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
fieldset { border: 0; padding: 0; margin: 0 0 16px; }
.choices { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.choice {
  border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px;
  cursor: pointer; background: var(--card); font-size: 14px;
}
.choice[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-soft); }
.choice strong { display: block; font-size: 15px; margin-bottom: 2px; }

.drop {
  border: 1.5px dashed var(--line); border-radius: var(--radius);
  padding: 22px; text-align: center; color: var(--muted); cursor: pointer;
}
.drop:hover { border-color: var(--accent); color: var(--ink); }
.thumbs { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 12px; }
.thumbs figure { margin: 0; position: relative; }
.thumbs img { width: 92px; height: 70px; object-fit: cover; border-radius: 8px; }
.thumbs button {
  position: absolute; top: -7px; right: -7px; width: 22px; height: 22px;
  border-radius: 50%; border: 1px solid var(--line); background: var(--card);
  cursor: pointer; line-height: 1; font-size: 13px; color: var(--ink);
}

/* ---------- notices ---------- */

.note {
  border-left: 3px solid var(--accent); background: var(--accent-soft);
  padding: 12px 16px; border-radius: 0 10px 10px 0; font-size: 14px;
}
.note.grey { border-color: var(--muted); background: var(--line); }
.error { color: #a52a1a; font-size: 14px; }
@media (prefers-color-scheme: dark) { .error { color: #ff9b86; } }

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

.stage { display: grid; grid-template-columns: 360px 1fr; gap: 28px; align-items: start; }
.viewer { position: relative; }
/* Renders are square, and saying so up front stops the page jumping when a
   nineteen-thousand-brick model takes two seconds to draw. */
.viewer img {
  width: 100%; aspect-ratio: 1 / 1; object-fit: contain;
  border-radius: var(--radius); background: var(--card); display: block;
}
.viewer .turns { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
.progress { display: grid; gap: 10px; margin: 16px 0; }
.progress .row { display: flex; gap: 10px; align-items: baseline; font-size: 14px; }
.progress .dot {
  width: 9px; height: 9px; border-radius: 50%; background: var(--line); flex: none;
  margin-top: 6px;
}
.progress .row.done .dot { background: var(--good); }
.progress .row.live .dot { background: var(--gold); animation: pulse 1.1s infinite; }
@keyframes pulse { 50% { opacity: .35; } }

.facts { display: grid; grid-template-columns: auto 1fr; gap: 6px 18px; font-size: 15px; margin: 0; }
.facts dt { color: var(--muted); }
.facts dd { margin: 0; }

/* ---------- one design, the way the app shows it ---------- */

/* The model gets the wider half: it is the thing being looked at, and the
   parts list beside it is a list of short lines. */
.stage.flip { grid-template-columns: 1.08fr .92fr; }

.viewer img { transition: opacity .18s; }
.viewer img.busy { opacity: .4; }

.peel { margin-top: 18px; }
.peel label { display: block; font-size: 14px; font-weight: 500; margin-bottom: 8px; }
.peel input[type=range] { width: 100%; accent-color: var(--accent); }

/* A colour is worth showing rather than naming: "Dark Orange" means nothing
   until it is next to "Medium Nougat". */
.chip {
  display: inline-block; width: 13px; height: 13px; border-radius: 3px;
  border: 1px solid var(--line); margin-right: 8px; vertical-align: -1px;
}

/* Three hundred and thirty lines is a scroll, not a page. */
.scroller { max-height: 540px; overflow: auto; margin-top: 14px; }

.jump { display: flex; gap: 8px; align-items: center; }
.jump input { width: 120px; }

.step-card {
  display: grid; grid-template-columns: 118px 1fr; gap: 16px;
  padding: 16px 0; border-top: 1px solid var(--line); align-items: start;
}
.step-card:first-child { border-top: 0; padding-top: 0; }
.step-card img {
  width: 100%; border-radius: 8px; background: var(--paper); display: block;
}
.step-card strong { display: block; margin: 3px 0 5px; }

/* ---------- sizes ---------- */

/* One design built at more than one size: a card for each, side by side
   under the summary, the one on this page marked. The whole card is the
   link, so the choice is one tap. */
.sizes { margin: 4px 0 30px; max-width: 760px; }
.sizes .eyebrow { margin-bottom: 4px; }
.sizes .choices { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 14px; margin-top: 12px; }
.sizes .choice {
  display: grid; grid-template-columns: 96px 1fr; gap: 14px; align-items: center;
  text-decoration: none; color: var(--muted);
}
.sizes .choice strong { color: var(--ink); }
.sizes .choice img {
  width: 96px; height: 96px; object-fit: contain;
  border-radius: 8px; background: var(--paper); display: block;
}
.sizes a.choice:not([aria-current]):hover { border-color: var(--muted); }
.choice[aria-current="page"] { border-color: var(--accent); background: var(--accent-soft); }

/* ---------- pixel, voxel, heirloom ---------- */

/* The studio's three pictures. The words keep the logo's inks, as they do
   in the hero: voxel in green, heirloom in gold -- the owner's call. */
.pvh-page .vox { color: var(--accent); }
.pvh-page .loom { color: var(--gold); }

.pvh-examples { margin: 26px 0; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.pvh-examples .choice {
  display: grid; grid-template-columns: 64px 1fr; gap: 12px; align-items: center;
  text-align: left; text-decoration: none; color: var(--muted); font: 14px/1.4 var(--sans);
}
.pvh-examples .choice strong { color: var(--ink); }
.pvh-examples .choice img, .pvh-examples .own {
  width: 64px; height: 64px; border-radius: 8px; background: var(--paper); display: block; object-fit: contain;
}
.pvh-examples .own {
  display: grid; place-items: center; border: 1.5px dashed var(--line);
  font-size: 26px; color: var(--muted); box-sizing: border-box;
}
.pvh-examples a.choice:hover, .pvh-examples button.choice:not([aria-pressed="true"]):hover { border-color: var(--muted); }

.pvh-photos { display: grid; grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); gap: 8px; margin: 10px 0 12px; }
.pvh-photos figure { margin: 0; }
.pvh-photos img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 8px; display: block; }
.pvh-photos figcaption { font-size: 11px; line-height: 1.3; color: var(--muted); margin-top: 3px; }
.pvh-photos p { grid-column: 1 / -1; margin: 0; }

.pvh-steps { display: flex; align-items: stretch; gap: 8px; margin-bottom: 12px; }
.pvh-steps button {
  flex: 1; min-width: 0; padding: 10px 12px; border-radius: 10px; cursor: pointer; text-align: left;
  border: 1px solid var(--line); background: var(--card); color: var(--ink);
  font: 600 18px/1.15 var(--serif);
}
.pvh-steps button small { display: block; margin-top: 3px; font: 13px/1.3 var(--sans); color: var(--muted); }
.pvh-steps button[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-soft); }
.pvh-steps button:disabled { opacity: .45; cursor: default; }
.pvh-steps .arrow { align-self: center; color: var(--muted); }

.pvh-view canvas {
  width: 100%; aspect-ratio: 1 / 1; display: block;
  border-radius: var(--radius); background: var(--card);
  /* A sideways drag turns the cubes; an upward one still scrolls the page. */
  touch-action: pan-y;
}
.pvh-view #voxels { cursor: grab; }
.pvh-view #voxels:active { cursor: grabbing; }
.pvh-standin {
  position: absolute; left: 12px; bottom: 12px; margin: 0; padding: 4px 10px; border-radius: 999px;
  background: rgba(27, 26, 23, .72); color: #fff; font-size: 12px;
}
.pvh-wait {
  position: absolute; inset: 0; margin: 0; display: grid; place-items: center;
  color: var(--muted); font-size: 15px; pointer-events: none;
}
.pvh-caption { margin: 10px 2px 12px; min-height: 2.8em; }

/* The live studio's strip: three pictures in a row with arrows between, as on
   the front page -- the photograph, the voxels, the LEGO set -- each filled in
   as it is drawn and each a button that puts it in the big frame. */
.pvh-strip {
  list-style: none; margin: 0 0 14px; padding: 0;
  display: grid; grid-template-columns: 1fr auto 1fr auto 1fr; align-items: start; gap: 8px;
}
.pvh-strip li { margin: 0; text-align: center; }
.pvh-strip .arrow { align-self: center; margin-top: -1.4em; color: var(--muted); }
.pvh-strip .pic {
  position: relative; display: block; aspect-ratio: 3 / 2; overflow: hidden;
  border-radius: 8px; background: var(--paper);
}
.pvh-strip .pic img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pvh-strip .label { display: block; margin-top: 6px; font: 600 15px/1.2 var(--sans); color: var(--ink); }
.pvh-strip .label.vox { color: var(--accent); }
.pvh-strip .label.loom { color: var(--gold); }
.pvh-example { margin-top: 16px; }
.pvh-card {
  display: block; width: 100%; padding: 0; border: 0; background: none;
  cursor: pointer; text-align: center; color: inherit; font: inherit;
}
.pvh-card .pic { outline: 2px solid transparent; outline-offset: 2px; transition: outline-color .15s; }
.pvh-card[aria-pressed="true"] .pic { outline-color: var(--accent); }
.pvh-card:focus-visible .pic { outline-color: var(--gold); }
.pvh-card:disabled { cursor: default; }
.pvh-card:disabled .label { opacity: .5; }
/* A picture still being drawn: a slow sheen across its empty frame. */
.pvh-card .pic.drawing {
  background: linear-gradient(100deg, var(--paper) 30%, var(--line) 50%, var(--paper) 70%);
  background-size: 250% 100%;
}
@media (prefers-reduced-motion: no-preference) {
  .pvh-card .pic.drawing { animation: sheen 1.6s linear infinite; }
}
@keyframes sheen { from { background-position: 100% 0; } to { background-position: -150% 0; } }

/* The big frame. The drawn pictures are 3:2, and so is the frame, so the page
   does not jump when one replaces the photograph. */
.pvh-big { position: relative; }
.pvh-big canvas, .pvh-big img {
  width: 100%; aspect-ratio: 3 / 2; display: block;
  border-radius: var(--radius); background: var(--card); object-fit: contain;
}
.pvh-busy {
  position: absolute; left: 12px; bottom: 12px; margin: 0; padding: 6px 12px; border-radius: 999px;
  display: flex; gap: 8px; align-items: center;
  background: rgba(27, 26, 23, .74); color: #fff; font-size: 13px;
}
.pvh-busy .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--gold); flex: none; }
@media (prefers-reduced-motion: no-preference) {
  .pvh-busy .dot { animation: pulse 1.1s infinite; }
}
.pvh #view, .pvh #journey { scroll-margin-top: 78px; }   /* clear of the sticky header */
.pvh #brief .progress { margin: 18px 0 12px; }

@media (max-width: 560px) {
  .pvh-steps { gap: 6px; }
  .pvh-steps .arrow { display: none; }
  .pvh-steps button { padding: 8px 9px; font-size: 16px; }
  .pvh-steps button small { font-size: 12px; }
  .pvh-strip { gap: 5px; }
  .pvh-strip .label { font-size: 13px; }
}

/* ---------- gift ideas ---------- */

/* Three designs from the gallery under the opening: a family home, a place
   couples marry, a new home -- the three gifts people think of first. */
.gift-pics { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin: 30px 0 8px; }
.gift-pics a { display: block; text-decoration: none; color: var(--ink); }
.gift-pics img {
  width: 100%; height: auto; aspect-ratio: 1 / 1; object-fit: contain; display: block;
  border-radius: var(--radius); background: var(--card);
}
.gift-pics span { display: block; margin-top: 8px; font: 600 15px/1.3 var(--serif); }
@media (prefers-reduced-motion: no-preference) {
  .gift-pics img { transition: transform .15s ease; }
  .gift-pics a:hover img { transform: translateY(-2px); }
}

/* The way down the page, by who the gift is for. */
.gift-jump { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 26px; }
.gift-jump a {
  padding: 7px 14px; border-radius: 999px; border: 1px solid var(--line);
  background: var(--card); color: var(--ink); text-decoration: none; font-size: 14px;
}
.gift-jump a:hover { border-color: var(--accent); }
.gifts section[id] { scroll-margin-top: 78px; }   /* clear of the sticky header */

.gift-cards { margin-top: 24px; }
.gift-cards .card { display: flex; flex-direction: column; }
.gift-line { font: italic 17px/1.35 var(--serif); color: var(--accent); margin: 2px 0 12px; }
/* "Think of" sits at the foot of each card, wherever the words above end. */
.think { margin: auto 0 0; padding-top: 12px; border-top: 1px solid var(--line); font-size: 13px; color: var(--muted); }
.think strong { color: var(--ink); font-weight: 600; }
.gift-quiet { max-width: 760px; }
.gift-quiet .think { margin-top: 14px; }
/* The lines that carry the feeling: set like the front page's verse. */
.gift-verse { font: 16px/1.6 var(--serif); color: var(--ink); margin: 0 0 12px; }
.gift-actions { margin-top: 26px; }

/* Each group of gifts in a colour of its own, the owner's call: hearth for
   family, rose for partners, sky for new chapters, brass for thank-yous and
   dusk for remembrance. A deep ink for words and buttons, a pale wash for the
   cards, and lighter inks on darker washes after dark. */
.hue-family      { --hue: #a4502a; --hue-soft: #f8ebe0; --hue-on: #fff; }
.hue-partners    { --hue: #a63a55; --hue-soft: #f8e6ea; --hue-on: #fff; }
.hue-milestones  { --hue: #2d6a96; --hue-soft: #e4eef6; --hue-on: #fff; }
.hue-thanks      { --hue: #85650f; --hue-soft: #f6eed6; --hue-on: #fff; }
.hue-remembrance { --hue: #6b5b8e; --hue-soft: #eeeaf4; --hue-on: #fff; }
@media (prefers-color-scheme: dark) {
  .hue-family      { --hue: #e8a07a; --hue-soft: #2a1e17; --hue-on: #1b1a17; }
  .hue-partners    { --hue: #ec97aa; --hue-soft: #2b1b20; --hue-on: #1b1a17; }
  .hue-milestones  { --hue: #93c2e6; --hue-soft: #172330; --hue-on: #1b1a17; }
  .hue-thanks      { --hue: #e2c26a; --hue-soft: #2a2412; --hue-on: #1b1a17; }
  .hue-remembrance { --hue: #bcadde; --hue-soft: #221e2c; --hue-on: #1b1a17; }
}
.gift-group .eyebrow, .gift-group .gift-line, .gift-group .gift-verse a { color: var(--hue); }
.gift-group .card { background: var(--hue-soft); border-top: 4px solid var(--hue); }
.gift-group .think { border-top-color: color-mix(in srgb, var(--hue) 28%, transparent); }
.gift-group .think strong { color: var(--hue); }
.gift-group .btn.primary { background: var(--hue); border-color: var(--hue); color: var(--hue-on); }
.gift-group .btn:not(.primary) { border-color: var(--hue); color: var(--hue); }
.gift-jump a[class^="hue-"] { border-color: var(--hue); color: var(--hue); }
.gift-jump a[class^="hue-"]:hover { background: var(--hue-soft); }

/* The front page's reminder: words on the left, the way in on the right. */
.gift-band { display: grid; grid-template-columns: 1fr auto; gap: 24px; align-items: center; }
.gift-band h2 { margin-top: 4px; }
.gift-band p.muted { max-width: 60ch; margin-bottom: 0; }
@media (max-width: 860px) { .gift-band { grid-template-columns: 1fr; } }

.gift-days { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.gift-days li {
  padding: 6px 12px; border-radius: 999px; background: var(--accent-soft);
  color: var(--ink); font-size: 14px;
}

@media (max-width: 560px) {
  .gift-pics { gap: 8px; }
  .gift-pics span { font-size: 13px; }
}

/* ---------- a customer's account ---------- */

.account-card { max-width: 460px; margin-top: 24px; }
.account-bar {
  display: flex; justify-content: space-between; align-items: center; gap: 16px; flex-wrap: wrap;
  margin-top: 24px; padding: 14px 18px; border-radius: var(--radius); background: var(--card);
}
.account-pics { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px; margin-top: 12px; }
.account-pics a { display: block; text-decoration: none; color: var(--ink); }
.account-pics img {
  width: 100%; aspect-ratio: 3 / 2; object-fit: cover; display: block;
  border-radius: var(--radius); background: var(--card);
}
.account-pics span { display: block; margin-top: 8px; font: 600 15px/1.3 var(--serif); }
.account-pics small { color: var(--muted); font-size: 13px; }
.account-quotes { display: grid; gap: 12px; margin-top: 12px; max-width: 760px; }
.account-quote { display: flex; justify-content: space-between; align-items: center; gap: 16px; padding: 16px 18px; }
.account-status { text-align: right; flex: none; }

/* A kept picture opened again in the studio has no photograph: it was not kept. */
.pvh-strip .pic .gone {
  display: grid; place-items: center; height: 100%; padding: 6px;
  font-size: 12px; line-height: 1.3; color: var(--muted); text-align: center;
}

/* ---------- tables ---------- */

table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line); vertical-align: top; }
th { color: var(--muted); font-weight: 500; }
tr.pick { cursor: pointer; }
tr.pick:hover td { background: var(--accent-soft); }

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

footer.site {
  border-top: 1px solid var(--line); padding: 34px 0 54px;
  color: var(--muted); font-size: 14px;
}
footer.site .cols { display: flex; gap: 28px; flex-wrap: wrap; justify-content: space-between; }
footer.site a { text-decoration: none; }
footer.site a:hover { text-decoration: underline; }
.legal { margin-top: 18px; max-width: 62ch; font-size: 13px; }

/* ---------- narrow ---------- */

@media (max-width: 860px) {
  .hero .grid, .grid.two, .grid.three, .grid.four, .stage, .stage.flip { grid-template-columns: 1fr; }
  section { padding: 44px 0; }
  nav.site { gap: 14px; }
  nav.site a.hide-sm { display: none; }
  .brand img { height: 30px; }
}

/* On a phone the wordmark and three links share 375px, so the logo gives up
   the room rather than the navigation wrapping to a second line. */
@media (max-width: 560px) {
  .brand img { height: 25px; }
  nav.site { gap: 11px; }
  nav.site a { font-size: 14px; }
  .btn.small { padding: 7px 12px; }
}

/* The studio's link says "Studio" where "Design studio" would not fit. */
.nav-short { display: none; }
@media (max-width: 560px) {
  .nav-long { display: none; }
  .nav-short { display: inline; }
  header.site .wrap { gap: 14px; }
  nav.site { gap: 10px; }
  nav.site .btn.small { padding: 7px 10px; }
}
/* On most phones the wordmark, gift ideas, the studio and the price button
   leave no room for a fifth link; the gallery is a tap away from the front
   page and from the studio. Measured: the four fit from 422px. */
@media (max-width: 429px) {
  nav.site a[href="/gallery"] { display: none; }
}

/* The menu button (assets/menu.js). Below 861px every link but the price
   button folds into it, and opens as a list under the header -- so nothing
   on the site is out of reach on a phone, whatever the header has room for.
   The rules above still apply where the script does not run. */
.menu-toggle { display: none; }
@media (max-width: 860px) {
  .has-menu .menu-toggle {
    display: inline-flex; flex-direction: column; justify-content: center; gap: 5px;
    width: 42px; height: 38px; padding: 0 10px; flex: none; cursor: pointer;
    border: 1px solid var(--line); border-radius: 10px; background: var(--card);
  }
  .has-menu .menu-toggle span {
    display: block; height: 2px; border-radius: 2px; background: var(--ink);
    transition: transform .18s ease, opacity .18s ease;
  }
  .has-menu .menu-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
  .has-menu .menu-open .menu-toggle span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .has-menu .menu-open .menu-toggle span:nth-child(2) { opacity: 0; }
  .has-menu .menu-open .menu-toggle span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

  .has-menu header.site .wrap { gap: 12px; }
  .has-menu nav.site a:not(.btn) { display: none; }
  /* Open, the list leaves the row, and the button keeps its place at the end. */
  .has-menu header.site.menu-open .menu-toggle { margin-left: auto; }

  /* Open: the whole list, full width under the gold rule. */
  .has-menu header.site.menu-open nav.site {
    position: absolute; top: 100%; left: 0; right: 0; margin: 2px 0 0;
    flex-direction: column; align-items: stretch; gap: 0;
    padding: 6px 20px 18px; background: var(--paper);
    border-bottom: 2px solid var(--gold); box-shadow: var(--shadow);
  }
  .has-menu header.site.menu-open nav.site a {
    display: block; padding: 13px 2px; font-size: 17px; color: var(--ink);
    border-bottom: 1px solid var(--line);
  }
  .has-menu header.site.menu-open nav.site a[aria-current="page"] { color: var(--accent); font-weight: 600; }
  .has-menu header.site.menu-open nav.site .nav-long { display: inline; }
  .has-menu header.site.menu-open nav.site .nav-short { display: none; }
  .has-menu header.site.menu-open nav.site a.btn {
    margin-top: 14px; padding: 12px; text-align: center; color: #fff; border-bottom: 0;
  }
}
@media (max-width: 860px) and (prefers-reduced-motion: reduce) {
  .has-menu .menu-toggle span { transition: none; }
}
