/*
 * The home page.
 *
 * Tokens, type roles and components all come from shell.css — this file arranges them and
 * adds nothing to the palette. The language is References/UI Inspo: a coloured field with an
 * inset rounded sheet, every image seated on its own colour tile, one dark and one hot
 * colour repeated with the rest as tints, and a slow band of words above the footer.
 */
.home { padding-top: var(--s4); }

/* the rhythm between sections, which is what stops the page reading as one long column */
.home-section { margin-top: var(--s12); }
@media (min-width: 760px) { .home-section { margin-top: 72px; } }

.section-h { font-size: 26px; line-height: 1.1; margin: 0 0 var(--s4); }
@media (min-width: 760px) { .section-h { font-size: 34px; } }
.section-sub { margin: calc(var(--s4) * -1) 0 var(--s6); color: var(--muted); font-size: 15px; max-width: 52ch; }

/* ── 1. hero ─────────────────────────────────────────────────────────────── */
.hero { display: grid; gap: var(--s8); align-items: center; }
@media (min-width: 900px) {
  .hero { grid-template-columns: 1fr minmax(0, 46%); gap: var(--s12); padding: var(--s6) 0 var(--s8); }
}
/* a grid item's min-width is auto, which is its min-content — one wide child would
   otherwise set the column and push the whole page sideways */
.hero > * { min-width: 0; }

.hero-lede { font-size: 38px; line-height: 1.04; margin: var(--s2) 0 var(--s4); max-width: 14ch; }
@media (min-width: 760px) { .hero-lede { font-size: 60px; } }
@media (min-width: 1100px) { .hero-lede { font-size: 68px; } }
.hero-sub { margin: 0 0 var(--s6); color: var(--muted); font-size: 17px; line-height: 1.5; max-width: 44ch; }
/* two doors, equal weight: the same pill, the same size, neither one a "secondary" */
.hero-ctas { display: flex; flex-wrap: wrap; gap: var(--s3); }
.hero-cta { display: inline-block; width: auto; padding: 15px 34px; min-width: 200px; }
@media (max-width: 559px) {
  .hero-ctas { flex-direction: column; }
  .hero-cta { width: 100%; }
}

.hero-art { display: grid; justify-items: center; gap: var(--s3); }
/* The box carries the poster's shape, so the painting can arrive whenever it likes without
   the page jumping — and so a paint that fails leaves a poster-shaped hole rather than a
   collapsed column. */
/*
 * THE SHOWCASE: one poster on stage at a time, every slide stacked in one box of the
 * poster's shape, crossfading. The box never changes size, so nothing on the page moves
 * when the poster does — and the copy beside it never changes at all.
 *
 * Only the slide on stage can be clicked or focused; the others are transparent, inert and
 * hidden from assistive tech (the script keeps `aria-hidden`/`tabindex` in step).
 */
.show {
  position: relative; width: min(100%, 380px); aspect-ratio: 5 / 7;
  background: var(--sheet-2); border-radius: 2px;
  box-shadow: 0 2px 4px rgba(42, 42, 40, .07), 0 26px 56px -26px rgba(42, 42, 40, .5);
  transition: transform 160ms ease;
}
@media (min-width: 900px) { .show { width: min(100%, 420px); } }
.show:hover { transform: translateY(-3px); }
.show-slide {
  position: absolute; inset: 0; display: block; overflow: hidden; border-radius: 2px;
  opacity: 0; visibility: hidden; pointer-events: none;
  /* visibility waits for the fade to finish, so the outgoing poster fades rather than vanishes */
  transition: opacity 600ms ease, visibility 0s linear 600ms;
}
.show-slide.is-on { opacity: 1; visibility: visible; pointer-events: auto; transition: opacity 600ms ease, visibility 0s; z-index: 1; }
.show-slide img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: fill; }
.show-slide:focus-visible { outline: 2px solid var(--tomato); outline-offset: 3px; }

/* the meta line swaps while it is invisible, never while it is being read */
.hero-note { transition: opacity 300ms ease; min-height: 1.5em; text-align: center; }
.hero-note.swap { opacity: 0; }

