/* Mindrise landing — mobile-first, on the Classical system (classical.css).
   All colors, fonts, radii, shadows come from classical.css tokens.
   28px leading unit carried from the design handoff. */
:root {
  --leading: 28px;
  --half: 14px;
  --edge: clamp(20px, 5vw, 72px);
  /* The cap on the text column. Below the cap it does nothing (--edge is the whole
     margin); above it, the leftover splits either side as the centring gutter, so
     the page margin on a wide screen is that gutter *plus* --edge. See the desktop
     value under .nav — anything that has to line up with the column reads this. */
  --wrap: 1100px;
  --measure: 58ch;
  --oak: #c89b6a; --maple: #e3cda4; --walnut: #5f4432;
  /* Mirrors .plate in classical.css. Needed as a variable because any figure that
     also casts a shadow has to restate the grade in the same filter chain — see
     the nested-filter note on .hero-figure. Keep in sync if .plate changes. */
  --plate-grade: sepia(0.22) saturate(0.82) contrast(1.05);
  /* The maker section's band, in two forms. --maker-bg is the color as painted —
     a warm sand, chosen to sit with --color-bg. It shows only in the box the video
     reserves before the first frame paints; once playing, the clip covers it edge
     to edge (no feather), so the two no longer have to blend.
     --maker-wall is the same color pre-graded, for anything that sits *inside* the
     .plate filter, so it lands on --maker-bg once sepia/saturate/contrast are
     applied. Change one, change both — run the value back through --plate-grade. */
  --maker-wall: #c3b8a1;
  --maker-bg: #d0c4ab;
}
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body { margin: 0; text-wrap: pretty; }
.arete-wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 var(--edge); }
.nav { padding-inline: max(var(--edge), calc((100% - var(--wrap)) / 2 + var(--edge))); position: sticky; top: var(--wp-admin--admin-bar--height, 0px); background: color-mix(in srgb, var(--color-bg) 92%, transparent); backdrop-filter: blur(6px); z-index: 10; }
/* Client's call: the desktop margins read too wide. They were the 1100 cap and
   --edge stacked — at 1512 that is a 206px gutter plus 72px of padding, 278px of
   air either side of a 956px column. Opening the cap to 1320 spends that gutter on
   the column (1176px, 168px margins) and keeps the page centred, since the margin
   is still whatever the cap leaves, split evenly.
   --edge deliberately did *not* shrink with it, because the product rail's arrows
   stood in that gutter and were sized off it. Those arrows went with the clock
   edition, so nothing is pinned to --edge any more — but it stays where it is: the
   cap alone is what was making the margins wide, and --edge is the page's own
   gutter at every other section. */
/* --nav-h is the desktop nav's own height, declared rather than left to the
   content. Everything in the bar is sized in px (the 22.5/25.5 lockup, the 20px
   cart icon, 13.8px padding either side), so it lands on 64.6 at every width —
   pinning it at 65 changes nothing visually and gives the hero an exact number to
   subtract for its full-screen height. Move one and the other follows. */
@media (min-width: 880px) { :root { --wrap: 1320px; --nav-h: 65px; } }

/* Brand is the drawn logo, not set type. The artwork is a stacked lockup, but
   stacked it can't survive a 10svh nav — fitting all three parts in the bar's
   ~52px of content height drops the wordmark under 14px. So it's relaid
   horizontally: mark left, wordmark (caps over their hairline rule) right.
   The two heights are tuned so the mark spans exactly cap-top to rule —
   change one and the lockup stops lining up. */
.nav-brand { display: flex; align-items: center; gap: 8px; line-height: 0; }
.nav-brand img { display: block; width: auto; }
.nav-mark { height: 22.5px; }
.nav-wordmark { height: 25.5px; }

/* Still the label voice, but the landing page no longer uses it — see
   .section-title below. Kept because the 404 and the checkout both load this
   file for it (inc/arete-404.php, inc/arete-checkout.php). */
.kicker {
  display: block; font-size: 16px; line-height: var(--half);
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--color-accent-700); font-feature-settings: "tnum" 1;
}

/* — section titles —
   Every section on the page carries exactly one, and this is the only thing that
   sets it: one element (h2), one face, one size, one color, one axis. It replaces
   what had drifted into three treatments — a 16px gold kicker, a 22px gold kicker
   over the product rail, and 28/30px serif headings in ink over the story, the
   closing CTA and the contact form — which is what made the titles read as
   unrelated things.

   34px is not a free choice: the card headings underneath these are 30px
   (.display-name) and 27px (.feature h3), so a section title set at the old 30px
   would tie with the card names it is supposed to be a level above. It has to
   clear the largest of them, and 34 is the first step that does.

   text-box trims the ascender slack so the space above a title is measured from
   the ink, which is what lets the per-section margins below stay in whole
   leadings. */
.section-title {
  font-family: var(--font-heading); font-weight: 400;
  font-size: clamp(34px, 4.4vw, 44px); line-height: 1.15;
  color: var(--color-text); text-align: center;
  letter-spacing: normal; text-transform: none;
  margin: 0; text-box: trim-both cap alphabetic;
  /* These were labels short enough to hold one line at 16px; at 34 the longer
     ones wrap, and left to itself the closing CTA broke as "One good thought a /
     day. Framed." — a sentence cut before its own noun. balance evens the two
     lines instead, which puts the break at the full stop. */
  text-wrap: balance;
}

/* — hero — */
/* mobile: 10svh nav + a 90svh hero the photo fills edge to edge.
   Three stacked layers, painted bottom-up: the portrait photo (.hero-figure),
   a darkening scrim (.hero::before), then the copy. The copy is the only one
   that participates in flow — the other two are absolute and pinned to .hero. */
.nav { min-height: 10svh; box-sizing: border-box; }
.hero { box-sizing: border-box; min-height: 90svh;
  padding: calc(2 * var(--leading)) 0 var(--leading);
  display: flex; flex-direction: column;
  position: relative; isolation: isolate; }

/* Full-bleed portrait photo, breaking out of the wrap's --edge padding.
   The asset is shot 9:16 for this box, so nothing is synthesised — the room above
   the frame is real depth of field, and the only thing done to it here is the
   scrim below. This is also the element that crops the img's overscale, so it
   has to keep overflow hidden. The grade stays on the img, never the figure, so
   it never touches the scrim. */
.hero-figure {
  position: absolute; z-index: -2; inset: 0 calc(-1 * var(--edge));
  margin: 0; overflow: hidden; pointer-events: none;
}
/* The <picture> is only a source switch (portrait on the phone, 16:9 from 880 up),
   never a layout box. Blocking it and giving it the figure's full height is what
   lets the img keep sizing in percentages of the figure, as it did when it was a
   direct child. */
.hero-figure picture { display: block; width: 100%; height: 100%; }
/* Taller than its clipping box on purpose. The photo is framed with the product
   dead centre, which puts it too high behind the copy; overscaling and letting
   .hero-figure crop the excess off the bottom pushes the frame down the hero and
   buys the headline its clear room. Growing the box is also what does the zoom —
   cover scales to whichever edge is proportionally short, and at these aspects
   that is the height. */
.hero-figure img {
  width: 100%; height: 122%; object-fit: cover; object-position: 50% 0; display: block;
  filter: var(--plate-grade);
}
/* Darkening scrim over the photo's upper band — what makes the copy legible.
   It is warm (accent-900), never neutral black: a grey scrim would drain the
   amber out of the room behind it.
   The stops are px, not percentages, because the thing the scrim has to clear is
   the button, and the copy is a fixed stack — the button's bottom sits at ~345px
   below the top of the hero at every width we support, while the hero itself is
   90svh and swings from ~575px to over 800px. Percentages would slide the fade
   off the button on a short viewport; px keep it pinned to what it protects.
   The list is a plateau to 230px, then a smoothstep (3u²-2u³) to nothing at
   410px — just past the button, well clear of the frame's lit face. What reads
   as a *line* is not where a fade ends but how abruptly: a ramp still descending
   when it hits zero leaves a slope discontinuity and the eye sees an edge.
   Smoothstep reaches both junctions with zero slope, so it joins the plateau and
   the bare photo without a crease. Recompute the whole curve if you move a stop
   — pulling one out of line is what puts the edge back. */
.hero::before {
  content: ""; position: absolute; z-index: -1; inset: 0 calc(-1 * var(--edge));
  pointer-events: none;
  background: linear-gradient(to bottom,
    color-mix(in srgb, var(--color-accent-900) 80%, transparent) 0,
    color-mix(in srgb, var(--color-accent-900) 78%, transparent) 180px,
    color-mix(in srgb, var(--color-accent-900) 74%, transparent) 230px,
    color-mix(in srgb, var(--color-accent-900) 71%, transparent) 250px,
    color-mix(in srgb, var(--color-accent-900) 65%, transparent) 270px,
    color-mix(in srgb, var(--color-accent-900) 55%, transparent) 290px,
    color-mix(in srgb, var(--color-accent-900) 43%, transparent) 310px,
    color-mix(in srgb, var(--color-accent-900) 31%, transparent) 330px,
    color-mix(in srgb, var(--color-accent-900) 19%, transparent) 350px,
    color-mix(in srgb, var(--color-accent-900) 9%, transparent) 370px,
    color-mix(in srgb, var(--color-accent-900) 3%, transparent) 390px,
    transparent 410px);
}
/* Copy sits on the dark band, so the whole hero inverts to light-on-dark.
   Values come off the neutral/accent ramps — the same family as the page, read
   from the light end instead of the dark one. */
