/* Kristi Marie Creative — home page sections
   Depends on tokens.css and base.css. Load order is tokens → base → home.

   Nothing here redefines a shared component. Where a section needs its own
   reveal, the rule lives beside the section rather than in base.css, so the
   shared motion file stays readable by pages that never use it. */

/* ---------- masthead ----------
   Copy left, media right. Darrell picked the composition and the 45/55 split
   off compare.html on 2026-08-27; the old masthead stacked a full-width
   headline over a full-bleed 16:9 plate and spent ~1100px before the first
   claim.

   ⚠️ THE SPLIT IS A TOKEN, NOT A HARDCODED FRACTION. It is the one number in
   this composition anyone argues about, so it is named once. 1.1fr/0.9fr is
   55 copy / 45 media — Darrell, 2026-08-27, after seeing it the other way
   round: "retain the 45/55, with 45 of it being the hero and 55 being the
   copy section." The rig offered 55/45, 50/50, 45/55 and 37/63. */

.masthead { padding: 4.5rem 0 0; position: relative; }
.mast-grid {
  display: grid;
  grid-template-columns: var(--mast-cols, 1.1fr 0.9fr);
  gap: 3.5rem;
  align-items: end;   /* see the 1:1 note in the hero slot below */
}
.mast-copy { min-width: 0; }

.masthead h1 {
  /* ⚠️ SIZE, LEADING AND MEASURE LIVE IN emerald.css §3b. This is the d1 step
     of the system's display scale, shared with every other headline on the
     page — a per-section clamp here is exactly how the page came to have
     seven of them, each a little smaller than the step it stood in for.
     Only the space above the headline belongs to the masthead. */
  margin-top: 1.25rem;
}

/* ⚠️ ONE RULE, WHERE THERE USED TO BE TWO. The old masthead carried a 52px
   amber tick above the standfirst AND a full-width ink border under the whole
   section. In a split composition those stack three horizontals inside 200px
   and the eye reads a fence, not a masthead. This is the survivor, and it is
   the page's signature arrival: it draws left to right under the headline.

   The section no longer ends on a line at all — it ends where the media does,
   which is what makes the split read as one object instead of two columns in
   a box. */
.mast-rule {
  height: 1px;
  border: 0;
  margin: 1.6rem 0 1.5rem;
  background: var(--amber);
  transform-origin: left center;
}

.standfirst {
  /* the second voice: small, roman, secondary. It was a display italic with
     an amber tick of its own, which put two display voices in one masthead.
     See emerald.css §3b. */
  margin: 0;
}
.mast-ctas { display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; margin-top: 2rem; }

/* ---------- the hero slot ----------
   ⚠️ THE BOX OWNS THE RATIO. THE MEDIA ONLY FILLS IT.

   A <video> replaces the <picture> in the markup with no change to this file
   at all — which is the entire reason the aspect-ratio is on the figure and
   not on the image. 4:5 is the framing the hero video is being shot to.

   ⚠️ 1:1, CHANGED FROM 4:5 ON 2026-08-27 at Darrell's call. A square is
   shorter than the copy beside it, where the portrait was taller — so the row
   no longer centres, it sits to the copy's baseline. Centring a short media
   column left it floating with air above and below.

   The placeholder photograph is 16:9, so it is cropped and loses the length
   of the table. That is expected and temporary; object-position keeps the
   crop on the settings rather than on the empty wall above them. */
.heromedia {
  margin: 0;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border-radius: var(--radius-lg);
  background: var(--plate);
  position: relative;
}
.heromedia picture,
.heromedia video { display: block; height: 100%; }
.heromedia img,
.heromedia video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 62%;
}

