/* POSLab marketing site — REPO-SIDE additions only.
   Nothing in here exists in the design source (ui_kits/marketing/). Keeping it
   in its own file means site.css / page.css stay byte-identical to the design
   project and a future re-sync is a straight overwrite, not a merge.

   Three concerns live here:
     1. Honest degradation for product screenshots that have not been exported
        yet (the 16 shots/*.png). A missing image must SAY it is missing — it
        must not silently collapse the layout or render a broken-image glyph.
        Same rule as the rest of the product: no fake success, no fake state.
     2. Inline form status/error styling for the lead-capture forms, which post
        to POST /v1/access-requests and must report the real outcome.
     3. The three-state theme control, and the one dark-theme repair the
        light-first design source needed.
*/

/* ── 3. Theme control — three states, three glyphs ───────────────────
   site.css shows sun/moon off the RESOLVED data-theme, which can only ever
   describe two states. The control has three (System · Light · Dark), so
   which glyph shows is driven by the stored CHOICE — #theme-toggle[data-pref],
   written by site-shell.js. The id gives these rules the specificity to win
   over site.css's [data-theme="dark"] pair without editing the design file. */
#theme-toggle .ico-sun,
#theme-toggle .ico-moon,
#theme-toggle .ico-auto { display: none; }
#theme-toggle[data-pref="light"]  .ico-sun  { display: block; }
#theme-toggle[data-pref="dark"]   .ico-moon { display: block; }
#theme-toggle[data-pref="system"] .ico-auto { display: block; }

/* Dark-theme repair — the one thing the light-first kit got wrong.
   .frame-phone draws its chassis with var(--text-primary), which is only
   "near-black" in the light theme; in dark it resolves to #F4F2EC and the
   handset renders as a WHITE slab, with its fixed-white notch invisible on it
   and the pending-shot copy (--text-secondary, also near-white in dark) sitting
   unreadable on top. A phone body is a physical object, not type: it stays the
   same colour in both themes, exactly like the Hub drawing on hub.html, which
   is honestly black either way. Pinning the chassis fixes all three symptoms at
   the source — the notch and the copy inside it become correct for free. */
.frame-phone { --device-shell: #1A1814; border-color: var(--device-shell); background: var(--device-shell); }

/* ── 1. Screenshot pending placeholders ──────────────────────────────
   The placeholder is swapped in by site-local.js ONLY when the real file
   fails to load. It deliberately keeps the img's own classes (shot-t / l / d)
   so the existing light/dark visibility rules keep working untouched.

   Space is reserved so that when the real PNGs land NOTHING reflows:
   inside a frame the parent .screen already carries the aspect ratio, and
   the design's `aspect-ratio:auto` release is gated on .is-loaded (below),
   so the frame holds its shape until a real image actually decodes. */
.shot-pending {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;                 /* fallback when no framed parent sets one */
  border: 1px dashed var(--border-strong);
  border-radius: 10px;
  background:
    linear-gradient(0deg, var(--accent-subtle), var(--accent-subtle)),
    repeating-linear-gradient(45deg, var(--surface-elevated) 0 10px, var(--surface-card) 10px 20px);
  overflow: hidden;
}
/* Inside any framed .screen the parent already reserves the ratio — fill it. */
.shot .screen > .shot-pending { height: 100%; aspect-ratio: auto; border: none; border-radius: 0; }

.shot-pending .sp-inner {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; padding: 20px; text-align: center;
}
.shot-pending .sp-tag {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-mono); font-size: 9.5px; font-weight: 600;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--accent);
  border: 1px solid var(--accent-border); border-radius: var(--radius-sm);
  background: var(--surface-card); padding: 4px 9px;
}
.shot-pending .sp-desc {
  max-width: 46ch;
  font-size: 12px; line-height: 1.5; color: var(--text-secondary);
}
.shot-pending .sp-file {
  font-family: var(--font-mono); font-size: 10px; color: var(--text-faint);
  word-break: break-all;
}
/* The phone frame is small and dark-bordered — shrink the copy so it fits. */
.frame-phone .shot-pending .sp-desc { font-size: 11px; }
.frame-phone .shot-pending .sp-file { display: none; }

/* ── 2. Lead form status ─────────────────────────────────────────────
   The form may only claim success when the row actually landed (ADR 0099 A1).
   These are the states it reports honestly. */
