/* ============================================================
   SHIFTSIMPLE — LAYOUT SHELL (styles/layout.css)
   ============================================================
   The page column (.wrap), sticky nav, nav avatar, the fixed appearance /
   language controls and the global footer — the chrome shared by every
   view of every domain. */
  /* ---------- Layout shells ---------- */
  .wrap{max-width:1120px;margin:0 auto;padding:0 28px;}
  .rule{border:none;border-top:1px solid var(--line);}

  /* ---------- Nav ---------- */
  /* iOS/Chrome blank-space + scroll-jump bug — structural mitigation.
  Multiple rounds of production diagnostics (see DIAGNOSTICS.md and the
  'blankspace' mode) pinned the actual trigger precisely: it fires within
  ~20ms of window.scrollY + visualViewport.height reaching
  document.documentElement.scrollHeight exactly (i.e. the literal bottom
  of the page) while visualViewport.height has shrunk to a small value —
  the browser's dynamic toolbar mid-reveal, triggered by scroll momentum
  decelerating into the bottom boundary. documentElement.scrollHeight and
  the footer's position never move during any of this — confirmed there
  is no DOM/layout defect. Two earlier attempts are documented failures:
  a compositor-resync scroll nudge caused a worse regression (an infinite
  scroll-to-top loop) and was reverted outright, and adding a few px of
  bottom padding was considered and rejected before implementation — the
  trigger is reaching the scroll maximum itself, not a specific pixel
  value, so padding only moves where the same bug refires.
  This is a documented category of WebKit bug: backdrop-filter on a
  position:sticky/fixed element is a known, cataloged source of
  compositing complexity, and WebKit has repeatedly mishandled it during
  scroll-boundary and dynamic-toolbar-transition moments — exactly the
  circumstance the evidence points to. Since nav is the only sticky/fixed
  element on the page during normal use (confirmed via the diagnostic's
  stickyFixed capture), it's the only candidate. The fix here is
  structural and touches nothing about scroll position or timing: drop
  backdrop-filter (the expensive, documented-risky compositing operation)
  and add contain:layout paint (the standard, documented technique for
  isolating a sticky/fixed element's rendering from the rest of the page,
  reducing what the compositor has to redo during exactly this kind of
  transition) alongside the existing transform:translateZ(0) GPU-layer
  hint. Verified nav has no children relying on overflowing its box or
  using it as a positioning ancestor, so contain:paint's clipping and
  contain:layout's containing-block behavior are both safe here. This
  cannot itself cause a scroll-position regression — it never reads or
  writes scroll state — so unlike the reverted fix, a failed attempt here
  degrades to "bug persists," not "bug gets worse." Still unconfirmed on
  the affected device; needs real-device retest. */
  nav{
    position:sticky;top:0;z-index:50;
    background:var(--paper);
    border-bottom:1px solid var(--line);
    transform:translateZ(0);
    contain:layout paint;
  }
  .nav-inner{
    max-width:1120px;margin:0 auto;padding:16px 28px;
    display:flex;align-items:center;justify-content:space-between;gap:24px;
  }
  @media screen and (max-width:1024px){
    body > nav{transition:transform .18s ease;}
    body > nav.mobile-header-hidden{transform:translate3d(0,-100%,0);pointer-events:none;}
  }
  @media screen and (max-width:1024px) and (prefers-reduced-motion:reduce){
    body > nav{transition:none;}
  }
  .brand{display:flex;align-items:center;gap:10px;cursor:pointer;}
  /* ---------- Nav mascot avatar — a small "visual assistant profile"
  treatment, deliberately isolated from the .shift-helper/.shift-helper-slot
  component used for full illustration placements elsewhere (see
  mountShiftHelpers()). It reuses the same source PNG referenced from
  SHIFT_HELPERS (never a hardcoded path — see NAV_AVATAR_HELPER_ID below)
  but applies its own cropped, circular viewport: an oversized copy of the
  image is absolutely positioned to show only its top ~44% (face + start of
  shoulders), so the character reads clearly at 46-58px. A decorative gold
  ring sits inset from the photo's own circular edge with a masked gap near
  the lower-right, so the ring reads as open rather than a closed badge and
  the character appears to spill slightly past it. Purely decorative:
  alt="" + aria-hidden="true", no click handler, no new functionality.
  The avatar must never set the nav's height or make it wrap
  (BLANKSPACE_SCROLL_BUG.md, Tenth investigation): the nav is one 67px row
  whose height comes from the 34px tab buttons, so the avatar is 34px
  (adds zero height) and is left out of the layout entirely below 800px,
  where its width would push the tabs onto a second row (measured: wraps
  up to 780px in Spanish). Helpers OFF hides it at every width
  (components.css). ---------- */
  /* Enlarged ~20% on 2026-10-11 (owner request): the picture is 41px
  (34 x 1.2), and -3.5px top/bottom margins keep its layout height at the
  same 34px as the tab buttons, so the nav's 67px row height is unchanged —
  the extra 7px sits inside the nav's own 16px vertical padding. The ring
  inset scales with it (4px -> 5px). */
  .nav-avatar{display:none;position:relative;width:41px;height:41px;margin:-3.5px 0;border-radius:50%;overflow:hidden;flex:0 0 auto;background:transparent;}
  @media (min-width:800px){
    .nav-avatar{display:block;}
  }
  .nav-avatar img{position:absolute;top:0;left:50%;width:228%;height:228%;transform:translateX(-50%);}
  .nav-avatar-ring{position:absolute;top:5px;left:5px;right:5px;bottom:5px;border-radius:50%;border:2px solid var(--gold);pointer-events:none;
    -webkit-mask-image:conic-gradient(#000 0deg 100deg, transparent 100deg 150deg, #000 150deg 360deg);
    mask-image:conic-gradient(#000 0deg 100deg, transparent 100deg 150deg, #000 150deg 360deg);}
  /* Red, White & Blue Pearl only (.nav-avatar-open, toggled in JS by
  paintNavAvatar() when data-theme="red-white-blue"): swaps the cropped
  circular photo above for the supplemental profile-helper-no-text.png,
  shown uncropped via object-fit:contain and anchored to the bottom of the
  same box so it visibly leans out past the open gold ring rather than
  being clipped into it. Every other theme keeps the treatment above,
  completely untouched. */
  /* Gold-rimmed profile medallions (.nav-avatar-medallion, toggled in
  JS by paintNavAvatar() for the themes listed in NAV_AVATAR_MEDALLIONS —
  Original, Neon Blue and Pink/Purple, each with its OWN image): the approved
  profile image already carries its own gold rim, so it fills the SAME
  34px circular box edge to edge (object-fit:cover, no oversized crop)
  and the decorative CSS ring is hidden rather than drawn twice. Box size,
  spacing, alignment and the brand click behavior are unchanged. */
  .nav-avatar.nav-avatar-medallion img{position:absolute;top:0;left:0;width:100%;height:100%;transform:none;object-fit:cover;}
  .nav-avatar.nav-avatar-medallion .nav-avatar-ring{display:none;}
  .nav-avatar.nav-avatar-open{overflow:visible;border-radius:0;background:none;}
  .nav-avatar.nav-avatar-open img{position:absolute;left:50%;bottom:0;top:auto;width:auto;height:120%;max-width:none;transform:translateX(-50%);object-fit:contain;}
  @media (max-width:860px){
    .nav-avatar.nav-avatar-open img{height:140%;}
  }
  .brand-name{font-family:'Fraunces',serif;font-weight:600;font-size:19px;letter-spacing:-0.01em;}
  .brand-shift{color:var(--pine);}
  .brand-slash{color:var(--gold);font-weight:700;margin:0 1px;}
  .nav-right{display:flex;align-items:center;gap:14px;flex-wrap:wrap;justify-content:flex-end;}
  .tabs{display:flex;gap:4px;flex-wrap:wrap;}
  /* Persistent "change appearance" control — icon-only (aria-label + title
  tooltip carry the accessible name; visible text label is sr-only below).
  PRODUCTION REGRESSION FIX (blank-space/scroll bug — see
  BLANKSPACE_SCROLL_BUG.md): this was originally a normal flex item inside
  .nav-right, alongside .tabs. Measurement during that investigation showed
  it pushed nav onto a second row (115px instead of 67px) at most widths
  in the 520–860px range, including every iPad in portrait orientation
  (744–834px) — nav is the one element that bug's fix history already
  isolates for iOS toolbar-transition sensitivity (contain:layout paint,
  no backdrop-filter). Two later attempts to keep the button visually
  "in" the nav row (icon-only breakpoints; then position:absolute inside
  .nav-inner with reserved padding) both still failed at 744px specifically:
  the 4 full-text tabs alone (515.9px) already consume nearly all of
  .nav-right's available width there (529.1px), so there is no width left
  to reserve for a second control on that row at that breakpoint without
  shrinking the tabs. Rather than shrink nav's primary navigation to make
  room, this button is a floating action button pinned to the viewport's
  bottom-right corner — entirely outside nav's box, never competing for
  its row width at any viewport size, so nav's height is byte-identical to
  its pre-button state at every width (verified 360–1200px). */
  .theme-toggle-btn{
    position:fixed;bottom:20px;right:20px;z-index:60;
    display:inline-flex;align-items:center;justify-content:center;
    background:transparent;border:0;border-radius:50%;overflow:hidden;
    width:48px;height:48px;padding:0;color:var(--ink-soft);
    box-shadow:0 2px 10px rgba(18,21,26,0.18);
    cursor:pointer;transition:transform .12s,box-shadow .12s;
  }
  /* The owner's palette / speaker artwork (appearance and music), ring included. */
  .theme-toggle-img{display:block;width:100%;height:100%;border-radius:50%;}
  .theme-toggle-btn:hover{transform:scale(1.06);box-shadow:0 3px 14px rgba(18,21,26,0.26);}
  .theme-toggle-btn:focus-visible{outline:2px solid var(--pine);outline-offset:2px;}
  .theme-toggle-label{
    position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
    clip:rect(0,0,0,0);white-space:nowrap;border:0;
  }
  @media (max-width: 480px){
    .theme-toggle-btn{bottom:14px;right:14px;width:44px;height:44px;}
  }
  /* Language switcher — same fixed-FAB pattern as .theme-toggle-btn above,
  and for the SAME reason: it lives OUTSIDE <nav> (see that comment) rather
  than as a nav-row flex item, and outside nav's transform:translateZ(0)
  containing-block scope, so it can never repeat the nav-wrapping
  regression the blank-space investigation already isolated and fixed.
  Positioned immediately left of the appearance button with a 10px gap. */
  .lang-switch{
    position:fixed;bottom:20px;right:74px;z-index:60;
    display:inline-flex;background:var(--white);border:1.5px solid var(--line);
    border-radius:20px;box-shadow:0 2px 10px rgba(18,21,26,0.18);overflow:hidden;
  }
  .lang-switch-btn{
    background:none;border:none;padding:11px 13px;font-size:12.5px;font-weight:700;
    letter-spacing:0.4px;color:var(--ink-soft);cursor:pointer;transition:background .12s,color .12s;
  }
  .lang-switch-btn.selected{background:var(--pine);color:var(--white);}
  .lang-switch-btn:not(.selected):hover{color:var(--ink);}
  @media (max-width: 480px){
    .lang-switch{bottom:14px;right:64px;}
    .lang-switch-btn{padding:9px 11px;font-size:11.5px;}
  }
  .tab-btn{
    background:none;border:none;padding:9px 14px;font-size:14px;font-weight:500;
    color:var(--ink-soft);border-radius:20px;transition:background .15s, color .15s;
    white-space:nowrap;
  }
  .tab-btn:hover{background:var(--paper-dim);}
  .tab-btn.active{background:var(--pine);color:var(--primary-contrast);}
  /* The "Existing Reference ID" lookup toggle is a FIFTH control on the nav's
  tab row. The four primary tabs already fill the row at iPad-portrait widths
  — the documented reason (above) the appearance and language controls are
  floating FABs rather than nav-row items, since at 744px the four tabs alone
  (~516px) consume nearly all of .nav-right's width (~529px). Shrinking the
  tabs enough to fit a fifth item inline (~44px/tab) would make them unreadable,
  so from 601–1024px the tab strip instead scrolls horizontally INSIDE the nav
  rather than wrapping to a second row: the nav stays one 67px row at every
  width in both languages and all six themes. min-width:0 keeps the overflow
  contained in the strip (no page-level horizontal scroll), and the scrollbar
  is hidden so it never adds height. Above 1024px the full row fits, so the
  base wrap behavior is left untouched. */
  @media (min-width:601px) and (max-width:1024px){
    .nav-right{flex-wrap:nowrap;min-width:0;}
    .tabs{flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;min-width:0;scrollbar-width:none;}
    .tabs::-webkit-scrollbar{display:none;}
    /* The reference-ID toggle stays pinned and fully visible at the right of
    the row (never scrolled off): only the four primary tabs scroll. */
    .nav-ref{flex:0 0 auto;}
  }

  /* ---------- GLOBAL FOOTER ---------- */
  footer{padding:50px 0 60px;border-top:1px solid var(--line);}
  .foot-cols{display:flex;justify-content:space-between;gap:40px;flex-wrap:wrap;}
  .foot-brand{max-width:280px;font-size:13px;color:var(--ink-soft);line-height:1.6;}
  .foot-brand .brand-name{display:block;margin-bottom:10px;}
  .foot-col h4{font-size:11.5px;letter-spacing:0.6px;color:var(--ink-soft);margin-bottom:12px;text-transform:uppercase;}
  .foot-col a{display:block;font-size:13.5px;color:var(--ink-soft);margin-bottom:9px;text-decoration:none;background:none;border:none;padding:0;text-align:left;cursor:pointer;font-family:inherit;}
  .foot-col a:visited{color:var(--ink-soft);}
  .foot-col a:hover{color:#1B2A4A;text-decoration:underline;}
  .foot-bottom{margin-top:36px;padding-top:20px;border-top:1px solid var(--line);font-size:12px;color:var(--ink-soft);}

  /* Tablet-and-below overrides (max-width:860px) for the rules above — kept in
  this file, after them, so the cascade is exactly what it was when they all
  lived in one shared media block. */
  @media (max-width:860px){
    .foot-cols{flex-direction:column;gap:28px;}
  }
