/* ============================================================================
   GOKAIT PUBLIC SHELL — the one place the public surface is defined.

   Loaded by every public page: the six marketing pages, the homepage (for the
   header contract only), the customer app shell (login / register / 2fa /
   dashboard) and the public payment page. Two concerns live here and nowhere
   else:

     1. THE PUBLIC BACKGROUND      .pagebg
     2. THE MOBILE HEADER CONTRACT .bar / .kait-hdr-ctl / .navtoggle

   Both used to be written per stylesheet -- site.css owned one background and
   the homepage owned another, and the header rules were duplicated across
   site.css and styles.css with DIFFERENT breakpoints. Anything that must be
   identical on every public page belongs in this file.

   It deliberately contains no component styling: pages keep their own layout.
   ========================================================================= */


/* ============================ 1. PUBLIC BACKGROUND =========================
   Derived from the accepted homepage identity (styles.css .bg), held back for
   pages whose job is reading rather than impact. The homepage keeps its own
   fuller composition; this is the same scene, quieter.

   Markup is five empty divs. On the marketing pages site.js injects them
   (it already owns the shared shell); the app shell and the payment page carry
   them statically. Either way this file is the only definition.

   WHY IT LOOKED "ALMOST PLAIN BLACK" BEFORE: the photo was set to opacity .18
   and then put through brightness(.55), so it contributed under a tenth of the
   luminance -- and a 62-94% black scrim was then laid over that. The scene was
   present in the DOM and invisible on screen. The photo is now carried at a
   real strength and the scrim does its darkening where text actually sits
   (top, bottom, and behind the content column) instead of flatly everywhere. */