@media (max-width: 900px) {
  .mast-grid { grid-template-columns: 1fr; gap: 2.25rem; }
  .masthead { padding-top: 2.75rem; }
  /* ⚠️ THE SLOT STAYS SQUARE ON ONE COLUMN, AND THAT REVERSES A RULE THAT WAS
     RIGHT FOR A PHOTOGRAPH. This said `aspect-ratio: 4 / 3` and explained
     itself well: a square at 346px is 346px tall, the copy above it is already
     400, and stacked they filled a phone screen and a half before the page's
     first sentence. All of that is still true, and it is no longer the
     deciding argument.

     ⚠️ THE MEDIA IS A COMPOSED FRAME NOW, NOT A CROPPABLE ONE. The hero is a
     1:1 video with type set INSIDE it. `object-fit: cover` in a 4:3 box shows
     only the middle 75% of a square source, and object-position 62% takes
     15.5% of that off the top — measured, on the shipped file, against ink
     that starts at 10.6%. It sliced 53px off "Your designs." and the headline
     came out decapitated on every phone. There is no object-position that
     fixes it: the word is at the top and the caption is at the bottom, so any
     crop of a 4:3 window eats one of them.

     The cost is 83px of extra height at a 375px viewport, and it buys a hero
     that says what it was built to say. If the stacked masthead ever needs
     that height back, shorten the COPY above it — do not re-crop the video. */
  .heromedia { aspect-ratio: 1 / 1; }
}

/* ---------- why we exist ----------
   The claim on the left, the account of it on the right, both bottoming out
   on the same line. align-items:end is the editorial move: the headline is
   the taller voice, so it hangs from the paragraph's last line rather than
   floating at the top of a column twice its height. */

.spread {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: 3.5rem;
  align-items: end;
  margin-top: 1.125rem;
}
.spread h2 { margin: 0; }   /* d2 · emerald.css §3b */
.spread-copy .lede { font-size: 1.0625rem; }
.spread-copy .text-link { display: inline-block; margin-top: 1.25rem; }

@media (max-width: 900px) {
  .spread { grid-template-columns: 1fr; gap: 1.5rem; align-items: start; }
}

/* ---------- the three that back the claim ----------
   ⚠️ THIS REPLACED ~310 LINES, AND ALMOST NONE OF THEM WERE WRONG.

   What stood here was a vertical index: three two-column rows, each carrying
   a title and TWO paragraphs, with a hover bump on the text, a scroll wink on
   arrival, a dimming interaction on the siblings, an always-visible
   disclosure that had itself replaced a hover-reveal, and a row-height
   equaliser holding the whole thing level. Every piece of it was reasoned,
   measured and guarded by its own check.

   All of it existed to make three long paragraphs readable. Darrell,
   2026-08-27: compare.html wins on copy, and compare.html says the same three
   things in one short line each. A hover bump on a nine-word sentence is
   machinery with nothing to move; a disclosure with nothing to disclose is
   just a gesture. So the machinery went with the copy it was built for.

   What is left is what the mockup has: three cells on hairlines, dealt in. */

/* ---------- the three that back the claim · Outline / Trio ----------
   Replaces the hairline row above, 2026-08-29, from the Why We Exist lab's
   handoff. Three silk cards on the paper page instead of three cells sharing
   a rule.

   ⚠️ THE GAP IS A CONSTRAINT, NOT A PREFERENCE. DO NOT TIGHTEN IT BELOW 26px.
   build/verify/system.mjs counts a dark block as anything with luminance
   <= 0.05 that is at least 400px wide and 160px tall, and allows exactly one
   per page. These cards are silk (luminance 0.0129) and 199.9px tall, so the
   ONLY thing keeping three of them out of that count is their width:

       card width = (1248 - 2 * gap) / 3      [1248 = the .wrap content box
                                               at the 1440 viewport the suite
                                               judges at]
       gap 56  ->  378.7px   1 dark block   (the CTA panel)   ✓
       gap 25  ->  399.3px   1 dark block                     ✓
       gap 24  ->  400.0px   4 dark blocks                    ✗

   Measured, not derived: 24px is the exact flip. At 56 there is 21.3px of
   room, which is real but is not much, and "tighten the gutter" is a far more
   likely future edit than anything else that could trip this. checkTrioGap
   asserts the margin so this comment is not the only thing holding it.

   ⚠️ THE CORNER IS var(--radius), NOT THE 3px THE HANDOFF SPECIFIED. Same
   number today. Written as the token so it follows the house if the scale
   ever moves again, which it did once already on the day this landed. */
.toc {
  list-style: none;
  margin: 3.25rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 56px;
  border-top: 0;
}
.toc li { display: grid; }
.toc-row {
  position: relative;
  padding: 32px;
  background: var(--silk);
  border: 1px solid var(--emerald-lit);
  border-radius: var(--radius);
  transition: box-shadow 0.3s ease;
}
.toc h3 {
  margin: 0;
  color: var(--wash);
  font-family: var(--sans);
  font-weight: 500;
  font-size: 0.9375rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1.45;
}
.toc h3::after {
  content: "";
  display: block;
  width: 34px;
  height: 2px;
  background: var(--emerald-lit);
  margin-top: 0.9375rem;
}
.toc p { margin: 0.9375rem 0 0; color: var(--wash); font-size: 18px; }