/* the incoming painting sits on top and fades in; no crossfade means no flash of the sheet */
#hero-next { opacity: 0; }
#hero-next.fading { animation: heroFade 420ms ease forwards; }
@keyframes heroFade { from { opacity: 0; } to { opacity: 1; } }

.hero-note { margin: 0; font-size: 12px; color: var(--muted); letter-spacing: 0.02em; }

/* ── 2. product grid ─────────────────────────────────────────────────────── */
/* Three columns and two rows on a desktop, two up on a tablet, one up on a phone. Every
   cell the same size: five products with one of them twice the size would say the studio
   has a favourite. */
.cards { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s4); }
@media (min-width: 620px) { .cards { grid-template-columns: repeat(2, 1fr); gap: var(--s6); } }
@media (min-width: 1100px) { .cards { grid-template-columns: repeat(3, 1fr); } }

.card-link {
  display: grid; grid-template-rows: auto 1fr; gap: var(--s4);
  text-decoration: none; color: inherit; height: 100%;
  background: var(--sheet-2); border-radius: var(--r-panel); padding: var(--s6);
  transition: transform 140ms ease, background-color 140ms ease;
}
.card-link:hover { transform: translateY(-3px); background: var(--butter); }

/*
 * The artwork well: paper tone, no coloured mat.
 *
 * The poster used to sit on a block of --sky, which is how both references seat an image —
 * but those are illustrations, and a printed poster photographed on a wall does not come
 * with a blue border. Paper tone and a real shadow read as a poster on a surface; a colour
 * block reads as a swatch.
 */
.card-art {
  position: relative; display: block; background: var(--sheet);
  border-radius: var(--r-tile); padding: var(--s4);
}
.card-art img {
  display: block; width: 100%; height: auto; aspect-ratio: 5 / 7; object-fit: fill;
  /* two shadows: a tight contact shadow where the sheet meets the surface, and a wide soft
     one for the light. One shadow alone reads as a sticker. */
  box-shadow: 0 1px 2px rgba(42, 42, 40, .16), 0 18px 34px -18px rgba(42, 42, 40, .5);
}

/*
 * The rotating photo card: two stacked layers, the top one fading in.
 *
 * The incoming layer's width is stated OUTRIGHT rather than left to the insets. With
 * `inset: var(--s4)` and `width: auto` it should have been sized by its offsets — but the
 * `aspect-ratio: 5 / 7` it inherits from `.card-art img` wins that argument, and the box
 * came out at the well's full width with a height derived from it: 312x437 over a 280x392
 * base. The well does not clip (the poster's shadow has to spill), so for 600ms the
 * incoming photograph hung 32px past the card's right edge and 45px below it, then snapped
 * back the moment it was handed down to the base layer.
 *
 * Percentages on an absolutely positioned box resolve against the containing block's
 * PADDING box, so `100% - 2 * --s4` is exactly the content width the base image fills, and
 * the aspect ratio then gives it the same height rather than a different one.
 */
#photo-art-next {
  position: absolute;
  left: var(--s4); top: var(--s4);
  width: calc(100% - var(--s4) * 2);
  height: auto;
  opacity: 0; pointer-events: none;
}
#photo-art-next.fading { animation: cardFade 600ms ease forwards; }
@keyframes cardFade { from { opacity: 0; } to { opacity: 1; } }

.card-body { display: grid; gap: var(--s2); align-content: start; }
.card-name { font-size: 22px; }
@media (min-width: 760px) { .card-name { font-size: 24px; } }
.card-blurb { color: var(--muted); font-size: 14px; line-height: 1.5; }

/* the footer sits at the bottom of every card, so the row of them lines up */
.card-foot {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3);
  margin-top: auto; padding-top: var(--s3);
}
.card-go {
  font-size: 13px; font-weight: 600; color: var(--forest);
  border-bottom: 2px solid var(--tomato); padding-bottom: 2px;
}
.card-from { font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; }

