/* ============================================================================
   legal-documents.css — responsive treatment for the three legal documents.

   LOADED BY BOTH LAYOUTS, deliberately:
     - app/Views/layout/marketing.php  → public /terms, /privacy, /client-portal-terms
     - app/Views/layout/legal-app.php  → in-app ?page=legal-terms|legal-privacy|
                                          legal-client-portal-terms

   The two surfaces render the SAME partials
   (app/Views/landing/partials/legal_*_document.php) with the same <html> theme
   attributes, so they must not drift. One file, both fixed.

   --------------------------------------------------------------------------
   WHY A SEPARATE FILE RATHER THAN EDITING THE PARTIALS
   --------------------------------------------------------------------------
   Each partial carries its own ~600-line <style> block and the three are near
   duplicates of one another, already drifted (privacy has 580px/600px
   breakpoints the other two lack). Editing all three in place would triple
   every future change and widen the diff over 190KB of markup. The desktop
   treatment is not what was wrong, so it is left completely untouched.

   --------------------------------------------------------------------------
   ⚠ SPECIFICITY — READ BEFORE ADDING A RULE
   --------------------------------------------------------------------------
   The partials' <style> blocks sit INSIDE <body>, not <head>. At EQUAL
   specificity they therefore win on document order over anything in this file,
   which is linked from <head>. Every rule below is prefixed `html body` to add
   two element selectors, so it outranks the in-body block on specificity and
   order stops mattering. That is why the prefix looks redundant and is not.

   Do NOT reach for !important instead — the partials already use it in places
   and stacking more makes the cascade unreadable.

   --------------------------------------------------------------------------
   TOKENS
   --------------------------------------------------------------------------
   var(--s1..s4), --bd*, --t1..t4, --gold* are aliased to --res-* on the
   document roots (#legal-terms / #legal-privacy / #legal-portal-terms) inside
   each partial, so they resolve ONLY inside those roots. Every rule in
   sections 2 and 3 is scoped to one of them and may use them.

   ⚠ Section 1 (the in-app back bar) is NOT inside those roots — `.legal-appbar`
   is a SIBLING of the document in layout/legal-app.php. Custom properties
   inherit down, not across, so `var(--res-*)` there silently falls back to its
   literal. Section 1 therefore uses `--lp-*`, which are declared on
   `body.landing-body` (landing-desktop.css:35) and so DO inherit into the bar.

   BREAKPOINTS: 800px (must match the partials' own layout collapse — see the
   note above section 2) and 520px (phone).
   ============================================================================ */


/* ============================================================================
   0. SCROLL-REVEAL SAFETY (both surfaces, all viewports)

   The partials hide every section with `.reveal{opacity:0}` and rely on an
   IntersectionObserver adding `.visible`, whose only effect is
   `animation: fade-up .4s ease forwards`. So the END STATE of legally-required
   text is produced by a CSS ANIMATION: if the animation does not run or does
   not complete, the section stays at opacity 0 and the page is blank even
   though the observer fired and the class is present.

   Measured on the public /terms page: elements carried class
   "doc-header reveal visible" while computed opacity was still 0.

   Setting opacity on `.visible` directly makes the resting state declarative.
   The fade-up still plays exactly as before for everyone who can see it — this
   only removes the dependency of *being readable* on the animation finishing.

   The in-app layout already forces opacity:1 for the same reason; this extends
   the same protection to the public pages, which had none.
   ============================================================================ */

html body #legal-terms .reveal.visible,
html body #legal-privacy .reveal.visible,
html body #legal-portal-terms .reveal.visible {
    opacity: 1;
}


/* ============================================================================
   1. IN-APP CHROME — the sticky back bar (layout/legal-app.php only)

   THE escape hatch. A legal document runs to 60+ clauses; a link at the bottom
   is not a way out. iOS WKWebView in the Capacitor wrapper has no browser
   chrome, no address bar and no guaranteed swipe-back, so without this the page
   traps the reader — App Review Guideline 2.1.
   ============================================================================ */

html body.legal-app-body {
    /* The documents' own sticky offsets assume the marketing header exists.
       It does not in the app shell, so collapse the reserved space. */
    --lp-header-height: 0px;
}

/* landing-desktop.css reserves `calc(var(--lp-header-height,76px) + 28px)` above
   the document to clear the fixed marketing header. The app shell has no such
   header — its own chrome is the sticky back bar — so that reservation is pure
   dead space at the top of the first screen. Zeroed for the app only; the public
   pages still need it. */
html body.legal-app-body .lp-main--legal-proto {
    padding-top: 0;
}

