/* ============================================================
   Bespoke Digital — bespoke-blocks.css   (v2, 2026-07-30)

   THE BLOCK LAYER. bespoke.css holds the tokens, the reset and the
   base classes; this file holds block-specific rules and nothing
   else. Split deliberately, for two reasons:
     1. it mirrors blocks/ — adding a block adds a section here
     2. bespoke.css stops needing a ?v= bump every time a block
        lands, and this file gets its own cache key
   Both are linked from every page and both carry ?v=N. Bump the
   number on the file you changed, in the same deploy as the pages
   (assets here are served with max-age=604800 — seven days).

   DEPENDS ON bespoke.css for: --paper --card --ink --ink-2 --muted
   --rule --brass --brass-flat --brass-ink --cream --cream-2 --mono
   --s1..--s8 --ease, and .wrap .sec .btn* .eyebrow .mono .lead
   .small .d1..d3 .h4 .plate .plate__bar .plate__view .plate__url
   .ledger .rv. On its own this file renders unstyled markup — that
   is the point, and it is written down so nobody has to discover it.
   ============================================================ */

/* Grid items default to min-width:auto, which refuses to shrink below the
   content's min-content width — so one 390px phone iframe stretched the whole
   375px layout out to 421px. bespoke.css already guards its own grids this
   way; these are the new ones. Measured, not guessed: the offending item
   reported width 397 inside a 327 parent. */
.reel__in>*,.vs>*,.vs__row>*,.duo>*,.sheet__row>*{min-width:0}

/* ---------- plate-scroll-reel -------------------------------
   A pinned browser plate that scrolls the REAL site inside it as
   you scroll the page. The whole point is that it is not a
   screenshot — the demo cannot go stale, because it IS the demo.
   Static fallback: the plate sits in flow showing the top of the
   site, which is exactly the plain plate. --rs (fit scale) and
   --rt (pre-scale travel) are published per element by script,
   because neither is knowable in CSS; the motion itself is CSS.
   ------------------------------------------------------------ */
.reel{position:relative;border-top:1px solid var(--rule)}
.reel__stage{padding:var(--s7) 0}
.reel__in{display:grid;grid-template-columns:1fr;gap:var(--s4);align-items:center}
@media(min-width:1000px){.reel__in{grid-template-columns:.72fr 1.28fr;gap:var(--s6)}}
.reel__copy .d3{margin-bottom:var(--s3)}
.reel__count{font-family:var(--mono);font-size:11px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--brass);margin-top:var(--s3);display:block}
.reel__view{position:relative;aspect-ratio:16/10;overflow:hidden;background:var(--card)}
@media(min-width:1000px){
  /* the pinned stage is nearly a full viewport tall; a 16/10 plate left half of
     it empty, so on desktop the frame is driven by viewport height instead */
  .reel__view{aspect-ratio:auto;height:clamp(320px,60vh,640px)}
}
.reel__doc{position:absolute;top:0;left:0;width:1440px;max-width:none;border:0;
  transform-origin:0 0;transform:scale(var(--rs,.32));pointer-events:none}

@media(prefers-reduced-motion:no-preference){
  @supports (animation-timeline:view()){
    /* The runway only exists when the motion does. Putting height:300vh
       outside this guard would hand a reduced-motion visitor three
       viewports of empty paper to scroll past for nothing. */
    .js .reel{height:300vh;view-timeline-name:--reel;view-timeline-axis:block}
    .js .reel__stage{position:sticky;top:74px;height:calc(100vh - 74px);
      display:flex;align-items:center;padding:0}
    .js .reel__doc{animation:reeldrive linear both;animation-timeline:--reel;
      animation-range:contain 0% contain 100%}
    @keyframes reeldrive{
      from{transform:scale(var(--rs,.32)) translateY(0)}
      to{transform:scale(var(--rs,.32)) translateY(calc(-1 * var(--rt,0px)))}
    }
  }
}

/* ---------- template-vs-bespoke -----------------------------
   The positioning argument, drawn. Both panels are OUR OWN
   illustration — never a screenshot of somebody else's site.
   ------------------------------------------------------------ */