.hero .display { color: var(--color-neutral-100); }
.hero .sub { color: color-mix(in srgb, var(--color-neutral-100) 84%, transparent); }
/* The page's one conversion target, and the only hero element sitting on the
   *bright* part of the photo instead of the scrim — a 1px accent-300 hairline
   dissolves into it. Read the stroke a step lighter off the ramp, double it, and
   back it with the same accent-900 wash the hero scrim is built from so the
   button holds its shape over whatever the photo does behind it. Still outlined,
   never filled: the wash is scrim, not the button's own color. */
.hero .row .btn-primary { color: var(--color-accent-200); border-color: var(--color-accent-200);
  border-width: 2px; letter-spacing: 0.03em;
  background: color-mix(in srgb, var(--color-accent-900) 38%, transparent); }
.hero .row .btn-primary:hover { background: color-mix(in srgb, var(--color-accent-300) 16%, color-mix(in srgb, var(--color-accent-900) 38%, transparent)); }
.hero .row .btn-primary:active { background: color-mix(in srgb, var(--color-accent-300) 26%, color-mix(in srgb, var(--color-accent-900) 38%, transparent)); }
/* the page's --color-accent focus ring is too dark to read against the scrim */
.hero .row .btn:focus-visible { outline-color: var(--color-accent-300); }
.display {
  font-family: var(--font-heading); font-weight: 400;
  font-size: clamp(46px, 14.1vw, 84px); /* 55px at the 390 reference, falls back on smaller phones */
  line-height: 1.08; letter-spacing: -0.01em; margin: 0; margin-left: -0.042em;
  margin-bottom: 3rem;
  text-box: trim-both cap alphabetic;
}
.display .line { display: block; }
.hero .sub { font-size: clamp(17px, 4.87vw, 19px); line-height: calc(var(--leading) + 2px); max-width: var(--measure);
  margin: calc(1.5 * var(--leading) - 1cap) 0 0; text-box: trim-both cap alphabetic; }
/* Keeps a hyphenated term whole across a line break (see the hero sub's "e-ink"). */
.nb { white-space: nowrap; }
.hero .row { display: flex; gap: var(--space-3); flex-wrap: wrap; margin-top: var(--leading); align-items: center; }
/* Semibold — the system's interface-button weight. The CTA is display-sized at
   19px, but it reads as an interface control rather than a headline, and the
   heavier cut holds the label against the photo behind it. */
.hero .row .btn { white-space: nowrap; font-size: 19px; font-weight: var(--font-heading-weight); min-height: 58px;
  padding-inline: calc(var(--space-3) * 3.2); }
@media (min-width: 880px) {
  .nav { min-height: var(--nav-h); }
  /* Desktop is the same three layers as the phone — photo, scrim, copy — but the
     photo is the 16:9 landscape shot and the band runs the full width of the
     window, not the 1320 column. The break-out is the standard pair: negative
     margins that spend the wrap's half-width out to each viewport edge, then
     padding that puts the page gutter back, so the copy still starts on the same
     axis as every section below it (the expression is .nav's, with 100vw for the
     100% that no longer refers to the right box).
     100vw counts a classic scrollbar, so on platforms that reserve one the band
     is ~15px wider than the window; `overflow-x: clip` on the body absorbs it
     without creating a scroll container (`hidden` would, and would break the
     sticky nav). Nothing else on the page bleeds, so this clips only that.
     Height: the whole first screen, less the nav above it and the admin bar above
     that when one is showing — the desktop reading of the phone's 10svh + 90svh
     split, so the hero is the window and the section below it starts off-screen.
     svh, not vh, for the same reason the rest of the file uses it.
     The photo is 16:9 and this box is wider than that at any normal desktop
     window, so cover scales to the width and takes the difference off the top and
     bottom — room and table, never the frame. It only starts cropping the sides
     on a window taller than it is wide, which is not a shape this page is for. */
  body { overflow-x: clip; }
  .hero { display: grid; grid-template-columns: minmax(0, 6fr) minmax(0, 5fr); grid-template-rows: none;
    align-items: center; gap: clamp(24px, 5vw, 80px);
    margin-inline: calc(50% - 50vw);
    padding-inline: max(var(--edge), calc((100vw - var(--wrap)) / 2 + var(--edge)));
    min-height: calc(100svh - var(--nav-h) - var(--wp-admin--admin-bar--height, 0px));
    /* The copy is centred, then lifted: the extra bottom padding is dead weight
       under an `align-items: center` row, so half of whatever is added here is how
       far the block rises. Geometric centre is not optical centre — the eye reads
       a block sitting exactly halfway down a full-screen band as slightly low,
       because it weights the bottom edge — so the block is set to about 41/59 of
       the free space instead of 50/50. That is the symmetry being kept: it is
       measured against how the band reads, not against the pixel midpoint.
       The lift is a share of the window (~3.5svh, so it stays in the same
       proportion as the band grows) rather than a fixed number of leading units,
       and is capped at 4u so it stops growing on very tall screens where a share
       of the height would run away from the type. */
    padding-top: calc(2 * var(--leading));
    padding-bottom: calc(2.5 * var(--leading) + min(7svh, 4 * var(--leading))); }
  /* Stays absolute and pinned to the hero's padding box, which is now the whole
     window. No overscale here — the landscape frame is composed for this crop. */
  .hero-figure { inset: 0; }
  .hero-figure img { height: 100%; object-position: 50% 50%; }
  /* The mobile scrim darkens the top band because the copy sits above the photo;
     here the copy sits beside it, so the same warm accent-900 wash runs left to
     right instead. The photo is shot for this: the frame occupies the right
     ~third and the left is open room, so the gradient has the whole left half to
     spend and reaches zero at 62%, clear of the frame's lit face.
     Same curve as the mobile scrim and the same reason — a plateau to 26%, then a
     smoothstep (3u²-2u³) to nothing. Percentages are right here, unlike the
     vertical fade: what this has to clear is the copy column, and that column is
     a fraction of the width at every size. Recompute the whole ramp if you move a
     stop; a value out of line is what puts a visible edge back.
     74% is the peak because of the sub, not the headline. Measured against the
     brightest pixel that falls under the copy at 1440, neutral-100 at 84% over
     this scrim reads 4.59:1 — clear of AA for 21px body text. 70% drops it to
     3.93 and fails; 82% was the first pass and buys only 0.2 more while
     flattening the room the photo is there to show. */
  .hero::before {
    inset: 0;
    background: linear-gradient(to right,
      color-mix(in srgb, var(--color-accent-900) 74%, transparent) 0,
      color-mix(in srgb, var(--color-accent-900) 74%, transparent) 26%,
      color-mix(in srgb, var(--color-accent-900) 72%, transparent) 29.8%,
      color-mix(in srgb, var(--color-accent-900) 66%, transparent) 33.6%,
      color-mix(in srgb, var(--color-accent-900) 58%, transparent) 37.4%,
      color-mix(in srgb, var(--color-accent-900) 48%, transparent) 41.2%,
      color-mix(in srgb, var(--color-accent-900) 37%, transparent) 45%,
      color-mix(in srgb, var(--color-accent-900) 26%, transparent) 48.8%,
      color-mix(in srgb, var(--color-accent-900) 16%, transparent) 52.6%,
      color-mix(in srgb, var(--color-accent-900) 8%, transparent) 56.4%,
      color-mix(in srgb, var(--color-accent-900) 2%, transparent) 60.2%,
      transparent 64%);
  }
  /* The copy keeps the mobile hero's light-on-dark treatment — including the
     CTA's accent-900 wash — because on desktop it is now sitting on the same
     scrim it sits on there. Sizes change below, and so does the CTA's stroke:
     see the .btn-primary block at the end of this query. */
  .display { font-size: clamp(42px, 7.4vw, 84px); }
  /* Was 17px, then 21px — the desktop hero was the one place the sub read smaller
     than it does on a phone, under an 84px headline. 24px at the client's request:
     the copy column is wide enough at this measure to carry it without the line
     count changing, and it holds its own against the display size beside it.
     Leading grows with it — 34px keeps the same ~1.42 ratio the 21px setting had,
     expressed off the 28px unit like every other vertical value on the page. */
  .hero .sub { font-size: 24px; line-height: calc(var(--leading) + 6px); }
  /* Desktop only, at the client's request: the sub drops the 84% mix the mobile
     hero uses and takes the display's full neutral-100, so headline and
     description read in one voice at this size. */
  .hero .sub { color: var(--color-neutral-100); }
  /* Desktop has the column height to breathe, so the hero's three beats are set
     wider apart than the mobile stack allows. The gap is carried entirely on each
     following element's margin-top, in leading units less a cap — the page's
     convention — so the .display's own bottom margin is cleared rather than left
     to collapse against the sub and decide the spacing by whichever is larger. */
  .hero .display { margin-bottom: 0; }
  .hero .sub { margin-top: calc(2.5 * var(--leading) - 1cap); }
  .hero .row { margin-top: calc(2 * var(--leading)); }
  /* A step above the maker/close section CTAs (18px / 48px) rather than a step
     below the 14px control size — the hero button sits alone beside a 84px
     headline, and at the control size it read as a caption to it. */
  .hero .row .btn { font-size: 21px; font-weight: var(--font-heading-weight); letter-spacing: 0.03em;
    min-height: 62px; padding: var(--space-3) calc(var(--space-4) * 2.4); box-sizing: border-box; }
  /* Desktop only, at the client's request: the CTA reads bolder and warmer than
     the phone's. Three moves, all inside the system — no fill.
     Colour: the stroke and label step off accent-200 (a cream that is barely a
     colour at all against the scrim) onto accent-300, the first genuinely gold
     stop on the ramp. Same hue the wordmark and the section rules use, so it
     joins the page's accent family instead of introducing a new one.
     Weight: 700 rather than the system's 600 interface cut. The bold is retired
     everywhere else on the page — it is spent here, on the one control the whole
     screen is pointed at, and only where the button is 21px beside an 84px
     headline. Do not carry it to the other CTAs.
     Ground: the accent-900 wash goes 38% -> 58%. Still scrim, not the button's
     own colour — it is the same wash the hero gradient is built from, deepened
     so the gold has something dark to sit on wherever the photo is brightest.
     A hairline of accent-400 just outside the border doubles the stroke into a
     rule-and-shadow pair, the way the plate mats read, without thickening it
     into a slab. */
  .hero .row .btn-primary {
    color: var(--color-accent-300); border-color: var(--color-accent-300);
    border-width: 3px;
    background: color-mix(in srgb, var(--color-accent-900) 58%, transparent);
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-accent-400) 55%, transparent);
    font-weight: 700;
  }
  .hero .row .btn-primary:hover { background: color-mix(in srgb, var(--color-accent-300) 20%, color-mix(in srgb, var(--color-accent-900) 58%, transparent)); }
  .hero .row .btn-primary:active { background: color-mix(in srgb, var(--color-accent-300) 30%, color-mix(in srgb, var(--color-accent-900) 58%, transparent)); }
  /* Centred on the copy column — the same centred single-button row the maker and
     close sections use. Mobile keeps it left, ranged with the headline. */
  .hero .row { justify-content: center; }
}

