/* ═══════════════════════════════════════════════════════════════════
   PORTAL IFRAME LAYOUT (styles/embed.css)

   Loaded by EVERY served page (index.html + tutorial.html). It must not
   live in a page stylesheet: tutorial.html does not load the input-screen
   layers, so a framed rule parked there would be dead on the other page.

   Every rule here is inert unless <html> carries the `framed` class, which
   each page's init() sets:

       if (window.self !== window.top) document.documentElement.classList.add('framed');

   Without that line this whole file is dead CSS. It is set inside init()
   (not at parse time) so the corrected layout is what auth.js measures when
   it posts the first rvo-height — completeSignIn order is
   setState('signed-in') → onAuthenticated() → signalRendered().

   ── WHY min-height:100vh HAS TO GO ──
   The portal sizes the iframe from the height WE post via rvo-height, and
   frames us with scrolling="no". So inside the frame `100vh` IS the height
   we last reported. With the nav as a sibling above the offender:

       reported = nav + max(content, 100vh)  →  portal grows the frame
                                             →  100vh grows  →  repeat

   Each pass adds the nav's height: dead space below the report that grows
   forever. Fix by removing the phantom height, NEVER by capping the posted
   height — a cap clips a legitimately tall report (two letter pages ≈ 2300px).

   Coverage is per-offending-selector, not just #pg2. Regenerate the list with:
       grep -rn 'min-height:100[vd]' styles/
   ═══════════════════════════════════════════════════════════════════ */

/* body itself is stable (it cannot add height outside the element being
   measured) but is reset for symmetry — the offenders below are the ones
   that actually ratchet. */
html.framed body{min-height:0;}

/* input screen — hfg-tool-shell.css:284 */
html.framed #pg2{min-height:0;}

/* tutorial screen — hfg-tutorial-v2.css:31. Also drops the padding that
   only existed to reserve room for the fixed control bar flattened below. */
html.framed #tut-app{min-height:0;padding-bottom:0;}

/* mobile live screen — hfg-tool-shell.css:189/193 and mobile.css:17/19 */
html.framed #mv .mapp.dk,
html.framed #mv .sub{min-height:0;}

/* ── position:fixed / sticky do not work inside the embed ──
   No local viewport: `sticky` is inert, and `fixed` resolves against the
   FULL content height — so a bottom:0 bar pins to the far bottom of a very
   tall frame instead of to the reader's view. Flatten both to static.

   SPECIFICITY: `#tut-app .site-nav` is (1,1,0) and BEATS a bare
   `html.framed .site-nav` at (0,2,0). The ID has to be repeated or the
   override silently does nothing. Same for `#tut-app .tut-ctrl`. */
html.framed .site-nav{position:static;}
html.framed #tut-app .site-nav{position:static;}
html.framed #tut-app .tut-ctrl{position:static;box-shadow:none;border-top:1px solid var(--iv-line,#dfe4e9);}

/* The heading is the focus target that scrolls the framed view to the top —
   window.scrollTo is a silent no-op for a cross-origin child, but moving
   focus is a user-agent action and the UA scrolls every ancestor scroll
   container to reveal the target, crossing the iframe boundary. Suppress the
   ring for the non-keyboard case only, so keyboard users keep it. */
#pg1Heading:focus:not(:focus-visible),
#pg2Heading:focus:not(:focus-visible){outline:none;}
