/* =============================================================================
   PD Cash — responsive / cross-browser layer
   -----------------------------------------------------------------------------
   Sections 1-11 (2026-08-23) targeted the prerendered-React build that was
   replaced on 2026-08-25. A census across all 21 routes found every one of their
   selectors matching 0 elements, except two that were actively WRONG for this
   build:
     - section 8 zeroed scroll-margin-top below 1024px, which put every mobile
       in-page anchor under the fixed header (removed 2026-08-26, unit U18);
     - section 3 forced #mobile-navigation to display:none above 1020px, which
       would block a drawer opened in the 1021-1023px band.
   Sections 1-11 were removed on 2026-08-26 (unit U22). What remains is sections
   12-13, written for the current build.
   Loaded last on all 22 public pages. Additive and presentation-only.
   ========================================================================== */

/* ---- 12. Current-theme viewport system (2026-08-25) -------------------------
   Fluid sizing and resilient layout guards for the current Tailwind public
   shell. The black/green art direction, 1280px reading width, and existing
   component hierarchy are deliberately preserved. */
:root {
  --pd-compact-gutter: 1rem;
  --pd-touch-target: 44px;
  --pd-pointer-target: 28px;
  --pd-compact-card-radius: 1.5rem;
  --pd-wide-display-min: 3.9rem;
  --pd-wide-display-max: 4.25rem;
}

html {
  max-width: 100%;
  overflow-x: clip;
}

@supports not (overflow: clip) {
  html { overflow-x: hidden; }
}

main :is(h1, h2) {
  text-wrap: balance;
}

main :is(p, li, dd) {
  text-wrap: pretty;
}

main :is(h1, h2, h3, p, li, dd) {
  overflow-wrap: break-word;
}

main :is(.grid, .flex) > * {
  min-width: 0;
}

/* A visible but compact scrollbar should not consume 10px of a phone screen. */
@media (max-width: 1023.98px) {
  html { scrollbar-width: thin; }

  ::-webkit-scrollbar {
    width: 4px;
    height: 4px;
  }

  main input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  main select,
  main textarea {
    font-size: 16px;
  }

  footer nav :is(a, button) {
    display: inline-flex;
    min-height: var(--pd-touch-target);
    max-width: 100%;
    align-items: center;
  }
}

/* 320-359px: reclaim card/gutter space without shrinking readable body text. */
@media (max-width: 359.98px) {
  main > section > [class~="mx-auto"][class*="px-"],
  footer > [class~="relative"][class~="mx-auto"] {
    padding-inline: var(--pd-compact-gutter);
  }

  main h1.display {
    font-size: clamp(2rem, 10vw, 2.15rem);
    line-height: 1;
  }

  main .card[class~="p-7"],
  main .card[class~="p-8"],
  main .auth-card[class~="p-7"] {
    padding: 1.25rem;
  }

  #navShell {
    padding-inline: 1rem;
  }
}

/* Compact laptops: keep the full desktop navigation comfortably separated. */
@media (min-width: 1024px) and (max-width: 1180px) {
  header [class~="gap-8"] {
    gap: 1.25rem;
  }

  #navShell {
    padding-inline: 1rem;
  }
}

@media (min-width: 1024px) {
  header .nav-link,
  footer nav :is(a, button) {
    display: inline-flex;
    min-height: var(--pd-pointer-target);
    align-items: center;
  }
}

/* Short laptop viewports retain the CTA while avoiding a wasteful top gap. */
@media (min-width: 1024px) and (max-height: 720px) {
  /* Only the tall homepage hero: it starts flush under the fixed header, so 7.5rem still
     clears it while reclaiming height. The 21 breadcrumbed pages already start at y=143
     with a 3.5rem hero - applying this to them ADDS 64px instead of removing any. */
  main > section:first-child[class*="pt-28"] {
    padding-top: 7.5rem;
  }
}

/* Large desktops gain hierarchy, not wider reading lines. */
@media (min-width: 1600px) {
  main h1.display {
    font-size: clamp(
      var(--pd-wide-display-min),
      3.2vw,
      var(--pd-wide-display-max)
    );
    line-height: .98;
  }
}


