/* snapit2share — booth layout.
 *
 * Everything here is the geometry the previous build arrived at the hard way: the stage sized in
 * JavaScript rather than viewport units, the sticky action bar, the step machine, and the rotated
 * column. The colours come from styles.css.
 *
 * ORDER MATTERS IN THIS FILE. The orientation blocks are last because they override .actions,
 * #frames and main, all defined above; placed earlier they silently did nothing.
 */

/* ── the page ──────────────────────────────────────────────────────────────────
   The booth is a column: a bar, a main that grows, and a sticky action row at the bottom. These
   rules were lost when this file was split out of the original stylesheet, and the symptom was a
   booth that looked right on a phone and sprawled edge-to-edge on a laptop with nothing centred. */

body {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  -webkit-text-size-adjust: 100%;
}

main {
  flex: 1 0 auto;
  display: flex; flex-direction: column; gap: 14px;
  width: 100%; max-width: 560px; margin-inline: auto;
  padding: 16px 16px 24px;
}

/* 560px is a phone's worth of column, which is what the booth is even on a desktop - the frame
   should not stretch to 1200px just because the window can. The bar and footer keep the same
   measure so the whole page reads as one column rather than a stripe across a wide screen. */
.bar > .wrap, .foot > .wrap { width: 100%; max-width: 560px; margin-inline: auto; }

.bar {
  display: block;
  padding: 0 16px; border-bottom: 1px solid var(--line); background: var(--paper);
}
.bar > .wrap { display: flex; align-items: center; gap: 12px; min-height: 60px; padding: 8px 0; }
/* The brand shrinks to its mark when the event name needs the room — which on a 375pt phone with
   a long event name is always. The name is still in the accessible name of the link. */
.bar .brand {
  display: flex; align-items: center; gap: 8px; flex: 0 0 auto;
  font-family: var(--display); font-weight: 600; font-size: 1rem;
  color: var(--ink); text-decoration: none;
}
.bar .brand .dot {
  width: 28px; height: 28px; border-radius: 9px; background: var(--coral); color: #fff;
  display: grid; place-items: center; font-size: .95rem; flex: 0 0 auto;
}
.bar .brand-name { display: none; }
@media (min-width: 480px) { .bar .brand-name { display: inline; } }