/* — quote rotator — */
.quotes { padding: calc(2 * var(--leading)) 0; text-align: center; }
/* Swipeable: one slide per view, snapped. Native scrolling carries the gesture,
   so there is momentum and drag-follow on touch and a keyboard-scrollable region. */
.quotes .stage {
  position: relative; min-height: calc(9 * var(--leading));
  display: grid; grid-auto-flow: column; grid-auto-columns: 100%;
  align-items: center;
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x mandatory; overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.quotes .stage::-webkit-scrollbar { display: none; }
.quotes .stage:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 6px; }
.q-item { scroll-snap-align: center; scroll-snap-stop: always; min-width: 0; margin: 0; }
/* Portrait dissolves into the page — a circular mask with a long tail, so there is
   no edge, just ink thinning out. The paper is already transparent in the asset. */
.q-portrait {
  display: block; margin: 0 auto calc(0.75 * var(--leading));
  width: clamp(132px, 44vw, 208px); height: auto; aspect-ratio: 1;
  -webkit-mask-image: radial-gradient(circle at 50% 48%,
    #000 34%, rgba(0,0,0,0.88) 50%, rgba(0,0,0,0.5) 66%, rgba(0,0,0,0.16) 79%, transparent 90%);
  mask-image: radial-gradient(circle at 50% 48%,
    #000 34%, rgba(0,0,0,0.88) 50%, rgba(0,0,0,0.5) 66%, rgba(0,0,0,0.16) 79%, transparent 90%);
}
.q-item blockquote {
  font-family: var(--font-heading); font-weight: 400;
  font-size: clamp(27px, 5.4vw, 44px); line-height: 1.28;
  letter-spacing: -0.005em; margin: 0 auto; max-width: 22ch;
}
.q-item figcaption { font-size: 14px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--color-accent-700); margin-top: var(--leading); }

/* Open laurel wreath closing the section under the attributions. It sits outside
   the stage, so it holds still while the quotes swipe past above it. Stroke only,
   in accent gold and held back from full strength, so it reads as an ornament and
   never outweighs the name above it. */
.q-laurel {
  display: block; margin: 0 auto calc(0.75 * var(--leading));
  width: clamp(76px, 21vw, 98px); height: auto;
  color: var(--color-accent); opacity: 0.7;
}

/* Sits where the dots were. Light — 300 weight and muted ink — so it reads as a
   footnote to the quote above rather than a second thing competing with it. */
.q-more { margin: calc(1.5 * var(--leading)) auto 0; max-width: 32ch; }
.q-more-label {
  display: block; font-size: 13px; line-height: var(--half); letter-spacing: 0.06em;
  color: color-mix(in srgb, var(--color-text) 48%, transparent);
}
.q-more-names {
  display: block; margin-top: calc(var(--leading) - var(--half));
  font-family: var(--font-heading); font-weight: 300;
  font-size: 20px; line-height: var(--leading); letter-spacing: 0.01em;
  color: color-mix(in srgb, var(--color-text) 66%, transparent);
  margin-bottom: 1rem;
}

/* — product / buy — */
/* Deliberately more than one screen. Unlike the hero, this section does not share
   the viewport with the nav: it takes 98svh below the 10svh nav, so the pair runs
   past the fold. The overhang is measured, not loose — this is the largest value
   that still lands the whole card, Buy Now included, above the fold at the
   390x844 reference; what spills is the section's own bottom padding, which is
   exactly the "there is more here" cue we want. Going further starts cutting the
   button.
   Two rows now, not three: the third was the display carousel's hairline bars, and
   with one product there is no carousel (see .display-card). The card is the
   flexible row's only child.
   Everything in the buy panel is a fixed cost (a price, a paragraph, three
   swatches, a button); the photograph is the one elastic element, so it takes the
   1fr row and gets whatever is left. On a tall phone it is large, on a short one
   it gives ground first. 640px is the floor, for landscape phones that can't show
   this card whatever we do. */
.product {
  height: 98svh; min-height: 640px; box-sizing: border-box;
  padding: var(--leading) 0;
  display: grid; grid-template-rows: auto minmax(0, 1fr); gap: var(--half);
  /* land the section under the sticky nav when jumped to from #product */
  scroll-margin-top: 10svh;
}
.product-head { margin-bottom: 0; }
/* Nothing to override: the title is .section-title like every other one. The old
   rule here re-set it a size up and cancelled a trailing letter-space, both of
   which existed only because this section's title was a kicker set larger than
   the rest. */

/* — product card — */
/* There was a scroll-snap rail here: two display variants side by side, chosen by
   swiping, the card held --peek narrower than the text column so its neighbour
   always showed past the right edge as the affordance. The clock edition is gone,
   so the rail, the peek, the snapping and the overflow container are gone with it —
   a carousel of one is a control that does nothing.
   What is left is a single card sitting straight on the text column, at its full
   width, as the .product grid's flexible row. Nothing here scrolls sideways, so
   nothing needs a snap target, a scrollbar to hide or a min-width of 0. */
/* No stroke around it either, as of 2026-07-30 at the client's request. It used to
   carry the same hairline the FAQ and specs tables use, which made sense while a
   second card sat beside it on the rail — the rule was what said "one of these" —
   but a card of one has nothing to be told apart from, and the ring read as a box
   drawn around the whole section. Ungirded, the photograph and the buy panel sit
   straight on the page like every other section's content.
   The side padding went with it: it existed to hold the content off that rule, and
   without one it was an invisible 12px indent that left the Buy Now button
   narrower than the same button in the closing CTA. Vertical padding stays — it is
   the section's rhythm, not the frame's inset.
   The desktop pass had already dropped both (see the 880 block at the foot of this
   file, which now restates a border that no longer exists); this is mobile catching
   up, so the card is unframed at every width. */
/* Photo row flexes, buy row is its own natural height. */
.display-card {
  min-height: 0; /* a grid item defaults to min-content; without this the 1fr row can't shrink */
  padding: var(--space-4) 0;
  display: grid; grid-template-rows: minmax(0, 1fr) auto; gap: 0;
}
/* Name over price, not name beside price: the price is the name's subtitle, so
   it reads as one block rather than as two competing figures on a rule. It pays
   ~26px of card height, which comes out of the photograph's 1fr row. */
/* The gaps either side of the name are wider than the type alone would ask for:
   text-box trims the ascender and descender slack away, so these numbers are
   the ink-to-ink distance, and the name is now tracked out to the wordmark's
   0.286em — a letter-spaced line needs air around it or the tracking reads as
   the line falling apart rather than as the brand. Both come out of the
   photograph's 1fr row. */
.card-head { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-1); margin-top: var(--space-6); }
.display-name {
  font-family: var(--font-heading); font-weight: 400;
  font-size: 30px; line-height: 1.15; letter-spacing: -0.005em;
  margin: 0; text-box: trim-both cap alphabetic;
  margin-bottom: var(--space-2);
}
/* The product IS the brand, so the card sets its name the way the nav draws it:
   lowercase Cormorant at the wordmark's own 0.286em tracking, struck in the
   accent. Only the letters come across — the guillemet mark stays the nav's.
   Tracking is added after the last glyph as well as between, so the negative
   right margin takes that trailing space back off; without it the word's inked
   width and its box disagree by a whole letter-space and it sits left of where
   it looks like it should. It used to matter twice over, because the name on the
   second card was "mindrise Clock" and the trailing space read as two; that card
   is gone and the name is the brand on its own. */