.pagebg{position:fixed;inset:0;z-index:-1;overflow:hidden;
  background:#05080C;pointer-events:none;contain:strict}

/* The environment photograph. position:fixed on the LAYER (never
   background-attachment:fixed, which iOS ignores and Android janks) is what
   makes a 12-screen Docs page share one background with no seam and no repaint
   cost while scrolling. */
.pagebg .env{position:absolute;inset:-2% -2%;
  background:url("mountain-environment.webp") 72% 40%/cover no-repeat;
  opacity:.46;filter:brightness(.74) saturate(.86) contrast(1.03)}

/* Grade the scene into the page. Heaviest at the very top and very bottom so
   the sticky header and the footer stay solid chrome, and along the left,
   which is where every inner page puts its heading and lede. The MIDDLE is
   deliberately left open -- that is the band the picture lives in. */
.pagebg .shade{position:absolute;inset:0;background:
  linear-gradient(180deg,rgba(3,5,9,.92) 0%,rgba(3,5,9,.58) 16%,
                  rgba(3,5,9,.40) 46%,rgba(3,5,9,.72) 82%,rgba(3,5,9,.93) 100%),
  linear-gradient(90deg,rgba(3,5,9,.78) 0%,rgba(3,5,9,.34) 38%,
                  rgba(3,5,9,.20) 66%,rgba(3,5,9,.46) 100%)}

/* The gold. Same hue and same placement as the hero's sun, at roughly half
   strength -- this is the whole "premium black/gold" cue on inner pages. */
.pagebg .glow{position:absolute;inset:0;background:
  radial-gradient(ellipse 54% 48% at 76% 22%,rgba(242,199,91,.14),transparent 66%),
  radial-gradient(ellipse 46% 36% at 10% 94%,rgba(185,133,34,.075),transparent 72%)}

.pagebg .vignette{position:absolute;inset:0;background:
  radial-gradient(ellipse 88% 84% at 50% 44%,transparent 54%,rgba(0,0,0,.62) 100%)}

/* identical grain to the homepage, so both surfaces share one finish */
.pagebg .grain{position:absolute;inset:0;opacity:.05;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/></filter><rect width='140' height='140' filter='url(%23n)' opacity='0.55'/></svg>")}

/* Content sits above the atmosphere. Cards keep their own opaque surface, so
   card text contrast is fixed by the token palette and cannot be affected by
   whatever the photograph is doing behind it. */
main.page,main.app,.wrap{position:relative;z-index:1}
/* The FOOTER is ordinary flow chrome, lifted above the atmosphere. The HEADER
   is PINNED and is therefore NOT reset here -- see section 3. This rule used to
   name both, and `position:relative` on header.site silently defeated
   site.css's `position:sticky`: public-shell.css loads AFTER site.css on every
   inner page, so the shared bar scrolled away while .doc-nav went on assuming a
   pinned header to offset itself from. */
footer.site{position:relative;z-index:2}

/* READING SCRIM. Long-form pages (Docs, Pricing, FAQ) put body copy directly
   on the background rather than inside a card. This is a local darkening that
   follows the content column, so those pages get a stronger backdrop without
   the whole site turning black again. */
.pagebg .read{position:absolute;left:50%;top:0;bottom:0;width:min(1180px,96vw);
  transform:translateX(-50%);
  background:linear-gradient(90deg,transparent,rgba(3,5,9,.34) 12%,
             rgba(3,5,9,.42) 50%,rgba(3,5,9,.34) 88%,transparent)}

/* RESPONSIVE CROP: the asset is re-anchored per form factor, never stretched,
   so no width shows an empty corner or a distorted horizon. */
@media (max-width:1180px){
  .pagebg .env{background-position:68% 42%;opacity:.42}
}
@media (max-width:900px){
  .pagebg .env{background-position:62% 46%;opacity:.38}
  .pagebg .glow{background:
    radial-gradient(ellipse 72% 36% at 66% 14%,rgba(242,199,91,.13),transparent 70%),
    radial-gradient(ellipse 58% 30% at 14% 96%,rgba(185,133,34,.07),transparent 74%)}
}
@media (max-width:640px){
  /* phones read at arm's length: the scene steps back a little further and the
     gold carries the identity, but it stays clearly present rather than
     collapsing to black the way the first version did */
  .pagebg .env{background-position:58% 48%;opacity:.32;
    filter:brightness(.7) saturate(.8) contrast(1)}
  .pagebg .shade{background:
    linear-gradient(180deg,rgba(3,5,9,.94) 0%,rgba(3,5,9,.66) 18%,
                    rgba(3,5,9,.5) 48%,rgba(3,5,9,.8) 84%,rgba(3,5,9,.95) 100%)}
  .pagebg .read{width:100%;background:linear-gradient(90deg,rgba(3,5,9,.3),rgba(3,5,9,.3))}
}
@media (max-height:520px) and (orientation:landscape){
  .pagebg .env{background-position:62% 30%;opacity:.34}
}
/* A viewer who asks for less motion is not asking for less contrast, so the
   background stays; only the homepage's animated layers stand down (styles.css
   already handles those). Nothing here animates. */


/* ========================= 2. MOBILE HEADER CONTRACT =======================
   ONE header on every public page. Desktop is the accepted baseline and is
   left exactly as it is -- everything below is inside a max-width query.

   The required mobile row is:

       [logo + Gokait] ................... [compact lang] [hamburger]

   The DOM order is brand, toggle, nav, language control, and BOTH the toggle
   and the control carried margin-left:auto -- so the free space was split
   between them and the row rendered brand / hamburger / language, leaving the
   hamburger stranded in the middle and the language pill against the edge.
   Flex `order` fixes the visual sequence without touching the DOM, so the
   existing nav/toggle wiring in site.js and landing.js is untouched and no
   second navigation implementation is introduced. */

@media (max-width:860px){
  .bar{gap:10px}
  /* iPhone safe area is applied as MARGIN on the edge children, never as
     padding on .bar: the header element is <div class="wrap bar">, so the two
     class names are the SAME box and any padding here silently replaces the
     .wrap gutter (26px on the subpages, 30px on the homepage) -- which pinned
     the brand and the hamburger flat against the screen edge. */
  .bar .brandblk{order:1;margin-right:auto;margin-left:env(safe-area-inset-left)}
  .bar .kait-hdr-ctl{order:2;margin-left:0}
  .bar .navtoggle{order:3;margin-left:0;margin-right:env(safe-area-inset-right)}
  /* the collapsed panel is positioned, so its order is irrelevant visually --
     it is pinned last only so tab order still reaches it after the controls */
  .bar nav.site,.bar nav{order:4}

  /* COMPACT LANGUAGE CONTROL.
     i18n.js injects `@media(pointer:coarse){.kait-lang-btn{min-height:44px;
     font-size:15px}}`, which is what made the trigger a 73x44 pill on every
     phone. The touch target is kept at 44px through an invisible expanded hit
     area instead of through visible padding, so the control reads as chrome:
     the box shrinks, the tappable region does not. */
  .kait-hdr-ctl .kait-lang-btn{min-height:0;height:32px;padding:0 8px;
    font-size:12px;border-radius:8px;gap:5px;
    border-color:rgba(242,199,91,.34);opacity:.92;position:relative}
  .kait-hdr-ctl .kait-lang-btn::after{content:"";position:absolute;
    top:-7px;bottom:-7px;left:-4px;right:-4px}      /* 46px tall hit area */
  .kait-hdr-ctl .kl-flag{font-size:12.5px}
  .kait-hdr-ctl .kl-code{font-size:11px;letter-spacing:.03em}
  .kait-hdr-ctl .kl-chev{font-size:8.5px;opacity:.75}
  /* the open list must not run off the right edge now that it sits inboard */
  .kait-hdr-ctl .kait-lang-list{right:0;left:auto}
}

/* Very narrow phones (320-360). The lockup already steps down here; the
   language control follows so the three elements never compete for the row. */
@media (max-width:380px){
  .bar{gap:8px}
  .kait-hdr-ctl .kait-lang-btn{height:30px;padding:0 6px;gap:4px}
  .kait-hdr-ctl .kl-code{font-size:10.5px}
  .kait-hdr-ctl .kl-flag{font-size:11.5px}
}
/* No flag-hiding fallback: measured at 320px the row is brand 86 + gap 8 +
   control 56 + gap 8 + toggle 40 inside a 26px gutter either side = 250 of
   320, so flag, code and chevron all survive at the narrowest width tested.
   Dropping the flag would have been a fix for a problem that does not exist. */

/* ====================== 3. THE SHELL POSITION CONTRACT =====================
   Two behaviours, deliberately different, and this is the one place either is
   decided.

   THE HEADER IS PINNED. It stays at the top of the viewport for the whole
   scroll, so the brand, the destinations and the language control are one
   gesture away from anywhere on a page. `position:sticky`, never `fixed`: the
   bar keeps its own row in normal flow, so nothing below it has to be pushed
   down by a compensating offset and there is NO layout shift at the moment it
   starts sticking -- it never left flow to begin with. A `fixed` bar would have
   needed a hardcoded padding on every public page to replace the row it stopped
   occupying, and that number would have had to track three header heights.

   THE FOOTER IS NOT PINNED. It is the END OF THE DOCUMENT and it is reached,
   not carried: normal flow, no sticky, no fixed, nothing that could make it
   float over the page mid-journey. `body` is a min-height:100svh flex column
   whose content region grows (main.page here, main.hero on the homepage, both
   flex:1), which is what settles the footer at the bottom of a SHORT page
   without pinning it to the viewport on a long one.

   WHY STICKY RESOLVES TO THE VIEWPORT AT ALL: both public sheets clip the x
   axis with `overflow-x:clip`, not `hidden`. `clip` is not a scrollport, so the
   bar's nearest scrolling ancestor is still the viewport. `hidden` would have
   made <body> a scroll container and pinned the bar to a box that never
   scrolls -- i.e. it would have rendered as if it were static.

   Z ORDER IS EXPLICIT, not incidental. The background sits at -1, page content
   at 1, the footer at 2, this bar at 20, and the modal overlays -- body-level
   siblings of the header, not descendants -- at 50. So the bar covers hero,
   chart and prose, and a dialog covers the bar. The language list's own
   z-index (2000, set by i18n.js) is local to the stacking context this rule
   creates, which is exactly why it can open over the page without anything
   else in the header needing to know about it.

   The homepage's header carries no class -- it is `body>header` -- so its own
   sheet pins it under the same contract. */
header.site{position:sticky;top:0;z-index:20}

/* ~1cm of page BELOW the footer, before the background ends. 1cm is 37.8px at
   the CSS reference resolution of 96dpi, so 38px is the desktop target; the
   clamp steps it down on narrow screens, where a fixed 38px is a much larger
   share of the screen than the gap it is imitating. It is DECLARED here -- one
   name, one value, both public sheets -- and APPLIED there, as body padding.
   Not applied here: this file is also loaded by the customer app shell and by
   /pay, neither of which has a public footer to breathe under. */
:root{--public-footer-bottom-breathing-room:clamp(28px,3.5vw,38px)}


/* FINAL SWEEP F4 -- a heading that exists for assistive technology only.
   Three pages jumped h1 -> h3 because a whole region (the XAUUSD panel, the
   plan grid, the feature grid) had no heading of its own: the cards inside it
   were h3 with nothing at h2 above them. Promoting the cards would have said
   they are page-level sections, which they are not, and would have moved the
   visual type. Naming the region instead fixes the outline AND gives each
   region the accessible name it never had. Layout is untouched by design:
   this is removed from flow entirely, so nothing reflows by a pixel. */
.vh{position:absolute!important;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;
  border:0}