/* A divider, so the brand and the event name read as two things rather than one long title. */
.bar-text { border-left: 1px solid var(--line); padding-left: 12px; }
.bar-text { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.bar-text strong {
  font-family: var(--display); font-size: 1.02rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bar-text span { color: var(--muted); font-size: .8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Except on the arrival screen, where both lines were being cut - "Ganesh Chaturthi 2026…" over
   "Shree Radheshyam Mandir, Ma…". This is the one screen where a guest checks they are in the right
   place, and it is also the one screen with room to spare: everywhere else they are looking at the
   frame, and a taller header would come straight out of it. */
body[data-step="details"] .bar-text strong,
body[data-step="details"] .bar-text span {
  white-space: normal; text-overflow: clip; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden;                     /* line-clamp does nothing without this */
}

.back[hidden] { display: none; }
.qr-chip {
  margin-left: auto; font-size: .75rem; font-weight: 700; letter-spacing: .03em;
  color: var(--on-mint); background: var(--mint-tint);
  padding: 5px 12px; border-radius: var(--pill); white-space: nowrap;
}
.foot { padding: 16px; color: var(--muted); font-size: .8125rem; text-align: center; border-top: 2px solid var(--line); }
.foot a { color: var(--muted); }
main h1 { font-size: 1.3rem; }
.hint { font-size: .875rem; color: var(--muted); margin: 0; }
.label-note { font-weight: 600; color: var(--muted); font-size: .8125rem; }

/* ── stage ─────────────────────────────────────────────────────────────────── */

#stage {
  position: relative;
  background: #0d0d10;
  border-radius: var(--r-tile);
  overflow: hidden;
  user-select: none;
  display: grid;
  place-items: center;
  /* The stage is the biggest thing on screen, so whatever it does with touch decides whether the
     page can be scrolled at all. Before there is a photo there is nothing to pan, so it must not
     swallow the gesture - doing so left the shutter unreachable on a phone: the finger lands here,
     tries to scroll, and nothing moves. */
  touch-action: pan-y;
  width: 100%;             /* replaced by sizeStage() with the frame's exact width */
  margin-inline: auto;
}

/* Height is set by sizeStage() to exactly what the frame needs; this is only the starting value
   for the moment before the first measurement. */
#stage { height: 46vh; }

/* Explicit width and height come from sizeStage(). The max rules stay only as a floor for the
   first paint: max-width and max-height together do not reliably contain a canvas, which is what
   cropped the portrait frames. */
#canvas { display: block; max-width: 100%; }

/* ── frame strip ───────────────────────────────────────────────────────────── */

.frames {
  display: flex; gap: 8px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: 4px;
  -webkit-overflow-scrolling: touch;
}
.frame-chip {
  flex: 0 0 auto;
  scroll-snap-align: start;
  width: 84px;
  background: var(--surface);
  border: none;
  border-radius: 12px;
  padding: 4px;
  cursor: pointer;
  font: inherit;
  color: var(--muted);
  box-shadow: 0 6px 14px rgb(43 36 64 / .08);
  min-height: 0;                        /* the 50px floor on `button` would distort the strip */
}
/* One box for every chip whatever the frame's shape, with the artwork contained inside it. A strip
   where a 2:1 frame sits beside a 3:2 one is otherwise visibly ragged. */
.frame-chip img {
  display: block; width: 100%; aspect-ratio: 1 / 1;
  object-fit: contain; border-radius: var(--r-thumb); background: var(--peach); padding: 3px;
}
/* Board: a 3px coral ring plus a coral-tinted shadow, not a border - a border would
   resize the chip and shuffle the whole strip on every selection. */
.frame-chip.is-selected { color: var(--ink); box-shadow: 0 0 0 3px var(--coral), 0 6px 14px rgb(255 122 77 / .3); }

/* ── actions ───────────────────────────────────────────────────────────────── */

/* Sticky, so the primary control is reachable whatever else is on the page. Banners, a long event
   name or a fourth frame must never be able to push the shutter off the bottom of the screen. */
.actions {
  display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
  position: sticky; bottom: 0; z-index: 4;
  margin-top: auto;
  /* Inside main now (event.html), across main's own padding, so it is as wide as it was outside. */
  margin-inline: -16px;
  padding: 10px 0 calc(10px + env(safe-area-inset-bottom));
  background: var(--paper);
  border-top: 1px solid var(--line);
}
/* ...and as low: main's foot padding was below the bar when it sat outside, and the step above it
   ended 24px clear of it, not main's 14px gap. */
body:is([data-step="pick"], [data-step="camera"], [data-step="adjust"], [data-step="done"]) main { padding-bottom: 0; }
.step[data-for="done"] { margin-bottom: 10px; }

/* Board: buttons are Fredoka 600, radius 16px, 2px border on the secondary, coral glow on the
   primary and nothing else. Height is 52 on the board and 50 here - this bar has up to three
   controls across a 375pt phone, and 54 wraps them. */
button, .upload span {
  font-family: var(--display); font-weight: 600; font-size: 1rem;
  cursor: pointer; border-radius: var(--r-btn);
  padding: 13px 22px; border: 2px solid transparent;
  min-height: 50px;                    /* thumb-sized: this is used one-handed, in a queue */
}
.primary { background: var(--coral); color: var(--on-coral); box-shadow: var(--glow); }
.primary:hover { background: var(--coral-hover); }
.ghost { background: var(--surface); color: var(--ink); border-color: var(--line); }
.ghost:hover { border-color: var(--line-active); }
button:disabled { opacity: .6; cursor: default; }

.upload { position: relative; display: inline-block; }
.upload input { position: absolute; inset: 0; opacity: 0; width: 100%; cursor: pointer; }
.upload span { display: inline-block; background: var(--surface); border: 2px solid var(--line); }

.shutter {
  width: 72px; height: 72px; border-radius: 50%; padding: 0;
  box-shadow: inset 0 0 0 4px #fff, 0 0 0 3px var(--coral);
}

/* ── review ────────────────────────────────────────────────────────────────── */

.review { display: none; flex-direction: column; gap: 6px; }
.review label { font-size: .8rem; text-transform: uppercase; letter-spacing: .07em; color: var(--muted); }
#caption {
  -webkit-appearance: none; appearance: none;
  -webkit-text-fill-color: var(--ink);   /* iOS ignores `color` on some inputs without this */
  font: inherit; font-size: 1rem; line-height: 1.45;
  padding: 12px; border: 1px solid var(--line);
  border-radius: 14px; resize: vertical; background: var(--paper); color: var(--ink);
  min-height: 5.5em; width: 100%;
}
.label-note { font-weight: 400; text-transform: none; letter-spacing: 0; color: var(--muted); }
/* The credit added after the caption (phase 9 step 3): said where the words are, never added unseen. */
.caption-credit { margin-top: 4px; }

/* ── bhav picker ────────────────────────────────────────────────────────────
   Both live inside .step[data-for="done"], which sizeStage() measures whole - so the frame gives up
   exactly the height these take and nothing has to be told about them separately.

   Six chips wrap to three rows at 320px. That was measured against the real labels rather than
   guessed, and it is why the labels are short: "Little one's first", not "Little one's first
   Ganpati", which would take a row to itself. */
/* ── reel (experimental) ───────────────────────────────────────────────────── */
.reel-toggle {
  font-family: var(--display); font-weight: 600; font-size: .9rem;
  padding: 11px 16px; margin-bottom: 12px; width: 100%;
  border-radius: var(--r-btn, 16px); border: 2px solid var(--line);
  background: var(--surface); color: var(--ink); cursor: pointer;
}
.reel-toggle[aria-pressed="true"] { background: var(--coral); border-color: var(--coral); color: var(--on-coral); }
.reel-toggle[disabled] { opacity: .55; }
/* Shown and hidden by its `hidden` attribute alone (booth.js showReel): `[hidden]` wins site-wide,
   so a state rule here could never show it - and did not, until phase 8 (check-site now refuses one). */
#reel-video {
  display: block; width: 100%; max-width: 100%; margin: 0 auto;
  border-radius: var(--r-tile, 18px); background: #0d0d10;
}
body[data-step="done"].reel-mode #stage-wrap { display: none; }