/* ── 3. gallery ──────────────────────────────────────────────────────────── */
/*
 * Multi-column, not grid — and that is the whole trick.
 *
 * A grid with `grid-auto-rows: 1fr` and row spans STRETCHES each tile to its row, which
 * overrode the boxes' aspect ratios: the "squares" came out oblong and the captions landed
 * at ragged heights, so a deliberate arrangement read as a broken one. Columns let each
 * tile keep its own shape and simply flow down, which is what a loose editorial grid is —
 * two tall tiles take more of their column and the four squares fill in around them, with
 * no cross-column alignment for anything to be slightly wrong about.
 */
/*
 * THREE columns, not four. With nine tiles the browser's own balancing put three in each of
 * the first three columns and left the fourth empty — a quarter of the row as blank cream,
 * which reads as a bug rather than as space. Three columns of three also makes each room
 * shot half again as wide, which is what a photograph of a room wants.
 */
.tiles { columns: 2; column-gap: var(--s3); }
@media (min-width: 760px) { .tiles { columns: 3; column-gap: var(--s4); } }

.tile {
  margin: 0 0 var(--s3); display: grid; gap: var(--s2);
  /* a tile must never be split across a column break */
  break-inside: avoid; page-break-inside: avoid;
}
@media (min-width: 760px) { .tile { margin-bottom: var(--s4); } }

/*
 * The BOX holds the shape, not the image — which is why an empty tile is exactly the size a
 * full one will be, and why dropping the shoot in later changes nothing about the layout.
 */
.tile-box {
  display: grid; place-items: center; overflow: hidden;
  background: var(--sheet-2); border-radius: var(--r-tile);
  aspect-ratio: 1 / 1;
}
/* a tall tile is the photograph's own shape, so nothing is cropped out of it at all */
.tile-tall .tile-box { aspect-ratio: 3 / 4; }
/*
 * A square tile crops a 3:4 room shot, and it crops from the TOP — the poster hangs in the
 * upper half of every one of these frames, so a centred crop takes the furniture and loses
 * the thing being sold.
 */
.tile-box img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 18%; display: block; }
.tile-tall .tile-box img { object-position: center; }

.tile-empty {
  font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted);
  padding: var(--s2) var(--s3); border: 1px dashed var(--rule); border-radius: var(--r-pill);
  background: var(--sheet); white-space: nowrap;
}
.tile-cap { font-size: 12px; color: var(--muted); }

/* ── 5. from your hands to your wall ────────────────────────────────────── */
/*
 * Four steps in a row, bare. The shared `.step` from shell.css draws a tinted tile, which
 * is right on the painted product and wrong here — a row of four cards is furniture, and
 * this page's only decoration is the posters.
 *
 * SUBGRID IS WHAT MAKES THE ROW SIT STILL. The four steps share three rows — the number,
 * the heading, the copy — so every heading starts on one line and every paragraph starts
 * on another, whatever any of them does when it wraps. Without it each column sized its own
 * rows, so a heading that went to two lines at one width pushed only its own copy down and
 * the row came apart. Browsers without subgrid fall back to exactly that, which is the old
 * behaviour rather than a broken one.
 *
 * Alignment is only half of it: the four bodies are also written to the same length, which
 * is the half no stylesheet can fix.
 */
.hw {
  list-style: none; padding: 0;
  /* room to breathe under the heading: .section-h gives 16, this takes it to 40 */
  margin: var(--s6) 0 0;
  display: grid; gap: var(--s8) var(--s6);
}
@media (min-width: 680px) {
  .hw { grid-template-columns: repeat(2, 1fr); grid-template-rows: auto auto auto; }
  .hw-step { grid-row: span 3; grid-template-rows: subgrid; }
}
@media (min-width: 1040px) {
  .hw {
    grid-template-columns: repeat(4, 1fr);
    grid-template-rows: auto auto auto;
    gap: var(--s6);
  }
}
@media (min-width: 760px) { .hw { margin-top: var(--s8); } }
.hw > * { min-width: 0; }

.hw-step { display: grid; gap: var(--s2); align-content: start; }

.hw-n {
  margin: 0; font-family: 'Fraunces', Georgia, serif; font-size: 13px; font-weight: 600;
  letter-spacing: 0.14em; color: var(--tomato); font-variant-numeric: tabular-nums;
}
.hw-h { margin: 0; font-size: 19px; line-height: 1.25; align-self: start; }
@media (min-width: 760px) { .hw-h { font-size: 20px; } }
/* generous: this is the one place on the page that explains the whole transaction */
.hw-p { margin: 0; color: var(--muted); font-size: 15px; line-height: 1.6; max-width: 34ch; }
@media (min-width: 760px) { .hw-p { font-size: 15.5px; } }

