/* ══════════════════════════════════════════════════════════════════════════
   /book-shoot v3 — the SITE's card anatomy, at portal scale.
   CS-PLAT-09 / book-v3, Dom 2026-08-23.

   WHAT THIS SHEET IS. Dom asked for capitalshots.ca/book, cloned: "a smaller
   version of what we have on the site with the toasts etc — identical but more
   compact, not crowded." So every measurement here is the LIVE SITE's own
   `.pk` / `.ala` card, taken from the served /book stylesheet and multiplied by
   ~0.7 — not a new visual language:

     site  →  here          site  →  here
     --pk-pad 20px → 14px   .pk__name  32px → 20px/600
     media  2.4/1  → 16/10  .pk__amt   29px → 21px
     .pk__item 14.5/600 → 14/600       flip 580ms → 250ms (portal's own)

   The flip MECHANIC is the portal's, not the site's: .ad-pcard/.ad-flip in
   agent-dash.css (250 ms, reduced-motion instant, `inert` on the hidden face).
   One motion vocabulary in this product, not two.

   WHY IT IS ITS OWN FILE. agent-dash.css owns `.bk-*` — the SMALL rate tile
   that the Dash's "Book a shoot" section renders through
   agent-book.js#rateTileHtml. That tile is still live on the Dash and is NOT
   this screen. Rewriting it in place would have changed a screen this lane does
   not own, so the booking screen's own anatomy lives here under `.bkv3`,
   exactly as cs-today.css was split out for the Today screen.

   COLOUR LAW (feedback_cs_backend_palette_red_black, 2026-08-22): --brand
   (#FF0016) on small elements and accents only; the flip card's BACK is black.
   White type and white icons on the red button, both themes.
   ══════════════════════════════════════════════════════════════════════════ */

/* The black face's palette lives on :root, NOT on .bkv3 — the upgrade popover
   is rendered into <body> (it has to escape the card's overflow and its 3D
   context), so a token defined on .bkv3 does not reach it and the panel comes
   out transparent. Measured on staging 2026-08-23. */
:root {
  --bkc-black: #0A0A0A;         /* Dom 2026-08-23: back of the flip card BLACK */
  --bkc-black-ink: #F4F4F4;
  --bkc-black-ink-2: rgba(244,244,244,.66);
  --bkc-black-line: rgba(244,244,244,.14);
}
.bkv3 { --bkc-pad: 14px; }      /* the site's 20px × 0.7 */

/* ── Page frame: main column + the sticky order rail ──────────────────────
   One column until there is honestly room for two. 1080 is where a 300px rail
   plus a 3-up card grid both fit without either being squeezed. */
.bkv3-cols { display: grid; gap: var(--sp-6); align-items: start; }
@media (min-width: 1080px) {
  .bkv3-cols { grid-template-columns: minmax(0, 1fr) 304px; gap: var(--sp-6); }
  .bkv3-rail { position: sticky; top: var(--sp-4); }
}
.bkv3-main { display: grid; gap: var(--sp-3); min-width: 0; }

/* On a narrow column the section hint ("Turn a card for the description and
   upgrades") squeezes into a 3-line stack beside its own heading. It drops to
   its own row instead — it is the only thing telling a touch user that the
   card turns, so hiding it is not an option. */
@media (max-width: 700px) {
  .bkv3 .ad-sec-h { flex-wrap: wrap; }
  .bkv3 .ad-sec-h .ad-sub { flex: 1 0 100%; }
}

/* ══ PACKAGE CARDS ════════════════════════════════════════════════════════ */

.bkp-grid {
  display: grid; gap: var(--sp-6);
  grid-template-columns: 1fr;
  align-items: stretch;                 /* every card is the tallest card */
}
@media (min-width: 620px) { .bkp-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 980px) { .bkp-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.bkp { position: relative; min-width: 0; height: 100%; perspective: 1400px; }
.bkp-flip {
  position: relative; display: grid; height: 100%; min-height: 380px;
  transform-style: preserve-3d;
  transition: transform 250ms var(--ease);
}
.bkp.is-flipped .bkp-flip,
.bks.is-flipped .bkp-flip { transform: rotateY(180deg); }
@media (prefers-reduced-motion: reduce) { .bkp-flip { transition: none; } }

.bkp-face {
  grid-area: 1 / 1;
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--bg-elevated); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r-3);
  box-shadow: var(--shadow-1);
  -webkit-backface-visibility: hidden; backface-visibility: hidden;
  transition: border-color var(--t-fast) var(--ease), box-shadow 200ms var(--ease);
}
/* `backface-visibility` is a PAINT rule, not a hit-testing one — inside a
   preserve-3d stack Chrome still hit-tests the hidden face (measured on this
   portal's listing cards, 2026-08-22). The JS sets `inert`; this is the same
   guarantee for anything that does not honour it. */