html body .legal-appbar {
    position: sticky;
    top: 0;
    z-index: 60;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 14px;
    background: var(--lp-color-surface, #fff);
    border-bottom: 1px solid var(--lp-panel-border, rgba(0, 0, 0, 0.1));
    /* iPhone notch / Dynamic Island. viewport-fit=cover is set by the layout. */
    padding-top: max(8px, env(safe-area-inset-top));
}

html body .legal-appbar__back {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    /* 44px is the Apple HIG minimum touch target. */
    min-height: 44px;
    padding: 0 10px 0 4px;
    margin-left: -4px;
    border-radius: 8px;
    font-size: 15px;
    font-weight: 600;
    line-height: 1.2;
    color: var(--lp-color-text-strong, #14181f);
    text-decoration: none;
}

html body .legal-appbar__back:hover,
html body .legal-appbar__back:focus-visible {
    background: var(--lp-color-surface-soft, rgba(0, 0, 0, 0.04));
}

html body .legal-appbar__icon {
    width: 20px;
    height: 20px;
    flex-shrink: 0;
}

html body .legal-appbar__title {
    margin-left: auto;
    font-size: 13px;
    font-weight: 500;
    color: var(--lp-color-text-muted, #55606f);
    /* Never let the title push the back control off-screen. */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

@media (max-width: 400px) {
    /* On the narrowest phones the back control alone earns the width. */
    html body .legal-appbar__title {
        display: none;
    }
}

/* The end-of-document button keeps a comfortable gap from the last clause. */
html body .legal-doc-endback {
    margin: 28px 0 8px;
}


/* ============================================================================
   2. CONTENTS RAIL — the clause navigation

   TWO bugs fixed here.

   (a) ORDERING. Each partial sets the mobile rail inside @media(max-width:800px)
       — but the DESKTOP `#legal-x .sidebar` rule appears LATER in the same
       stylesheet at equal specificity, so `width:220px` and the desktop `top`
       beat the mobile `width:100%` and `top:0`. Media queries add no
       specificity. The author hit this and patched `display` with !important
       without realising width and top were losing the same way, which is why
       the rail renders as a narrow clipped box instead of a full-width strip.

   (b) CLIPPED LABELS. Because the rail was 220px wide with ~1190px of content,
       labels were cut mid-word ("Data protectior", "Acceptanc").
   ============================================================================ */

/* 800px, NOT the site's 860px tablet breakpoint. It must match the partials'
   own `@media(max-width:800px)`, which is where `.page-wrap` collapses from
   `220px 1fr` to a single column. At 860 the rail was restyled into a
   full-width horizontal strip while the grid still had a 220px left column, so
   between 801 and 860 a ~1190px-wide pill row was crammed into 220px, the
   desktop card chrome was stripped, and on the public pages the rail stuck
   underneath the fixed marketing header. Consistency with the site scale is
   worth less than agreeing with the layout this actually restyles. */
@media (max-width: 800px) {
    /* NOTE ON STRUCTURE — do not "simplify" this back to display:contents.
       The partials make .sidebar the scroller and flatten .sidebar-inner with
       `display:contents`, intending the three .nav-group elements to become
       flex items of .sidebar and sit in one row. Measured in Chrome, they do
       not: the rail rendered 149px tall (3 x 44px stacked) with every label
       clipped. Making .sidebar-inner itself the flex row removes the dependency
       on contents-flattening and lays out predictably. */
    html body #legal-terms .sidebar,
    html body #legal-privacy .sidebar,
    html body #legal-portal-terms .sidebar {
        /* NB `display` here is INERT below 800px: the partials declare
           `display: flex !important` on this element, and !important beats any
           specificity. Left in place because it is correct for the element and
           documents the intent, but the rail's row layout must not depend on it
           — that is why .sidebar-inner below is the flex row, not this. */
        display: block;
        position: sticky;
        top: 0;
        z-index: 20;
        width: 100%;
        max-width: 100%;
        min-width: 0;
        flex-shrink: 0;
        padding: 8px 12px;
        overflow-x: auto;
        overflow-y: hidden;
        overscroll-behavior-x: contain;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        scroll-snap-type: x proximity;
        background: var(--s1);
        border-right: none;
        border-bottom: 1px solid var(--bd);
    }

    html body #legal-terms .sidebar::-webkit-scrollbar,
    html body #legal-privacy .sidebar::-webkit-scrollbar,
    html body #legal-portal-terms .sidebar::-webkit-scrollbar {
        display: none;
    }

    /* Sticky offset is resolved against the nearest scrollport, and in the app
       shell that scrollport already begins directly beneath the back bar. A
       `top: 60px` intended to "clear the bar" therefore double-counts it and
       pushes the rail 60px down the page at rest — measured: rail at y=121 with
       top:60px, y=61 (flush under the bar) with top:0. Keep this at 0. */
    html body.legal-app-body #legal-terms .sidebar,
    html body.legal-app-body #legal-privacy .sidebar,
    html body.legal-app-body #legal-portal-terms .sidebar {
        top: 0;
    }

    /* Specificity note: the partials' own rule is `#legal-x .sidebar
       .sidebar-inner` = (1,2,0). Two classes outrank two element selectors, so
       `html body #legal-x .sidebar-inner` (1,1,2) would LOSE. Matching their
       two classes and adding the elements gives (1,2,2), which wins. */
    html body #legal-terms .sidebar .sidebar-inner,
    html body #legal-privacy .sidebar .sidebar-inner,
    html body #legal-portal-terms .sidebar .sidebar-inner {
        display: block;
        /* Size to content so the parent actually has something to scroll. */
        width: max-content;
        min-width: 100%;
        background: none;
        border: none;
        border-radius: 0;
        overflow: visible;
    }

    /* ⚠ THE ACTUAL ROW CONTAINER IS AN UNCLASSED <nav>.
       The real structure is  .sidebar > .sidebar-inner > nav > .nav-group x3,
       and that bare <nav> is a plain block, so it stacked the three groups
       vertically no matter what .sidebar or .sidebar-inner were set to. Measured,
       not assumed: the rail computed 149px tall (3 x 44px) with flex-direction
       reporting `row` on both ancestors, which is what makes this misleading.
       Nothing in the partials targets this element. */
    html body #legal-terms .sidebar nav,
    html body #legal-privacy .sidebar nav,
    html body #legal-portal-terms .sidebar nav {
        display: flex;
        flex-direction: row;
        flex-wrap: nowrap;
        align-items: center;
        gap: 6px;
        width: max-content;
        min-width: 100%;
    }

    /* The 2px gradient hairline is drawn on .sidebar-inner and would now stretch
       across the full scrollable width, above the pills. */
    html body #legal-terms .sidebar .sidebar-inner::before,
    html body #legal-privacy .sidebar .sidebar-inner::before,
    html body #legal-portal-terms .sidebar .sidebar-inner::before {
        content: none;
    }

    html body #legal-terms .sidebar .nav-group,
    html body #legal-privacy .sidebar .nav-group,
    html body #legal-portal-terms .sidebar .nav-group {
        display: flex;
        flex-direction: row;
        gap: 6px;
        padding: 0;
        flex-shrink: 0;
        /* The stacked-rail separator would draw a vertical line mid-strip. */
        border-top: none;
    }

    html body #legal-terms .sidebar .nav-link,
    html body #legal-privacy .sidebar .nav-link,
    html body #legal-portal-terms .sidebar .nav-link {
        display: inline-flex;
        align-items: center;
        white-space: nowrap;
        min-height: 44px;
        padding: 0 14px;
        font-size: 13px;
        border-left: none;
        border-radius: 8px;
        background: var(--s2);
        border: 1px solid var(--bd);
        scroll-snap-align: start;
    }
}