/* ── 2b. the wall ────────────────────────────────────────────────────────── */
/*
 * Three rows of prints drifting past each other — left, right, left — very slowly. The
 * rows bleed to the sheet's edges, so the drift reads as a wall passing behind the page
 * rather than a boxed carousel.
 *
 * One rule pauses all three: hovering anywhere on the wall, or holding a finger on it
 * (landing.js sets `.held`). A row that stopped on its own while the others moved would
 * read as broken.
 */
.wall-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--s4); }
.wall-more {
  flex: 0 0 auto; margin-bottom: var(--s6); white-space: nowrap;
  font-size: 15px; font-weight: 600; color: var(--forest); text-decoration: none;
}
.wall-more:hover { text-decoration: underline; }
.wall-more span { display: inline-block; transition: transform 140ms ease; }
.wall-more:hover span { transform: translateX(3px); }
@media (max-width: 559px) {
  .wall-head { display: block; }
  .wall-more { display: inline-block; margin: calc(var(--s2) * -1) 0 var(--s4); }
}

.wall-rows {
  display: grid; gap: var(--s3);
  margin-inline: calc(var(--s4) * -1);
  -webkit-touch-callout: none;
}
@media (min-width: 760px) { .wall-rows { margin-inline: calc(var(--s8) * -1); gap: var(--s6); } }
/* room above and below for the shadows, which overflow:hidden would otherwise cut */
.wall-row { overflow: hidden; padding: var(--s2) 0 var(--s6); margin-bottom: calc(var(--s6) * -1 + var(--s2)); }
.wall-track {
  list-style: none; margin: 0; padding: 0;
  display: flex; width: max-content;
  animation: wallLeft var(--wall-dur, 96s) linear infinite;
  will-change: transform;
}
.wall-row[data-dir="right"] .wall-track { animation-name: wallRight; --wall-dur: 110s; }
.wall-row-3 .wall-track { --wall-dur: 102s; }
@keyframes wallLeft { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes wallRight { from { transform: translateX(-50%); } to { transform: translateX(0); } }
.wall-rows:hover .wall-track,
.wall-rows:focus-within .wall-track,
.wall-rows.held .wall-track { animation-play-state: paused; }

/* each tile carries its gap as a margin, so the doubled track is exactly two halves */
.wall-item { flex: 0 0 auto; width: 140px; margin-right: var(--s3); }
@media (min-width: 768px) { .wall-item { width: 220px; margin-right: var(--s6); } }
.wall-link {
  display: block; aspect-ratio: 5 / 7; background: var(--sheet-2);
  box-shadow: 0 1px 3px rgba(42, 42, 40, .08), 0 16px 34px -18px rgba(42, 42, 40, .42);
  transition: transform 160ms ease;
}
.wall-link img { width: 100%; height: 100%; object-fit: fill; -webkit-user-drag: none; }
.wall-link:hover { transform: translateY(-3px); }
.wall-link:focus-visible { outline: 2px solid var(--tomato); outline-offset: 3px; }

/* phones: two rows */
@media (max-width: 767px) { .wall-row-3 { display: none; } }

/* ── 7. today's shelf ────────────────────────────────────────────────────── */
/*
 * A straight strip of posters that scrolls sideways. No shelf line, no lean, no overlap,
 * no second depth, no label — all of that was built and taken out again. A poster seated
 * on its own shadow, the same treatment as the product grid, is enough.
 *
 * The scroller bleeds to the sheet's edges so the strip runs off both sides rather than
 * reading as a boxed carousel.
 */
.shelf-scroll {
  margin-inline: calc(var(--s4) * -1);
  padding: var(--s2) var(--s4) var(--s4);
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
}
.shelf-scroll::-webkit-scrollbar { display: none; }
@media (min-width: 760px) { .shelf-scroll { margin-inline: calc(var(--s8) * -1); padding-inline: var(--s8); } }

.shelf {
  list-style: none; margin: 0; padding: 0;
  display: flex; align-items: flex-start; gap: var(--s4); width: max-content;
}
@media (min-width: 760px) { .shelf { gap: var(--s6); } }

.shelf-item { flex: 0 0 auto; width: 150px; scroll-snap-align: center; }
@media (min-width: 760px) { .shelf-item { width: 178px; } }

.shelf-link {
  display: block; position: relative; text-decoration: none; color: inherit;
  transition: transform 140ms ease;
}
.shelf-link img {
  display: block; width: 100%; height: auto; border-radius: 3px; background: var(--sheet-2);
  /* the same seating the product grid gives a poster: a shadow, not a coloured mat */
  box-shadow: 0 1px 3px rgba(42, 42, 40, .14), 0 14px 28px -18px rgba(42, 42, 40, .5);
}
.shelf-link:hover { transform: translateY(-3px); }

/*
 * The style's name, on hover and on focus and at no other time. Absolutely positioned so
 * it cannot take a line of its own: a persistent caption under every poster turns the
 * strip into a catalogue, which is the thing this section is not.
 */
.shelf-style {
  position: absolute; left: 0; right: 0; top: calc(100% + 6px);
  font-size: 11px; line-height: 1.3; color: var(--muted);
  opacity: 0; transition: opacity 140ms ease; pointer-events: none;
}
/*
 * `:focus`, not `:focus-visible`, for the LABEL — a name appearing is not a focus ring and
 * should not wait on the browser's heuristic for whether to draw one. The ring itself does
 * use `:focus-visible`, which is what that selector is for.
 */
.shelf-link:hover .shelf-style, .shelf-link:focus .shelf-style { opacity: 1; }
.shelf-link:focus-visible img { outline: 2px solid var(--tomato); outline-offset: 3px; }

/* ── 6. marquee ──────────────────────────────────────────────────────────── */
/*
 * The list is written twice into the track and the animation travels exactly half the
 * track's width, which is what makes the loop seamless: with one copy it would snap back.
 */
.marquee {
  margin-top: var(--s12); overflow: hidden; background: var(--forest); color: var(--sheet);
  border-radius: var(--r-pill); padding: var(--s3) 0;
}
.marq-track {
  display: flex; width: max-content; gap: var(--s8);
  padding-left: var(--s8);
  animation: marq 38s linear infinite;
}
.marquee:hover .marq-track, .marquee:focus-within .marq-track { animation-play-state: paused; }
.marq-item {
  font-size: 13px; letter-spacing: 0.14em; text-transform: uppercase; white-space: nowrap;
}
.marq-item::after { content: '·'; margin-left: var(--s8); color: var(--butter); }
@keyframes marq { from { transform: translateX(0); } to { transform: translateX(-50%); } }

@media (prefers-reduced-motion: reduce) {
  /* a row standing still, not a row that is not there */
  .marq-track { animation: none; }
  .show { transition: none; }
  .show:hover { transform: none; }
  /* no rotation: the painted piece, standing still — by CSS, so it holds even before script */
  .show-slide, .show-slide.is-on { opacity: 0; visibility: hidden; transition: none; }
  .show-slide[data-kind="painted"] { opacity: 1; visibility: visible; pointer-events: auto; z-index: 1; }
  #hero-next.fading { animation: none; opacity: 1; }
  .card-link { transition: none; }
  .card-link:hover { transform: none; }
  #photo-art-next.fading { animation: none; opacity: 1; }

  .wall-link, .wall-more span { transition: none; }
  .wall-link:hover, .wall-more:hover span { transform: none; }
  /* the wall stands still and scrolls by hand instead; the loop copies have nothing to do */
  .wall-track { animation: none; }
  .wall-row { overflow-x: auto; scrollbar-width: none; }
  .wall-row::-webkit-scrollbar { display: none; }
  .wall-item[aria-hidden="true"] { display: none; }
  .wall-row .wall-item:first-child { margin-left: var(--s4); }

  /* the shelf does not lift; the style's name still appears, because that is not motion */
  .shelf-link, .shelf-style { transition: none; }
  .shelf-link:hover { transform: none; }
}