.display-name .wordmark {
  text-transform: lowercase;
  letter-spacing: 0.286em; margin-right: -0.286em;
  color: var(--color-accent);
}

/* The accent now belongs to the name above it — the brand is the only thing on
   this card set in gold. So the price goes back into ink: a figure stated
   plainly rather than a second gold line competing with the wordmark for the
   same colour. Being in ink is also what lets it sit this close to the name's
   size without fighting it — colour, not scale, is what separates them now. */
.display-card .price { font-size: 28px; color: var(--color-text); }

/* An explicit track each rather than a free-flowing row, so the three finishes
   come out the same width and read as one control. Written when the card was
   --peek narrower than the text column and the three no longer fit on a row; the
   card is full-width now and they would, but equal tracks are the better setting
   regardless. The 74px floor keeps all three on one line down to a 360px phone
   (the widest label, "Walnut", needs ~72px with this chip and padding); below
   that auto-fit drops to two and wraps rather than crushing them. */
.display-card .swatches { display: grid; grid-template-columns: repeat(auto-fit, minmax(74px, 1fr)); gap: var(--space-2); }
.display-card .swatch { justify-content: center; gap: 7px; padding: 11px 6px; font-size: 14.5px; min-height: 46px; }
.display-card .swatch .chip { width: 16px; height: 16px; flex: none; }

/* Short phones (an SE is 667): the buy panel is a fixed cost and the photo pays
   for it, so on these the copy tightens a step and hands ~55px back to the
   photograph. Everything here is spacing and type scale — nothing is dropped,
   and the tap targets are untouched. */
@media (max-height: 720px) {
  .display-card .card-head { margin-top: var(--space-2); }
  .display-card .display-name { font-size: 26px; }
  .display-card .price { font-size: 24px; }
  .display-card .lede { font-size: 15.5px; line-height: 23px; margin-top: var(--space-2); }
  .display-card fieldset.opt { margin-top: var(--space-3); }
  .display-card fieldset.opt legend { margin-bottom: var(--space-1); }
  .display-card .cta-row { margin-top: var(--space-3); }
  /* Still clear of the button's outer rule, just by less — the photo is paying for
     this line too and on an SE it is already the tightest thing on the card. */
  .display-card .pay-note { margin-top: var(--space-2); }
}

/* Hairline bars rather than dots: the page's other indicators are rules, and a
   filled dot would be the one solid shape in a system built on stroke.
   These belonged to two carousels. The display rail's set (.display-bars /
   .display-bar) went with the clock edition — one card has nothing to index — so
   what is left is the quote rotator's, and it only ever appears on desktop, where
   there is no swipe to make the gesture obvious (see the desktop pass at the foot
   of this file). */
.q-bars { display: flex; align-items: center; justify-content: center; gap: var(--space-3);
  height: 2px; margin-top: var(--space-2); }
.q-bar {
  appearance: none; border: 0; padding: 0; cursor: pointer;
  width: 34px; height: 2px; background: var(--color-divider);
  /* the bar is 2px; the tap target is not */
  position: relative;
}
.q-bar::after { content: ""; position: absolute; inset: -21px -6px; }
.q-bar.on { background: var(--color-accent); }
.q-bar:hover { background: var(--color-accent-400); }
.q-bar:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 6px; }
/* Mobile swipes the quotes, so it has no need of them and never shows them. */
.q-bars { display: none; }

/* Mobile is the designed layout (see CLAUDE.md); this is only enough to keep the
   card from running the full width of a wide screen as one tall column. */
@media (min-width: 880px) {
  /* the one-viewport fit is composed for the stacked mobile card; a wide screen
     gets its own pass later, so let the section size to its content there */
  .product { height: auto; min-height: 0; padding: calc(2.5 * var(--leading)) 0 calc(3 * var(--leading)); gap: calc(1.5 * var(--leading)); }
  .display-card { grid-template-columns: minmax(0, 6fr) minmax(0, 5fr); column-gap: clamp(24px, 4vw, 56px); padding: var(--space-6); }
  .display-card .card-head { margin-top: 0; }
}
.product-head h2 { font-family: var(--font-heading); font-weight: 400; font-size: clamp(33px, 4vw, 42px); line-height: 1.15; margin: 0; text-box: trim-both cap alphabetic; }
/* Shadow lives in the figure's own filter chain, not on the img — same nested-filter
   trap as the hero, and here it bites harder: the photos are cut to 950x849 and the
   box carries that exact aspect-ratio, so the frame reaches the box edge with no slack.
   Kept shorter than the hero's (~25px reach) to sit inside the 42px gap above the lede.
   Generated from the composite, so it fades in step with the finish swap. */
/* The picture's box, holding the rail, the dots under it, and the arrows in the
   rail's own cell. Two rows: the photograph flexes, the dots are their own natural
   height, so the whole indicator costs the picture ~17px and nothing else on the
   card moves for it. */
.product-media {
  min-height: 0;
  display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto;
}
.product-figure {
  grid-area: 1 / 1;
  margin: 0; display: grid;
  /* Fills the card's flexible row rather than deriving its height from the image:
     one track pinned to the figure's own (definite) height, so the rail — and the
     stacked photos inside it — can resolve height:100% against it. */
  min-height: 0; grid-template-rows: minmax(0, 1fr);
  --product-shadow:
    drop-shadow(0 6px 5px color-mix(in srgb, var(--color-accent-900) 24%, transparent))
    drop-shadow(0 14px 11px color-mix(in srgb, var(--color-accent-900) 16%, transparent));
}
.product-figure.plate { filter: var(--plate-grade) var(--product-shadow); }

/* Three views of the object, one per slide, snapped — the quote rotator's rail
   (see .quotes .stage) for the same reason: native scrolling carries the gesture,
   so a phone gets momentum, drag-follow and rubber-banding without a line of JS,
   and the region is keyboard-scrollable.
   The overflow clip is the one thing to watch, because the frame photos cast a
   shadow. It survives: the drop-shadow is drawn from the *composited* figure, after
   the clip, so it still reaches outside the card exactly as it did when the front
   was the only photograph. What the clip does cost is mid-gesture — a neighbouring
   frame arriving at the rail's edge is cut off square there, and for the length of
   the swipe that straight cut carries a shadow of its own. That is the price of not
   letting the other two views sit visible across the card at rest. */
.product-views {
  grid-area: 1 / 1; min-height: 0;
  display: grid; grid-auto-flow: column; grid-auto-columns: 100%;
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x mandatory; overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.product-views::-webkit-scrollbar { display: none; }
.product-views:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 6px; }
/* One slide. It carries a definite row of its own so the three stacked finishes can
   resolve height:100% against it, which is what the figure used to give them
   directly. min-width so a slide can't be widened by its own contents. */
.product-view {
  scroll-snap-align: center; scroll-snap-stop: always;
  min-width: 0; min-height: 0;
  display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr);
}
/* Finishes are stacked in one cell and fade in sequence — out, then in. A true
   cross-dissolve would ghost, since the frames differ slightly in proportion and
   both silhouettes would show at once against the page. The fade is per view: all
   nine photos are toggled together, so a finish change never moves the rail and you
   stay on the view you were looking at. */
/* Sized by the grid, not by the file: the row is definite, so object-fit letterboxes
   the frame inside it and no aspect-ratio is needed to hold the space. All nine are
   cut to the same 950x849 canvas, so front, side and back read at one scale. */
.finish-photo {
  grid-area: 1 / 1; width: 100%; height: 100%;
  object-fit: contain;
  opacity: 0; visibility: hidden;
  transition: opacity 160ms ease, visibility 0s linear 160ms;
}
.finish-photo.on {
  opacity: 1; visibility: visible;
  transition: opacity 200ms ease 160ms, visibility 0s;
}
@media (prefers-reduced-motion: reduce) {
  .finish-photo, .finish-photo.on { transition: none; }
}

/* Dots, at the client's request — the page's other indicator is the quote rotator's
   hairline bars, and the rule of the system is that colour arrives as stroke. So a
   view you are not on is an accent hairline ring and the one you are on is that same
   ring inked in: three small marks rather than three filled spots.
   8px reads as punctuation under a photograph and is far too small to press, so the
   ::after carries the target — 44px tall and reaching half the gap either side, which
   makes the three of them one continuous, comfortably tappable strip at 390px. */
/* The gap clears the frame's shadow rather than sitting in it. --product-shadow
   reaches ~25px below the silhouette, and on a phone the picture is height-limited —
   the frame's bottom edge *is* the figure's bottom edge — so at a half-leading the
   dots landed inside the blur and read as smudged. --space-6 is the first step past
   its reach, so they sit on clean paper.
   It costs the fold nothing: the dots are the card's second row and the photograph is
   the flexible one, so this comes out of the picture's height (~18px) and everything
   below — the name, the swatches, Buy Now — stays exactly where it was. */
.view-dots { display: flex; align-items: center; justify-content: center; gap: var(--space-3); margin-top: var(--space-6); }
.view-dot {
  appearance: none; padding: 0; cursor: pointer;
  width: 8px; height: 8px; border-radius: 50%;
  background: transparent; border: 1px solid var(--color-accent-400);
  position: relative;
}
.view-dot::after { content: ""; position: absolute; inset: -18px calc(var(--space-3) / -2); }
.view-dot.on { background: var(--color-accent); border-color: var(--color-accent); }
.view-dot:hover { border-color: var(--color-accent); }
.view-dot:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 6px; }