/* ---- 13. Contextual interaction sizing -------------------------------------
   Standalone links and demo controls need a real hit area; prose links retain
   the WCAG inline-link exception and keep natural line flow. */
@media (max-width: 1023.98px) {
  main .card h3 > a,
  main a[class*="font-bold"],
  #ckQrToggle {
    display: inline-flex;
    min-height: var(--pd-touch-target);
    align-items: center;
  }

  label:has(> #scSearch) {
    min-height: var(--pd-touch-target);
  }
}

@media (min-width: 1024px) {
  main .card h3 > a,
  main a.inline-flex,
  main a[class*="font-bold"],
  #ckQrToggle,
  .footer-contact {
    display: inline-flex;
    min-height: var(--pd-pointer-target);
    align-items: center;
  }
}

@media (max-width: 1023.98px) { main :is(select, textarea).auth-input { font-size: 16px; } }

@media (min-width: 1600px) { main h1.display[class*="xl:text-[3.9rem]"] { font-size: 3.9rem; line-height: 1; } }

/* ---- 14. Hash-arrival landing for the /contact anchors (U21, 2026-08-27) ----
   #onboarding-form is <div class="reveal-now min-w-0" id="onboarding-form">;
   #contact-form is the sr-only <span> that is its FIRST CHILD. Both anchors
   resolve to the same box, so a .sr-only selector would miss one of them.

   Two defects compose:
   (1) OFFSET. The only anchor convention in the build is
       section[id]{scroll-margin-top:96px} - which is why /#pricing lands
       correctly. A <div> and a <span> match nothing, compute 0px, and park at
       viewport top 0 behind the 76/80px fixed header.
   (2) RESIDUE. .reveal-now{animation:revealIn .8s ... both} holds the box at
       0%{transform:translateY(26px) scale(.985)} while the browser resolves the
       fragment scroll; the box then settles 26 + 0.0075*H higher and nothing
       re-aligns. Transform only, so document height stays constant at 1977 -
       which is what rules out font swap and the IntersectionObserver pass.
       Measured live on a real top-level tab, 2026-08-27:
         1280: marker 557.01 -> 525.41 = 31.60 residue (H 745.31)
          375: marker 491.79 -> 457.97 = 33.82 residue (H 1041)

   scroll-margin-top is consumed at the instant the scroll target is computed,
   so it cancels (1) but not (2). One constant sized to header + residue absorbs
   both: 128 rests the marker at 96.41 on 1280 (17.4px clear of the 80px header)
   and 93.97 on 375 (18.0px clear of 76px) - the same resting position
   /#pricing already produces. Residue would have to exceed 48px (H > ~2900)
   to occlude again.

   px, not rem: this tracks a header specified in px, so it survives any change
   to the root size from the type scale in sections 12-13. scroll-margin has no
   layout, paint or box effect - it moves the scroll position only. */
#contact-form,
#onboarding-form {
  scroll-margin-top: 128px;
}

/* The build ships @media (prefers-reduced-motion:reduce){.reveal-now{animation:none}},
   so that cohort has residue 0 on every path and the build own 96px is exact for
   them (measured 96.41). Written as an override on a 128 base so an engine that
   cannot resolve the query fails toward whitespace, never toward occlusion. */
@media (prefers-reduced-motion: reduce) {
  #contact-form,
  #onboarding-form {
    scroll-margin-top: 96px;
  }
}

/* ---- 15. Print: the page currently prints blank (U23, 2026-08-26) ----------
   Measured on the live build, /terms:
     - @media print rule count across every stylesheet on the page: 0
     - html and body background: rgb(0, 0, 0)
     - text colour histogram in main: 164 elements rgba(255,255,255,.65),
       37 rgb(255,255,255), 22 rgba(255,255,255,.6), 2 green. No dark text.
     - 51 of the 52 .reveal blocks below the fold sit at opacity 0, because
       their IntersectionObserver has not fired for content that was never
       scrolled into view.
   Browsers omit background colours when printing unless the reader turns
   background graphics on, so today a printed Terms, Privacy or AML page is
   white text on white paper - and most of it is at opacity 0 regardless.
   Merchants and payment-partner reviewers print exactly these pages.

   This block is print-only: it cannot affect screen rendering. !important is
   used deliberately - the colours come from Tailwind utilities like
   text-white/65 (specificity 0-1-0) which an element selector cannot beat, and
   there are no competing print rules to fight. */
