/* ─── styles-responsive.css: every media query, covering selectors defined
   in all four files above. MUST load last — several rules here rely on
   normal cascade order (later rule wins at equal specificity), not just
   the !important ones, to override the base (desktop) rules. ─── */

/* ─── prefers-reduced-motion ───
   Every CSS animation/transition in the app (fades, slides, the FAB bump)
   collapses to effectively instant, not just "fewer" — no coverage of this
   existed before. Kept as duration overrides rather than deleting the
   animations, so nothing that depends on layout settling still works the
   same, just without the motion. This can't reach the SMIL <animate>
   elements inside the Pocketbook's inline SVG illustrations (CSS doesn't
   govern SVG SMIL) — see pbSetRunVisual()'s prefersReducedMotion() check
   in pocketbook-activities.js for that half of this. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ─── RESPONSIVE ─── */
@media (max-width: 1100px) {
  .pb-host { grid-template-columns: 1fr; padding-bottom: 88px; }

  /* Builder on mobile: popup that grows OUT of the FAB. Ironclad hide
     when not .expanded — visibility:hidden + opacity:0 + scale near 0 +
     pointer-events:none. The visibility transition is delayed so the
     element only becomes hittable AFTER it has finished animating in.
     80vh (was 70) — a bit more headroom before the activity list needs to
     scroll at all, and a taller scroll region once it does.
     The popup itself is a fixed-size flex column that never scrolls as a
     whole (overflow:hidden) — only #pb-builder-list (flex:1, min-height:0,
     its own overflow-y:auto below) scrolls internally. Everything else —
     header, stats, arc balance, the "Session details" panel, and the
     action buttons — is flex-shrink:0, so it's always rendered at full
     size below the last activity, footer-style, never mid-scroll content
     the practitioner has to hunt for. */
  .pb-builder {
    position: fixed !important;
    bottom: 96px !important;          /* clears the 64px circular FAB */
    left: 16px !important;
    right: 16px !important;
    top: auto !important;
    max-height: calc(var(--vh, 1vh) * 80);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    border-radius: var(--pb-r-lg);
    transform-origin: bottom right;
    transform: scale(0.05);
    opacity: 0;
    visibility: hidden;
    transition: transform 0.22s ease, opacity 0.22s ease, visibility 0s linear 0.22s;
    z-index: 50;
    pointer-events: none;
    box-shadow: var(--shadow-lg);
  }
  .pb-builder.expanded {
    transform: scale(1);
    opacity: 1;
    visibility: visible;
    transition: transform 0.22s ease, opacity 0.22s ease, visibility 0s linear 0s;
    pointer-events: auto;
  }
  .pb-builder-header { cursor: pointer; }
  .pb-builder-header, .pb-builder-stats, .pb-arc-balance,
  .pb-session-meta, .pb-builder-actions, .pb-builder-hint { flex-shrink: 0; }
  .pb-builder-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; }

  /* Dims and separates the page content behind the popup so it reads as
     a modal rather than a box floating on top of the activity list. */
  .pb-builder-backdrop {
    display: block;
    position: fixed; inset: 0;
    background: rgba(20,48,42,0.45);
    z-index: 45;               /* below .pb-builder (50), above page content */
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.22s ease, visibility 0s linear 0.22s;
  }
  .pb-builder-backdrop.active {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity 0.22s ease, visibility 0s linear 0s;
  }

  /* Circular FAB. Just a number on a forest-ink disc. No icon.
     env(safe-area-inset-*) keeps it clear of a phone's gesture-nav bar
     / rounded corners (the inset is 0 on devices without one, so this
     is never less than the plain 16px). */
  .pb-fab {
    position: fixed;
    right: max(16px, calc(16px + env(safe-area-inset-right)));
    bottom: max(16px, calc(16px + env(safe-area-inset-bottom)));
    z-index: 60;                /* above .pb-builder (50), below run-mode (200) */
    width: 64px;
    height: 64px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: var(--forest-ink);
    color: white;
    box-shadow: var(--shadow-lg);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    align-items: center;
    justify-content: center;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
  }
  .pb-fab.bump { animation: pbFabBump 0.32s ease; }
  .pb-fab.open { transform: scale(0.92); opacity: 0.9; }
  .pb-fab-count {
    font-family: 'Open Sans', sans-serif;
    font-size: 24px;
    font-weight: 700;
    line-height: 1;
    transform-origin: center;
    display: inline-block;
  }
  .pb-fab-count.bump { animation: pbFabCountBump 0.34s ease; }

  /* Visibility gates — FAB only renders while the pocketbook module is
     the focused module. Run-mode hides both FAB and builder.
     Class/attribute selectors (not :has()) for compatibility with the
     older WebView used by the Odoo embed test path. */
  body[data-focused="mod-pocket"] .pb-fab { display: inline-flex; }
  /* !important: Run Mode is a full-screen overlay — the FAB/builder/
     backdrop must never show through it regardless of what other state
     (data-focused, .expanded) says they should otherwise do. */
  body.pb-run-active .pb-fab,
  body.pb-run-active .pb-builder,
  body.pb-run-active .pb-builder-backdrop { display: none !important; }
  /* Hard guard: builder cannot be expanded outside the pocketbook. */
  body:not([data-focused="mod-pocket"]) .pb-builder {
    transform: scale(0.05) !important;
    opacity: 0 !important;
    visibility: hidden !important;
    pointer-events: none !important;
  }
  body:not([data-focused="mod-pocket"]) .pb-builder-backdrop {
    opacity: 0 !important;
    visibility: hidden !important;
    pointer-events: none !important;
  }
}
/* ─── HEADER DENSITY (desktop, below full width) ───
   The header is one straight line at every width (styles-base.css:
   auto/minmax(0,1fr)/auto with a nowrap nav that scrolls rather than
   wraps). Between the mobile breakpoint and ~1440px that line is tight
   enough that the nav starts scrolling links out of sight — measured 138px
   of hidden nav in the participant path at 1280px, 226px in FR. These two
   tiers buy that space back from the chrome around the nav instead, in
   order of what costs the least to lose: first the search button's text
   (the magnifier alone is unambiguous, and ⌘K still works), then the
   padding on the nav links and mode buttons. Nothing is hidden outright
   and the row stays a single line — only the breathing room shrinks. */