/* hover — the glow, not a lift. Nothing moves, so nothing reflows. */
.toc li:hover .toc-row {
  box-shadow: 0 0 0 1px var(--emerald-lit),
              0 0 40px -6px color-mix(in srgb, var(--emerald-lit) 70%, transparent);
}

/* ⚠️ ARRIVAL IS ALREADY OWNED BY THE HOUSE LIBRARY. index.html carries
   data-deal and --i on each .toc li, and base.css drives it: 14px throw, 62ms
   stagger, one shot. There is nothing to add here, and a fourth arrival
   language would be a decision rather than a paste. */

@media (max-width: 900px) {
  .toc { grid-template-columns: 1fr; gap: 24px; }
}

/* ---------- what we offer · the staircase ----------
   ⚠️ ONE RULE CARRIES ALL THREE, AND THE BUTTON IS THE ONLY FRAME.
   Until 2026-08-31 these were three bordered cards, the first framed heavier,
   all three taking the house lift on hover. Darrell called the motion "a loose
   afterthought," and the diagnosis under that is exact: only the FIRST column
   has a control in it. The other two rose under the pointer and led nowhere.

   So the borders came off and the section says the same thing with less: three
   columns hang from a single hairline, and the one that acts is the only one
   still wearing a box. That is the "one step acts, two reassure" sentence
   drawn rather than written — which is why a border on .svc is not a style
   preference to revisit. It puts a click promise back on two blocks that
   cannot keep it.

   Alternatives, including today-as-it-was, live in build/tune-offer.mjs. */

.svc-grid {
  display: grid;
  grid-template-columns: 1.2fr 1fr 1fr;
  gap: 44px;
  margin-top: 2.125rem;
  border-top: 1px solid var(--rule-line);
}
.svc {
  display: flex;
  flex-direction: column;
  position: relative;
  isolation: isolate;          /* the wash below sits behind the type, not over it */
  padding-top: 1.5rem;
}

/* THE GLOW. A wash panel that only exists while the control is live, drawn on
   a pseudo-element with NEGATIVE inset so it breathes past the type instead of
   hugging it — the column itself carries no padding, because padding here
   would push the numerals off the hairline they hang from.
   ⚠️ IT STOPS SHORT OF THE RULE (top: 0.55rem, not a negative top). The
   hairline is the section's structure; letting a hover state paint across it
   makes the structure look like it belongs to the hover. */
.svc::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0.55rem -1.15rem -0.9rem;
  background: var(--wash);
  opacity: 0;
  transition: opacity 0.26s ease;
}

/* ⚠️ :has() AND NOT .svc:hover — THIS IS THE WHOLE FIX. The bump and the glow
   fire off the BUTTON, so the thing that moves is the thing you are already
   pointing at. Columns 02 and 03 contain no .btn, so the selector cannot
   reach them and they never move. Changing this to .svc:hover restores the
   exact bug this section was rebuilt to remove.
   :focus-visible is in for the keyboard: tabbing to the button lights the same
   column a pointer would, so the two inputs tell the same story. */
.svc:has(.btn:hover)::before,
.svc:has(.btn:focus-visible)::before { opacity: 0.55; }
.svc:has(.btn:hover) h3,
.svc:has(.btn:focus-visible) h3 { transform: scale(1.04); }
.svc:has(.btn:hover) .svc-num,
.svc:has(.btn:focus-visible) .svc-num { color: var(--amber-deep); }

/* the 01/02/03 — a bare numeral hung under the rule. It was a bordered chip,
   which was the only box left once the cards went and read as a leftover. */
.svc-num {
  align-self: flex-start;
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  color: var(--muted);
  transition: color 0.25s ease;
}

.svc h3 {
  font-size: 1.375rem;
  margin-top: 0.875rem;
  transform-origin: left center;
  transition: transform 0.3s var(--ease-out);
}
.svc p { margin-top: 0.625rem; color: var(--muted); font-size: var(--text-sm); flex: 1; }
.svc .btn { align-self: flex-start; margin-top: 1.375rem; }