/* ============================================================================
   3. PHONE (<=520px)
   ============================================================================ */

@media (max-width: 520px) {

    /* ---- 3a. Page padding -------------------------------------------------
       40px/20px/80px is desktop-derived and wastes a lot of a phone screen. */
    html body #legal-terms .page-wrap,
    html body #legal-privacy .page-wrap,
    html body #legal-portal-terms .page-wrap {
        grid-template-columns: 1fr;
        padding: 0 0 56px;
        gap: 0;
    }

    html body #legal-terms .content,
    html body #legal-privacy .content,
    html body #legal-portal-terms .content {
        padding-left: 16px;
        padding-right: 16px;
        min-width: 0;
    }


    /* ---- 3b. THE WORST DEFECT: one character per line ---------------------
       `.prose ul li` / `ol li` are flex containers, so the leading <strong>
       label ("Business use:", "Workspace:") is a FLEX ITEM. A flex item shrinks
       to min-content, and the partials also set `word-break:break-word` at
       640px, which lets min-content fall below a whole word — so the label
       collapsed into a one-character-wide column reading vertically:

           · B  these Terms apply where you use
             u  the service for business purposes
             si ...

       Fixed by taking the list item out of flex layout entirely and hanging the
       marker in the padding, so the label and the text share one inline flow
       and wrap like ordinary prose. */
    /* `.prose ol li` is deliberately absent: there is no <ol> in any of the
       three documents (grep: 0/0/0), so those selectors were dead weight. The
       partials style `ol` defensively; this file only fixes what renders. */
    html body #legal-terms .prose ul li,
    html body #legal-privacy .prose ul li,
    html body #legal-portal-terms .prose ul li,
    html body #legal-terms .ov-list li,
    html body #legal-privacy .ov-list li,
    html body #legal-portal-terms .ov-list li {
        display: block;
        position: relative;
        padding-left: 18px;
        gap: 0;
    }

    html body #legal-terms .prose ul li::before,
    html body #legal-privacy .prose ul li::before,
    html body #legal-portal-terms .prose ul li::before,
    html body #legal-terms .ov-list li::before,
    html body #legal-privacy .ov-list li::before,
    html body #legal-portal-terms .ov-list li::before {
        position: absolute;
        left: 0;
        top: 0;
        /* The marker was a flex item aligned on the shared baseline. Once
           absolutely positioned it forms its own line box, so it only lines up
           with the first line of text if it shares the text's font-size AND
           line-height — at 10px/1.75 against 15px/1.55 it floated near the cap
           height and read as a stray tick. */
        font-size: inherit;
        line-height: inherit;
    }

    /* .ov-list is the "at a glance" summary list — same flex-item problem, and
       at 12.5px it was among the smallest body text on the page. All three
       documents define it identically. */
    html body #legal-terms .ov-list li,
    html body #legal-privacy .ov-list li,
    html body #legal-portal-terms .ov-list li {
        font-size: 15px;
        line-height: 1.55;
    }

    /* `word-break:break-word` breaks INSIDE words that would otherwise fit,
       which is what made the collapse possible. `overflow-wrap:anywhere` breaks
       only when a token genuinely cannot fit (long emails, URLs, clause refs) —
       the behaviour actually wanted here. */
    html body #legal-terms .prose,
    html body #legal-privacy .prose,
    html body #legal-portal-terms .prose,
    html body #legal-terms .prose em,
    html body #legal-privacy .prose em,
    html body #legal-portal-terms .prose em,
    html body #legal-terms .prose code,
    html body #legal-privacy .prose code,
    html body #legal-portal-terms .prose code {
        word-break: normal;
        overflow-wrap: anywhere;
    }


    /* ---- 3c. Type scale ---------------------------------------------------
       61 declarations across the three documents sit under 12px, the smallest
       at 9.5px. Legible on a 27" monitor, not on a phone held at arm's length.
       Only the mobile floor is raised; desktop is untouched. */
    html body #legal-terms .prose,
    html body #legal-privacy .prose,
    html body #legal-portal-terms .prose {
        font-size: 16px;
        line-height: 1.62;
    }

    html body #legal-terms .prose em,
    html body #legal-privacy .prose em,
    html body #legal-portal-terms .prose em {
        font-size: 13px;
    }

    /* Monospace eyebrows/labels: 9.5–11px → 12px, and let them wrap rather
       than force their container wider. */
    html body #legal-terms .ov-label,
    html body #legal-privacy .ov-label,
    html body #legal-portal-terms .ov-label,
    html body #legal-terms .sidebar-eyebrow,
    html body #legal-privacy .sidebar-eyebrow,
    html body #legal-portal-terms .sidebar-eyebrow,
    html body #legal-terms .nav-group-label,
    html body #legal-privacy .nav-group-label,
    html body #legal-portal-terms .nav-group-label,
    html body #legal-privacy .feat-label,
    html body #legal-privacy .sp-cat {
        font-size: 12px;
        letter-spacing: .06em;
        white-space: normal;
    }

    html body #legal-privacy .feat-desc,
    html body #legal-privacy .right-desc,
    html body #legal-privacy .right-title,
    html body #legal-terms .tl-value {
        font-size: 14px;
        line-height: 1.55;
    }

    html body #legal-terms .doc-sub,
    html body #legal-privacy .doc-sub,
    html body #legal-portal-terms .doc-sub {
        font-size: 16px;
        max-width: none;
    }


    /* ---- 3d. Grids that never collapsed -----------------------------------
       .timeline-row is a fixed `120px 1fr` with no mobile rule at all, so the
       value column was squeezed to ~200px on a 360px screen. .feature-row stops
       at two columns and stayed 2-up at 11.5px. */
    html body #legal-terms .timeline-row {
        grid-template-columns: 1fr;
    }

    html body #legal-terms .tl-label {
        border-right: none;
        border-bottom: 1px solid var(--bd);
        font-size: 12px;
    }

    html body #legal-privacy .feature-row {
        grid-template-columns: 1fr;
    }

    html body #legal-privacy .feat {
        border-right: none;
        border-bottom: 1px solid var(--bd);
    }

    html body #legal-privacy .feat:last-child {
        border-bottom: none;
    }

    html body #legal-terms .overview-grid,
    html body #legal-privacy .overview-grid,
    html body #legal-portal-terms .overview-grid,
    html body #legal-privacy .basis-grid,
    html body #legal-privacy .rights-grid {
        grid-template-columns: 1fr;
    }


    /* ---- 3e. Tap targets --------------------------------------------------
       The accordion header is the primary control on these pages and was sized
       for a mouse. NOTE the documents use two different accordions: terms and
       portal-terms use .clause-head/.clause-title; privacy uses
       .expand-head/.expand-title. Both are covered — checked against the
       markup, not assumed. */
    html body #legal-terms .clause-head,
    html body #legal-portal-terms .clause-head,
    html body #legal-privacy .expand-head {
        min-height: 44px;
        padding: 12px 14px;
    }

    html body #legal-terms .clause-title,
    html body #legal-portal-terms .clause-title,
    html body #legal-privacy .expand-title {
        font-size: 15px;
        line-height: 1.35;
    }

    /* The secondary in-document nav rail. Present in ALL THREE documents
       (10 / 11 / 10 anchors), not just privacy — counted, not assumed. */
    html body #legal-terms .snav-link,
    html body #legal-privacy .snav-link,
    html body #legal-portal-terms .snav-link {
        min-height: 44px;
        display: inline-flex;
        align-items: center;
    }


    /* ---- 3f. Containment --------------------------------------------------
       ⛔ DO NOT ADD `overflow-x: hidden` TO THE DOCUMENT ROOTS.

       It was here as belt-and-braces against sideways scroll and it silently
       broke the sticky contents rail that section 2 exists to build. Per CSS
       Overflow 3, when one axis is not `visible` the other computes to `auto`,
       so `#legal-terms { overflow-x: hidden }` turns the root into a SCROLL
       CONTAINER — and `position: sticky` on a descendant then resolves against
       that container instead of the viewport.

       Measured in Chrome at a 500px viewport: computed `overflow-y: auto`, and
       after `scrollTo(0, 900)` the rail's top was -839px, i.e. scrolled clean off
       the page. At rest it looks perfect, which is why a screenshot cannot catch
       it — only scrolling can.

       It was also unnecessary: the document already measured
       `scrollWidth === clientWidth` at 500px. Long tokens are handled by
       `overflow-wrap: anywhere` in 3b and `min-width: 0` below. If sideways
       scroll ever does reappear, use `overflow-x: clip` (which does NOT create a
       scroll container) — never `hidden`. */

    html body #legal-terms .clause-inner,
    html body #legal-portal-terms .clause-inner,
    html body #legal-privacy .expand-inner,
    html body #legal-terms .content,
    html body #legal-privacy .content,
    html body #legal-portal-terms .content {
        min-width: 0;
    }
}