@media print {
  html,
  body {
    background: #fff !important;
    color: #111 !important;
  }

  /* Content that never revealed must still print. */
  .reveal,
  .reveal-now {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
    filter: none !important;
  }

  /* Text has to be legible on paper. */
  main,
  main *,
  footer,
  footer * {
    color: #111 !important;
    background-image: none !important;
    box-shadow: none !important;
    text-shadow: none !important;
  }
  main h1,
  main h2,
  main h3,
  main h4 {
    color: #000 !important;
  }
  main a,
  footer a {
    color: #00407d !important;
    text-decoration: underline;
  }

  /* Chrome and decoration waste paper; a fixed header repeats on every sheet. */
  header,
  canvas,
  .site-header,
  details.toc,
  #mobileCta,
  [aria-hidden="true"] svg {
    display: none !important;
  }

  /* Scroll containers must not clip their content on paper. */
  main *,
  footer * {
    overflow: visible !important;
    max-height: none !important;
  }

  /* Do not split a heading from the text it introduces. */
  h1, h2, h3, h4 {
    break-after: avoid-page;
    page-break-after: avoid;
  }
  p, li, tr, img, figure {
    break-inside: avoid;
    page-break-inside: avoid;
  }
}


/* ---- 14. Collapsed disclosure regions must not be exposed to assistive tech ---
   .faq-a and .cmp-panel collapse with grid-template-rows:0fr plus overflow:hidden on the
   inner div. That clips them visually but leaves the text in the accessibility tree, so a
   screen reader reads every answer while the control reports aria-expanded="false"
   (WCAG 2.2 SC 4.1.2 Name, Role, Value).

   Gated on .pd-a11y, set by this layer's own JS: if that script does not run the rules never
   apply and behaviour is exactly as before, so no content is stranded. FAQ hiding follows its
   close transition. Comparison content hides immediately so its scroll region cannot receive
   focus while closing; showing is immediate. visibility is inherited by the whole subtree. */
.pd-a11y .faq-a > div {
  visibility: hidden;
  transition: visibility 0s linear .38s;
}
.pd-a11y .faq-item.is-open .faq-a > div {
  visibility: visible;
  transition-delay: 0s;
}
.pd-a11y .cmp-panel > div {
  visibility: hidden;
  transition: visibility 0s linear 0s;
}
.pd-a11y .cmp-panel.is-open > div {
  visibility: visible;
  transition-delay: 0s;
}


/* ---- 15. Authored swipe cues follow measurement, not a viewport number -------
   "Swipe horizontally to compare both plans." is authored with sm:hidden, so it stays on
   screen from ~602px to 639px after the table has stopped overflowing. markScrollers() sets
   data-pd-cue from scrollWidth-clientWidth, and these two rules let that measurement win.
   Element+attribute (0,1,1) outranks the utility class (0,1,0), and this sheet loads after
   the bundle, so no !important is needed. */
p[data-pd-cue="off"] { display: none; }
p[data-pd-cue="on"]  { display: block; }

/* 2026-09-29: print must show collapsed FAQ/compare answers and drop fixed chrome.
   Section 14 hides collapsed .faq-a/.cmp-panel content with visibility:hidden (.pd-a11y), and the
   print block above only un-clips it, so paper got questions with empty gaps. The fixed bars
   (#mobileCta, #toTop, #prog, #ambient) otherwise repeat on every printed sheet.
   transition:none keeps the FAQ visibility delay from painting a blank frame in
   DevTools print emulation. Print-only; cannot affect screen rendering. */