@media (min-width: 769px) and (max-width: 1440px) {
  .search-trigger-label, .search-trigger-kbd { display: none; }
  .search-trigger { padding: 0 12px; }
  .header-inner { column-gap: 12px; }
  .header-controls { gap: 8px; }
  .site-nav-link { font-size: 12px; letter-spacing: 0; }
  .mode-btn { padding: 0 13px; }
}
@media (min-width: 769px) and (max-width: 1180px) {
  .site-nav-link { font-size: 11.5px; padding: 0 8px; }
  .mode-btn { padding: 0 10px; font-size: 11px; }
  .lang-btn { padding: 5px 9px; }
  .header-text h1 { font-size: 18px; }
  /* "← Back to the forest" is ~150px of the nav's remaining width at this
     size. Collapsed to the arrow alone via font-size:0 on the button and
     a ::before that re-states it, rather than display:none on a label
     span — the button's accessible name IS its text node (there is no
     aria-label on it), so the text has to stay in the DOM and stay
     reachable; font-size:0 hides it visually without removing it from the
     accessibility tree. Escape and clicking the scene's open space remain
     the same action (appEscapeAction, router.js). */
  .wf-back-btn { font-size: 0; padding: 0 12px; }
  .wf-back-btn::before {
    content: '←';
    font-size: 15px;
    line-height: 1;
  }
}