/* The one box (FR-8, D6.7; the canvas's BoothConsent): a card the whole of which is the label, so
   the tap target is the sentence, not a 24px square. Red, with its sentence, when details were
   typed and it was left unticked. */
.consent-card {
  margin: 4px 0 6px; padding: 14px 16px;
  background: var(--surface); border: 2px solid var(--line); border-radius: var(--r-tile, 18px);
}
.consent-card.invalid { border-color: var(--error); }
.consent-card .consent { margin: 0; font-size: .9rem; font-weight: 400; color: var(--ink); cursor: pointer; }
.consent-card .consent strong { font-weight: 800; }
.consent-card .consent input:focus-visible { outline: 3px solid var(--coral); outline-offset: 2px; }
.consent-card .consent-deletes { margin: 8px 0 0 35px; }
.consent-card .error:not(:empty) { margin: 8px 0 0 35px; }
/* "No thanks, just the photo": a real button, quieter than Continue, never hidden behind it. */
.lead-skip {
  display: block; width: 100%; min-height: 44px; margin: 6px 0 0; padding: 10px;
  background: none; border: 0; cursor: pointer;
  font: inherit; font-weight: 700; font-size: .95rem; color: var(--ink);
}
.under-18 { margin: 2px 0 0; text-align: center; }

.field-label {
  display: block; font-size: .8rem; text-transform: uppercase; letter-spacing: .07em;
  color: var(--muted); margin-bottom: 6px;
}
.bhavs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.bhav-chip {
  font: inherit; font-size: .8rem; font-weight: 700; line-height: 1;
  padding: 9px 12px; border-radius: var(--pill, 999px);
  border: 2px solid var(--line); background: var(--surface); color: var(--ink);
  cursor: pointer; white-space: nowrap;
  transition: background-color .12s ease, border-color .12s ease, color .12s ease;
}
.bhav-chip:hover { border-color: var(--line-active); }
.bhav-chip[aria-pressed="true"] {
  background: var(--coral); border-color: var(--coral); color: var(--on-coral);
  box-shadow: 0 5px 12px rgb(255 122 77 / .32);
}
@media (prefers-reduced-motion: reduce) { .bhav-chip { transition: none; } }
.hint { font-size: .8rem; color: var(--muted); margin: 2px 0 0; }

/* Where there is no share sheet, do not offer a button that can only apologise. */
body.no-share #download { background: var(--coral); color: var(--on-coral); font-weight: 600; border-color: transparent; }

/* ── step switching ───────────────────────────────────────────────────────── */

/* Everything is hidden by default and each step names what it wants. Opt-in rather than opt-out:
   a control that appears at the wrong moment is then a missing line rather than a forgotten one. */