@media print {
  .pd-a11y .faq-a > div,
  .pd-a11y .cmp-panel > div {
    visibility: visible !important;
    transition: none !important;
  }
  #mobileCta,
  #toTop,
  #prog,
  #ambient {
    display: none !important;
  }
}

/* Keep the fixed mobile menu reachable on short landscape screens. */
@media (max-width: 1023.98px) {
  #mobile-navigation {
    max-height: calc(100vh - 88px - var(--pd-eb, 0px) - var(--pd-compact-gutter) - env(safe-area-inset-bottom, 0px));
    max-height: calc(100dvh - 88px - var(--pd-eb, 0px) - var(--pd-compact-gutter) - env(safe-area-inset-bottom, 0px));
    overflow-y: auto;
  }
}

/* The stacked mobile hero stays interactive while the page scrolls. */
@media (max-width: 1023.98px) {
  #heroCopy,
  #heroVisual {
    opacity: 1 !important;
  }
}


/* ---- 15c. Focus not obscured by fixed chrome (WCAG 2.2 SC 2.4.11, technique C43) --------
   The header is position:fixed (76-80px) at every width and #mobileCta is fixed at the bottom below
   1024px (69px). Chrome scrolls a focused control only just into view and ignores fixed layers, so
   Tab / Shift+Tab parked focus behind them. Measured with real key presses on the live site: 10 of
   127 stops on / at 390px (Tab, behind #mobileCta); 20 of 145 (390px) and 21 of 140 (1280px) with
   Shift+Tab (behind the header). The scroll-padding-top in pd-polish-20260823e.css never ships: its
   injector anchors on the retired index-*.css link.
   Bottom: html scroll-padding. Nothing else sets scroll-margin-bottom, so nothing stacks.
   Top: NOT html scroll-padding. section[id] (96px), .scroll-mt-28 (112px) and #contact-form /
   #onboarding-form (128px, section 14) already carry tuned scroll-margin-top for #hash arrival, and
   padding would be added on top of them (/#pricing landed at 192px instead of 96px in a trial).
   A margin that exists only while a Tab-reachable control holds keyboard focus leaves those landings
   alone; tabindex="-1" targets (main, after the skip link) are excluded so that landing is unchanged. */
@media (max-width: 1023.98px) {
  html {
    scroll-padding-bottom: calc(6rem + env(safe-area-inset-bottom, 0px));
  }
}

:is(a[href], button, input, select, textarea, summary, [tabindex]:not([tabindex="-1"])):focus-visible {
  scroll-margin-top: calc(6rem + env(safe-area-inset-top, 0px));
}

/* ---- 16. Public mobile polish (2026-09-06) --------------------------------
   Preserve the current dark/green theme while fitting card geometry to narrow
   screens. Contact path descriptions are decision-making copy, so they wrap
   instead of disappearing behind an ellipsis at 320px. */
@media (max-width: 639.98px) {
  main .card {
    border-radius: var(--pd-compact-card-radius);
  }
}

#onboarding-form .path-tab > .min-w-0 > .truncate {
  overflow: visible;
  white-space: normal;
  text-overflow: clip;
  text-wrap: pretty;
  line-height: 1.5;
}

@media (max-width: 1023.98px) {
  #mobileCta .pill {
    min-height: var(--pd-touch-target);
  }
}

/* 2026-09-29: the sticky bar is parked off-screen with transform only; keep it out of the tab order and AT tree until it slides in. */
#mobileCta:not(.is-on) {
  visibility: hidden;
  transition: transform .4s cubic-bezier(.2, .7, .3, 1), visibility 0s linear .4s;
}


/* Public navigation: keep page context, align the tablet panel, and allow
   enough room for the primary action on the smallest phone widths. */
