/* ==========================================================================
   Anchored page header (the bank-transactions template, made reusable)
   Source pattern: bank-transactions .tx-stickyhead (JOHN REVIEW).

   Wrap a page's <header class="page-header"> (+ its .toolbar-row) in
   <div class="page-stickyhead">. The title + toolbar stay pinned at the top;
   anything marked .is-collapsible (the note, the stat cards, any summary)
   collapses away once the page is scrolled. ui.js auto-toggles .is-stuck on
   every .page-stickyhead (scroll past ~100px) — no per-page JS needed.
   ========================================================================== */

/* Kill the browser's scroll-anchoring: when the header collapses (shorter page)
   the browser would scroll up to "keep content in place", which re-crosses the
   collapse threshold and makes the header flap/vibrate. bank-transactions sets
   this too; here it protects every page that uses the shared anchored header. */
html:has(.page-stickyhead) { overflow-anchor: none; }

.page-stickyhead {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--color-surface);
  /* EXACT bank-transactions collapse rhythm (.tx-stickyhead) so every page
     animates identically and never jumps mid-way (Peter, 29 Jun). */
  --ph-dur: 0.62s;
  --ph-fade: 0.82s;
  --ph-ease: cubic-bezier(0.4, 0, 0.2, 1);
}

/* Summary bits that fold away when stuck (mark them .is-collapsible) */
.page-stickyhead .is-collapsible {
  overflow: hidden;
  transition: max-height var(--ph-dur) var(--ph-ease),
              opacity var(--ph-fade) var(--ph-ease),
              margin var(--ph-dur) var(--ph-ease),
              padding var(--ph-dur) var(--ph-ease);
  max-height: 240px;
}
/* A collapsible CARD RAIL still needs to slide sideways: the collapse only needs
   overflow-y hidden, so keep overflow-x scrollable (identical to the transactions
   account rail, which does exactly this). Without it the rail can't be slid. */
.page-stickyhead .stat-cards.is-collapsible { overflow-x: auto; overflow-y: hidden; }
.page-stickyhead.is-stuck .is-collapsible {
  max-height: 0;
  opacity: 0;
  padding-top: 0 !important;
  padding-bottom: 0 !important;
  margin-top: 0;
  margin-bottom: 0;
}

/* Restore (returning to a page) sets the collapsed state with NO animation, so
   it lands instantly instead of flickering through the collapse. */
.page-stickyhead.ph-no-anim,
.page-stickyhead.ph-no-anim * { transition: none !important; }

/* The list label pins right under the collapsed header (like the transactions
   date pill) at the measured collapsed height — a stable anchor so the snap
   doesn't chase. ui.js sets --ph-stickyh. */
.list-stuck-head {
  position: sticky;
  top: var(--ph-stickyh, 0px);
  z-index: 6;
  background: var(--color-surface);
  margin: 0;
  padding: 12px 0;
}

/* Once collapsed the cards fold away, so the pinned toolbar loses its top gap — give it
   its own breathing room above (global standard, Peter 3 Jul) and keep the bar compact below. */
.page-stickyhead .toolbar-row { transition: padding-top var(--ph-dur) var(--ph-ease); }
.page-stickyhead.is-stuck .toolbar-row { padding-top: 20px; padding-bottom: 16px; }

/* Stuck: drop the lede ("All money in and out…") and lift the action buttons
   (camera + Actions) up onto the title/breadcrumb row, so the pinned bar is a
   single line: [Title] … [cam] [Actions]. (Peter, 29 Jun.) Default unchanged.
   header-sub stays in flow (negative margin) so its Actions dropdown still
   anchors under the button. --ph-lift defaults to the desktop title metric. */
.page-stickyhead .page-header { position: relative; }
.page-stickyhead .page-header__title { transition: padding-bottom var(--ph-dur) var(--ph-ease); }
.page-stickyhead .header-sub { transition: margin-top var(--ph-dur) var(--ph-ease); }
.page-stickyhead .header-sub .page-header__lede { transition: max-width var(--ph-dur) var(--ph-ease), opacity var(--ph-fade) var(--ph-ease); }