.step { display: none; flex-direction: column; gap: 8px; }
body[data-step="closed"]  .step[data-for="closed"],
body[data-step="details"] .step[data-for="details"],
body[data-step="mode"]    .step[data-for="mode"],
body[data-step="pick"]    .step[data-for="pick"],
body[data-step="done"]    .step[data-for="done"] { display: flex; }

#take-selfie, .upload, #shutter, #flip, #use-photo,
#share, #download, #copy-caption, #retake,
#stage-wrap, #frames, #adjust-hint, #rotate-hint, .actions { display: none; }

body[data-step="pick"]   #stage-wrap,
body[data-step="camera"] #stage-wrap,
body[data-step="adjust"] #stage-wrap,
body[data-step="done"]   #stage-wrap { display: block; }

body[data-step="pick"] #frames { display: flex; }

body[data-step="pick"]   .actions,
body[data-step="camera"] .actions,
body[data-step="adjust"] .actions,
body[data-step="done"]   .actions { display: flex; }

body[data-step="pick"] #take-selfie,
body[data-step="pick"] .upload { display: inline-block; }

body[data-step="camera"] #shutter,
body[data-step="camera"] #flip { display: inline-block; }

body[data-step="adjust"] #use-photo { display: inline-block; }
body[data-step="adjust"] #adjust-hint { display: block; }
body[data-step="pick"]   #rotate-hint:not([hidden]),
body[data-step="camera"] #rotate-hint:not([hidden]) { display: block; }
#rotate-hint { color: var(--coral-deep); font-weight: 600; }

body[data-step="done"] #download,
body[data-step="done"] #copy-caption,
body[data-step="done"] #retake { display: inline-block; }

/* The photo is taken by now, so the preview can give up height to the caption and the buttons -
   all three have to be on screen together, or the flow stalls at the moment it succeeds. */
@media (max-height: 700px) {
  body[data-step="done"] .frame-chip span { display: none; }
  body[data-step="done"] #share-hint { display: none; }
  main { gap: 10px; padding-top: 10px; }
  /* The caption options wrap, every one in view (owner, 1 Oct 2026: a row that scrolled sideways
     hid the options past the edge, and guests did not find them). On a short screen the chips are
     smaller, so the rows they take leave the caption on screen. */
  body[data-step="done"] .bhavs { gap: 5px; margin-bottom: 8px; }
  body[data-step="done"] .bhav-chip { font-size: .75rem; padding: 7px 10px; }
  /* ...and the caption box shorter: three and a half lines, scrolling inside, all of it on screen. */
  body[data-step="done"] #caption { min-height: 3.5em; height: 3.5em; padding: 9px 12px; }
}

/* Only once there is a photo does dragging mean "move it" rather than "scroll the page". */
body[data-step="adjust"] #stage,
body[data-step="done"]   #stage { touch-action: none; }

/* ── back button and step headings ────────────────────────────────────────── */

.back {
  min-height: 40px; width: 40px; padding: 0; border-radius: 50%;
  border: 1px solid var(--line); background: transparent; color: var(--ink);
  font-size: 1.5rem; line-height: 1; flex: 0 0 auto;
}
.back[hidden] { display: none; }

main h1 { font-size: 1.25rem; margin: 0; }

/* ── mode cards ───────────────────────────────────────────────────────────── */

.modes { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 4px; }
.mode-card {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 20px 12px; border: 2px solid var(--line); border-radius: var(--r-tile);
  background: var(--surface); color: var(--ink); cursor: pointer; min-height: 140px;
  justify-content: center; box-shadow: var(--shadow);
}
.mode-card:hover:not(:disabled) { border-color: var(--line-active); }
.mode-card:disabled { opacity: .4; cursor: not-allowed; }
.mode-card strong { font-size: 1rem; }
.mode-card small { color: var(--muted); font-size: .8125rem; font-weight: 700; }
.mode-shape { display: block; border: 3px solid var(--coral); border-radius: 6px; }
.mode-shape.portrait  { width: 44px; height: 58px; }
.mode-shape.landscape { width: 58px; height: 40px; }

/* ── dialog ────────────────────────────────────────────────────────────────── */

dialog {
  border: none; border-radius: var(--r-card); padding: 26px;
  max-width: 420px; width: calc(100% - 32px);
  color: var(--ink); background: #fff;
}
dialog::backdrop { background: rgb(0 0 0 / .55); }
dialog h2 { margin: 0 0 4px; font-size: 1.15rem; }
.lead-intro { margin: 0 0 16px; color: var(--muted); font-size: .92rem; }