@media (max-width: 900px) {
  .svc-grid { grid-template-columns: 1fr; gap: 0; }
  /* stacked, the columns need a line each or the single top rule is doing the
     work of three and the numerals stop reading as steps */
  .svc { padding-bottom: 2rem; border-bottom: 1px solid var(--rule-line); }
  .svc:last-child { border-bottom: 0; padding-bottom: 0; }
  .svc::before { inset: 0.55rem -1rem 0.9rem; }
}
@media (prefers-reduced-motion: reduce) {
  .svc h3 { transition: none; }
  .svc:has(.btn:hover) h3,
  .svc:has(.btn:focus-visible) h3 { transform: none; }
}

/* The numbered funnel — "Browse. Wishlist. Done." — was cut on 2026-08-27
   with the compare.html copy: the mockup has no such section, and the page
   already answers the same question in "Your design, ready to book" and in
   the close. Its CSS went with it rather than sitting here unreferenced. */

/* ---------- the glimpse ----------
   Four cells, one leading, so the block reads as a composition rather than a
   row of four equal squares. The lead tile stands two rows; the fourth lies
   across two columns. */

.featured-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 2rem;
  flex-wrap: wrap;
  margin-bottom: 2.125rem;
}
.featured-head h2 { margin-top: 1.25rem; }   /* d2 · emerald.css §3b */

.cat-grid {
  display: grid;
  grid-template-columns: 1.35fr 1fr 1fr;
  grid-auto-rows: 220px;
  gap: 0.875rem;
  list-style: none;
  padding: 0;
  margin: 0;
}
.cat-grid > li:first-child { grid-row: span 2; }
.cat-wide { grid-column: span 2; }

.cat {
  position: relative;
  display: block;
  height: 100%;
  overflow: hidden;
  border: 1px solid var(--rule-line);
  transition: border-color 0.25s ease, transform 0.4s var(--ease-out), box-shadow 0.4s var(--ease-out);
}
.cat:hover, .cat:focus-visible {
  border-color: var(--ink);
  transform: translateY(-4px);
  box-shadow: 0 16px 34px -18px rgba(10, 9, 8, 0.42);
}

.thumb { position: absolute; inset: 0; display: block; background: var(--plate); }
/* ⚠️ THE CROP IS BIASED BELOW CENTRE. These are wide room shots dropped into
   short cells; a centred crop framed the ceiling on two of the four and threw
   the table away entirely. */
.thumb img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 68%;
  transition: transform 0.7s var(--ease-out);
}
.cat:hover .thumb img, .cat:focus-visible .thumb img { transform: scale(1.05); }

/* ⚠️ THE SCRIM IS ON THE TILE, NOT ON THE LABEL, and that is a contrast
   decision rather than a tidiness one. Four labels run over four different
   exposures. With the gradient inside the label box, the label's own top half
   sits on the transparent end of it — so a bright patch of photograph could
   land directly under white type, and the measured worst case for the label
   was whatever that patch happened to be. Moving it to the tile means the
   label box is 42px tall and sits entirely inside the ≥.7 alpha band: white
   on the composite measures ~6.6:1 against even a blown-out white photo. */
.cat::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(to top, rgba(10, 9, 8, 0.88) 0, rgba(10, 9, 8, 0.62) 30%, rgba(10, 9, 8, 0) 58%);
}
.chip-label {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 2;
  padding: 0.875rem 1rem;
  font-family: var(--sans);
  font-size: var(--label-sm);
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: #F4F1EA;
}

/* the corner mark — a stroke that rides in on hover, never a filled badge */
.cat .glyph {
  position: absolute;
  right: 0.75rem; bottom: 0.75rem;
  z-index: 3;
  width: 18px; height: 18px;
  border: 1.5px solid var(--emerald-lit);
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 0.3s ease, transform 0.3s var(--ease-out);
}
.cat:hover .glyph, .cat:focus-visible .glyph { opacity: 1; transform: none; }