@media (max-width: 1023.98px) {
  header:has(#navShell) > #menuScrim {
    background-color: rgba(0, 0, 0, .8);
  }
  body.menu-open header #navShell {
    background-color: #0a0b0a;
    border-color: rgba(255, 255, 255, .1);
  }
  /* 2026-09-29: html{overflow-x:clip} stops body{overflow:hidden} reaching the viewport, so the open drawer did not lock page scroll. */
  html:has(body.menu-open) {
    overflow: hidden;
  }
}
@media (min-width: 640px) and (max-width: 1023.98px) {
  header:has(#navShell) > #mobile-navigation {
    margin-inline: 2rem;
  }
}
@media (max-width: 359.98px) {
  header:has(#navShell) > #mobile-navigation > nav > .grid:has(> a[href="/register"]) {
    grid-template-columns: minmax(0, .7fr) minmax(0, 1.3fr);
  }
}

/* 2026-09-29: this surface is dark-only, so say so (native scrollbars, <select> popups and
   spellcheck otherwise follow the OS light theme). Also give the form fields and the home
   demo's contenteditable .edit spans a focus indicator that survives forced-colors: the bundle
   sets outline:none on both and keeps only a border colour, tint or box-shadow, which
   forced-colors drops. */
html { color-scheme: dark; }
@media (forced-colors: active) {
  .auth-input:focus-visible,
  .edit:focus-visible { outline: 2px solid Highlight; outline-offset: 2px; }
}

/* A full row prevents the homepage demo search shrinking behind its chips. */
@media (max-width: 639px) {
  #showcase label:has(> #scSearch) {
    flex-basis: 100%;
    width: 100%;
    max-width: 100%;
    margin-left: 0;
  }
}

/* Keep the public footer brand mark circular when its flex row is narrow. */
body > footer a[aria-label="PD CASH home"] > span:first-child {
  flex-shrink: 0;
}

/* Keep the compact-screen back-to-top control in its existing place after the footer,
   so its hit area cannot cover form fields or disclosure buttons. */
@media (max-width: 1023.98px) {
  body > footer + #toTop {
    position: static;
    margin: 0 18px calc(18px + env(safe-area-inset-bottom, 0px)) auto;
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }
}

/* Give the brand its own row before the four tablet footer link columns. */
@media (min-width: 768px) and (max-width: 1023.98px) {
  body > footer > .relative > .grid:has(> nav[aria-label="Product links"]) {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  body > footer > .relative > .grid:has(> nav[aria-label="Product links"]) > div:first-child {
    grid-column: 1 / -1;
  }
}

/* WCAG 1.4.11 / 1.4.3 (A11Y-12): the /contact fields (.auth-input) and the hero e-mail on / drew a 1.27:1 border
   (rgba(255,255,255,.12) on black) and /contact's two hint texts sat at 3.1:1. .42 alpha = 3.95:1 border, .5 alpha =
   5.3:1 hint (same value as templates/auth_polish.php). Source order beats the bundle utilities at equal specificity;
   :focus (0,2,0) still wins, and aria-invalid is restated one step brighter so it stays distinguishable from the
   new resting border (the bundle's invalid rule is white .45). */
.auth-input,
#hero-email:not(:focus) { border-color: rgba(255, 255, 255, .42); }
.auth-input::placeholder { color: rgba(255, 255, 255, .5); }
.auth-input[aria-invalid="true"] { border-color: rgba(255, 255, 255, .7); }

/* 2026-09-29: the sticky mobile CTA wraps instead of ellipsizing its claim (WCAG 1.4.10). */
#mobileCta p.truncate {
  overflow: visible;
  text-overflow: clip;
  white-space: normal;
  line-height: 1.25;
}
@media (max-width: 359.98px) {
  #mobileCta p.truncate + p.truncate { display: none; }
}

/* ---- Legal long-form measure (2026-09-29) ----------------------------------
   The 7 legal pages (terms, privacy, refund, acceptable-use, aml-cft,
   disclaimer, security) set body copy at 15px in a 768px column: paragraph
   median 92.5 and max 109.5 characters per line at 1280/1440 (target 45-80;
   WCAG 1.4.8 AAA, Bringhurst 45-75). 16px in a 40rem column gives paragraph
   median 70-79, max 78-85 at every desktop width; mobile column (335px) is
   unchanged. Hook is unique to the legal articles:
   <article class="reveal-now min-w-0 max-w-3xl">. Only elements that carry
   text-[15px] are bumped, so the 13px "Questions about this page?" callout keeps
   its smaller size. Unlayered, so it beats the Tailwind layer without !important. */