/* Board: label Nunito 700 - 13px; field 52px, radius 14, 2px border, cream fill, active border
   #ffd9c9. Same as the marketing forms, with tighter margins - this form is the one thing between
   a guest and the camera, and every reclaimed pixel keeps the submit button above the fold. */
.field { margin-bottom: 14px; display: flex; flex-direction: column; gap: 7px; }
.field label { font-size: .8125rem; font-weight: 700; color: var(--muted); }
.field input {
  -webkit-appearance: none; appearance: none;
  -webkit-text-fill-color: var(--ink);
  font-family: var(--text); font-weight: 600;
  font-size: 16px;                       /* below 16px iOS zooms the page on focus */
  padding: 13px 15px; border: 2px solid var(--line);
  border-radius: 14px; background: var(--paper); color: var(--ink); min-height: 52px;
}
.field input:focus { border-color: var(--line-active); outline: 2px solid var(--coral); outline-offset: 1px; }
/* Same trap as styles.css: -webkit-text-fill-color on the input beats `color` here. The booth has
   no placeholders today, but lead fields come from events.json and an event that adds one would
   otherwise get ink-black placeholder text that reads as a pre-filled value. */
.field input::placeholder {
  color: var(--placeholder);
  -webkit-text-fill-color: var(--placeholder);
  font-weight: 600;
}
.field abbr { color: var(--coral); text-decoration: none; }

/* The drawn checkbox from board 2. The real <input> stays, so the label, the focus ring and every
   keyboard behaviour remain the browser's rather than a reimplementation of them. */
.consent { display: flex; gap: 11px; align-items: flex-start; font-size: .8125rem; line-height: 1.5; font-weight: 600; color: var(--muted); margin: 8px 0 6px; }
.consent input {
  -webkit-appearance: none; appearance: none;
  margin: 1px 0 0; width: 24px; height: 24px; flex: 0 0 auto; cursor: pointer;
  border: 2px solid var(--line); border-radius: 8px; background: var(--surface);
}
.consent input:checked {
  background: var(--coral) no-repeat center/14px
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232b2440' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
  border-color: var(--coral);
}

/* The booth's red, through the token styles.css draws every .error with (its colour wins over any
   "p" rule, !important there). */
:root { --error: #B3261E; }
.error { font-size: .8125rem; font-weight: 700; margin: 2px 0 0; min-height: 1em; }
/* Reserve the line only when there is something to say. Three empty error slots cost ~50px, which
   on a 667pt phone is the difference between the submit button being reachable and not. */
.error:empty { min-height: 0; margin: 0; }
.fine { font-size: .8125rem; color: var(--muted); margin: 12px 0 0; }

/* The privacy promise, given a panel instead of being the smallest grey text on the page. */
.assurance {
  display: flex; gap: 10px; align-items: flex-start;
  margin-top: 14px; padding: 12px 14px;
  background: var(--mint-tint); color: var(--on-mint);
  border-radius: var(--r-input, 14px);
}
.assurance b { font-weight: 800; }
.assurance-icon { flex: 0 0 auto; width: 20px; height: 20px; margin-top: 1px; }
.assurance-icon path { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linejoin: round; }
.assurance-icon .tick { stroke-linecap: round; }
#lead-submit { width: 100%; margin-top: 8px; }

/* The camera element has to be in the document to decode, but must never be seen. Clipped rather
   than display:none, which would stop it rendering and leave videoWidth at 0. */
.offscreen-video {
  position: absolute; width: 1px; height: 1px;
  opacity: 0; pointer-events: none; clip-path: inset(50%);
}

/* ── misc ──────────────────────────────────────────────────────────────────── */

.warning {
  margin: 0; padding: 12px 14px; background: var(--sunny-tint);
  border: 2px solid var(--sunny); border-radius: var(--r-input); font-size: .875rem; font-weight: 600; color: var(--on-sunny);
}
.warning.dryrun { background: var(--sky-tint); border-color: var(--sky); color: var(--on-sky); }

/* Share floats above everything on the result step. It is the action the booth exists to reach;
   it should not compete for width with Download and Copy caption in the same row. */
/* Anchored to the column's right edge, not the window's: on a wide screen the share button was
   floating alone in the margin, a third of a screen away from the photo it belongs to. */
.fab {
  display: none;
  position: fixed;
  right: max(16px, calc(50vw - 264px));
  /* Clear of the sticky bar, not on top of it - at 76px it sat across "Start again". */
  bottom: calc(96px + env(safe-area-inset-bottom));
  z-index: 6;
  align-items: center; gap: 8px;
  padding: 14px 20px;
  border: none; border-radius: 999px;
  background: var(--coral); color: var(--on-coral);
  font: inherit; font-weight: 600;
  box-shadow: 0 6px 20px rgb(0 0 0 / .3);
  cursor: pointer;
}
/* #share, not .fab: the blanket hide rule above is an ID selector, and a class selector here would
   lose to it however specific the rest of the chain looks. */
body[data-step="done"] #share { display: inline-flex; }
body.no-share #share { display: none; }
.fab svg { display: block; }

.note {
  position: fixed; left: 50%; bottom: 160px; transform: translateX(-50%);
  background: var(--ink); color: var(--paper); padding: 12px 16px;
  border-radius: var(--r-input); font-size: .875rem; font-weight: 600; max-width: 90vw; z-index: 5;
}
.foot { padding: 14px 16px; color: var(--muted); font-size: .76rem; text-align: center; }

@media (prefers-reduced-motion: no-preference) {
  .frame-chip { transition: border-color .15s ease; }
}

/* No dark-mode variant, deliberately. This is used by strangers on phones we do not control, and
   following each device's theme made the caption and the form fields render black on an iPhone
   while an Android next to it looked completely different. One light theme, stated explicitly, is
   worth more here than adapting. */
}