@media (max-width: 768px) {
  #site-header {
    transition: transform 0.25s ease, opacity 0.25s ease;
    will-change: transform;
    /* The desktop breakout (styles-base.css) isn't needed here — .container
       isn't even constrained below its own 960px cap at these widths — and
       vw-based centering math gets thrown off by this same breakpoint's
       own body{zoom:0.75} density pass (confirmed: header rendered at
       0.75x the expected width, off-center). It also fights the
       .header-hidden scroll-away transform below, which needs sole
       ownership of this element's transform on mobile. */
    width: auto;
    max-width: none;
    position: static;
    left: auto;
    transform: none;
    padding-left: 0;
    padding-right: 0;
  }
  /* No room for this here (it was pushing onto its own row above
     Practitioner/Exploring) — the blurred-backdrop hotspot
     (body.wf-scene-deep #main-content margin-top, styles-base.css) is
     mobile's route back instead. Desktop keeps both. */
  .wf-back-btn { display: none !important; }
  #site-header.header-hidden {
    transform: translateY(-110%);
    opacity: 0;
    pointer-events: none;
  }
  /* Lang-bar lives in the header flex row at every width; on narrow
     screens header-controls wraps to its own line, so push lang-bar to
     that line's right edge. */
  .lang-bar {
    margin-left: auto;
  }
  /* Desktop centers the nav in its own grid column (styles-base.css) —
     too little width for that on narrow screens, so fall back to the
     title/nav/controls each taking a full stacked row, wrapping flex
     rather than grid. */
  .header-inner { display: flex; flex-wrap: wrap; }
  .site-nav, .header-controls { flex-basis: 100%; justify-content: flex-start; }
  .search-trigger-label { display: none; }
  .search-trigger-kbd { display: none; }

  /* Belt-and-suspenders against horizontal scroll. body already had
     overflow-x: hidden, which is enough in a standalone tab, but this
     app is normally viewed inside a host page's <iframe> — an iframe is
     its own scroll container, and doesn't reliably inherit/propagate a
     same-origin-looking-but-actually-separate document's root-scroller
     behavior the exact same way every mobile engine does. Repeating the
     clamp on html and on .container directly means there's no path left
     for a stray wide element to force a scrollbar the host page has to
     render around. */
  html, body { overflow-x: hidden; max-width: 100%; }
  .container { overflow-x: hidden; max-width: 100%; }

  /* Run Mode's illustration as the visual centerpiece of the step. Bleeds
     out to the card's full outer edge (cancelling .pb-run-card's own
     side padding) rather than sitting narrower inside it, so it renders
     at its biggest — a fixed min-height would just leave empty space
     above/below instead, since the illustration's own aspect ratio is
     wide and short. */
  .pb-run-card { padding-left: 0; padding-right: 0; }
  .pb-run-card > *:not(.pb-run-visual) { padding-left: 34px; padding-right: 34px; }
  .pb-run-visual { border-radius: 0; border-left: none; border-right: none; margin: 4px 0 24px; }

  /* Phone-only density pass. `zoom` (not `transform`) is used deliberately:
     it triggers a real re-layout at the reduced scale rather than a
     post-layout visual transform, so it shrinks type, spacing, and total
     scroll height together in one step — instead of hunting down every
     hardcoded font-size in this file individually, which is most of them.
     Support: Chromium/Android WebView, Safari 16.4+, Firefox 126+ — i.e.
     effectively every mobile browser this size range targets. Scoped to
     this existing ≤768px breakpoint only, so nothing above it changes. */
  body { zoom: 0.75; }

  /* Run Mode entered by scanning a shared QR code/link (pocketbook-init.js
     sets .pb-qr-launch on <body> for that path only) counter-zooms back to
     native scale. That entry is always a phone, often outdoors, glanced at
     rather than browsed — the density pass is the wrong tradeoff there,
     unlike the rest of the app where it stays on. Same reciprocal-zoom
     technique as the export templates below; safe here since this is a
     live on-screen render, not an html2canvas capture. */
  body.pb-qr-launch .pb-run-mode { zoom: calc(1 / 0.75); }
}
/* The off-screen export templates (#print-session/#print-report) are direct
   children of <body> and render at a fixed, print-native 794px width
   regardless of viewport — but with no reset they'd inherit the 0.75 zoom
   above on phones. That desyncs the export pipeline's own height
   measurements (taken against this zoomed, live DOM) from what html2canvas
   actually rasterizes (its internal clone is 794px wide, wider than the
   768px breakpoint, so the zoom rule never applies there) — producing
   overlapping rows/columns and mis-kerned text on phones only. A CSS-only
   counter-zoom on the templates (their own zoom set to the reciprocal,
   e.g. 1/0.75) does restore their true on-screen *size*, but nested/
   cancelled zoom still confuses html2canvas's own text-layout pass —
   confirmed: the rasterized text stays garbled even once the element's
   measured size is correct again. Resetting body's zoom to 1 for the
   brief span of measuring + rasterizing (pbWaitFontsReady() callers in
   pocketbook-export.js) sidesteps that entirely — one zoom context, not a
   nested one — then restores it immediately after. */
@media (max-width: 640px) {
  .pb-host .pb-activity-detail { padding: 4px 14px 18px; }
  .pb-detail-grid { grid-template-columns: 1fr; gap: 4px 0; }
  .pb-detail-label { padding-top: 12px; }
  .pb-detail-grid > div:first-child { padding-top: 0; }
  .pb-adapt-row { grid-template-columns: 1fr; gap: 8px; padding: 16px 18px; }
  .pb-group-title { font-size: 18px; }
  .pb-group-num { font-size: 22px; }
}