.bkp .bkp-back, .bks .bkp-back { pointer-events: none; transform: rotateY(180deg); }
.bkp.is-flipped .bkp-back, .bks.is-flipped .bkp-back { pointer-events: auto; }
.bkp.is-flipped .bkp-front, .bks.is-flipped .bkp-front { pointer-events: none; }

.bkp-front:hover { border-color: var(--line-strong); }
.bkp.is-on .bkp-face { border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand) inset, var(--shadow-1); }

/* ── the BLACK back (Dom 2026-08-23) ─────────────────────────────────────── */
.bkp-back {
  background: var(--bkc-black); color: var(--bkc-black-ink);
  border-color: rgba(244,244,244,.10);
}
.bkp.is-on .bkp-back { border-color: var(--brand); }
.bkp-back .bkp-rule { background: var(--bkc-black-line); }
.bkp-back .bkp-save { color: var(--bkc-black-ink-2); }
.bkp-back .bkp-save b { color: var(--bkc-black-ink); }
.bkp-back .bkp-was { color: rgba(244,244,244,.42); }

/* ── photo ────────────────────────────────────────────────────────────────
   16 : 10, the site's 2.4:1 band opened up because a portal card is narrower
   and a 2.4:1 strip on 300px is 125px of letterbox. */
.bkp-media { display: block; aspect-ratio: 16 / 10; overflow: hidden; background: var(--bg-sunken); flex: none; }
.bkp-media img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ── clicking the card turns it over (Dom: "clicking the card flips to a BLACK
   back"). The trigger is a STRETCHED, empty overlay button covering the upper
   area — not a wrapper. A wrapper would put a <ul> inside a <button> (invalid
   content model) and make the foot's Select a button inside a button. */
.bkp-top {
  position: relative; flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; align-items: stretch;
}
.bkp-turn {
  position: absolute; inset: 0; z-index: 2;
  margin: 0; padding: 0; border: 0; background: none; cursor: pointer;
  border-radius: var(--r-3) var(--r-3) 0 0;
}
.bkp-turn:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }

.bkp-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-2);
  padding: var(--bkc-pad) var(--bkc-pad) 0;
}
.bkp-name { font-size: calc(20px * var(--text-scale, 1)); font-weight: 600; line-height: 1.15; letter-spacing: -.02em; color: inherit; }
.bkp-tag {
  flex: none; align-self: center;
  padding: 4px 7px 5px; border-radius: var(--r-1);
  background: var(--brand); color: #FFFFFF;
  font: 700 calc(11px * var(--text-scale, 1))/1 var(--font-sans); letter-spacing: .01em; white-space: nowrap;
}

/* ── the inclusion list — EVERY line, never "+N more" (Dom 2026-08-23) ───── */
.bkp-list { list-style: none; display: grid; gap: 7px; margin: 0; padding: 11px var(--bkc-pad) 0; }
.bkp-item {
  display: flex; align-items: flex-start; gap: 8px;
  font-size: calc(14px * var(--text-scale, 1)); font-weight: 600; line-height: 1.3; letter-spacing: -.01em; color: inherit;
}
.bkp-item .bki { width: 14px; height: 14px; flex: none; margin-top: 1px; color: var(--brand); }
.bkp-back .bkp-item .bki { color: var(--brand); }

.bkp-fill { flex: 1 1 auto; min-height: var(--sp-3); }
.bkp-rule { height: 1px; background: var(--line); margin: 0; flex: none; }

/* ── price row ────────────────────────────────────────────────────────────
   "Save $135 vs à la carte · $585 $450" — the site's own row, one line. */