.page-stickyhead.is-stuck .page-header__title { padding-bottom: 16px; }
.page-stickyhead.is-stuck .header-sub { margin-top: calc(-1 * var(--ph-lift, 51px)); }
.page-stickyhead.is-stuck .header-sub .page-header__lede {
  max-width: 0;
  opacity: 0;
  overflow: hidden;
  white-space: nowrap;
  pointer-events: none;
}

/* Mobile: the title wraps and the header stacks — skip the lift, just fold the summary */
@media (max-width: 768px) {
  .page-stickyhead.is-stuck .header-sub { margin-top: 0; }
  .page-stickyhead.is-stuck .header-sub .page-header__lede { max-width: none; opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .page-stickyhead .is-collapsible,
  .page-stickyhead .page-header__title,
  .page-stickyhead .header-sub,
  .page-stickyhead .header-sub .page-header__lede { transition: none; }
}

/* Enough scroll room below the list for the sticky header to collapse even when there are
   only a few cards — without it a short list can't scroll far enough to fold the header
   (and the fold shrinks the page under itself and oscillates). GLOBAL (Peter, 8 Jul).
   The room is now EXACTLY what the fold needs, not a flat 380px: ui.js measures the
   collapsed header and sets --ph-minh to `100vh - collapsedH + 40px`, so once the header
   has folded the page has nothing left to scroll. A flat 380px let a short dashboard
   scroll into 380px of white nothing with the content gone off the top (Peter, 23 Jul).
   The literal stays as the fallback for the moment before the measurement lands. */
/* Scroll room only where the header actually collapses (default flipped to
   opt-in — Peter, 29 Aug 2026). A non-collapsing page gets no dead scroll. */
.app__main:has(.page-stickyhead--collapse) .app__content { min-height: var(--ph-minh, calc(100vh + 380px)); }

/* Short form/step pages (not scrolling lists — e.g. the payroll onboarding workflow) opt OUT
   with .page-stickyhead--static: no forced scroll room + no bottom egg, so the page doesn't
   scroll, the header never collapses/resets, and nothing hides under it (Peter, 13 Jul). */
.app__main:has(.page-stickyhead--static) .app__content { min-height: 0; }
.app__main:has(.page-stickyhead--static) .page-bottom-egg { display: none; }

/* The end-of-page notice the scroll room ends on (injected by ui.js on every anchored-header
   page; bank-transactions keeps its own .tx-bottom-egg — same look). */
.page-bottom-egg { text-align: center; color: var(--color-text-muted); font-size: var(--text-sm); margin: 0; padding: 44px 0 120px; }

/* --------------------------------------------------------------------------
   "THERE IS MORE ABOVE YOU" (Peter, 28 Jul 2026)
   Come back to a dashboard whose header has already collapsed and the stat
   cards are off the top of the screen with nothing to say so — you can be
   looking at a filtered list believing that is all there is. A faint circle
   with an up arrow sits under the anchored header while it is collapsed, and
   takes you back to the top.

   Faint on purpose: a hint, not a control. It brightens when you go for it.
   -------------------------------------------------------------------------- */
.ph-uptop {
  position: fixed;
  top: var(--ph-up-top, 80px);
  left: 50%;
  transform: translateX(-50%) translateY(-6px);
  z-index: 40;
  width: 30px;
  height: 30px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: var(--border-width) solid var(--color-border);
  border-radius: 50%;
  background: var(--color-surface);
  color: var(--color-text-muted);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity .35s ease, transform .35s cubic-bezier(0.16, 1, 0.3, 1), border-color .15s ease, color .15s ease;
}
.ph-uptop svg { width: 15px; height: 15px; }
/* IT FAILED CONTRAST AT .55 (Peter asked, 30 Jul — measured, and he was right).
   #757575 at 55% over white lands on #b3b3b3, which is 2.10:1 against the page.
   WCAG wants 3:1 for a non-text control, so the arrow was below the floor for
   anyone who does not have good eyes. Full strength is 4.61:1 and still reads as
   quiet, because what makes it quiet is that it is 30px with a hairline border —
   not that it is faded. */
.ph-uptop.is-on { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }
.ph-uptop.is-on:hover { border-color: var(--color-border-strong); color: var(--color-text); }
.ph-uptop:focus-visible { opacity: 1; outline: 2px solid var(--color-text); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .ph-uptop { transition: opacity .2s ease; } }