/* Arrows for a pointer, which has no swipe. Asked as a pointer question rather than
   as a width one — a touch laptop keeps the gesture and loses the arrows, which is
   right, and mobile-only work stays mobile-only (see CLAUDE.md).
   No absolute positioning: they share the photograph's grid cell, centered on it and
   ranged hard left and right, and the frame is letterboxed inside that cell — so
   they sit in the air beside the picture rather than on top of it. Outlined, never
   filled, like every other control on the page; a translucent page-coloured ground
   only so a chevron that does land on wood stays legible.
   Disabled at the ends rather than wrapping: there are three photographs of one
   object, not a loop, and the dots are the way to jump. */
/* Above the photograph, and it has to be said out loud: .product-figure carries a
   filter, which makes it paint as though it had z-index 0 — later in the order than a
   static sibling, however far down the markup that sibling sits. Without this the half
   of each arrow that overlaps the frame is painted over by the picture and simply
   disappears, leaving a chevron sliced down the middle at the wood's edge. */
.view-arrow {
  grid-area: 1 / 1; align-self: center;
  position: relative; z-index: 1;
  display: none;
  appearance: none; cursor: pointer; padding: 0;
  width: 40px; height: 40px;
  border: 1px solid var(--color-accent-400); border-radius: 50%;
  background: color-mix(in srgb, var(--color-bg) 86%, transparent);
  color: var(--color-accent-700);
}
.view-arrow.prev { justify-self: start; }
.view-arrow.next { justify-self: end; }
.view-arrow svg { display: block; width: 20px; height: 20px; margin: 0 auto; }
.view-arrow:hover { border-color: var(--color-accent); color: var(--color-accent); }
.view-arrow:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 3px; }
.view-arrow[disabled] { opacity: 0.28; cursor: default; }
@media (hover: hover) and (pointer: fine) {
  .view-arrow { display: block; }
}
/* Spacing inside the card is a half-leading rhythm, not the page's full one — the
   card has a viewport to live in and the photo is spending what the copy saves. */
/* The one thing in the card that is NOT scaled up with the rest. At this measure
   15.5px sets in five lines and 16.5px in six, and that sixth line costs the
   photograph ~37px — more than the whole 6svh the section gained. The names, the
   price and the button carry the size; the supporting paragraph pays for the
   picture. Only the leading is opened up. */
.buy .lede { font-size: 15.5px; line-height: calc(var(--leading) - 2px); color: color-mix(in srgb, var(--color-text) 78%, transparent); margin: var(--half) 0 0; }
.price { font-family: var(--font-heading); font-size: 37px; line-height: 1.15; font-feature-settings: "tnum" 1; }
fieldset.opt { border: 0; padding: 0; margin: var(--space-4) 0 0; }
fieldset.opt legend { font-size: 13.5px; letter-spacing: 0.08em; text-transform: uppercase; color: color-mix(in srgb, var(--color-text) 70%, transparent); padding: 0; margin-bottom: var(--space-2); }
.swatches { display: flex; gap: var(--space-3); flex-wrap: wrap; }
.swatch { display: flex; align-items: center; gap: 10px; border: 1px solid var(--color-divider); border-radius: var(--radius-sm, 4px); padding: 10px 14px; cursor: pointer; min-height: 44px; box-sizing: border-box; font-size: 14.5px; }
.swatch input { position: absolute; opacity: 0; pointer-events: none; }
.swatch .chip { width: 18px; height: 18px; border-radius: 50%; border: 1px solid color-mix(in srgb, var(--color-text) 25%, transparent); }
.swatch:hover { border-color: var(--color-accent); }
.swatch:has(input:checked) { border-color: var(--color-accent); box-shadow: inset 0 0 0 1px var(--color-accent); }
.swatch:has(input:focus-visible) { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.buy .cta-row { display: grid; gap: var(--space-2); margin-top: var(--space-6); }
.buy .cta-row .btn { min-height: 52px; font-size: 17px; }
/* The card is a stack of outlined boxes — three swatches and then this — so at the
   shared hairline weight the one thing to press read as the fourth box in the row.
   It gets a double rule instead: the outer line is a spread shadow with a page-colored
   gap, so the button keeps its own 1px border as the inner rule and the hover tint
   still fills the box cleanly (an inset ring would have been painted over by it).
   Size, a darker gold and the extra clear room above do the rest. Still stroke only —
   nothing here is filled.
   The height and the ring's 3px reach are the whole budget: the button's bottom edge
   sits just above the fold at the 390x844 reference — measured at 834 in an 844
   viewport, so the outer rule lands at 837 with ~7px to spare — and this is 56 + 3
   rather than something rounder because that room is all there is. The extra space
   above is free by comparison: it comes out of the photo's 1fr row, not the button's
   position (see the .product note). Retiring the clock edition spent ~14px of the
   margin here, since the card grew into the row the carousel's bars were using. */
.buy .cta-row .btn-primary {
  min-height: 56px; font-size: 20px; letter-spacing: 0.012em;
  color: var(--color-accent-700); border-color: var(--color-accent-600);
  box-shadow: 0 0 0 2px var(--color-bg), 0 0 0 3px var(--color-accent-600);
}
/* clears the outer rule instead of landing on it */
.buy .cta-row .btn-primary:focus-visible { outline-offset: 6px; }
/* Centered under the button and set at the footer's own trust size, in muted ink
   rather than the accent: it is a footnote to the press, not a second thing to
   look at. The padlock is the footer's icon shrunk to sit on the x-height of the
   line beside it. ~22px of card height, paid out of the photograph's 1fr row. */
.buy .pay-note {
  display: flex; align-items: center; justify-content: center; gap: var(--space-2);
  /* --space-3 rather than --space-2: the button's outer rule stands 3px clear of
     its box, so the margin is measured from a line that isn't the one you see and
     a half-step here lands the note ~6px under the gold. */
  font-size: 13px; line-height: 1.25; margin: var(--space-3) 0 0;
  color: color-mix(in srgb, var(--color-text) 65%, transparent);
}
.buy .pay-note .trust-icon { width: 14px; height: 14px; }
.buy .cart-error { font-size: 13.5px; color: var(--color-accent-800); margin: var(--half) 0 0; }

/* — reviews — */
/* Centered stack under the buy card, on the page's own axis. Separated by the
   same hairline the FAQ uses rather than boxed into cards: four short reviews
   read as one column of testimony, and four outlined boxes would compete with
   the buy card directly above them. */
.reviews { padding: calc(1.25 * var(--leading)) 0; text-align: center; }
.reviews .section-title { margin-bottom: calc(0.75 * var(--leading)); }
.review-list { list-style: none; margin: 0; padding: 0; }
.review-list > li + li { border-top: 1px solid var(--color-divider); }
/* The padding is the rhythm *between* reviews — it belongs to the hairlines, and
   is paid twice over every rule. At the two ends there is no rule to hold off, so
   it only doubles up with the section's own padding; the section carries the outer
   space alone. */
.review { display: flex; flex-direction: column; align-items: center;
  padding: var(--leading) 0; }
.review-list > li:first-child .review { padding-top: 0; }
.review-list > li:last-child .review { padding-bottom: 0; }
/* 88px sets each star at ~15px — the size of the micro-type it sits above, so the
   row reads as a mark rather than as a headline. See the star note in the template
   for why these are filled where every other icon on the page is stroked. */
.stars { display: block; width: 88px; height: auto; color: var(--color-accent); fill: currentColor; }
/* Body face, not the display serif: the quote rotator upstairs is already set in
   Cormorant at 27px+, and matching it here would put a customer's line at the same
   weight as Seneca's. Lora keeps these as what they are — plain spoken, and the
   only justified-off, centered body text besides the virtues. */
.review blockquote { margin: calc(0.5 * var(--leading)) 0 0; font-size: 16.5px;
  line-height: var(--leading); max-width: 34ch;
  color: color-mix(in srgb, var(--color-text) 82%, transparent); }
/* Overrides classical.css's figcaption defaults — this one is a portrait and a
   name, not a caption under a plate. */
.review-by { display: flex; flex-direction: column; align-items: center;
  margin-top: calc(0.65 * var(--leading)); font-size: inherit; color: inherit; }
/* Graded like every other photograph on the page, so a real portrait dropped in
   here lands in the same sepia as the product shots. Hairline ring, no fill. */
.review-photo { width: 72px; height: 72px; border-radius: 50%; object-fit: cover;
  border: 1px solid var(--color-divider); filter: var(--plate-grade); }
/* Same attribution micro-type as the quote rotator's figcaption. */
.review-name { display: block; margin-top: calc(0.4 * var(--leading));
  font-size: 14px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--color-accent-700); }
/* The virtues open with 3 leadings of clear room, sized for the buy card that used
   to sit above them. Stacked straight under the reviews, that space reads as a break
   in the page, so the pair closes up. Scoped to the adjacency, leaving the section's
   own padding untouched wherever else it lands. */
.reviews + .features { padding-top: calc(1.75 * var(--leading)); }

/* — story — */
/* The section runs on the page color like every other one — no band of its own.
   The clip's wall and the page meet at a hard edge, by request: the video reads
   as a plain rectangle sitting on the page. */
.story { padding: calc(1.5 * var(--leading)) 0; position: relative; }
/* Centered, unlike the justified body copy elsewhere: it is a two-line display
   heading standing alone over a full-width rectangle, so it centers on the video's
   axis rather than hanging off the left edge. margin-inline keeps the measure
   centered too, for the widths where 62ch is narrower than the wrap. */