.wide { width: 100%; }
.step[data-for="details"] .field { margin-bottom: 10px; }

/* The details step has no sticky action bar of its own, and the form is tall enough on a small
   phone to push Continue past the fold - which stalls the whole booth at step one.
   `position: sticky` cannot fix this: sticky is clamped to the parent's box, and the form's box
   ends below the fold as well. Fixed is the only thing that guarantees the button is on screen
   whatever number of fields the event configures. */
/* Fixed so it is always in reach on a phone, but held to the same 560px column as everything
   else - `left: 16px; right: 16px` alone stretched Continue across the full width of a laptop. */
/* ...and because it is FIXED it is out of flow, so it sat permanently on top of the footer: "About
   this event" was half-covered by Continue and no amount of scrolling could free it. A sticky bar
   would eventually scroll clear; a fixed one never does. So the page has to reserve the space the
   button occupies. Only on this step, because the button is only fixed on this step. */
body[data-step="details"] .foot {
  padding-bottom: calc(78px + env(safe-area-inset-bottom));
}

/* The form needs the same clearance the footer got, and for the same reason: Continue is FIXED, so
   anything in the scroll flow can sit under it. On a 280px-wide Galaxy Fold it landed squarely on
   the consent row - elementFromPoint at the centre of both Yes and No returned the button, so a tap
   would have answered a question the guest never saw. Reserving the space means every control can
   always be scrolled clear of it. */
body[data-step="details"] .step[data-for="details"] {
  padding-bottom: calc(72px + env(safe-area-inset-bottom));
}

body[data-step="details"] #lead-submit {
  position: fixed;
  left: 0; right: 0;
  bottom: calc(10px + env(safe-area-inset-bottom));
  width: calc(100% - 32px);
  max-width: 528px;
  margin-inline: auto;
  z-index: 5;
  box-shadow: 0 6px 24px rgb(0 0 0 / .25);
}
/* Room for it, so the fine print is never trapped underneath. */
body[data-step="details"] main { padding-bottom: 84px; }


/* ── orientation ───────────────────────────────────────────────────────────────
   Last in the file on purpose. These override `.actions`, `#frames` and `main`, all of which are
   defined above; placed earlier, the later base rules simply won and the rotated layout silently
   did nothing - the button column stayed a bar across the middle of the screen. */

@media (orientation: portrait) {
  body[data-mode="landscape"][data-step="pick"] #frames {
    flex-wrap: wrap;
    justify-content: center;
    overflow: visible;
    gap: 10px;
  }
  body[data-mode="landscape"][data-step="pick"] .frame-chip { width: calc(50% - 6px); }
  body[data-mode="landscape"][data-step="pick"] .frame-chip img { aspect-ratio: 16 / 10; }
}