@media (max-width: 900px) {
  /* ⚠️ THE SPANS BOTH GO, NOT JUST THE ROW ONE. Keeping `.cat-wide`'s
     `grid-column: span 2` on a two-column grid left the third tile alone in
     its row with an empty cell beside it and the fourth stranded below —
     a hole in the middle of a composition whose whole point is that it has
     no holes. Four tiles, two by two. */
  .cat-grid { grid-template-columns: 1fr 1fr; grid-auto-rows: 168px; }
  .cat-grid > li:first-child { grid-row: auto; }
  .cat-wide { grid-column: auto; }
}
@media (prefers-reduced-motion: reduce) {
  .cat, .thumb img, .cat .glyph { transition: none; }
  .cat:hover { transform: none; }
  .cat:hover .thumb img { transform: none; }
}

/* ---------- the showroom · the one split ----------
   The accusation on the tinted half, the answer on the paper half, inside one
   frame. It replaced a 48rem centred pull-quote, which said the same words
   with no one to say them to. */

.pull {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  border: 1px solid var(--rule-line);
}
.pull-claim {
  background: var(--wash);
  padding: 3rem 2.5rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.pull-quote {
  font-family: var(--serif);
  font-size: clamp(1.375rem, 2.1vw, 1.75rem);
  line-height: 1.2;
  margin: 1.375rem 0 0;
}
.pull-body { padding: 3rem 2.5rem; }
.pull-body h2 { margin-top: 1rem; }   /* d2 · emerald.css §3b */
.pull-body p { margin-top: 1rem; max-width: 46ch; }

@media (max-width: 900px) {
  .pull { grid-template-columns: 1fr; }
  .pull-claim, .pull-body { padding: 2.25rem 1.5rem; }
}

/* ---------- the family · a directory, not a card row ----------
   ⚠️ THE LEFT BORDER CARRIES EACH SISTER\'S OWN COLOUR, via --bs set inline.
   It is the only place on this page another brand\'s stroke appears, and it
   appears as 2px of edge on hover — not as a fill, not as a logo. Emerald for
   Kristi Marie Events, Fleur\'s rose for Fleur.

   ⚠️ THE ROWS CARRIED [data-wink] UNTIL 2026-08-30 AND NOTHING REPLACES IT.
   They arrived making the colour move a hover would, 900ms apart, so three
   hairline rows landed as three separate thoughts rather than as one fence.
   Darrell removed it: the wink was written for a text-heavy directory that
   needed telling it was interactive, and on the short rows that replaced it
   there was nothing left to explain — just type moving on a timer.
   The rule it went out under, now in §10 of the shared motions doc: a bump or
   a wink belongs to an INTERACTION, not to arrival. It may be caused by a
   hover, a focus or a press, or at minimum be scroll-LINKED so the reader
   drives it. It may not fire because a section came into view.
   ⚠️ So do not re-add an arrival animation here. The hover this section has
   is the whole treatment. */

.sis-grid { margin-top: 2.125rem; border-top: 1px solid var(--rule-line); }

.col-item {
  display: grid;
  /* ⚠️ THE THIRD COLUMN IS FIXED, NOT auto. On `auto` each row sized its own
     link column — "kristimarieevents.com" is wider than "fleurphx.com" — so
     the copy column started at a different x in every row and the directory
     stopped reading as a table. */
  grid-template-columns: 0.9fr 1.4fr 18rem;
  gap: 1.875rem;
  align-items: center;
  padding: 1.875rem 1.25rem 1.875rem 1.375rem;
  border-bottom: 1px solid var(--rule-line);
  border-left: 2px solid transparent;
  background: transparent;
  text-decoration: none;
  transition: border-left-color 0.25s ease, background 0.25s ease;
}
/* ⚠️ THE HOVER GROUND IS THE SISTER'S WASH, NOT THE HOUSE'S. It was
   var(--wash) for all three, which is KMC's emerald mist — so Fleur, a rose
   brand, hovered to green, and the largest coloured area on the whole
   interaction was the one part of it that was not hers. The name, border and
   link were all correctly branded and it still read as unbranded, because the
   ground outweighs them.
   ⚠️ --bw FALLS BACK TO var(--wash), so a row added without one degrades to
   the house mist rather than to nothing. */
.col-item:hover, .col-item:focus-visible {
  border-left-color: var(--bs);
  background: var(--bw, var(--wash));
}

.col-kind {
  display: block;
  font-family: var(--sans);
  font-size: var(--label-sm);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--muted);
}
/* ⚠️ EACH SISTER'S NAME IS SET IN THAT SISTER'S OWN DISPLAY FACE, from --bf
   beside --bs on the row. Bodoni Moda for Kristi Marie Events, Playfair
   Display for Fleur; the Shop shares KMC's stack, so it sets no --bf and the
   fallback carries it. Darrell, 2026-08-30: a reader who clicks through should
   already know she is landing in the right place, and after the accent the
   typeface is the strongest signal this row can spend.
   ⚠️ THE FALLBACK IS var(--serif), NOT A LITERAL. A row with no --bf gets
   whatever the house display face is at the time, so the Shop follows KMC
   rather than pinning a copy of it that could drift. */