.vs{display:grid;grid-template-columns:1fr;gap:var(--s4)}
@media(min-width:820px){.vs{grid-template-columns:1fr 1fr;gap:var(--s5)}}
.vs__col>.mono{display:block;margin-bottom:14px}
.vs__wf{border:1px solid var(--rule);border-radius:3px;background:var(--card);
  padding:18px;display:grid;gap:11px;align-content:start}
.vs__col--bespoke .vs__wf{border-color:var(--brass-flat)}
.vs__wf i{display:block;background:var(--rule);border-radius:2px}
.vs__wf .acc{background:var(--brass-flat)}
.vs__row{display:grid;gap:11px}
.vs__note{margin-top:14px;color:var(--muted);font-size:15px}

/* ---------- plate-devices -----------------------------------
   One build, two screens, both live. Evidence rather than a claim.
   ------------------------------------------------------------ */
.duo{display:grid;grid-template-columns:1fr;gap:var(--s5);align-items:end}
@media(min-width:900px){.duo{grid-template-columns:1fr 300px;gap:var(--s5)}}
.duo__phone{width:100%;max-width:300px;margin:0 auto;border:9px solid var(--ink);
  border-radius:34px;overflow:hidden;background:var(--card);
  box-shadow:0 26px 60px -34px rgba(20,18,14,.5)}
.duo__screen{position:relative;height:520px;overflow:hidden;background:var(--card)}
.duo__screen iframe{position:absolute;top:0;left:0;width:390px;max-width:none;
  height:1560px;border:0;transform-origin:0 0;transform:scale(.7154);pointer-events:none}
.duo__cap{display:flex;flex-wrap:wrap;gap:var(--s2) var(--s4);margin-top:18px}
.duo__cap span{font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--muted)}

/* ---------- spec-sheet --------------------------------------
   Measured things get a measured face. A spec table with dotted
   leaders instead of the usual three-icon feature row.
   ------------------------------------------------------------ */
.sheet{border-top:1px solid var(--rule)}
.sheet__row{display:grid;grid-template-columns:1fr;gap:6px;
  padding:var(--s3) 0;border-bottom:1px solid var(--rule)}
@media(min-width:760px){
  .sheet__row{grid-template-columns:230px 1fr;gap:var(--s4);align-items:baseline}
}
/* leader drawn as a flex sibling, not a negative-z pseudo-element: a
   z-index:-1 rule disappears behind any section that paints a background,
   which is most of them. Colour is --muted at .4, not --rule: --rule dotted
   on --paper measured 1.15:1 and was simply not visible. */
.sheet__k{display:flex;align-items:baseline;gap:10px;font-family:var(--mono);
  font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--ink)}
.sheet__k b{font-weight:500;flex:none}
.sheet__k i{flex:1;height:0;border-bottom:1px dotted var(--muted);opacity:.4;
  transform:translateY(-4px);min-width:20px}
@media(max-width:759px){.sheet__k i{display:none}}
.sheet__v{color:var(--ink-2);font-size:16.5px;max-width:64ch}
.sheet__v em{font-style:normal;color:var(--brass)}

/* ---------- social row --------------------------------------
   A labelled button, not a bare icon: the job here is "there is a
   real business behind this", which a word does and a glyph does not.
   ------------------------------------------------------------ */
.social{display:flex;flex-wrap:wrap;gap:12px;align-items:center}
.btn--fb{gap:9px}
.btn--fb svg{width:15px;height:15px;flex:none}
.ftr .social{margin-top:18px}
.ftr .btn--lineCream{min-height:42px;padding:10px 18px}

/* ---------- contact channels -------------------------------- */
.chan{border-top:1px solid var(--rule);margin-top:var(--s4)}
.chan__row{display:flex;flex-wrap:wrap;align-items:baseline;
  justify-content:space-between;gap:var(--s2);padding:16px 0;
  border-bottom:1px solid var(--rule)}
.chan__k{font-family:var(--mono);font-size:10.5px;letter-spacing:.18em;
  text-transform:uppercase;color:var(--muted)}
.chan__v{font-size:16.5px}