@media (orientation: landscape) and (max-height: 560px) {
  main { max-width: none; padding: 6px 16px 6px; gap: 6px; }
  .bar > .wrap { min-height: 0; padding: 2px 0; }
  .bar span, .foot, #share-hint, .lead-intro { display: none; }
  .frames { max-height: 62px; }
  .frame-chip { width: 58px; }
  main h1 { font-size: 1rem; }

  /* The controls move to a column down the right. A rotated phone has 390px of height and about
     840 of width; leaving the buttons in a bar across the bottom spends the scarce dimension on
     them and leaves the frame 200px tall. Down the side they cost width, which there is plenty of,
     and the frame gets nearly the whole height. */
  .actions {
    position: fixed; top: 0; bottom: 0; right: 0; left: auto;
    width: 172px;    /* "Choose from gallery" needs 127px of text; 144 cropped it by two pixels */
    flex-direction: column; justify-content: center; align-items: stretch;
    gap: 8px;
    border-top: none;
    border-left: 1px solid var(--line);
    padding: 8px calc(8px + env(safe-area-inset-right)) 8px 8px;
    margin: 0;
  }
  /* Uniform height down the column. "Copy caption" wrapped to two lines and stood 70px tall
     beside 46px neighbours, which is what "the buttons are not aligning" looked like. */
  /* One width, one height, one size of text, and no wrapping - so the column reads as a set
     rather than as buttons that happen to be near each other. */
  .actions button, .actions .upload span {
    width: 100%;
    padding: 10px 10px;
    min-height: 46px;
    height: 46px;
    font-size: .84rem;
    line-height: 1;
    white-space: nowrap;
    display: flex; align-items: center; justify-content: center;
  }
  .actions .upload { width: 100%; }
  /* `.actions button.shutter`, not `.shutter`: the generic `.actions button { width: 100% }` is
     (0,2,0) and would beat a lone class selector whatever the order, stretching the shutter into
     an ellipse. */
  /* The shutter is deliberately not the same shape as the rest: it is the camera's own control,
     and a round one reads as a shutter where a full-width pill would read as another menu item. */
  .actions button.shutter {
    width: 66px; height: 66px; min-height: 66px;
    align-self: center; border-radius: 50%; padding: 0;
    margin: 4px 0;
  }
  main, .bar { padding-right: 188px; }
  .fab { right: 188px; bottom: 12px; }
  .note { bottom: 12px; }
  #caption { min-height: 3.5em; }
  /* The bar is a fixed column here, so main keeps its own foot padding (the rule beside .actions
     is for a bar in the flow). */
  body:is([data-step="pick"], [data-step="camera"], [data-step="adjust"], [data-step="done"]) main { padding-bottom: 6px; }
  .step[data-for="done"] { margin-bottom: 0; }
}

/* ── a wide screen: the photo beside what goes with it (owner, 2 Oct 2026; the canvas's "Booth on a
   laptop A") ────────────────────────────────────────────────────────────────────────────────────
   One column is a phone's. On a laptop it gave the photo whatever the choices, the caption, Share and
   the buttons left - about 180px of a 720px screen - and left the sides empty. From 900px wide, in
   landscape and taller than a rotated phone (that is the block above): the photo on the left at the
   screen's height, the step's words and controls in a column on the right, Share and the bar at its
   foot. sizeStage() asks the same question (WIDE in booth.js). The demo keeps its one column: its
   guide has the sides. Phones never match this. */
@media (min-width: 900px) and (min-height: 561px) and (orientation: landscape) {
  body:not(.demo) .bar > .wrap, body:not(.demo) .foot > .wrap { max-width: 1120px; }
  body:not(.demo):is([data-step="pick"], [data-step="camera"], [data-step="adjust"], [data-step="done"]) main {
    max-width: 1120px;
    display: grid;
    /* 440: Download, Copy caption and Start again on one row. */
    grid-template-columns: minmax(0, 1fr) 440px;
    /* Each item on the right takes a row of its own height; the photo spans every row, and only the
       last row is flexible, so it alone takes the photo's extra height - the items on the right
       stay together at the top instead of being spread out to match it. */
    grid-template-rows: repeat(14, auto) 1fr;
    column-gap: 40px; row-gap: 0;
    align-items: start;
  }
  body:not(.demo) main > * { grid-column: 2; margin-bottom: 14px; }
  body:not(.demo) #stage-wrap,
  body:not(.demo) #reel-video { grid-column: 1; grid-row: 1 / -1; margin: 0; }
  body:not(.demo) #reel-video { width: auto; max-width: 100%; max-height: calc(100vh - 150px); justify-self: center; }
  /* The frames as a grid down the column, all in view: there is the height for it here. */
  body:not(.demo) .frames { flex-wrap: wrap; overflow: visible; }
  /* Share, then the bar, at the column's foot: in the flow, not floating over the caption. */
  body:not(.demo) #share { order: 1; position: static; justify-content: center; width: 100%; }
  body:not(.demo) .actions {
    order: 2; position: static; margin-inline: 0; margin-top: 0;
    padding: 0; border-top: none; background: none;
  }
}
/* A laptop's 720px: the caption box shorter (it scrolls inside), so the column ends on screen. */
@media (min-width: 900px) and (min-height: 561px) and (max-height: 800px) and (orientation: landscape) {
  body:not(.demo) #caption { min-height: 0; height: 4.4em; }
}