.col-item h3 {
  font-family: var(--bf, var(--serif));
  font-size: 1.375rem; line-height: 1.16; margin-top: 0.4375rem;
  transform-origin: left center;
  transition: color 0.22s, transform 0.28s var(--ease-out);
}
/* On hover the name takes the sister's own colour and lifts a little.
   ⚠️ 1.05, NOT THE 1.12 THE TEXT LINKS USE. This is a 1.375rem display name,
   not an 11px label — the same ratio on type this size reads as a jolt rather
   than a lift. Origin is left center for the reason .text-link's is: the first
   letter stays put and the name grows rightward, instead of sliding out from
   under the eye already reading it.
   ⚠️ AND IT IS A HOVER, NOT AN ARRIVAL. The rows carried [data-wink] until
   2026-08-30 and it came off precisely because it fired on scroll. A bump
   belongs to an interaction. This one is caused by the pointer, and by
   :focus-visible so a keyboard gets it too. */
/* ⚠️ THE NAME GOES TO --bsd ON HOVER, NOT --bs, AND THAT FIXES A LIVE AA
   FAILURE. On the accent the Shop's name measured 4.42:1 against the hover
   ground — under the 4.5:1 it needs at 22px. The link had the identical
   problem and was deepened on 2026-08-30; the name was missed in the same
   pass, so it shipped failing while the other two rows looked fine. That is
   the shape of it: one brand, one state, two rows that hide it.
   On each sister's own wash the deep values measure 10.38:1, 8.97:1 and
   6.54:1 — headroom rather than a squeak past. The border stays on --bs, so
   the accent is still present and the name and link are not the only colour
   in the row. */
.col-item:hover h3,
.col-item:focus-visible h3 { color: var(--bsd, var(--amber-deep)); transform: scale(1.05); }
.col-item p { margin: 0; color: var(--muted); font-size: var(--text-sm); }
/* ⚠️ <b> DEFAULTS TO 700 AND THIS FACE SHIPS 400/500. The lead-in clause in
   each sister's line is a <b>; left alone the browser synthesises a bold by
   smearing the outline, which on a reading serif fills its own counters.
   checkFaces catches it, which is the only reason it is not shipping. */
.col-item p b { font-weight: 500; color: var(--ink); }

.col-go {
  font-family: var(--sans);
  font-size: var(--label-md);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  /* ⚠️ THE SISTER'S OWN ACCENT, NOT THE HOUSE'S. Darrell, 2026-08-30: the
     brand colour should carry the link too, not just the name. All three
     clear AA as normal text on paper — KME 7.69:1, Fleur 6.50:1, Shop
     5.21:1 — measured rather than assumed. This is a drop from --amber-deep's
     12.24:1, which is the cost of the colour being the sister's and is
     accepted. */
  color: var(--bs, var(--amber-deep));
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  white-space: nowrap;
  transition: color 0.22s;
}
/* ⚠️ IT DEEPENS ON HOVER BECAUSE THE ROW'S GROUND CHANGES UNDER IT, and one of
   the three does not survive that. The row fills with --wash on hover, and the
   Shop's jade #0F7A6E measures 4.42:1 on it — under the 4.5:1 AA needs for
   12px uppercase. The other two clear it (6.52 and 5.51), so this is one brand
   failing on one state, which is exactly the kind of thing that ships unnoticed
   because it looks fine in the other two rows.
   --bsd is each brand's own deep value, not a darkened --bs: on the wash they
   measure 10.4:1, 9.3:1 and 6.4:1. The deepening also gives the hover a second
   thing to say, which the flat version did not. */
.col-item:hover .col-go,
.col-item:focus-visible .col-go { color: var(--bsd, var(--amber-deep)); }
.col-go .arrow { display: inline-block; transition: transform 0.28s var(--ease-out); }
.col-item:hover .col-go .arrow,
.col-item:focus-visible .col-go .arrow { transform: translateX(5px); }