/* ==========================================================================
   Run-in labels: extend the <=520px fix up to the single-column breakpoint
   ==========================================================================
   The block at :327 solves this properly - `li { display: block }` with an
   absolutely-positioned marker - and its own comment calls the flex-item
   collapse "THE WORST DEFECT". But it is scoped to <=520px, and the legal
   layout collapses to ONE COLUMN at <=1080px (marketing-2026.css:2067). In the
   521-1080 band the list items were still `display: flex`, so a bold run-in
   label such as "Platform, not advice:" became a flex item that shrank to
   min-content - measured 64px wide by 56px tall, three wrapped lines, inside a
   203px list item at 810px - and the values in a card started at three
   different left edges.

   Same treatment, same selectors, applied to the band the original fix did not
   reach. Kept as a separate block rather than widening the <=520px media query,
   so the existing rules are untouched if that block is ever revised. */
@media (min-width: 521px) and (max-width: 1080px) {
    html body #legal-terms .prose ul li,
    html body #legal-privacy .prose ul li,
    html body #legal-portal-terms .prose ul li,
    html body #legal-terms .ov-list li,
    html body #legal-privacy .ov-list li,
    html body #legal-portal-terms .ov-list li {
        display: block;
        position: relative;
        padding-left: 18px;
        gap: 0;
    }

    html body #legal-terms .prose ul li::before,
    html body #legal-privacy .prose ul li::before,
    html body #legal-portal-terms .prose ul li::before,
    html body #legal-terms .ov-list li::before,
    html body #legal-privacy .ov-list li::before,
    html body #legal-portal-terms .ov-list li::before {
        position: absolute;
        left: 0;
        top: 0;
        font-size: inherit;
        line-height: inherit;
    }
}