main article.reveal-now.max-w-3xl { max-width: 40rem; }
main article.reveal-now.max-w-3xl :is(p, li).text-\[15px\] { font-size: 1rem; line-height: 1.7; }

/* Legal pages (the only pages with a long-form <article class="reveal-now">): no revealIn entrance on the
   article. The browser resolves a #hash scroll once, while the article is still inside its
   translateY(26px) scale(.985) frame; on a 7,000-27,000 px box that residue is up to ~0.0075 x H, so a deep
   heading settles 35-170 px above its scroll-margin-top target, under the 76/80 px fixed header
   (/terms#6-security-deposits at 375 px landed at 14-48 px = fully covered; with this rule 112 px). */
main article.reveal-now {
  animation: none;
}

/* ---------------------------------------------------------------------------
   2026-09-30 public-shell (D19.1). Solutions menu: the desktop dropdown reuses .prod-menu; the drawer uses a native <details>.
   --------------------------------------------------------------------------- */
#solutions-menu{backdrop-filter:none;-webkit-backdrop-filter:none;background-color:#0a0b0a}
.sol-summary{list-style:none;cursor:pointer;display:flex;align-items:center;justify-content:space-between}
.sol-summary::-webkit-details-marker{display:none}
.sol-summary::after{content:"";width:.5rem;height:.5rem;margin-right:.25rem;border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:rotate(45deg) translateY(-2px);transition:transform .2s}
.sol-details[open]>.sol-summary::after{transform:rotate(225deg) translateY(-2px)}
.sol-summary:focus-visible{outline:2px solid #36d240;outline-offset:2px}
/* a drawer taller than the phone scrolls inside itself instead of cutting off the sign-in buttons */
#mobile-navigation{max-height:calc(100dvh - 5.75rem - var(--pd-eb, 0px) - env(safe-area-inset-bottom, 0px));overflow-y:auto;overscroll-behavior:contain}

/* home-14 (2026-09-30): copy under 12px on phones is raised to 12px. Illustrations (aria-hidden mock UI) keep their scale. */
@media (max-width: 640px) {
  main :is(.text-\[9px\], .text-\[10px\], .text-\[11px\], .text-\[11\.5px\]):not([aria-hidden="true"] *) { font-size: 12px; }
}

/* ---------------------------------------------------------------------------
   2026-09-30 MSR-11 (WCAG 2.2.2 / 2.3.3): decorative infinite animations stop under prefers-reduced-motion and can be paused
   with the "Pause animations" control (first tab stop and footer). The decorative canvas is hidden while paused.
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; animation-delay: 0s !important; scroll-behavior: auto !important; }
  canvas { display: none !important; }
}
html.pd-motion-paused *, html.pd-motion-paused *::before, html.pd-motion-paused *::after { animation-play-state: paused !important; }
html.pd-motion-paused canvas { visibility: hidden; }
.pd-motion-skip { position: absolute; left: -9999px; top: 8px; z-index: 100; }
.pd-motion-skip:focus { position: fixed; left: 8px; top: 8px; padding: .55rem 1rem; border-radius: 999px; background: #000; color: #fff; border: 2px solid #36d240; font: 700 13px/1.2 Inter, system-ui, sans-serif; cursor: pointer; }
.pd-motion-foot { font: inherit; font-size: 13px; white-space: nowrap; color: rgba(255,255,255,.55); background: none; border: 0; padding: 0; cursor: pointer; text-decoration: underline; text-underline-offset: 3px; }
.pd-motion-foot:hover { color: #36d240; }
.pd-motion-foot:focus-visible { outline: 2px solid #36d240; outline-offset: 3px; border-radius: 4px; }
.pd-motion-foot[aria-pressed="true"] { color: #36d240; }