@media (max-width: 900px) {
  .col-item { grid-template-columns: 1fr; gap: 0.75rem; }
  .col-go { white-space: normal; }
}
@media (prefers-reduced-motion: reduce) {
  .col-item, .col-go .arrow { transition: none; }
  .col-item:hover .col-go .arrow { transform: none; }
  /* The transform is the motion; the colour is not, and it stays — it is the
     hover affordance and removing it would cost the signal without reducing
     any movement. Same split base.css's block makes. */
  .col-item h3 { transition: none; }
  .col-item:hover h3, .col-item:focus-visible h3 { transform: none; }
}

/* ---------- the close · the one velvet panel ----------
   ⚠️ THIS PAGE SPENDS ITS SINGLE DARK BLOCK HERE AND NOWHERE ELSE. The topbar
   is chrome and does not count; a second dark SECTION does. It is also the
   page\'s only gilt — gold is an event.

   Contained rather than full-bleed. Full-bleed velvet under a paper page
   reads as a different site\'s footer; a panel inside the measure reads as a
   card the page is handing you. The ground and the gilt live in emerald.css;
   only the composition is here. */

.cta {
  display: grid;
  grid-template-columns: 1.25fr 0.75fr;
  gap: 3.25rem;
  align-items: center;
  padding: 3.5rem 3rem;
}
/* .cta h2 is d2 · emerald.css §3b */
.cta p { margin-top: 1.375rem; max-width: 46ch; }
.cta-copy .eyebrow { margin-bottom: 1rem; }
/* the enquiry: two fields and the one gilt control on the page */
.cta-act { display: flex; flex-direction: column; align-items: stretch; gap: 0.75rem; }
.cta-act input {
  padding: 0.875rem;
  border: 1px solid rgba(244, 241, 234, 0.16);
  background: transparent;
  color: var(--velvet-text);
  font-family: var(--text);
  font-size: 1rem;
  border-radius: var(--radius-sm);
  outline: none;
}
.cta-act input::placeholder { color: var(--velvet-soft); opacity: 1; }
.cta-act input:focus-visible { border-color: var(--gilt); }
.cta-act .btn { text-align: center; width: 100%; }
/* ⚠️ THE TWO EXPLORE LINKS SIT ON VELVET, so they take champagne rather than
   the paper page's --amber, which measures 2.4:1 on this ground. Champagne is
   12.78:1 and is the token's own job — "gilt as type on a dark ground". The
   rule that draws under them stays gilt so it reads as an underline and not as
   a second word. Same pairing as the wish tray's gallery link.
   ⚠️ `align-self: start` because .cta-act stretches its children: a text link
   stretched to the panel's width puts its underline three inches past the last
   letter, drawing a rule across empty velvet on hover. */
.cta-act .text-link { color: var(--champagne); align-self: start; }
.cta-act .text-link::after { background: var(--gilt); }

@media (max-width: 900px) {
  .cta { grid-template-columns: 1fr; gap: 2rem; padding: 2.5rem 1.5rem; }
}

/* Reduced motion.
   Every reveal defined in THIS file has to be neutralised in THIS file — the
   shared block in base.css cannot see .toc li.

   ⚠️ THIS BLOCK LOST SIX RULES ON 2026-08-27 AND THAT IS THE POINT. It was
   cancelling a hover bump, a rolling mark and a masthead rule that no longer
   exist. (The scroll wink outlived that pass and went on 2026-08-30; its
   neutraliser in base.css went with it, for the reason below.) A neutraliser for a deleted rule is worse than no
   neutraliser: it reads as coverage, it survives every search for dead code
   because the selector still parses, and it makes the block look thorough
   while guarding nothing. Only the reveals still on the page are here. */