.bkp-meta {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2);
  flex-wrap: wrap; padding: 10px var(--bkc-pad);
}
.bkp-save { font-size: calc(12.5px * var(--text-scale, 1)); font-weight: 500; color: var(--ink-3); }
.bkp-save b { font-weight: 700; color: var(--ink-2); }
.bkp-amt {
  font-size: calc(21px * var(--text-scale, 1)); font-weight: 700; line-height: 1; letter-spacing: -.03em;
  color: inherit; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.bkp-amt small { font-size: calc(11.5px * var(--text-scale, 1)); font-weight: 500; color: var(--ink-3); letter-spacing: 0; margin-left: 4px; }
.bkp-back .bkp-amt small { color: var(--bkc-black-ink-2); }
.bkp-was {
  font-size: calc(12.5px * var(--text-scale, 1)); font-weight: 500; color: var(--ink-4);
  text-decoration: line-through; margin-right: 6px;
}

/* ── foot: "Select Full →" ────────────────────────────────────────────────── */
.bkp-foot { display: flex; flex: none; }
.bkp-pick {
  flex: 1 1 auto; display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  min-height: 44px; padding: 0 var(--bkc-pad);
  margin: 0; border: 0; background: none; color: inherit; cursor: pointer;
  font: 600 calc(14px * var(--text-scale, 1))/1 var(--font-sans); letter-spacing: -.01em; text-align: left;
  border-radius: 0 0 var(--r-3) var(--r-3);
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.bkp-pick .bki { width: 16px; height: 16px; flex: none; transition: transform var(--t-fast) var(--ease); }
.bkp-pick:hover { background: color-mix(in srgb, var(--brand) 8%, transparent); color: var(--brand-deep); }
.bkp-back .bkp-pick:hover { background: rgba(244,244,244,.08); color: #FFFFFF; }
.bkp-pick:hover .bki { transform: translateX(3px); }
.bkp-pick:focus-visible { outline: 2px solid var(--brand); outline-offset: -3px; }
.bkp.is-on .bkp-pick { background: var(--brand); color: #FFFFFF; }
.bkp.is-on .bkp-pick .bki { color: #FFFFFF; transform: none; }
.bkp.is-on .bkp-pick:hover { background: var(--brand-deep); color: #FFFFFF; }

/* ── back face: header, description, upgrade dropdowns ────────────────────── */
.bkp-back .bkp-head { padding-bottom: 0; }
.bkp-backx {
  flex: none; width: 26px; height: 26px; display: grid; place-items: center;
  border: 1px solid var(--bkc-black-line); border-radius: var(--r-1);
  background: none; color: var(--bkc-black-ink-2); cursor: pointer; padding: 0;
}
.bkp-backx:hover { color: var(--bkc-black-ink); border-color: rgba(244,244,244,.3); }
.bkp-backx:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.bkp-backx .bki { width: 14px; height: 14px; }

.bkp-desc {
  margin: 9px 0 0; padding: 0 var(--bkc-pad);
  font-size: calc(13px * var(--text-scale, 1)); font-weight: 400; line-height: 1.55; color: var(--bkc-black-ink-2);
  text-wrap: pretty;
}
.bkp-cfg { display: grid; gap: 10px; padding: var(--sp-3) var(--bkc-pad) 0; }
.bkp-cfglab {
  display: block; margin-bottom: 4px;
  font: 600 calc(11px * var(--text-scale, 1))/1 var(--font-sans); letter-spacing: .06em; text-transform: uppercase;
  color: rgba(244,244,244,.5);
}
/* A fact, not a control — an inclusion that has nothing to choose renders as a
   row, never as a dropdown with one option (no dead controls). */
.bkp-fixed {
  display: flex; align-items: center; gap: 8px;
  min-height: 34px; padding: 0 10px;
  border: 1px dashed var(--bkc-black-line); border-radius: var(--r-2);
  font: 500 calc(12.5px * var(--text-scale, 1))/1.3 var(--font-sans); color: var(--bkc-black-ink-2);
}
.bkp-fixed .bki { width: 14px; height: 14px; flex: none; color: var(--brand); }

/* ══ POPOVER LISTBOX ══════════════════════════════════════════════════════
   Dom: "our popover listbox, not native". The panel is rendered into <body>,
   not into the card: a menu inside a rotateY(180deg) face with overflow:hidden
   is clipped by its own card and drawn behind its neighbours. Fixed position,
   measured off the trigger's rect. */
.bkl-btn {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  width: 100%; min-height: 38px; padding: 0 10px;
  background: rgba(244,244,244,.06); color: var(--bkc-black-ink);
  border: 1px solid var(--bkc-black-line); border-radius: var(--r-2);
  font: 600 calc(13px * var(--text-scale, 1))/1.2 var(--font-sans); letter-spacing: -.01em; text-align: left; cursor: pointer;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.bkl-btn:hover { background: rgba(244,244,244,.12); border-color: rgba(244,244,244,.26); }
.bkl-btn[aria-expanded="true"] { border-color: var(--brand); }
.bkl-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.bkl-btn .bki { width: 14px; height: 14px; flex: none; color: rgba(244,244,244,.6); transition: transform var(--t-fast) var(--ease); }
.bkl-btn[aria-expanded="true"] .bki { transform: rotate(180deg); }
.bkl-btn .v { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.bkl-pop {
  position: fixed; z-index: 90; margin: 0; padding: 5px;
  max-height: 280px; overflow-y: auto;
  background: #0A0A0A; background: var(--bkc-black, #0A0A0A);
  color: #F4F4F4; color: var(--bkc-black-ink, #F4F4F4);
  border: 1px solid rgba(244,244,244,.18); border-radius: 10px; border-radius: var(--r-2);
  font-family: var(--font-sans);
  box-shadow: 0 18px 40px -14px rgba(0,0,0,.6);
}
.bkl-pop[hidden] { display: none; }
.bkl-opt {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  width: 100%; min-height: 34px; padding: 6px 8px;
  border: 0; border-radius: var(--r-1); background: none; color: inherit; cursor: pointer;
  font: 500 calc(13px * var(--text-scale, 1))/1.3 var(--font-sans); text-align: left;
}
.bkl-opt .n { font-variant-numeric: tabular-nums; font-weight: 600; color: rgba(244,244,244,.72); white-space: nowrap; }
.bkl-opt:hover, .bkl-opt.is-cursor { background: rgba(244,244,244,.11); }
.bkl-opt[aria-selected="true"] { color: #FFFFFF; }
.bkl-opt[aria-selected="true"]::after {
  content: ""; flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--brand);
}
.bkl-opt:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }

/* ══ SINGLE SERVICES — the same anatomy, smaller ═════════════════════════
   Dom 2026-08-29: "All these should be flip cards with option in the back —
   has to make sense", and "keep our animated thumbs and regular too."

   So `.bks` is now a SIZE VARIANT of the package card, not a second card: it
   reuses `.bkp-flip` / `.bkp-face` / `.bkp-front` / `.bkp-back` / `.bkp-turn` /
   `.bkp-backx` verbatim — one 250 ms rotateY, one BLACK back, one reduced-
   motion rule, one `inert` contract — and only overrides what a smaller card in
   a 4-up grid genuinely needs (radius, min-height, type scale). Same component
   on the Grapevine screen (views/agent-book-gv.js). */
.bks-grid { display: grid; gap: var(--sp-4); grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: stretch; }
@media (min-width: 620px) { .bks-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 980px) { .bks-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* The article is the 3D stage now — the background, the border and the shadow
   moved onto the two faces (`.bkp-face`), which is what makes the faces equal
   height: `.bkp-flip` is a 1-cell grid and both faces sit in grid-area 1/1. */
.bks {
  position: relative; min-width: 0; height: 100%;
  border-radius: var(--r-2);
  perspective: 1400px;
}
.bks .bkp-flip { min-height: 320px; }
/* The package card's 12px radius is too generous at this size — the site's own
   à-la-carte tile is the 10px one. */
.bks .bkp-face { border-radius: var(--r-2); }
.bks .bkp-turn { border-radius: var(--r-2) var(--r-2) 0 0; }
.bks.is-on .bkp-face { border-color: var(--brand); }
/* The selected ring paints ABOVE the media (the cover image used to sit on top
   of the inset shadow — Dom 2026-08-24 "photo is on top of the outline"). It
   stays on the ARTICLE, outside the preserve-3d stack, so it reads on whichever
   face is showing. */
.bks.is-on::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; z-index: 3;
  border: 2px solid var(--brand); border-radius: inherit;
}
/* The upper area is the flip target — media + body, never the foot. */
.bks-top {
  position: relative; flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; align-items: stretch;
}
.bks-media { display: block; aspect-ratio: 16 / 10; overflow: hidden; background: var(--bg-sunken); flex: none; }
.bks-media img, .bks-media video { width: 100%; height: 100%; object-fit: cover; display: block; }
.bks-body { display: flex; flex-direction: column; gap: 5px; padding: 10px 11px 0; flex: 1 1 auto; }
.bks-name { font-size: calc(14.5px * var(--text-scale, 1)); font-weight: 600; line-height: 1.25; letter-spacing: -.015em; }
.bks-lines { list-style: none; display: grid; gap: 4px; margin: 2px 0 0; padding: 0; }
.bks-lines li {
  display: flex; align-items: flex-start; gap: 7px;
  font-size: calc(12.5px * var(--text-scale, 1)); font-weight: 500; line-height: 1.4; color: var(--ink-3);
}
.bks-lines li .bki { width: 13px; height: 13px; flex: none; margin-top: 2px; color: var(--brand); }

/* ── the BLACK back: head, full description, options ─────────────────────── */
.bks-bhead {
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-2);
  padding: 10px 11px 0; flex: none;
}
.bks-bbody { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 0 11px 10px; }
.bks-desc {
  margin: 7px 0 0;
  font-size: calc(12.5px * var(--text-scale, 1)); font-weight: 400; line-height: 1.5;
  color: var(--bkc-black-ink-2); text-wrap: pretty;
}
.bks-foot {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  margin-top: 10px; border-top: 1px solid var(--line); flex: none;
}
.bkp-back .bks-foot { border-top-color: var(--bkc-black-line); }
.bks-p {
  padding-left: 11px; font-size: calc(14px * var(--text-scale, 1)); font-weight: 700; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.bks-p small { font-size: calc(10.5px * var(--text-scale, 1)); font-weight: 500; color: var(--ink-3); letter-spacing: 0; margin-left: 3px; }
.bkp-back .bks-p small { color: var(--bkc-black-ink-2); }
.bks-add {
  display: flex; align-items: center; gap: 5px;
  min-height: 38px; padding: 0 11px; margin: 0;
  border: 0; background: none; color: var(--ink-2); cursor: pointer;
  font: 600 calc(13px * var(--text-scale, 1))/1 var(--font-sans); letter-spacing: -.01em;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.bks-add .bki { width: 14px; height: 14px; }
.bks-add:hover { background: color-mix(in srgb, var(--brand) 8%, transparent); color: var(--brand-deep); }
.bks-add:focus-visible { outline: 2px solid var(--brand); outline-offset: -3px; }
.bks.is-on .bks-add { background: var(--brand); color: #FFFFFF; }
.bks.is-on .bks-add .bki { color: #FFFFFF; }
.bks.is-on .bks-add:hover { background: var(--brand-deep); }
/* the same control on the BLACK face */
.bkp-back .bks-add { color: var(--bkc-black-ink); border-radius: 0 0 var(--r-2) 0; }
.bkp-back .bks-add:hover { background: rgba(244,244,244,.08); color: #FFFFFF; }
.bks.is-on .bkp-back .bks-add { background: var(--brand); color: #FFFFFF; }
.bks.is-on .bkp-back .bks-add:hover { background: var(--brand-deep); }

/* ══ SAMPLE STRIP — the site's "Photos" row ══════════════════════════════ */
.bkv3-strip-h { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.bkv3-title {
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--ink);
  font: 600 calc(15px * var(--text-scale, 1))/1 var(--font-sans); letter-spacing: -.005em;
}
.bkv3-title .bki { width: 15px; height: 15px; color: var(--brand); }
/* `align-items: start` is load-bearing: a grid item defaults to align-self
   stretch, which SETS a height and defeats `aspect-ratio` — measured on
   staging 2026-08-23, the six 16:10 stills came out as portrait slivers. */
.bkv3-strip {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-2);
  align-items: start;
}
@media (min-width: 620px) { .bkv3-strip { grid-template-columns: repeat(6, 1fr); } }
.bkv3-strip img {
  width: 100%; height: auto; aspect-ratio: 16 / 10; object-fit: cover; display: block;
  border-radius: var(--r-2); border: 1px solid var(--line); background: var(--bg-sunken);
}

/* ══ YOUR SHOOT — the order rail ═════════════════════════════════════════ */
.bkv3-rail .ad-sec-b { padding-top: var(--sp-1); }
.bkr-lines { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; }
.bkr-lines li { display: flex; justify-content: space-between; gap: var(--sp-3); font-size: calc(13.5px * var(--text-scale, 1)); }
.bkr-lines li > span:first-child { font-weight: 600; letter-spacing: -.01em; min-width: 0; }
.bkr-lines .n { font-weight: 500; font-variant-numeric: tabular-nums; color: var(--ink-2); white-space: nowrap; }
.bkr-lines li.is-sub { padding-left: 12px; }
.bkr-lines li.is-sub > span:first-child { font-weight: 400; color: var(--ink-3); }
.bkr-lines li.is-when > span:first-child { font-weight: 500; color: var(--ink-2); }
.bkr-empty { margin: 0; font-size: calc(13px * var(--text-scale, 1)); color: var(--ink-3); line-height: 1.5; }

.bkr-sums { margin: var(--sp-3) 0 0; padding-top: var(--sp-3); border-top: 1px solid var(--line); display: grid; gap: 6px; }
.bkr-row { display: flex; justify-content: space-between; gap: var(--sp-3); font-size: calc(13px * var(--text-scale, 1)); color: var(--ink-3); }
.bkr-row .n { font-variant-numeric: tabular-nums; color: var(--ink-2); }
.bkr-row.is-total {
  margin-top: 4px; padding-top: 8px; border-top: 1px solid var(--line);
  font-size: calc(14px * var(--text-scale, 1)); font-weight: 600; color: var(--ink);
}
.bkr-row.is-total .n { font-size: calc(19px * var(--text-scale, 1)); font-weight: 700; letter-spacing: -.03em; color: var(--ink); }
.bkr-fine { margin: var(--sp-2) 0 0; font-size: calc(12px * var(--text-scale, 1)); color: var(--ink-3); line-height: 1.5; }
.bkr-cta { margin-top: var(--sp-3); display: grid; gap: var(--sp-2); }
.bkr-cta .ad-btn { width: 100%; }
/* Dom 2026-08-23: white elements on the red buttons — text AND icon. */
.bkr-cta .ad-btn-primary, .bkr-cta .ad-btn-primary .bki { color: #FFFFFF; }
.bkr-cta .ad-btn .bki { width: 15px; height: 15px; margin-left: 6px; }
.bkr-miss { margin: 0; font-size: calc(12px * var(--text-scale, 1)); color: var(--ink-3); line-height: 1.5; }

/* ══ shared icon glyph ═══════════════════════════════════════════════════ */
.bkv3 .bki {
  display: inline-block; vertical-align: middle;
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}
.bkl-pop .bki { fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }


/* Per-photo quantity (Dom 2026-08-24): staging/twilight cards carry a count
   dropdown. It lives on the BLACK back now and is ALWAYS available there
   (Dom 2026-08-29) — on the front it only rendered once the card was already
   added, and since refresh() repaints in place it never actually appeared.
   House-styled select, 44px target, on the black face's palette. */
.bks-qtyrow {
  display: grid; gap: 6px;
  margin-top: var(--sp-3); padding-top: var(--sp-3);
  border-top: 1px solid var(--bkc-black-line);
  font: 500 calc(12.5px * var(--text-scale, 1))/1.2 var(--font-sans); color: var(--bkc-black-ink-2);
}
.bks-qtyrow select {
  width: 100%; min-height: 40px; padding: 0 10px;
  background: rgba(244,244,244,.06); color: var(--bkc-black-ink);
  border: 1px solid var(--bkc-black-line); border-radius: var(--r-2);
  font: 600 calc(13px * var(--text-scale, 1))/1 var(--font-sans);
}
.bks-qtyrow select option { background: var(--bkc-black); color: var(--bkc-black-ink); }
.bks-qtyrow select:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }


/* ══════════════════════════════════════════════════════════════════════════
   GRAPEVINE — the same screen, the GV catalogue (views/agent-book-gv.js).
   Dom 2026-08-29: "GV get the same pricing as on their booking flow… replace
   the services with what we have on our GV booking site and leave whatever is
   left", and the flip cards "identical on both ends so we dont have
   discrepencies."

   So there is NO new card here. The GV screen draws `.bks` — the same component
   as /book-shoot's singles — and the only additions below are the two states
   the CS screen has no use for: a COVERED tile (no Add, because there is
   nothing to add) and the builder's-plan swap toggle on the Floor Plan back.
   The purple is the tenant skin doing its job through --brand (html.is-gv,
   tokens.css); not one colour is written down here.
   ══════════════════════════════════════════════════════════════════════════ */

.gv-lede {
  margin: 0 0 var(--sp-4);
  font-size: calc(13.5px * var(--text-scale, 1)); line-height: 1.55; color: var(--ink-2);
  text-wrap: pretty;
}

/* ── a COVERED tile: included, still worth turning over ─────────────────────
   No ring and no tinted border — a covered card is not a SELECTED card, and
   six brand-edged tiles in a row read as six things the agent just clicked.
   The badge carries the state, and the card keeps its ordinary hover. */
.bks.is-covered .bks-p { font-weight: 600; letter-spacing: -.01em; color: var(--ink-2); }
/* A covered/carried card's foot is the word alone — the corner pip is the
   at-a-glance state, and a second badge repeating it truncated the word at 375
   (measured 2026-08-29). Kept as a class for the agency "Included" pill. */
.bks.is-covered .bks-foot, .bks.is-package .bks-foot { min-height: 38px; align-items: center; }
/* the builder's-plan swap, showing on the front */
.bks.is-swapped .bks-p { color: var(--ink-3); }

/* ── DIRECT MANIPULATION on the card front (Dom 2026-08-29) ───────────────
   Dom: "instead of reinventing do what we already have on GV booking page",
   and on the floor-plan swap: "deselecting is easier than clicking on the flip
   card to select builder floor plan — a bit badly planned."

   So the GV card front is the control, exactly as the live GV tile is
   (gv-4.28.10.js l.1519-1534: the whole `.svc` is role=button and one tap
   toggles). Three pieces, all mirroring that tile:
     .bks-hit    the stretched toggle   ← the tile's own click handler
     .bks-x      the corner + / − / ✓   ← the tile's `<span class="x">` (l.1953)
     .bks-qtybar the inline − n + row   ← the tile's `.qty` (l.1971), shown
                                          only once the service is on (l.1732)
   The flip survives as `.bks-info`, an explicit small target, because our card
   carries the long description the GV tile prints inline. No control is ever
   reachable only by turning the card. */
.bks-hit {
  position: absolute; inset: 0; z-index: 2;
  margin: 0; padding: 0; border: 0; background: none; cursor: pointer;
  border-radius: var(--r-2) var(--r-2) 0 0;
}
.bks-hit:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }

/* The corner pip. A span inside the hit area — never a button, which would be
   a button inside a button. The glyph is CSS content keyed off the state, the
   way the GV tile does it (l.1954-1955, l.1982). */
.bks-x {
  position: absolute; top: 8px; right: 8px; z-index: 3;
  width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center;
  font: 600 15px/1 var(--font-sans);
  background: rgba(10,10,10,.72); color: #FFFFFF;
  border: 1px solid rgba(255,255,255,.18);
  pointer-events: none;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.bks-x[data-badge="add"]::before     { content: "+"; }
.bks-x[data-badge="on"]::before      { content: "\2212"; }   /* − */
.bks-x[data-badge="covered"]::before { content: "\2713"; font-size: 13px; }  /* ✓ */
.bks-x[data-badge="swap"]::before    { content: "\21BA"; font-size: 14px; }  /* ↺ take ours back */
.bks-x[data-badge="on"], .bks-x[data-badge="covered"] {
  background: var(--brand); color: #FFFFFF; border-color: transparent;
}
.bks-x[data-badge="swap"] { background: var(--ink); color: var(--bg); border-color: transparent; }

/* The flip, demoted to an explicit affordance so the front can toggle.
   A 44px HIT BOX around a 26px circle — the GV tile's own arrangement for its
   corner control (l.1953-1954: a 44×44 `.x` whose `:before` is the 28px pill),
   and the shape that satisfies this portal's coarse-pointer touch law
   (main.css:8889, 44px minimum on every button) without a `.tap-exempt`
   escape hatch and without the button rendering as a 26×44 oval. */
.bks-info {
  position: absolute; top: 0; left: 0; z-index: 3;
  width: 44px; height: 44px; min-height: 44px; padding: 0;
  display: grid; place-items: center;
  border: 0; background: none; color: #FFFFFF; cursor: pointer;
}
.bks-info::before {
  content: ''; position: absolute; width: 26px; height: 26px; border-radius: 50%;
  background: rgba(10,10,10,.72); border: 1px solid rgba(255,255,255,.18);
  transition: background var(--t-fast) var(--ease);
}
.bks-info:hover::before { background: rgba(10,10,10,.92); }
.bks-info:focus-visible { outline: 2px solid var(--brand); outline-offset: -8px; border-radius: 50%; }
.bks-info .bki { position: relative; width: 14px; height: 14px; }

/* The inline quantity stepper — front, under the toggle's hit area so its own
   buttons are reachable, hidden until the service is on. */
.bks-qtybar {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  padding: 8px 11px; flex: none;
  border-top: 1px solid var(--line);
}
.bks-qtybar[hidden] { display: none; }
.bks-qlab { font: 500 calc(12px * var(--text-scale, 1))/1.2 var(--font-sans); color: var(--ink-3); }
.bks-qctl { display: inline-flex; align-items: center; gap: 6px; }
/* 44px, so the coarse-pointer law (main.css:8889) lands on a CIRCLE rather
   than stretching a 30px button into a 30×44 oval. GV's own stepper is 40
   (l.1972); 44 is that shape at this product's touch minimum. */
.bks-qctl button {
  flex: none;   /* never shrink into an oval in a narrow card */
  width: 44px; height: 44px; min-height: 44px; padding: 0; border-radius: 50%;
  border: 1px solid var(--line-strong); background: var(--bg); color: var(--ink);
  font: 600 15px/1 var(--font-sans); cursor: pointer;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.bks-qctl button:hover { background: var(--bg-hover); border-color: var(--brand); }
.bks-qctl button:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.bks-qv {
  min-width: 16px; text-align: center;
  font: 700 calc(13.5px * var(--text-scale, 1))/1 var(--font-sans);
  font-variant-numeric: tabular-nums; color: var(--ink);
}

/* A narrow card's foot must never let the price and the control collide —
   measured at 375 on 2026-08-29. The money is what gives way. */
.bks .bks-p { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.bks .bks-add { flex: none; }

/* ── the anchor price on an add-on card ────────────────────────────────── */
.bks-p s { font-weight: 500; color: var(--ink-4); margin-right: 3px; }
.bkp-back .bks-p s { color: rgba(244,244,244,.42); }

/* ── the rail's covered-set summary ────────────────────────────────────── */
.gv-covered-line {
  display: flex; align-items: flex-start; gap: 7px;
  margin: var(--sp-3) 0 0; padding-top: var(--sp-3); border-top: 1px solid var(--line);
  font-size: calc(12px * var(--text-scale, 1)); line-height: 1.5; color: var(--ink-3);
}
.gv-covered-line .bki { width: 13px; height: 13px; flex: none; margin-top: 2px; color: var(--brand); }
.gv-covered-line b { color: var(--ink-2); font-weight: 600; }

/* "optional" beside a field label — the label row is already uppercase meta,
   so this is the same row at a lighter weight, not a second type style. */
.bkv3 .bk-f > span i { font-style: normal; font-weight: 400; color: var(--ink-4); }

/* The GV screen's polite live region — gv-4.28.10.js announce() (l.1488). A tap
   that only moves a corner pip still has to be audible. Off-screen, never
   display:none, or a screen reader stops announcing it. */
.gv-sr {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* At 375 a 2-up service card is ~127px wide, and a foot carrying "$225 $175
   + HST" beside an Add button cannot fit both — measured in the browser
   2026-08-29. The money takes its own row and the control goes full width,
   which is the ordinary mobile answer and keeps every price readable.
   Scoped to the GV grids: the /book-shoot singles are an approved screen this
   lane does not own. */
@media (max-width: 460px) {
  #gv-included .bks-foot, #gv-addons .bks-foot, #gv-extras .bks-foot {
    flex-direction: column; align-items: stretch; gap: 0;
  }
  #gv-included .bks-p, #gv-addons .bks-p, #gv-extras .bks-p {
    padding: 8px 11px 0; overflow: visible; text-overflow: clip;
  }
  #gv-included .bks-add, #gv-addons .bks-add, #gv-extras .bks-add {
    justify-content: space-between; width: 100%;
  }
  #gv-included .bks-qtybar, #gv-addons .bks-qtybar, #gv-extras .bks-qtybar {
    flex-direction: column; align-items: stretch; gap: 6px;
  }
  #gv-addons .bks-qctl, #gv-extras .bks-qctl { justify-content: space-between; }
}