.story .body { max-width: 62ch; margin-inline: auto; text-align: center; }

/* Rectangular footage, not a cut-out, so it takes the .plate grade but none of the
   drop-shadow the frame photos use — a shadow under a hard video edge would read as
   a floating card, and the point here is that there is no card. aspect-ratio matches
   the encode (1280×720) so the box reserves its height before metadata arrives.
   The clip's edges meet the page directly: it plays as a plain rectangle, no feather.

   Unframed, at the client's request (2026-07-30) — same call as the product card.
   There was a 1px gold hairline drawn around the footage; without it the clip meets
   the page on all four sides the way the photographs do. Don't put the stroke back. */
.story-figure { margin: calc(1.5 * var(--leading)) 0 0; width: 100%; }
/* Overrides .plate from classical.css; the grade is restated on .story-video below,
   so the figure never grades a child of its own. */
.story-figure.plate { filter: none; }
.story-video {
  display: block; width: 100%; height: auto; aspect-ratio: 16 / 9;
  filter: var(--plate-grade);
  background: var(--maker-wall); /* inside the grade, so it lands on --maker-bg */
}
/* Same centred single-button row as .close, on the story's own rhythm: a full
   leading below the figure so the button clears the plate's border rather than
   sitting against it. */
.story-cta { display: flex; justify-content: center; margin-top: var(--leading); }
/* The two standalone CTAs — the maker section's and the closing one — are the
   same thing the buy card's button is: the single thing to press in a section
   that exists to send you to the product. They are given its treatment exactly
   (.buy .cta-row .btn-primary, above): the 20px size, the darker gold, and the
   double rule made of a spread shadow with a page-colored gap, so the button
   keeps its own 1px border as the inner line. Still stroke only — nothing filled.
   Unlike the buy button these are not btn-block, so they size to their label;
   the horizontal padding is what gives them the same presence at their width. */
.story-cta .btn,
.close .row .btn {
  font-size: 20px; letter-spacing: 0.012em; min-height: 56px; box-sizing: border-box;
  /* The closing label is long enough to reach the gutter at this size, so the
     padding gives way before the button does: 8vw at the 390px reference is the
     35px it would otherwise be, and it narrows with the screen instead of
     wrapping a line of Cormorant across two. The max-width is the outer rule's
     own 3px reach on each side — a shadow doesn't take up layout room, so
     without it the ring, not the border, is what lands on the page edge. */
  padding-block: var(--space-3);
  padding-inline: min(8vw, calc(var(--space-4) * 1.9));
  max-width: calc(100% - 8px);
  color: var(--color-accent-700); border-color: var(--color-accent-600);
  box-shadow: 0 0 0 2px var(--color-bg), 0 0 0 3px var(--color-accent-600);
}
/* clears the outer rule instead of landing on it */
.story-cta .btn:focus-visible,
.close .row .btn:focus-visible { outline-offset: 6px; }

/* — features / specs — */
/* Six centered virtues. The body copy here is centered, not justified like the
   rest of the page: each blurb is one or two lines, and justification on a line
   that short opens rivers. Measure is held near 30ch so every one of them breaks
   into two lines at 390px — a lone widow'd word under a 40px icon reads broken. */
.features { padding: calc(3 * var(--leading)) 0 calc(2.5 * var(--leading)); text-align: center; }
.feature-grid { list-style: none; margin: calc(1.75 * var(--leading)) 0 0; padding: 0;
  display: grid; grid-template-columns: 1fr; gap: calc(1.5 * var(--leading)); }
.feature { display: flex; flex-direction: column; align-items: center; }
/* 44px is the floor these drawings survive: below it the lamp's spout and the
   amphora's handles close up and both go to a blot. Client's call: set at 64px,
   so the drawings read as drawings on a phone rather than as marks. The glyphs
   sit well inside the 48 viewBox, so a 44→56 step barely showed; 64 is the first
   size where the ink is visibly larger, and the 1.1 stroke still reads hairline. */
.feature-icon { display: block; width: 64px; height: 64px; color: var(--color-accent); }
.feature h3 { font-family: var(--font-heading); font-weight: 400; font-size: 27px; line-height: var(--leading);
  margin: calc(0.75 * var(--leading) - 1cap) 0 0; text-box: trim-both cap alphabetic; }
.feature p { font-size: 17.5px; line-height: var(--leading); margin: calc(0.75 * var(--leading) - 1cap) 0 0;
  color: color-mix(in srgb, var(--color-text) 78%, transparent); max-width: 30ch; }
@media (min-width: 880px) {
  .feature-grid { grid-template-columns: repeat(3, 1fr); gap: calc(2 * var(--leading)) calc(1.5 * var(--leading)); }
}
.specs { padding: 0 0 calc(2 * var(--leading));
         margin-top:2rem;
        }
/* Three quarters of a leading, the same step the reviews put under their title.
   The old half-leading was measured under a 16px label; under a 34px heading it
   read as the table having been pushed up into it. */
.specs .table { width: 100%; margin-top: calc(0.75 * var(--leading)); }
.specs td:first-child { white-space: nowrap; color: color-mix(in srgb, var(--color-text) 62%, transparent); font-size: 13px; letter-spacing: 0.06em; text-transform: uppercase; }
.specs td { font-feature-settings: "tnum" 1; }
/* .spec-variant lived here: an uppercase micro-label naming which display variant
   a value belonged to, on the Power and Connectivity rows where the two differed.
   With the clock edition retired each row has one answer, so the labels are out of
   the markup and the rules went with them. */

/* — FAQ — */
.faq { padding: calc(2 * var(--leading)) 0; }
.faq .section-title { margin: 0 0 var(--leading); }
.faq details { border-top: 1px solid var(--color-divider); }
.faq details:last-of-type { border-bottom: 1px solid var(--color-divider); }
.faq summary { list-style: none; cursor: pointer; display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-3);
  font-family: var(--font-heading); font-size: 21px; padding: calc(var(--leading) * 0.75) 0; min-height: 44px; box-sizing: border-box; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; color: var(--color-accent); font-size: 22px; flex: none; }
.faq details[open] summary::after { content: "−"; }
.faq summary:hover { color: var(--color-accent-700); }
.faq summary:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.faq details p { font-size: 15.5px; line-height: var(--leading); margin: 0 0 var(--leading); max-width: 62ch;
  color: color-mix(in srgb, var(--color-text) 78%, transparent); }

/* — close + footer — */
/* The section reads as the band between two hairlines — the FAQ's last rule above
   and the contact's border-top below — so it is centred against those, not against
   its own box. The FAQ already lays 2 leadings of its own padding inside the band,
   so the top padding here is the remainder that makes both gaps 91px (3.25
   leadings). Both are constants, so the pair stays even however the line wraps. */
.close { padding: calc(1.25 * var(--leading)) 0 calc(3.25 * var(--leading)); text-align: center; }
/* The 91px above are measured from the ink rather than from the box — that trim
   is .section-title's, so nothing is restated here. */
/* The closing photograph: full measure, no rule, no radius, no shadow — a room on
   the page rather than a card of one. aspect-ratio
   matches the encode (1600×1067) so the box holds its height before the lazy file
   lands, which matters at the very bottom of the page. It carries the leading
   below it so the button keeps its own rhythm off the picture, not off the title. */
.close-figure { margin: var(--leading) 0 0; width: 100%; }
.close-photo {
  display: block; width: 100%; height: auto; aspect-ratio: 1600 / 1067;
  filter: var(--plate-grade);
}
.close .row { display: flex; justify-content: center; margin-top: var(--leading); }
/* — contact — */
/* Last section on the page, opened by the same hairline the FAQ closes with, so
   the two read as one continuous column of rules rather than as a form bolted on
   the end. Left-aligned where the sections above it are centered: this is
   something to fill in, and a centered field set reads as a poster.
   Fields are the system's .field/.input (classical.css) — stroke only, no fills,
   the page's own focus gold. Nothing here is restyled that the system covers;
   what's below is spacing, the 44px touch floor, and the error/status voices. */
.contact { padding: calc(2 * var(--leading)) 0 calc(2.5 * var(--leading));
  border-top: 1px solid var(--color-divider); }
/* Only the step down from the section's border-top; the type is .section-title's. */
.contact-title { margin: calc(0.75 * var(--leading) - 1cap) 0 0; 
                 margin-bottom: 1rem;

}
/* Centred with the title above it. The fields below stay left — they are things
   to fill in, not display type — but a 46ch paragraph left-ranged under a centred
   heading reads as a heading that has slipped off its own column. */
.contact-lede { font-size: 15.5px; line-height: var(--leading);
  margin: calc(0.75 * var(--leading) - 1cap) auto 0; max-width: 46ch;
  text-align: center;
  color: color-mix(in srgb, var(--color-text) 78%, transparent); }
.contact-form { margin-top: var(--leading); max-width: 46ch; }
.contact .field + .field { margin-top: var(--leading); }
/* Same uppercase micro-type the fieldset legends in the buy card use, so a label
   here is recognisably the same kind of thing as "Finish" up there. */
.contact .field > label { font-size: 13.5px; letter-spacing: 0.08em; text-transform: uppercase;
  color: color-mix(in srgb, var(--color-text) 70%, transparent); margin-bottom: var(--space-2); }
