/* dj.css — page-scoped additions for book-a-dj.html (agent C). Loads after site.css and home.css; consume tokens, never redefine them. KIT 2026-09-13.
   Evolve pass 2026-09-13: the wizard becomes the site's console — a glass panel with corner brackets standing on a lit floor,
   lit tier cards, a machined progress rail and a running total that counts. Additions only: the flow, the prices and the
   availability wording are untouched. */

/* ── 1 · the floor the console stands on ────────────────────────────────────────
   Desktop only (atmosphere layers never ship to phones — the plate is never fetched
   under 900px): the sanctioned wizard-floor plate, masked to black well before the
   panel ends so no crop edge or contrast loss ever reaches the copy. */
@media (min-width: 900px) {
  body[data-page="dj"] main { position: relative; isolation: isolate; }
  /* dj-09: home.css:270 selects `main:has(#dj-wizard)::before`, and :has() donates the id's weight —
     a plain `body[data-page="dj"] main::before` loses every conflicting property to it, so the scrim
     and the mask below were dead code. Match the :has() so this rule wins, and state opacity because
     specificity only arbitrates declared properties (home.css's .16 would otherwise still apply). */
  body[data-page="dj"] main:has(#dj-wizard)::before {
    content: ""; position: absolute; left: 0; right: 0; top: 0; bottom: auto; height: 940px; opacity: 1; z-index: -1; pointer-events: none;
    background-image:
      linear-gradient(180deg, rgba(0,0,0,.56) 0%, rgba(0,0,0,.74) 46%, rgba(0,0,0,.93) 78%, #000 100%),
      url("../media/atmos/atmos-wizard.jpg");
    background-size: cover, cover;
    background-position: center top, center 30%;
    background-repeat: no-repeat;
    -webkit-mask-image: linear-gradient(180deg, #000 0, #000 56%, transparent 100%);
    mask-image: linear-gradient(180deg, #000 0, #000 56%, transparent 100%);
  }
}

/* ── 2 · the console panel ──────────────────────────────────────────────────────
   The shell carries the glass and the brackets (::before and ::after, never .xe-lit
   with .xe-brackets); the step inside is the face, so no box sits inside a box. */
/* --sh-3 is the hero-adjacent panel shadow: the same drops as --sh-2 plus a white bloom at .08.
   This panel is the page's one decision surface, so it gets the bloom. */
.wizard.xe-glass { margin-top: clamp(18px, 3vw, 28px); box-shadow: var(--sh-3); }
.wizard .step { background: transparent; border: 0; box-shadow: none; }
/* the blur budget: the package step runs ~3.8k px tall and a full-height backdrop
   repaint is the one real jank hazard on this page. It keeps the glass fill, border
   and shadow; only the blur steps aside (behind it there is pure black anyway). */
.wizard.xe-glass:has(.pkg) { -webkit-backdrop-filter: none; backdrop-filter: none; }
/* the sticky action shelf blends into the glass instead of into the old flat ink.
   dj-05: the fade is measured in pixels, not percentages. The shelf is 78px on desktop but 161px on a
   phone (Back / running total / CTA stack to three rows), so percentage stops put the solid band 87px
   down — below the whole Back button, and a tier photo and its price read straight through the pill.
   A 26px ramp with 28px of padding above the first control puts every control on opaque ink at both
   shelf heights. */
.wizard .step:has(.pkg) .step-actions {
  padding-top: 28px;
  background: linear-gradient(180deg, rgba(13,13,13,0) 0, rgba(13,13,13,.86) 14px, rgb(13,13,13) 26px, rgb(13,13,13) 100%);
  box-shadow: 0 -1px 0 rgba(255,255,255,.06);
}

/* ── 3 · the progress rail, machined ────────────────────────────────────────────
   --edge on the track (the top light-strike), the fill keeps its light. Both are set,
   never tweened: only the fill's transform moves. */
.wizard .progress .fill { box-shadow: 0 0 12px rgba(255,255,255,.55), 0 0 34px rgba(255,255,255,.25); }

/* ── 4 · tier cards as lit controls ─────────────────────────────────────────────
   Every card carries .xe-lit (the corner-lit hairline, markup side); the checked one
   adds the machined bevel and a white bloom so the chosen package reads as switched on.
   The existing ring, the champagne border on photo cards and every price stay as they are. */
.wizard .pkg[data-checked="true"] {
  box-shadow: inset 0 0 0 1px var(--accent), var(--bevel), 0 20px 48px -28px rgba(255,255,255,.55);
}
.wizard .pkg.has-photo[data-checked="true"] {
  box-shadow: inset 0 0 0 1px var(--accent), var(--bevel), 0 20px 48px -28px rgba(255,255,255,.42);
}
/* The tier radio is visually hidden but it is still the hit target. At 1px it sat in the card's
   top-left corner, and once the cards went two-across (dj-10) a card's corner can scroll under the
   sticky shelf, which then swallows the click. Filling the card makes the card the control. */
.wizard .pkg input { inset: 0; width: auto; height: auto; min-height: 0; margin: 0; cursor: pointer; }
.wizard .pkg:active { transform: scale(.99); }
.wizard .pkg:focus-within { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ── 5 · answer chips ───────────────────────────────────────────────────────────
   .xe-lit rides on the span (the control), so the hairline follows its radius; the
   checked chip takes the same bevel as the primary — light on an object, no halo. */
.wizard .choice span { transition: transform var(--t-fast) var(--ease-spring), border-color var(--t-fast), background var(--t-fast); }
.wizard .choice span:active { transform: scale(.97); }
/* dj-11: the bevel-only override used to out-specify the kit rule (site.css:303 = bevel + the white
   bloom) and left this wizard's pressed chip different from the one on technical-setup.html. The kit
   rule owns the pressed state now; only the .xe-lit hairline is still cancelled on the white fill. */
.wizard .choice input:checked + span::after { opacity: 0; }

/* ── 6 · extras: the selected row lights, the rest stay quiet ───────────────────*/
.wizard .extra { transition: border-color var(--t-fast), background var(--t-fast); }
.wizard .extra:hover { border-color: var(--faint); }
/* dj-12: the ticked row takes the machined bevel, not a 20-point border nudge. */
.wizard .extra:has(input:checked) { border-color: var(--hair); box-shadow: var(--bevel), var(--edge); }
.wizard .extra:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
/* dj-12: the extras were the only controls left wearing the UA checkbox — a grey rounded square, and
   the brightest non-white object on a console built out of --edge and --bevel. Same box, drawn in the
   kit's own material: ink at rest, the white key when pressed. No transition: the tick is a state. */
.wizard .extra input {
  -webkit-appearance: none; appearance: none;
  width: 20px; height: 20px; border-radius: 6px;
  border: 1px solid var(--line-strong); background: var(--ink-2); box-shadow: var(--edge);
}
.wizard .extra input:checked { background: var(--accent); border-color: var(--accent); box-shadow: var(--bevel); }
.wizard .extra input:checked::after {
  content: ""; display: block; width: 10px; height: 6px; margin: 3px auto 0;
  border-left: 2px solid var(--ink-0); border-bottom: 2px solid var(--ink-0);
  transform: rotate(-45deg);
}
.wizard .extra input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* dj-04: on a 390px row the nowrap price column ate 168px of 316px and starved the label to 75px —
   the included rows ran to eight one-word lines and the row's min-content set the document's minimum
   width (a real 320px overflow with Diamond selected). Under 560px the price drops to its own line
   under the label and is allowed to wrap. */
@media (max-width: 560px) {
  .wizard .extra { grid-template-columns: auto minmax(0, 1fr); row-gap: 4px; align-items: start; }
  .wizard .extra > input, .wizard .extra > .inc-mark { margin-top: 3px; }
  .wizard .extra .price { grid-column: 2; justify-self: start; white-space: normal; }
}

/* ── 7 · the running total ──────────────────────────────────────────────────────
   The live number in the shelf: the figure counts on change (dj.js, 850ms cubic-out),
   so it needs room and a fixed width — tabular already, now sized to be read across the panel. */
/* dj-13: the live figure is the thing the whole step exists to produce, and it was rendering at
   16.32px against a 25.6px tier price on the card behind it — the same size as button text, so it
   read as a caption. It takes the display face at 1.5rem; the tier name and "incl VAT" stay quiet. */
.wizard .step:has(.pkg) .step-actions .running { display: inline-flex; align-items: baseline; gap: 8px; flex-wrap: wrap; font-size: .78rem; }
.wizard .step:has(.pkg) .step-actions .running b {
  font-family: var(--font-display); font-weight: 800; font-size: 1.5rem;
  letter-spacing: -.02em; font-variant-numeric: tabular-nums;
}
.wizard .step:has(.pkg) .step-actions .running .run-tier { color: var(--text); font-weight: 600; }
.wizard .step:has(.pkg) .step-actions .running .run-unit { color: var(--faint); }
@media (max-width: 560px) {
  .wizard .step:has(.pkg) .step-actions { gap: 8px; }
  .wizard .step:has(.pkg) .step-actions .running { margin-left: 0; width: 100%; }
}

/* ── 8 · the page head reads as a section head ─────────────────────────────────*/
.page-head .eyebrow[data-n] { display: inline-flex; align-items: center; }
body[data-page="dj"] .page-head .lede { max-width: 60ch; }

/* ── 9 · the grids stop laddering on a wide screen ──────────────────────────────
   dj-10: auto-fit put six tier cards 3-across at 223px inside a 760px console, which wrapped every
   ex-VAT line ("R 34 449 excl VAT · till" / "3 AM") and ran the bullet lists to ten lines each.
   Two columns give 341px cards: the ex-VAT line fits, the bullets settle.
   dj-23: six event-type chips on a four-column auto-fill left a two-column hole on row two. */
@media (min-width: 900px) {
  .wizard .packages.tiers { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .wizard .choices { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ── 10 · the tier rig reads as a list, not a run-on ────────────────────────────
   dj-20: each rig segment is a middot-delimited run that wrapped into 2–4 lines with the separators
   landing mid-line, where they stop separating anything. Same data, one item per line. */
.wizard .tier-seg .seg-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 3px; color: var(--muted); font-size: .9rem; line-height: 1.5; }
/* one item per line makes the segments very uneven (Lights & FX runs to 13, Canapés to 2), and a grid
   row is as tall as its tallest cell — which opened a hole beside it. Columns let them flow instead. */
@media (min-width: 900px) {
  .wizard .tier-detail .tier-segs { display: block; columns: 2; column-gap: clamp(18px, 2.4vw, 28px); }
  .wizard .tier-detail .tier-seg { break-inside: avoid; margin: 0 0 14px; }
}

/* ── 11 · the capacity cap clears AA on every plate ─────────────────────────────
   dj-08: the champagne cap sits 44px down, inside the scrim's .38–.56 band. On Platinum's stage-snow
   plate that backdrop measures rgb(128,125,117) and the label lands at 2.54:1 on an 11.8px mono line.
   Rather than darken all six photos (which flattens the photo-forward direction), the cap takes its
   own small plate: the capacity reads as a tag, and the backdrop drops to ~rgb(40,38,36) — about 9:1. */
.wizard .pkg.has-photo .cap {
  justify-self: start;
  padding: 4px 9px;
  border-radius: var(--r-pill);
  background: rgba(6, 5, 3, .72);
  box-shadow: var(--edge);
  text-shadow: none;
}

/* ── 12 · the answer panel: light on the object, never a halo on type ───────────
   dj-03: site.css:301 puts --glow-text on .answer.ok .status — a 44px bloom on the funnel's largest
   display sentence, which is exactly the tell Wayne had removed ("glowing" = light on objects). The
   light moves onto the panel, where it is set and never tweened.
   dj-01 / dj-17: green is the site's available/full semantic. The wizard makes no free/busy claim
   while the calendar feed is empty, and the done screen says in words that nothing has reached the
   desk yet — so neither takes the green panel any more. This is the neutral state they fall to. */
.wizard .answer { box-shadow: var(--sh-2); }
.wizard .answer.ok .status { text-shadow: none; }
.wizard .answer.ok { box-shadow: var(--sh-2), 0 0 40px -18px rgba(255, 255, 255, .45); }
.wizard .answer:not(.ok):not(.limited):not(.full) { border-color: var(--line-strong); }
.wizard .answer:not(.ok):not(.limited):not(.full) .dot { background: var(--accent); box-shadow: 0 0 0 5px var(--accent-soft); }

/* ── 13 · the done screen keeps one lit action ──────────────────────────────────
   dj-02: the terminal screen of the funnel had no lit object at all. Before the desk endpoint is
   live the WhatsApp button IS the delivery channel, so it takes the white light (on the object, at
   the primary's strength minus a third so the green still reads as WhatsApp) and "Start again" is
   demoted to a quiet ghost. In the delivered state the button is optional and stays quiet. */
.wizard .step[data-delivered="false"] .btn-wa {
  box-shadow: var(--bevel), 0 0 18px rgba(255, 255, 255, .30), 0 0 56px rgba(255, 255, 255, .16);
}
.wizard .step[data-delivered] .btn-ghost { --bd: var(--line); --fg: var(--muted); }

/* ── 14 · the summary's invalid state points at the offending field ─────────────
   dj-07: site.css:136 reddens every input inside the .field, so a correct name and an empty optional
   email were both flagged on the site's only submit. dj.js now sets aria-invalid per input; the red
   follows the flag. */
.wizard .field[data-invalid="true"] input:not([aria-invalid="true"]) { border-color: var(--line-strong); }