.form-error {
  display: none;
  margin-top: 12px; padding: 11px 13px;
  border: 1px solid var(--danger-border, var(--border-strong));
  background: var(--danger-subtle, var(--surface-elevated));
  border-radius: var(--radius-sm);
  font-size: 13px; line-height: 1.5; color: var(--text-primary);
}
.form-error.show { display: block; }
.form-error a { color: var(--accent); font-weight: 600; text-decoration: underline; }

/* honeypot — visually gone, still submittable by bots */
.hp {
  position: absolute !important;
  width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

button[disabled] { opacity: 0.62; cursor: progress; }

/* ── 4. Responsive repairs the design re-sync did not carry ──────────
   Operator, 2026-07-29: "I need our marketing site to be as responsive as the
   back office." The design's responsive pass lives in site.css and was synced
   in whole; these are the defects that remained when the result was MEASURED
   in Chromium at 320/360/390/414/768/1100 in both themes
   (scripts/check-landing-responsive.mjs). They are repo-side deltas on purpose:
   fixing them in site.css would be overwritten by the next design re-sync, and
   fixing them in each page's inline <style> would scatter one concern across
   nine files. Every rule below names the number that failed.

   The bar, same as the design pass: no horizontal overflow, no body copy under
   12px, no tap target under 40px at touch widths. */

/* 4a. The nav's Get started button measured 37–38px tall at every width from
   320 to 768 — under the 40px touch minimum on every page of the site. The
   design sizes it by padding alone, which the font metrics then decide; a
   min-height decides it instead. */
@media (max-width: 880px) {
  .cta { min-height: 44px; }
}

/* 4b. features.html's sticky chip nav: the chips measured 35px. The strip
   itself scrolls horizontally by design (that is not the bug), but a chip is
   still a thumb target. */
@media (max-width: 880px) {
  .jump a { min-height: 40px; display: inline-flex; align-items: center; }
}

/* 4c. home — the page's smallest breakpoint was 880px, so at 320/360 the
   plan teaser was still TWO columns (.pt reached 364px in a 320px viewport)
   and the lead form's paired row still split. Below 640 everything that is a
   grid of cards becomes one column. */
@media (max-width: 640px) {
  body[data-page="home"] .ptease,
  body[data-page="home"] .devices,
  body[data-page="home"] .mini-form .row { grid-template-columns: 1fr; }
}

/* 4d. home — the contact card reached 372px in a 320px viewport. Cloudflare
   renders the Turnstile widget at a fixed 300px, and 300 + 28px card padding
   either side + the wrap's own padding cannot fit a small Android screen. Trim
   the card's padding and let the widget scale down inside it rather than push
   the document sideways. */
@media (max-width: 640px) {
  .contact-card { padding: 20px 16px; }
  .cf-turnstile { max-width: 100%; overflow: hidden; }
  .cf-turnstile iframe { max-width: 100% !important; }
}

/* 4e. pricing — the comparison table overflowed to 348px in a 320px viewport
   because .cmp is `overflow:clip`, so it could neither scroll nor reflow: the
   plan columns were simply cut off. The design's answer was a fixed layout
   with all three plans visible rather than a scroller, so that is what this
   does — the feature column takes what is left after three equal plan columns,
   and long feature names wrap instead of widening the table. */
@media (max-width: 880px) {
  .cmp table { table-layout: fixed; width: 100%; }
  .cmp th:first-child, .cmp td:first-child { width: auto; }
  .cmp th:not(:first-child), .cmp td:not(:first-child) { width: 17%; text-align: center; }
  .cmp td, .cmp th { overflow-wrap: anywhere; }
}
@media (max-width: 480px) {
  .cmp td, .cmp th { padding-left: 8px; padding-right: 8px; font-size: 12.5px; }
  .cmp th:not(:first-child), .cmp td:not(:first-child) { width: 15%; }
}

/* 4f. storefront — the commission slider measured 234×16. A 16px track is not
   a thumb target; the whole control gets 44px and a thumb big enough to find. */
@media (max-width: 880px) {
  .calc input[type=range] { height: 44px; }
}
.calc input[type=range] { -webkit-appearance: none; appearance: none; background: transparent; }
.calc input[type=range]::-webkit-slider-runnable-track {
  height: 6px; border-radius: 3px; background: var(--surface-sunken, var(--surface-elevated));
}
.calc input[type=range]::-moz-range-track {
  height: 6px; border-radius: 3px; background: var(--surface-sunken, var(--surface-elevated));
}
.calc input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; margin-top: -10px;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--surface-card); cursor: pointer;
}
.calc input[type=range]::-moz-range-thumb {
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--surface-card); cursor: pointer;
}