.contact .input { min-height: 48px; padding: 11px 12px; font-size: 16px; line-height: var(--leading);
  border-radius: var(--radius-sm); background: transparent; }
/* 16px above is not a style choice: iOS zooms the page in on any field under it,
   and the zoom is not undone when the field is left. */
.contact textarea.input { min-height: calc(5 * var(--leading)); resize: vertical; }
/* Invalid is only ever set by the JS after a press — never :invalid, which would
   paint every empty required field red before anyone has typed a character. */
.contact .input.is-invalid { border-color: var(--color-accent-800); }
.field-error { font-size: 13.5px; line-height: var(--half); color: var(--color-accent-800);
  margin: var(--space-2) 0 0; }
.contact-actions { margin-top: var(--leading); }
/* The page's second-loudest button: the buy card's double rule is the loudest and
   has to stay that way, so this one is the plain outlined control at the buy
   button's size. */
.contact-actions .btn { min-height: 52px; font-size: 17px; margin-top: 0; }
/* Off-screen, not display:none — see the honeypot note in the template. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.form-status { font-size: 15px; line-height: var(--leading); margin: var(--leading) 0 0;
  padding-left: var(--space-3); border-left: 2px solid var(--color-accent); }
.form-status.is-error { border-left-color: var(--color-accent-800); color: var(--color-accent-800); }

/* The rule at the foot of the form. It is the page's last mark before the footer,
   and it stands in for a hairline — so it is held to the laurel's terms rather
   than given its own: stroke in the accent, short of full strength, so it closes
   the column without competing with the Send button a leading above it. Measured
   to the form (46ch), not to the page, because the thing it closes is the form. */
.vine-rule {
  display: block; width: 100%; max-width: 46ch; height: auto;
  margin: calc(1.75 * var(--leading)) auto 0;
  color: var(--color-accent); opacity: 0.72;
}

.arete-footer { padding: calc(2 * var(--leading)) 0; font-size: 13px; line-height: var(--leading);
  color: color-mix(in srgb, var(--color-text) 70%, transparent); text-align: center; }
/* Reassurances above the imprint. Wrapping is left to the flex box, so the row
   collapses to a column when the labels no longer fit side by side. */
.footer-trust { list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: calc(0.5 * var(--leading)) var(--space-4); }
.footer-trust li { display: flex; align-items: center; gap: var(--space-2); }
.trust-icon { display: block; width: 18px; height: 18px; flex: none; color: var(--color-accent); }
.footer-trust a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--color-divider); }
.footer-trust a:hover { color: var(--color-accent-700); border-bottom-color: currentColor; }

/* The imprint. The brand is set here as the *stacked* lockup — wordmark over
   mark — which is the arrangement of the original artwork and the one the nav
   can't fit (see the note on .nav-brand). The proportions are measured off that
   artwork, against the letters rather than the file: its mark stands 1.27x the
   height of the wordmark's letters and sits 0.77 of that height below the rule.
   At a 38px wordmark the letters run 25px (they are 101 of its 153 units), which
   is where 32 and 19 below come from — recompute both if the wordmark changes
   size, or the two stop reading as one drawing. Decorative, both of them: the
   line beneath already names the brand, so neither carries alt text. */
.footer-imprint { margin-top: calc(1.5 * var(--leading)); padding-top: calc(1.5 * var(--leading));
  border-top: 1px solid var(--color-divider);
  display: flex; flex-direction: column; align-items: center; gap: var(--leading); }
.footer-lockup { display: flex; flex-direction: column; align-items: center;
  gap: 19px; line-height: 0; }
.footer-lockup img { display: block; width: auto; }
.footer-wordmark { height: 38px; }
.footer-mark { height: 32px; }
/* tnum so the year sets on the same figures as the prices */
.footer-copy { margin: 0; letter-spacing: 0.04em; font-feature-settings: "tnum" 1; }
a { color: var(--color-accent-700); }
a:hover { color: var(--color-accent); }

/* ===========================================================================
   DESKTOP PASS  (≥880px)
   ---------------------------------------------------------------------------
   Everything above this line is the mobile design, and it is the design: one
   column, with the quote rotator reached by swiping. A pointer has no swipe, and a
   1400px window has room to simply show what a phone has to hide — so on desktop
   the rotator grows the hairline bars the phone does without, and every section
   that ran as a single narrow column re-flows across the width. (The product
   section was the page's second carousel until the clock edition was retired; it
   is one card at every width now.)

   The pass is kept in one block at the foot of the file rather than folded into
   the rules above, so the mobile design can still be read straight through and
   so it wins on source order without specificity games. It comes after the three
   earlier `min-width: 880px` blocks and deliberately overrides parts of them.

   Two shapes recur:
   • Label beside content — the section kicker takes a narrow left column and the
     thing it names takes the rest (specs, FAQ, contact). It is how a spec sheet
     is set, and it turns three sections that used ~40% of the width into ones
     that use all of it.
   • Rows instead of stacks — reviews and virtues become grids.
   =========================================================================== */