/* ── the demo (phase 9 step 5; the canvas's Demo B) ───────────────────────────────────────────
   The end card under Share, and on a wide screen the guide: what the organiser decides at each
   step, the one on screen lit from body[data-step], the trial on the other side. Below 1200px the
   booth's column needs the room, so the guide is left out and the end card carries the ask. */
.demo-end {
  display: flex; flex-direction: column; gap: 8px; margin-top: 10px;
  background: var(--ink); color: #fff; border-radius: 22px; padding: 18px;
}
.demo-end strong { font-family: var(--display); font-weight: 600; font-size: 1.2rem; }
.demo-end span { color: var(--on-ink-muted); font-size: .9375rem; line-height: 1.45; }
.demo-end a.primary { display: flex; align-items: center; justify-content: center; min-height: 50px; border-radius: 14px; text-decoration: none; font-weight: 800; margin-top: 4px; }
.demo-end .demo-again { color: #fff; text-align: center; font-weight: 700; padding: 6px; }

.demo-guide { display: none; }
@media (min-width: 1200px) {
  .demo-guide { display: block; position: fixed; inset: 132px 0 auto; pointer-events: none; z-index: 1; }
  .demo-steps, .demo-cta { position: absolute; top: 0; pointer-events: auto; }
  .demo-steps { left: 24px; width: 280px; display: flex; flex-direction: column; gap: 12px; }
  .demo-title { font-family: var(--display); font-weight: 600; font-size: 1.4rem; line-height: 1.15; }
  .demo-steps ol { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; counter-reset: d; }
  .demo-steps li {
    counter-increment: d; position: relative; padding: 12px 14px 12px 50px; border-radius: 16px;
    background: var(--surface); border: 2px solid var(--line); font-size: .9rem; line-height: 1.45; color: var(--muted);
  }
  .demo-steps li b { color: var(--ink); }
  .demo-steps li::before {
    content: counter(d); position: absolute; left: 12px; top: 11px; width: 26px; height: 26px; border-radius: 50%;
    display: grid; place-items: center; background: var(--peach); color: var(--on-peach); font-weight: 800; font-size: .85rem;
  }
  body[data-step="details"] .demo-steps li[data-demo="details"],
  body[data-step="mode"] .demo-steps li[data-demo="frame"],
  body[data-step="pick"] .demo-steps li[data-demo="frame"],
  body[data-step="camera"] .demo-steps li[data-demo="photo"],
  body[data-step="adjust"] .demo-steps li[data-demo="photo"],
  body[data-step="done"] .demo-steps li[data-demo="share"] { background: var(--peach); border-color: var(--coral); color: var(--ink); }
  body[data-step="details"] .demo-steps li[data-demo="details"]::before,
  body[data-step="mode"] .demo-steps li[data-demo="frame"]::before,
  body[data-step="pick"] .demo-steps li[data-demo="frame"]::before,
  body[data-step="camera"] .demo-steps li[data-demo="photo"]::before,
  body[data-step="adjust"] .demo-steps li[data-demo="photo"]::before,
  body[data-step="done"] .demo-steps li[data-demo="share"]::before { background: var(--coral); color: var(--on-coral); }
  .demo-cta {
    right: 24px; width: 240px; display: flex; flex-direction: column; gap: 10px;
    background: var(--ink); color: #fff; border-radius: 22px; padding: 20px;
  }
  .demo-cta strong { font-family: var(--display); font-weight: 600; font-size: 1.2rem; }
  .demo-cta span, .demo-cta small { color: var(--on-ink-muted); font-size: .875rem; line-height: 1.45; }
  .demo-cta a { background: var(--coral); color: var(--on-coral); border-radius: 14px; padding: 12px; text-align: center; font-weight: 800; text-decoration: none; }
  .demo-cta img { background: #fff; border-radius: 10px; padding: 8px; margin-top: 6px; }
}