@media (prefers-reduced-motion: reduce) {
  .mo .toc li {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .svc, .cat, .thumb img, .cat .glyph, .col-item { transition: none; }
  .cat:hover { transform: none; }
  .cat:hover .thumb img { transform: none; }
}

/* ============================================================
   INSTAGRAM — the follow strip

   ⚠️ This shows OUR OWN photography and links to the profile. It does not
   claim to be a feed. There are no captions, no like counts, no timestamps
   and no "2 days ago" — inventing any of those would be dressing five stock
   tiles up as live posts, and a visitor would have no way to tell.

   A real feed needs an Instagram Graph API token (a Business/Creator account
   linked to a Facebook Page) or a third-party widget service. Neither exists
   yet; when one does, the markup this replaces is a <ul> of tiles and the
   surrounding lockup does not change.

   The treatment is a contact sheet on a slow drift rather than the usual 3x3
   grid: a wedding is a sequence, and a strip that keeps moving reads more like
   a roll of film than a set of thumbnails. It pauses on hover so you can
   actually look at one.
   ============================================================ */

.ig { overflow: hidden; }
.ig-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 2rem; flex-wrap: wrap; margin-bottom: 2rem; }
.ig-handle { font-family: var(--serif); font-weight: 400; font-size: clamp(1.8rem, 4vw, 3rem); line-height: 1; letter-spacing: -0.01em; }
.ig-handle a { color: var(--ink); text-decoration: none; position: relative; }
.ig-handle a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -0.18em;
  height: 2px; background: var(--amber); transform: scaleX(0); transform-origin: left center;
  transition: transform 0.45s var(--ease-out);
}
.ig-handle a:hover::after, .ig-handle a:focus-visible::after { transform: scaleX(1); }
.ig-say { font-family: var(--text); font-size: var(--text-sm); color: var(--muted); max-width: 34ch; }

/* The strip. Two identical runs sit side by side and the track slides exactly
   one run's width, so the loop has no seam to notice. */
.ig-strip { position: relative; --run: 6; }
.ig-strip::before, .ig-strip::after {
  content: ""; position: absolute; top: 0; bottom: 0; width: 5rem; z-index: 2; pointer-events: none;
}
.ig-strip::before { left: 0; background: linear-gradient(to right, var(--ground), transparent); }
.ig-strip::after { right: 0; background: linear-gradient(to left, var(--ground), transparent); }

.ig-track { display: flex; gap: 0.75rem; width: max-content; animation: ig-drift 46s linear infinite; }
.ig-strip:hover .ig-track, .ig-track:focus-within { animation-play-state: paused; }
@keyframes ig-drift { to { transform: translateX(calc(-50% - 0.375rem)); } }

.ig-tile {
  position: relative; flex: none; display: block;
  width: clamp(11rem, 19vw, 16rem); aspect-ratio: 4 / 5;
  border-radius: var(--radius); overflow: hidden;
  background: var(--paper);
  transition: transform 0.4s var(--ease-out), box-shadow 0.4s var(--ease-out);
}
.ig-tile img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.7s var(--ease-out); }
.ig-tile::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  box-shadow: inset 0 0 0 0 var(--amber); transition: box-shadow 0.35s ease;
}
.ig-tile:hover, .ig-tile:focus-visible { transform: translateY(-6px); box-shadow: 0 16px 34px -18px rgba(15, 15, 14, 0.42); }
.ig-tile:hover img, .ig-tile:focus-visible img { transform: scale(1.05); }
.ig-tile:hover::after, .ig-tile:focus-visible::after { box-shadow: inset 0 0 0 2px var(--amber); }

/* The mark rides in the corner, stroke only. */
.ig-tile .glyph {
  position: absolute; right: 0.6rem; bottom: 0.6rem; z-index: 1;
  width: 22px; height: 22px; opacity: 0; transform: translateY(4px);
  transition: opacity 0.3s ease, transform 0.3s var(--ease-out);
}
.ig-tile:hover .glyph, .ig-tile:focus-visible .glyph { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  /* A strip that moves on its own is the definition of what this setting is
     asking us not to do. It becomes an ordinary scrollable row. */
  .ig-track { animation: none; }
  .ig-strip { overflow-x: auto; }
  .ig-tile, .ig-tile img, .ig-tile::after, .ig-tile .glyph { transition: none; }
  .ig-handle a::after { transition: none; }
}


/* ---------- the showroom gate (2026-08-30) ----------
 * "Start by" and two ways in. Replaced a single "Book a visit" link, because
 * nothing on this site books a visit any more — see the note at the markup.
 * A list rather than two loose links: they are alternatives, and a reader
 * scanning should see two of something rather than a sentence that happens to
 * contain links. */
.gate-lead {
  margin: 1.25rem 0 0.4rem;
  font-family: var(--sans);
  font-size: var(--label-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.gate-links { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.4rem; }