@media (min-width: 880px) {

  /* — body copy —
     One step up for every regular paragraph on the page. 15.5px is a phone size:
     it is what the mobile card and the mobile measure were tuned to, and read at
     arm's length on a desktop screen it sets small and thin. 17.5px is the same
     step the headings already take here, and it costs nothing — the paragraphs
     are all capped by their own measure (30ch, 44ch, 46ch, 62ch), so a bigger
     face widens the column rather than lengthening the page.
     The 28px leading carries it unchanged: 17.5/28 is 1.6, which is where Lora
     wants to be. The rest of the micro-type — legends, field labels, the footer —
     is deliberately not in this list: it is a different voice, not small body copy. */
  .buy .lede,
  .feature p,
  .faq details p,
  .contact-lede { font-size: 17.5px; line-height: var(--leading); }
  .review blockquote { font-size: 18px; }
  .form-status { font-size: 16.5px; }

  /* — kickers —
     Client's call: the section labels set too small on a desktop screen. Every
     kicker takes one step up, in the same proportion the body copy takes, so the
     labels keep their relationship to the text they name.
     Nothing on this page is a kicker any more — the rule is left for the 404 and
     the checkout, which load this file and still use one. The landing page's own
     titles take their desktop size from .section-title's clamp instead. */
  .kicker { font-size: 18px; }

  /* — section titles —
     Client's call: on a wide screen every title sits a little too close to the
     thing under it. There is no single rule to raise, because no two sections pay
     that gap the same way — the reviews set it on the title, the virtues on the
     grid below, the contact section on its lede, and the quote rotator sets
     nothing at all. So this adds the half-leading *inside* the heading box:
     padding, not margin, so it stacks on top of whatever each section already
     spends rather than replacing it, and the sections keep their own relative
     spacing. Nothing here is centred on a background or bordered, so padding
     under the type reads as pure space.
     Not on specs or the FAQ — their titles stand in a column *beside* what they
     name from 880 up, so there is no "below" to space; both zero it out where
     they take their grid placement. */
  .section-title { padding-bottom: calc(0.5 * var(--leading)); }

  /* The hero is not in this pass. It already lays out as two columns above 880
     and reads well at every desktop width; the 3rem under the headline was tried
     here as mobile-only spacing and is not — at 84px the display needs it, and
     closing it up crowds the sub against the descenders. Left alone deliberately.

     — quote rotator — */
  /* Stacked exactly as the phone sets it — portrait over quote over name, centred
     on the section's own axis under the laurel and the kicker. An earlier pass put
     the portrait beside the quote to reclaim height; the client asked for the
     mobile shape on both, so the only thing desktop changes is scale: a larger
     head and a larger display size. The measure stays `22ch` from the mobile rule
     and is right there — `ch` on the blockquote resolves against *its* font, the
     display Cormorant, not the 16px Lora the section inherits.
     The rotation is unchanged — it advances on its own, so nothing here has to be
     swiped; the bars below are for anyone who wants to go back to one. */
  .quotes { padding: calc(2 * var(--leading)) 0 calc(2.5 * var(--leading)); }
  /* No stage height here: the slides are columns of one grid row, so the row is
     already the tallest quote and the section cannot jump as the rotator turns.
     The mobile `min-height` stands as the floor it was written to be. */
  .q-portrait { width: clamp(180px, 17vw, 236px); }
  .q-item blockquote { font-size: clamp(29px, 3.1vw, 40px); }
  .q-bars { display: flex; margin-top: calc(1.25 * var(--leading)); }

  /* — product — */
  /* This pass was written around a one-slide-at-a-time rail: --peek to zero, a
     --bleed either side to keep the focus rings clear of the overflow clip, and a
     pair of arrows in the page gutter as the pointer's stand-in for the swipe. All
     of it existed to move between two cards. With the clock edition retired the
     rail, the bleed, the bars and the arrows are gone from every width, and this
     pass keeps only what it was already doing to the card itself. */
  .product { gap: calc(1.25 * var(--leading)); scroll-margin-top: 84px; }
  /* Photo beside the buy panel — the 6fr/5fr split from the earlier 880 block,
     which was written for exactly this: one card holding the whole width. Both
     children sit in the one row, so the picture takes ~490px where two cards on a
     row left it ~400, and the panel sets its paragraph in a column of its own
     instead of under the photograph.
     Client's call: no frame around the card here. On the phone the outline is what
     holds the card together as an object against a full-height section; on a wide
     screen it was drawing a box around the whole width for no work.
     With the frame gone the side padding has nothing left to hold off, and it was
     the one thing keeping the card out of line with the page: every other section
     — the reviews' divider, the specs table, the FAQ rules — starts on the text
     column, and the picture and the Buy Now button were standing 28px inside it.
     So the card runs the full column: the photograph's left edge and the button's
     right edge are the same two lines the rest of the page uses. The block padding
     stays — that is spacing, not alignment. */
  .display-card {
    grid-template-rows: auto;
    border: 0;
    padding: var(--space-6) 0 calc(1.15 * var(--space-6));
  }
  /* The section sizes to its content here rather than to a viewport, so the picture
     has no flexible row to fill — the aspect is what gives it a height, and it is
     the same 950x849 every finish photo is cut to, so swapping finishes cannot make
     the card jump. Nor can swiping to another view: front, side and back are cut to
     that one canvas too, so the aspect on the figure sizes the rail and every slide
     in it. */
  .product-figure { aspect-ratio: 950 / 849; }
  /* The buy panel's spacing is a mobile budget: there the card has to fit one
     viewport with the photograph, so every gap inside it is a half-leading and
     the four elements sit almost on top of each other. Here the section sizes to
     its content and the panel has a column of the card to itself — the room is
     free, so it is re-set on the page's own leading: the paragraph clears the
     name/price block by three quarters of one, the finishes by a full one, and the
     button keeps its own larger floor. Nothing moves except the space between
     things.
     The name is *not* cleared from the top: it is beside the photograph rather than
     under it, so its cap line is set against the top of the picture (the
     margin-top: 0 in the earlier 880 block). */
  /* Client's call: the name, the price and the paragraph all set too small here.
     Those three sizes are a phone budget — on the phone the card shares one viewport
     with the photograph, so the copy is held down to buy the picture its height.
     Beside the photograph there is no such trade: the panel is a column of its own
     with ~180px of slack above the button, and that slack pays for the whole step
     up. The name leads at 36 and the price follows at 33, keeping the ~1.07 ratio
     they already had — they still read as one block, still separated by colour
     rather than by scale, and the name still sets under the section title (42)
     rather than level with it. The gap between them goes 7 → 9 for the same reason:
     it is ink-to-ink under text-box trim, so it has to grow with the type or the
     block closes up.
     The paragraph takes one step past the 17.5px the desktop body pass gives it,
     onto 20/32. At 44ch that is the same two lines it already set in, at the 1.6
     Lora wants. 32 is the one line on the page off the 28px leading unit — 20/28 is
     too tight to read — and it is a leaf paragraph in a flex column, so nothing
     downstream is measured off it. */
  .display-card .display-name { font-size: 36px; margin-bottom: 9px; }
  .display-card .price { font-size: 33px; }
  .display-card .lede {
    max-width: 44ch; margin-top: calc(0.75 * var(--leading));
    font-size: 20px; line-height: 32px;
  }
  .display-card fieldset.opt { margin-top: var(--leading); }
  .display-card fieldset.opt legend { margin-bottom: var(--space-3); }
  .display-card .swatch { padding: 12px 8px; font-size: 15.5px; min-height: 50px; }
  /* The panel is a column beside a picture whose height is fixed by its aspect, so
     it has slack under the finishes — send the whole of it above the button rather
     than distributing it, and Buy Now sits on the foot of the photograph. The
     margin becomes the floor of the gap, not the gap itself. */
  .buy { display: flex; flex-direction: column; }
  .buy .cta-row { margin-top: auto; padding-top: calc(1.25 * var(--leading)); }

  /* — reviews — */
  /* Two columns, halving a stack that ran the better part of two screens. The
     hairline moves with the layout: a vertical rule between the pair, a
     horizontal one between the rows, and none at the four outer edges — the same
     rule the mobile stack follows, read in two dimensions. */
  .reviews { padding: calc(2 * var(--leading)) 0; }
  .review-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .review-list > li + li { border-top: 0; }
  .review-list > li:nth-child(2n) { border-left: 1px solid var(--color-divider); }
  .review-list > li:nth-child(n + 3) { border-top: 1px solid var(--color-divider); }
  .review { padding: var(--leading) clamp(20px, 3vw, 52px); }
  .review-list > li:nth-child(-n + 2) .review { padding-top: 0; }
  .review-list > li:nth-child(n + 3) .review { padding-bottom: 0; }

  /* — virtues — */
  /* Four of them, so the three-column grid above leaves one stranded on a row of
     its own. Two-up from here, and a single row across the width at 1040. */
  .feature-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* — specifications — */
  /* Kicker left, table right: the label names the column beside it instead of
     sitting on top of a table whose values then ran to 40% of the page. */
  .specs {
    display: grid; grid-template-columns: minmax(0, 210px) minmax(0, 1fr);
    column-gap: clamp(32px, 5vw, 72px); align-items: start;
    margin-top: calc(2 * var(--leading)); padding-bottom: calc(2.5 * var(--leading));
  }
  /* Placement only — the title is display type now, not a label, so the 22px
     leading that used to keep a two-line kicker from running into itself is gone
     with it. Whether a 34px+ heading still wants to sit in a 210px column beside
     its table is a desktop question, and desktop is a later pass. */
  .specs .section-title { grid-column: 1; padding-top: var(--space-3); padding-bottom: 0; }
  .specs .table { grid-column: 2; margin-top: 0; font-size: 15px; }
  .specs .table td { padding-block: var(--space-3); }
  .specs td:first-child { width: 26%; }

  /* — FAQ — */
  /* The same label-beside-content shape. Each <details> is pinned to column 2
     rather than the kicker being spanned down column 1: `grid-row: 1 / -1`
     resolves against the *explicit* grid, which has no rows here, so it would
     collapse to a single row. */
  .faq {
    display: grid; grid-template-columns: minmax(0, 210px) minmax(0, 1fr);
    column-gap: clamp(32px, 5vw, 72px); align-items: start;
    padding: calc(2.5 * var(--leading)) 0;
  }
  .faq .section-title { grid-column: 1; grid-row: 1; margin: 0; padding-top: var(--space-3); padding-bottom: 0; }
  .faq details { grid-column: 2; }
  .faq summary { font-size: 23px; }
  .faq details p { max-width: 70ch; }

  /* — contact — */
  /* Client's call: one column. Title, ask, form read top to bottom, the same
     order and the same single axis the phone sets them on — the section no
     longer splits into a copy column and a form column. The form keeps its own
     46ch measure cap from the base rule, which is what holds the fields to a
     sane width now that no grid column is doing it — and the lede keeps the same
     46ch, so copy and fields end on one edge. The two-column layout's narrower
     38ch lede goes with it. */
  /* Client's call: centered on desktop. The column sits on the page's own axis
     like every section above it, rather than hugging the left margin — the base
     rule's left alignment was written for the phone, where a 46ch column and the
     viewport are the same thing and there is no axis to be off. The field set
     itself stays left-aligned inside the centered column: labels and inputs are
     things to read down and fill in, not display type. */
  .contact {
    padding: calc(2.5 * var(--leading)) 0 calc(3 * var(--leading));
    text-align: center;
  }
  .contact-title, .contact-lede { margin-left: auto; margin-right: auto; }
  .contact-form { margin-left: auto; margin-right: auto; text-align: left; }
  /* Opened up on desktop. On the phone the 46ch column *is* the viewport, so a
     single leading between things is already a visible gap; here the same column
     sits in the middle of a wide page with margin either side, and the mobile
     rhythm packs the whole section into one dense block. Every step is one notch
     wider, in leadings so the section still counts in the page's unit:
     copy to field set is 2 (the only gap that separates two kinds of thing, so
     it is the largest), field to field 1.5, and the send button 1.75 — a hair
     more than the fields between them, so it reads as the end of the set rather
     than a fourth row of it. The title-to-lede step goes to a full leading, up
     from three quarters, measured cap to cap like the base rule. */
  .contact-lede { margin-top: calc(1 * var(--leading) - 1cap); }
  .contact-form { margin-top: calc(2 * var(--leading)); }
  .contact .field + .field { margin-top: calc(1.5 * var(--leading)); }
  .contact .field > label { margin-bottom: var(--space-3); }
  .contact-actions { margin-top: calc(1.75 * var(--leading)); }
  /* No override for the send button here on purpose: with one column the form is
     the whole line again, so it keeps the mobile shape — full width of the fields
     it sits under. */

  /* — closing CTA — */
  /* The button's own sizing is unconditional now — it shares the maker section's
     rule, which shares the buy button's (see .story-cta .btn above) — so all this
     width buys is the extra room under it. */
  .close { padding-bottom: calc(3.5 * var(--leading)); }
  /* The closing photograph is capped and centered here. At full measure it would
     be a 1320px band across the end of the page, which is the hero's job; held to
     640 it reads as one object on the page's axis, in scale with the title above
     and the button below rather than swallowing both. Client's call on 2026-07-30
     — desktop only, the phone keeps the full measure, where the wrap and the
     viewport are the same thing and there is nothing to center against. */
  .close-figure { max-width: 640px; margin-left: auto; margin-right: auto; }

  /* — footer — */
  .arete-footer { padding: calc(var(--leading)) 0 calc(2 * var(--leading)); }
}

/* The virtues get a row of their own once four of them fit without crushing the
   30ch measure each blurb is set to. */
@media (min-width: 1040px) {
  .feature-grid { grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: calc(1.5 * var(--leading)) clamp(20px, 2.4vw, 34px); }
}
