/* ═══════════════════════════════════════════════════════════════════════════
   QUAFI Mobile — overrides applied only at ≤ 1024px
   ───────────────────────────────────────────────────────────────────────────
   IMPORTANT: every top-level selector in this file MUST be inside a media
   query. If you find yourself writing a desktop rule here, put it in
   quafi.css instead. The whole file is gated so it cannot leak to desktop.

   The 3-breakpoint system (defined as tokens in quafi.css):
       --bp-mobile:   640px   ≤ 640px      phone
       --bp-tablet:  1024px   641–1024px   large phone landscape + tablet
       --bp-desktop: 1025px   ≥ 1025px     UNCHANGED desktop view

   See: docs/handoff-mobile-experience.md  for the full plan and rationale.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ═══════════════════════════════════════════════════════════════════════════
   §2 · CROSS-CUTTING COMPONENTS
   Components that appear on every screen. Get these right before per-screen
   work begins. Source: handoff §2.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── §2.0  Safe-area inset applied at the body level on mobile only ────────
   iOS Safari renders the system status bar (time/signal/battery) over the
   WebView; if the page has no top padding, that bar visually overlaps the
   page content. We apply the safe-top inset once, at the body, so every
   top element (status bar, navbar, auth-shell, home-container) starts
   safely below the iOS system bar — no matter which is the topmost visible. */
@media (max-width: 1024px) {
  body {
    padding-top: var(--safe-top);
  }
}

/* ── §2.1  Sticky navigation with backdrop-blur on scroll ──────────────────── */
@media (max-width: 1024px) {
  .nav-bar,
  .landing-nav {
    position: sticky;
    top: 0;
    z-index: 950;
    height: 56px;
    /* Tight padding & flex layout to prevent horizontal overflow on narrow
       viewports. The desktop default has padding 1.25rem 3rem which is way
       too wide for a 360–430 px phone. overflow:hidden is a final safety
       net so a long username or odd content can never push children past
       the viewport edge. */
    padding-top:    0;
    padding-bottom: 0;
    padding-left:   max(var(--sp-2), var(--safe-left));
    padding-right:  max(var(--sp-2), var(--safe-right));
    max-width: none;
    margin: 0;
    gap: 0.4rem;
    overflow: hidden;
    /* SOLID white background by default on mobile — eliminates the
       first-paint overlap with the status bar that lives just above. The
       backdrop-blur transition on scroll still fires but starts from
       opaque-white, so visually the navbar is always cleanly opaque. */
    background-color: var(--white);
    transition: backdrop-filter var(--m-medium) var(--m-ease),
                -webkit-backdrop-filter var(--m-medium) var(--m-ease),
                background-color var(--m-medium) var(--m-ease),
                box-shadow var(--m-medium) var(--m-ease);
  }
  .nav-bar.nav--scrolled,
  .landing-nav.nav--scrolled {
    backdrop-filter: blur(10px) saturate(160%);
    -webkit-backdrop-filter: blur(10px) saturate(160%);
    background-color: rgba(255, 255, 255, 0.92);
    box-shadow: 0 1px 0 rgba(58, 106, 114, 0.06);
  }

  /* ── §2.1.1  Brand — compact so the wordmark always fits in full ───────
     User feedback: with the wordmark sized for visual presence (1.05rem +
     32-px mark), the brand area was wider than the available space on
     a 430-px iPhone Pro Max once the busiest navbar (output screen) had
     all 5 right-side actions present, so the wordmark was getting clipped
     with an ellipsis ("QUA…"). Reducing the mark to 26 px and the
     wordmark to 0.92rem brings the brand back under width so the full
     "QUAFI" wordmark is always visible. */
  .nav-brand {
    flex: 1 1 auto;
    min-width: 0;
    gap: 0.5rem;                  /* 8 px between mark and wordmark */
    font-size: 0.92rem;
    letter-spacing: 0.1em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .nav-brand .quafi-mark,
  .nav-brand .quafi-mark-sm {
    width: 26px !important;
    height: 26px !important;
    margin-right: 0;
    flex-shrink: 0;
  }

  /* ── §2.1.2  Nav-actions: never wrap, always shrink-fit ─────────────── */
  .nav-actions {
    flex: 0 0 auto;
    min-width: 0;
    gap: 0.3rem;
    margin-left: auto;
  }

  /* ── §2.1.3  HIDE the redundant "Home" button — already in mobile menu ─ */
  .nav-actions > .btn.btn-secondary {
    display: none !important;
  }

  /* ── §2.1.4  Adjust / Back / Back-to-Portfolio: icon-only, sized to match
     the .nav-mini-action pills so the whole right-side action row is a
     single visual rhythm of 40-px circles that confidently fills the
     navbar's vertical space. */
  .nav-actions > .btn.btn-ghost {
    padding: 0;
    width: 40px;
    height: 40px;
    min-width: 40px;
    min-height: 40px;
    border-radius: 999px;
    gap: 0;
    border: 1px solid rgba(58, 106, 114, 0.18);
    background: transparent;
    color: var(--teal);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
  }
  .nav-actions > .btn.btn-ghost:active {
    background: var(--teal);
    color: var(--white);
    border-color: var(--teal);
  }
  /* Hide the trailing text label span; the icon (SVG arrow) carries meaning */
  .nav-actions > .btn.btn-ghost > span[data-i18n] {
    display: none;
  }
  .nav-actions > .btn.btn-ghost svg { width: 18px; height: 18px; }

  /* ── §2.1.4b  Generate Report (output screen primary action) ───────────
     Stays distinct from the secondary outlined pills via the teal-fill
     primary treatment; same 40 × 40 silhouette. */
  .nav-actions > #btn-print {
    padding: 0;
    width: 40px;
    height: 40px;
    min-width: 40px;
    min-height: 40px;
    border-radius: 999px;
    gap: 0;
    background: var(--teal);
    color: var(--white);
    border: 1px solid var(--teal);
    flex-shrink: 0;
  }
  .nav-actions > #btn-print:active { background: var(--teal-light); }
  .nav-actions > #btn-print > span[data-i18n] { display: none; }
  .nav-actions > #btn-print svg { width: 18px; height: 18px; }

  /* ── §2.1.5  User badge: icon-only on mobile ────────────────────────────
     Hides "Hello, ashehadi" text; keeps the Admin pill (tiny) and the cog
     icon, which still toggles the existing user-menu dropdown. This is
     the single account-affordance on mobile — app navigation goes through
     the hamburger menu. */
  .user-badge {
    padding: 0 0.3rem 0 0.4rem;
    gap: 0.3rem;
    border-radius: 999px;
    flex-shrink: 0;
    height: 40px;
  }
  .user-badge .ub-greeting,
  .user-badge .ub-name {
    display: none;
  }
  .user-badge .ub-admin {
    font-size: 0.52rem;
    padding: 0.1rem 0.4rem;
    letter-spacing: 0.08em;
    margin-left: 0;
  }
  .user-badge .ub-cog {
    width: 40px;
    height: 40px;
  }
  .user-badge .ub-cog svg {
    width: 18px;
    height: 18px;
  }
  /* Keep the user-menu dropdown anchored to the cog on mobile so it doesn't
     drift off-screen when the badge is compacted. */
  .user-badge .user-menu {
    right: 0;
    left: auto;
    min-width: 220px;
  }

  /* ── §2.1.6  Hamburger trigger: explicit dimensions so it can't be
     collapsed by the surrounding flex layout. flex-shrink:0 guarantees
     it survives even if the brand wordmark is long. */
  .nav-mobile-trigger {
    flex-shrink: 0;
    flex-grow: 0;
  }
}

/* ── §2.2  FABs: hidden on mobile — both lang and feedback move into the
   navbar as compact .nav-mini-action pills, which avoids collisions with
   sticky-bottom CTAs like "Generate My Portfolio" and reclaims thumb-zone
   real estate. The desktop FABs are unchanged. */
@media (max-width: 1024px) {
  #lang-fab,
  #feedback-fab { display: none !important; }
}

/* ── §2.2.1  Compact in-navbar action buttons (lang + feedback) ────────────
   Injected by app.js initMobileNavActions() into every .nav-bar on mobile.
   Sized at 40 × 40 to match the cog and back icons — the whole right-side
   row is a single visual rhythm that confidently fills the 56-px navbar. */
@media (max-width: 1024px) {
  .nav-mini-action {
    appearance: none;
    -webkit-appearance: none;
    background: transparent;
    border: 1px solid rgba(58, 106, 114, 0.18);
    border-radius: 999px;
    color: var(--teal);
    width: 40px;
    height: 40px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-family: inherit;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    line-height: 1;
    flex-shrink: 0;
    transition: background var(--m-fast) var(--m-ease),
                color var(--m-fast) var(--m-ease),
                border-color var(--m-fast) var(--m-ease);
  }
  .nav-mini-action:active {
    background: var(--teal);
    color: var(--white);
    border-color: var(--teal);
  }
  .nav-mini-action:focus-visible {
    outline: 2px solid var(--gold);
    outline-offset: 2px;
  }
  .nav-mini-action svg { display: block; width: 18px; height: 18px; }
}
@media (min-width: 1025px) {
  .nav-mini-action { display: none; }
}

/* ── §2.3  Status bar — IN NORMAL FLOW ABOVE THE NAVBAR on mobile ──────────
   On desktop the status bar is position: fixed at top: 0 with z-index 1000
   and the page reserves 40px of space (`.screen { padding-top: 2.5rem }`)
   so the navbar can sit right below it.

   On mobile that pattern broke: the navbar is sticky at top: 0, but
   `.screen`'s 40px padding pushed the navbar's *natural flow position*
   down to y=40, while the status bar floated independently at y=56+ →
   overlap at first paint.

   The fix used here is the simplest professional layout: status bar
   becomes `position: relative` (normal flow) on mobile and renders at the
   very top of the body, ABOVE the navbar. As the user scrolls down, the
   status bar scrolls away naturally and the navbar becomes "stuck" at
   top: 0 of the viewport. Matches the user's expectation: "I'm OK with
   the database header positioning below the main header after scroll." */
@media (max-width: 1024px) {
  #status-bar {
    position: relative;
    top: 0;
    left: 0;
    right: 0;
    width: 100%;
    border-radius: 0;
    /* No safe-top here — body padding-top already provided it (§2.0). */
    padding-top:    0.45rem;
    padding-bottom: 0.45rem;
    padding-left:   max(var(--sp-3), var(--safe-left));
    padding-right:  max(var(--sp-3), var(--safe-right));
    font-size: var(--fs-mobile-tiny);
    z-index: 1;
  }
  /* Remove the desktop top-gutter that was reserving space for the
     position:fixed status bar on big screens. On mobile the status bar is
     above the navbar in flow, so no gutter is needed. */
  .screen { padding-top: 0; }
}

/* ── §2.4  Toast: bottom-slide-up on mobile (snackbar pattern) ─────────────── */
@media (max-width: 1024px) {
  #toast {
    top: auto !important;
    bottom: calc(var(--sp-6) + var(--safe-bot));
    left: var(--sp-3);
    right: var(--sp-3);
    max-width: none;
    transform: translateY(120%);
    transition: transform var(--m-medium) var(--m-ease);
  }
  #toast.show { transform: translateY(0); }
}

/* ── §2.5  Modals become bottom sheets ─────────────────────────────────────── */
@media (max-width: 1024px) {
  .modal-overlay,
  .auth-modal,
  .terms-modal,
  .feedback-modal {
    align-items: flex-end;
  }
  .modal,
  .auth-modal-panel,
  .terms-panel,
  .feedback-panel {
    width: 100%;
    max-width: none;
    max-height: 92vh;
    border-radius: 18px 18px 0 0;
    padding-bottom: calc(var(--sp-4) + var(--safe-bot));
    animation: sheet-slide-up var(--m-medium) var(--m-ease);
  }
  /* Drag-handle indicator — purely decorative, communicates "this is draggable" */
  .modal::before,
  .auth-modal-panel::before,
  .terms-panel::before,
  .feedback-panel::before {
    content: "";
    display: block;
    width: 36px; height: 4px;
    background: var(--marble3);
    border-radius: 4px;
    margin: 0.6rem auto 0.4rem;
  }
}

/* ── §2.6  Mobile menu sheet ───────────────────────────────────────────────── */
.mobile-menu {
  display: none;
}
@media (max-width: 1024px) {
  .mobile-menu {
    position: fixed;
    inset: 0;
    z-index: 1100;
    align-items: flex-start;
    justify-content: stretch;
    pointer-events: none;
    opacity: 0;
    transition: opacity var(--m-medium) var(--m-ease);
  }
  .mobile-menu[aria-hidden="false"] {
    display: flex;
    pointer-events: auto;
    opacity: 1;
  }
  .mobile-menu-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(58, 58, 66, 0.45);
    backdrop-filter: blur(2px);
  }
  .mobile-menu-panel {
    position: relative;
    margin-left: auto;
    width: min(86vw, 360px);
    height: 100vh;
    background: var(--white);
    box-shadow: -8px 0 32px rgba(58, 58, 66, 0.18);
    display: flex;
    flex-direction: column;
    padding-top:    calc(var(--sp-4) + var(--safe-top));
    padding-bottom: calc(var(--sp-4) + var(--safe-bot));
    padding-left:   var(--sp-4);
    padding-right:  var(--sp-4);
    transform: translateX(100%);
    transition: transform var(--m-medium) var(--m-ease);
  }
  .mobile-menu[aria-hidden="false"] .mobile-menu-panel {
    transform: translateX(0);
  }
  .mobile-menu-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: var(--sp-4);
  }
  .mobile-menu-title {
    font-size: var(--fs-mobile-h3);
    font-weight: 700;
    color: var(--dark1);
    letter-spacing: 0.04em;
    text-transform: uppercase;
  }
  .mobile-menu-close {
    appearance: none;
    background: transparent;
    border: 0;
    font-size: 1.6rem;
    line-height: 1;
    color: var(--dark2);
    cursor: pointer;
    width: var(--tap);
    height: var(--tap);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
  }
  .mobile-menu-close:active { background: var(--marble2); }
  .mobile-menu-body {
    flex: 1 1 auto;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
  }
  .mobile-menu-body a,
  .mobile-menu-body button {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--dark1);
    text-align: left;
    font-family: inherit;
    font-size: var(--fs-mobile-body);
    font-weight: 500;
    padding: 0.85rem 0.6rem;
    border-radius: 10px;
    text-decoration: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: var(--tap);
    cursor: pointer;
  }
  .mobile-menu-body a:active,
  .mobile-menu-body button:active { background: var(--marble2); }
  .mobile-menu-body a + a,
  .mobile-menu-body button + a,
  .mobile-menu-body a + button,
  .mobile-menu-body button + button {
    border-top: 1px solid var(--marble2);
    border-top-left-radius: 0;
    border-top-right-radius: 0;
  }
  .mobile-menu-lang-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.7rem 0.6rem;
    margin-bottom: var(--sp-3);
    border: 1px solid var(--marble2);
    border-radius: 12px;
  }
  .mobile-menu-lang-row .mm-lang-label {
    font-size: var(--fs-mobile-tiny);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--dark2);
    font-weight: 700;
  }
  .mobile-menu-lang-row .mm-lang-btn {
    appearance: none;
    background: transparent;
    border: 1px solid rgba(58, 106, 114, 0.22);
    border-radius: 999px;
    color: var(--teal);
    font-family: inherit;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    padding: 0.35rem 0.75rem;
    min-height: 32px;
    cursor: pointer;
  }
  .mobile-menu-foot {
    margin-top: var(--sp-4);
    padding-top: var(--sp-3);
    border-top: 1px solid var(--marble2);
    text-align: center;
  }
  .mobile-menu-brand {
    font-weight: 800;
    letter-spacing: 0.18em;
    font-size: 0.95rem;
    color: var(--teal);
  }
  .mobile-menu-tag {
    font-size: var(--fs-mobile-tiny);
    color: var(--dark2);
    margin-top: 0.2rem;
  }

  /* Hamburger button shown only on mobile, hidden on desktop.
     Sized 40 × 40 — matches the right-side action-pill rhythm and tightens
     the brand area. Internal SVG centering yields ~9 px of natural
     horizontal padding inside the button; that's exactly the visual gap
     to the brand mark (which has its own 8-px gap to the wordmark). So
     left side reads as: [☰ ~9px ●─QUAFI] — symmetric spacing, no margin
     needed on the hamburger itself. */
  .nav-mobile-trigger {
    appearance: none;
    background: transparent;
    border: 0;
    width: 40px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--dark1);
    cursor: pointer;
    border-radius: 10px;
    margin-right: 0;
  }
  .nav-mobile-trigger:active { background: var(--marble2); }
  .nav-mobile-trigger svg { width: 20px; height: 20px; }
}
@media (min-width: 1025px) {
  .nav-mobile-trigger { display: none; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   §4 · REUSABLE ANIMATION LIBRARY
   Six keyframes used across the mobile experience. All declared once here.
   ═══════════════════════════════════════════════════════════════════════════ */

@keyframes sheet-slide-up {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}
@keyframes fade-up {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes float-y {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-3px); }
}
@keyframes pulse-glow {
  0%, 100% { box-shadow: 0 0 0 0 rgba(58, 106, 114, 0.0); }
  50%      { box-shadow: 0 0 40px 0 rgba(58, 106, 114, 0.15); }
}
@keyframes shimmer {
  0%   { background-position: -200% 0; }
  100% { background-position:  200% 0; }
}
@keyframes scale-tap {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(0.985); }
}

/* Reduced motion: every animation defined above collapses to nothing */
@media (prefers-reduced-motion: reduce) {
  .modal, .auth-modal-panel, .terms-panel, .feedback-panel,
  .mobile-menu-panel, [data-reveal] {
    animation: none !important;
    transition: none !important;
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
   §4.3 · REVEAL-ON-SCROLL INFRASTRUCTURE
   The [data-reveal] attribute on a node opts it in to a fade-up animation
   when it enters the viewport. The IntersectionObserver is bootstrapped in
   app.js (initRevealOnScroll). The CSS does the actual transition.
   ═══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 1024px) {
  [data-reveal] {
    opacity: 0;
    transform: translateY(12px);
    transition: opacity var(--m-medium) var(--m-ease),
                transform var(--m-medium) var(--m-ease);
    will-change: opacity, transform;
  }
  [data-reveal].is-revealed {
    opacity: 1;
    transform: translateY(0);
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
   §3 · PER-SCREEN MOBILE SPECIFICATIONS
   Source: handoff §3.1–§3.10
   ═══════════════════════════════════════════════════════════════════════════ */


/* ── §3.1  LANDING PAGE ────────────────────────────────────────────────────── */

/* §3.1.1  Hero ─ stack copy + brand mark vertically, mark centered ──────
   landing.css defines .quafi-mark-xl at 320 px desktop / 200 px at its own
   ≤ 980 px breakpoint and a 420/280-px radial-glow ::before that defaults
   to top-left positioning. Both are wrong for mobile: the mark dominates
   the viewport and the unpositioned glow appears at the left edge instead
   of behind the centered mark. We override both here with mobile-correct
   sizes and an explicitly-centered ::before. */
@media (max-width: 1024px) {
  .hero { padding: 3rem 1.25rem 2.5rem; }
  .hero-grid {
    display: flex;              /* override landing.css grid */
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 1.25rem;
  }
  .hero-art {
    order: -1;                  /* atom-mark moves ABOVE the headline */
    width: 100%;                /* full-width container so flex centers it */
    height: auto;
    padding: 0;
    margin-bottom: 0.25rem;
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
  }
  /* Mark size: 120 px is the sweet spot for a 360–430 px phone — present
     enough to feel like a brand anchor, not so big it dominates the hero. */
  .hero-art .quafi-mark,
  .hero-art .quafi-mark-xl {
    width: 120px !important;
    height: 120px !important;
    /* §4.2 float-y — subtle 6-second hover on the mark */
    animation: float-y 6s var(--m-ease-io) infinite;
  }
  /* Center the radial-glow ::before behind the mark, scaled proportionally
     to the new 120-px mark. */
  .hero-art::before {
    width: 180px !important;
    height: 180px !important;
    top: 50% !important;
    left: 50% !important;
    transform: translate(-50%, -50%);
  }
  @media (prefers-reduced-motion: reduce) {
    .hero-art .quafi-mark,
    .hero-art .quafi-mark-xl { animation: none; }
  }
  .hero-eyebrow {
    font-size: var(--fs-mobile-tiny);
    letter-spacing: 0.12em;
  }
  .hero-headline {
    font-size: var(--fs-mobile-display);
    line-height: 1.18;
    margin-top: 0.4rem;
  }
  .hero-sub {
    font-size: var(--fs-mobile-body);
    line-height: 1.55;
    max-width: 56ch;
    text-wrap: pretty;
  }
  .hero-cta-row {
    flex-direction: column;
    width: 100%;
    gap: 0.6rem;
  }
  .hero-cta-row .btn { width: 100%; min-height: var(--tap); }
  .hero-trust {
    flex-wrap: wrap;
    justify-content: center;
    font-size: var(--fs-mobile-tiny);
    gap: 0.4rem 0.6rem;
  }
}
@media (max-width: 360px) {
  /* Drop the middle trust badge on the tightest screens */
  .hero-trust > span:nth-child(3),
  .hero-trust > .dot:nth-child(2) { display: none; }
}

/* §3.1.2  Pillars ─ 1-col stack, reveal on scroll */
@media (max-width: 1024px) {
  .pillars { padding: 3rem 1.25rem; }
  .pillar-grid { grid-template-columns: 1fr; gap: 1rem; }
  .pillar { padding: 1.5rem 1.25rem; }
  .pillar-h { font-size: var(--fs-mobile-h3); }
  .pillar p {
    font-size: var(--fs-mobile-body);
    line-height: 1.55;
    text-wrap: pretty;
  }
}

/* §3.1.3  How-it-works ─ horizontal carousel with scroll-snap */
@media (max-width: 1024px) {
  .how { padding: 3rem 0; }
  .how > .section-eyebrow,
  .how > .section-h { padding: 0 1.25rem; }
  .how-grid {
    grid-template-columns: none;
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-padding-left: 8vw;
    -webkit-overflow-scrolling: touch;
    padding: 1.25rem 8vw 1rem;
    gap: 1rem;
    scrollbar-width: none;
  }
  .how-grid::-webkit-scrollbar { display: none; }
  .how-step {
    flex: 0 0 85vw;
    scroll-snap-align: center;
    padding: 1.5rem 1.25rem;
  }
  .how-step h3 { font-size: var(--fs-mobile-h3); margin-top: 0.5rem; }
  .how-step p { font-size: var(--fs-mobile-body); line-height: 1.55; }

  /* Pagination dots — appended by JS as .how-dots > button.
     The button itself is a 24-px tap target (small, but the carousel is
     primarily swiped — the dots are secondary). The VISIBLE dot is an 8 ×
     8 ::before circle centered inside, so the universal mobile
     min-height: var(--tap) rule (44 px) can't stretch the dot itself
     into an ellipse. */
  .how-dots {
    display: flex;
    justify-content: center;
    gap: 0.25rem;
    margin-top: 0.6rem;
  }
  .how-dots button {
    appearance: none;
    -webkit-appearance: none;
    width: 24px;
    height: 24px;
    min-width: 24px;
    min-height: 24px;          /* override the universal --tap min-height */
    background: transparent;
    border: 0;
    padding: 0;
    margin: 0;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .how-dots button::before {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--marble3);
    transition: background var(--m-fast) var(--m-ease),
                transform var(--m-fast) var(--m-ease);
  }
  .how-dots button.active::before {
    background: var(--teal);
    transform: scale(1.25);
  }
}
@media (min-width: 1025px) {
  .how-dots { display: none; }
}

/* §3.1.4  Methodology ─ stack + cards */
@media (max-width: 1024px) {
  .methodology { padding: 3rem 0; }
  .methodology-inner {
    flex-direction: column;
    padding: 0 1.25rem;
    gap: 1.5rem;
  }
  .methodology-left, .methodology-right { width: 100%; max-width: none; }
  .methodology-body {
    font-size: var(--fs-mobile-body);
    line-height: 1.55;
  }
  .methodology-right { display: flex; flex-direction: column; gap: 0.75rem; }
  .method-card { padding: 1.1rem 1rem; }
  .method-card-label { font-size: var(--fs-mobile-tiny); }
  .method-card-value { font-size: var(--fs-mobile-h3); }
  .method-card-sub { font-size: var(--fs-mobile-small); }
}

/* §3.1.5  Pricing ─ 1-col stack, featured plan first */
@media (max-width: 1024px) {
  .pricing { padding: 3rem 1.25rem; }
  .pricing-grid {
    grid-template-columns: 1fr;
    gap: 1rem;
  }
  /* Reorder: featured plan first, then Standard, Pro, Enterprise */
  .plan-card.featured { order: -1; }
  .plan-card {
    padding: 1.6rem 1.25rem;
    border-radius: 14px;
  }
  .plan-card .plan-name { font-size: var(--fs-mobile-h3); }
  .plan-card .plan-price .amount { font-size: 2rem; }
  .plan-features { font-size: var(--fs-mobile-body); }
  .plan-card .btn { min-height: var(--tap); width: 100%; }
  .pricing-note {
    text-align: center;
    font-size: var(--fs-mobile-small);
    line-height: 1.55;
    margin-top: 1.5rem;
  }
}

/* §3.1.6  Trust section ─ stats stay 3-col, fallback at <360px */
@media (max-width: 1024px) {
  .trust { padding: 3rem 1.25rem; }
  .trust-grid {
    grid-template-columns: 1fr;
    gap: 1.5rem;
  }
  .trust p {
    font-size: var(--fs-mobile-body);
    line-height: 1.55;
  }
  .trust-stats {
    grid-template-columns: repeat(3, 1fr);
    gap: 0.5rem;
  }
  .stat-card { padding: 1rem 0.5rem; }
  .stat-value { font-size: 1.6rem; }
  .stat-label { font-size: var(--fs-mobile-tiny); }
}
@media (max-width: 360px) {
  .trust-stats { grid-template-columns: 1fr; }
}

/* §3.1.7  Contact section ─ stack copy + CTA */
@media (max-width: 1024px) {
  .contact { padding: 3rem 1.25rem; }
  .contact-inner {
    flex-direction: column;
    gap: 1.5rem;
    text-align: center;
  }
  .contact-mail a { font-size: var(--fs-mobile-body); }
  .contact-cta .btn { width: 100%; min-height: var(--tap); }
}

/* §3.1.8  Footer ─ vertical stack with dividers */
@media (max-width: 1024px) {
  .landing-footer { padding: 2.5rem 1.25rem; }
  .footer-grid {
    flex-direction: column;
    gap: 1.5rem;
  }
  .footer-cols {
    grid-template-columns: 1fr;
    gap: 0;
  }
  .footer-cols > div {
    padding: 1rem 0;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
  }
  .footer-cols > div:first-child { border-top: 0; }
  .footer-col-h {
    font-size: var(--fs-mobile-tiny);
    letter-spacing: 0.12em;
    margin-bottom: 0.6rem;
  }
  .footer-cols a {
    display: block;
    padding: 0.45rem 0;
    font-size: var(--fs-mobile-body);
    min-height: var(--tap);
  }
  .footer-fineprint {
    font-size: var(--fs-mobile-tiny);
    line-height: 1.55;
    margin-top: 1.5rem;
  }
}


/* ── §3.2  AUTH SCREEN ─────────────────────────────────────────────────────── */
@media (max-width: 1024px) {
  .auth-shell { padding: 3rem 1rem calc(2rem + var(--safe-bot)); }
  .auth-back {
    top: 15px;
    font-size: 0.84rem;
    gap: 0.4rem;
  }
  .auth-back svg { width: 16px; height: 16px; }
  .auth-card {
    padding: calc(1.75rem + 20px) 1.25rem 1.75rem;
    border-radius: 16px;
  }
  .auth-brand { gap: 0.75rem; }
  .auth-word { font-size: 1.2rem; }
  .auth-tabs {
    height: 48px;
    border-radius: 12px;
    padding: 4px;
  }
  .auth-tab {
    font-size: var(--fs-mobile-body);
    border-radius: 8px;
  }
  .auth-grid { grid-template-columns: 1fr; gap: 0.85rem; }
  .auth-field input,
  .auth-field select,
  .auth-field textarea {
    min-height: 48px;
    font-size: 16px;   /* Critical: prevents iOS Safari from auto-zooming on focus */
    padding: 0.7rem 0.85rem;
  }
  .auth-label { font-size: var(--fs-mobile-small); }
  .auth-check { font-size: var(--fs-mobile-small); }
  .auth-foot { font-size: var(--fs-mobile-small); }
  .oauth-row { grid-template-columns: 1fr; gap: 0.6rem; }
  .oauth-btn { min-height: 48px; font-size: var(--fs-mobile-body); }
  .btn-lg { min-height: 52px; }
  /* Show / hide password eye-icon */
  .pw-toggle {
    position: absolute;
    right: 0.6rem;
    top: 50%;
    transform: translateY(-50%);
    appearance: none;
    background: transparent;
    border: 0;
    width: 36px;
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--dark2);
    cursor: pointer;
    border-radius: 8px;
  }
  .pw-toggle:active { background: var(--marble2); }
  .auth-field.has-toggle { position: relative; }
  .auth-field.has-toggle input { padding-right: 3rem; }
}


/* ── §3.3  HOME SCREEN ─────────────────────────────────────────────────────── */
@media (max-width: 1024px) {
  .home-container {
    padding: 2rem 1.25rem calc(3rem + var(--safe-bot));
    gap: 1.5rem;
  }
  .home-logo { gap: 0.75rem; }
  .wordmark { font-size: 1.6rem; }
  .tagline { font-size: var(--fs-mobile-small); }
  .home-intro {
    padding: 1.25rem 0.25rem;
  }
  .home-intro p {
    font-size: var(--fs-mobile-body);
    line-height: 1.6;
  }
  .home-intro .intro-highlight { padding: 1rem 0.85rem; }
  .home-question {
    font-size: var(--fs-mobile-display);
    line-height: 1.18;
  }
  .home-cards {
    grid-template-columns: 1fr;
    gap: 1rem;
  }
  .home-card {
    padding: 1.5rem 1.25rem;
    min-height: auto;
    transition: transform var(--m-fast) var(--m-ease),
                box-shadow var(--m-fast) var(--m-ease);
  }
  .home-card:active {
    transform: scale(0.985);
    transition-duration: 80ms;
  }
  .home-card .card-title { font-size: var(--fs-mobile-h3); line-height: 1.25; }
  .home-card .card-desc { font-size: var(--fs-mobile-body); line-height: 1.55; }
  .home-card .card-arrow { font-size: var(--fs-mobile-small); }
  .home-footer {
    font-size: var(--fs-mobile-tiny);
    line-height: 1.7;
  }
  .home-footer a { display: inline-block; padding: 0.25rem 0; }
}


/* ── §3.4  SELECTOR SCREEN ─────────────────────────────────────────────────── */
@media (max-width: 1024px) {
  .screen-body {
    padding: 1.5rem 1.25rem calc(7rem + var(--safe-bot));  /* room for sticky CTA */
  }
  .screen-title { font-size: var(--fs-mobile-h1); }
  .screen-subtitle { font-size: var(--fs-mobile-body); line-height: 1.55; }

  .form-section {
    margin-bottom: 1.25rem;
    padding: 1.25rem 1rem;
    border-radius: 14px;
  }
  .form-section-title {
    font-size: var(--fs-mobile-tiny);
    letter-spacing: 0.12em;
    padding-bottom: 0.5rem;
    position: relative;
  }
  /* Thin gold underline accent on each section head */
  .form-section-title::after {
    content: "";
    display: block;
    width: 32px;
    height: 3px;
    background: var(--gold);
    border-radius: 2px;
    margin-top: 0.4rem;
  }
  .form-row {
    flex-direction: column;
    align-items: stretch;
    gap: 0.85rem;
  }
  .form-label { font-size: var(--fs-mobile-body); font-weight: 600; }
  .form-hint  { font-size: var(--fs-mobile-small); }

  /* Number-input group */
  .num-input-group {
    align-self: flex-start;
    gap: 0.5rem;
  }
  .num-input-group button {
    width: 44px;
    height: 44px;
    font-size: 1.2rem;
    border-radius: 10px;
  }
  .num-input-group input {
    width: 80px;
    height: 44px;
    font-size: 1.2rem;
    text-align: center;
  }

  /* Chip groups — wrap-friendly, no horizontal scroll */
  .chip-group {
    gap: 0.4rem;
  }
  .chip {
    min-height: 36px;
    padding: 0.45rem 0.85rem;
    font-size: var(--fs-mobile-small);
  }

  /* Toggle groups — 3-col grid, full-width, tall */
  .toggle-group {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.5rem;
    width: 100%;
  }
  .toggle-btn {
    min-height: 56px;
    padding: 0.5rem 0.4rem;
    font-size: var(--fs-mobile-small);
    border-radius: 10px;
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.15rem;
  }
  .toggle-btn .toggle-sub {
    font-size: var(--fs-mobile-tiny);
    opacity: 0.65;
  }

  /* Generate button — sticky at bottom, full-width */
  .run-row {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    padding: 0.75rem var(--sp-3) calc(0.75rem + var(--safe-bot));
    background: linear-gradient(to top, var(--marble) 70%, rgba(242, 242, 238, 0));
    z-index: 900;
  }
  .run-row .btn-xl {
    width: 100%;
    min-height: 52px;
    font-size: var(--fs-mobile-body);
    border-radius: 12px;
  }
}


/* ── §3.5  PORTFOLIO (known-tickers) SCREEN ────────────────────────────────── */
@media (max-width: 1024px) {
  .search-container { margin-bottom: 0.75rem; }
  .search-input {
    height: 48px;
    font-size: 16px;
    padding-left: 2.5rem;
  }
  .search-icon { left: 0.75rem; }
  .search-dropdown {
    max-height: 60vh;
    border-radius: 12px;
  }
  .search-result-item {
    padding: 0.85rem 0.85rem;
    font-size: var(--fs-mobile-small);
    min-height: var(--tap);
  }
  .ticker-list { gap: 0.4rem; }
  .ticker-list-empty { font-size: var(--fs-mobile-small); }
}


/* ── §3.6  LOADING SCREEN ──────────────────────────────────────────────────── */
@media (max-width: 1024px) {
  #screen-loading.screen.active { display: flex; align-items: center; }
  .loading-container {
    padding: 2rem 1.25rem;
    width: 100%;
    max-width: 100%;
  }
  .loading-title { font-size: var(--fs-mobile-h2); }
  .loading-subtitle {
    font-size: var(--fs-mobile-body);
    min-height: 2.5rem;          /* prevents layout jump on phase change */
    line-height: 1.5;
  }
  .loading-spinner {
    animation: spin 1s linear infinite, pulse-glow var(--m-loop) var(--m-ease-io) infinite;
    border-radius: 50%;
  }
  .loading-progress {
    height: 6px;
    border-radius: 4px;
  }
}


/* ── §3.7  OUTPUT SCREEN ───────────────────────────────────────────────────── */
@media (max-width: 1024px) {
  .output-body {
    padding: 1rem 1rem calc(2rem + var(--safe-bot));
    /* On desktop .output-body is a centered, shrink-to-fit column (margin:0 auto,
       max-width:1100px) so it sizes to its content's max-content width. On a narrow
       phone that lets the chart carousel drag the whole body out to ~1100px and
       creates horizontal scroll. Pin it to the viewport so every child is bounded
       by the screen width and the carousel scrolls *internally* instead. */
    width: 100%;
    max-width: 100%;
    margin: 0;
    min-width: 0;
    box-sizing: border-box;
    overflow-x: hidden;
  }
  /* §3.7.1  Title wraps to 2 lines, badges below */
  .output-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.85rem;
  }
  .output-title {
    font-size: var(--fs-mobile-h1);
    line-height: 1.22;
  }
  .output-subtitle { font-size: var(--fs-mobile-tiny); }
  #profile-badges { gap: 0.4rem; }
  .profile-badge { font-size: var(--fs-mobile-tiny); padding: 0.25rem 0.6rem; }

  /* §3.7.2  FX banner ─ collapsible "Why this matters" */
  .fx-banner {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
    padding: 0.75rem 0.85rem;
    font-size: var(--fs-mobile-small);
  }
  .fx-banner-body details summary {
    cursor: pointer;
    font-weight: 600;
    color: var(--teal);
    font-size: var(--fs-mobile-small);
    list-style: none;
  }
  .fx-banner-body details summary::-webkit-details-marker { display: none; }
  .fx-banner-body details[open] summary { margin-bottom: 0.4rem; }

  /* §3.7.3  Insight pills ─ horizontal swipe */
  .insight-pills {
    flex-wrap: nowrap;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    gap: 0.4rem;
    padding-bottom: 0.4rem;
    scrollbar-width: none;
    margin: 0 -1rem;
    padding-left: 1rem;
    padding-right: 1rem;
  }
  .insight-pills::-webkit-scrollbar { display: none; }
  .insight-pill {
    scroll-snap-align: start;
    flex: 0 0 auto;
    font-size: var(--fs-mobile-tiny);
    padding: 0.4rem 0.7rem;
  }

  /* §3.7.4  Metric cards ─ 2-col + Sharpe full-width */
  .metrics-row {
    grid-template-columns: 1fr 1fr;
    gap: 0.6rem;
  }
  .metrics-row .metric-card {
    padding: 0.75rem 0.85rem;
    border-radius: 12px;
    position: relative;
  }
  /* Teal accent stripe on the left of each metric card */
  .metrics-row .metric-card::before {
    content: "";
    position: absolute;
    left: 0; top: 12px; bottom: 12px;
    width: 3px;
    background: var(--teal);
    border-radius: 0 2px 2px 0;
    opacity: 0.55;
  }
  .metrics-row .metric-label { font-size: var(--fs-mobile-tiny); }
  .metrics-row .metric-value { font-size: 1.4rem; }
  .metrics-row .metric-sub   { font-size: var(--fs-mobile-tiny); }
  /* Sharpe ratio spans full width — it's the headline metric */
  .metrics-row #m-sharpe-card { grid-column: 1 / -1; }
  .metrics-row #m-sharpe-card .metric-value { font-size: 1.6rem; }

  /* §3.7.5  Currency exposure row */
  #currency-exposure-row {
    flex-wrap: wrap;
    padding: 0.6rem 0.75rem;
    font-size: var(--fs-mobile-tiny);
  }
  .fx-pill { padding: 0.2rem 0.55rem; font-size: var(--fs-mobile-tiny); }

  /* §3.7.6  Chart ─ 260px tall, segmented window selector */
  .chart-section { padding: 0.85rem 0.75rem; border-radius: 12px; }
  .chart-header {
    flex-direction: column;
    align-items: stretch;
    gap: 0.75rem;
  }
  .chart-title { font-size: var(--fs-mobile-h3); }
  .chart-subtitle { font-size: var(--fs-mobile-small); }
  /* All six range buttons + the '?' on a single compact row (auto track for the
     circle), so the chrome stays short and the chart gets the height. */
  .chart-window-group {
    display: grid;
    grid-template-columns: repeat(6, 1fr) auto;
    gap: 0.2rem;
    background: var(--marble2);
    padding: 2px;
    border-radius: 9px;
    align-items: center;
  }
  /* Compact, harmonised range buttons — the chart is the priority, not the chrome. */
  .chart-win-btn {
    min-height: 0;
    padding: 0.3rem 0.2rem;
    font-size: var(--fs-mobile-tiny);
    border-radius: 7px;
  }
  /* The window 'how to read' circle sits inline at the end of the button grid. */
  .chart-window-group .info-hint-wrap { justify-content: center; }
  /* Slimmer 'How to read' pill — minimal vertical footprint on mobile. */
  .chart-howto-row { margin-top: 0.35rem; }
  .info-hint-pill {
    min-height: 0;
    padding: 0.14rem 0.5rem 0.14rem 0.36rem;
    font-size: 0.72rem;
    gap: 0.32rem;
  }
  .info-hint-pill-icon { width: 13px; height: 13px; font-size: 9px; }
  .chart-wrapper { height: 260px; }

  /* Generate Report → icon-only on mobile (the label eats header space). */
  .gen-report-btn .gen-report-label { display: none; }
  .gen-report-btn {
    padding-left: 0.7rem;
    padding-right: 0.7rem;
    gap: 0;
  }

  /* §3.7.7  Allocation table → stacked cards on mobile.
     The <table> stays in the DOM (renderTable still writes <tr>), but we
     restyle every row as a card. thead disappears; each td becomes a
     labeled block using the data-label attribute (added by renderTable). */
  .table-section { padding: 0; background: transparent; box-shadow: none; }
  /* Header gets a left+right inset so "Portfolio Allocation" / "N securities"
     visually align with the card content below (the cards have a 1-rem inner
     padding; matching it here prevents the title from looking glued to the
     viewport edge). */
  .table-header-row { padding: 0 0.6rem 0.6rem 0.6rem; }
  .table-title { font-size: var(--fs-mobile-h3); }
  .table-section table { display: block; width: 100%; }
  .table-section thead { display: none; }
  .table-section tbody { display: block; }
  .table-section tbody tr {
    display: block;
    background: var(--white);
    border: 1px solid var(--marble2);
    border-radius: 14px;
    padding: 1rem 1rem 0.85rem;
    margin-bottom: 0.75rem;
    box-shadow: var(--shadow-sm);
    position: relative;
  }
  .table-section tbody td {
    display: block;
    padding: 0;
    border: 0;
  }
  /* First td (ticker symbol + segment) — top of card, prominent */
  .table-section tbody td:first-child {
    padding-bottom: 0.6rem;
    border-bottom: 1px solid var(--marble2);
    margin-bottom: 0.6rem;
  }
  /* The "More info" td (the magnifier icon) gets pinned to the top-right */
  .table-section tbody td.info-cell,
  .table-section tbody td:nth-child(2) {
    position: absolute;
    top: 0.85rem;
    right: 0.85rem;
    padding: 0;
    margin: 0;
    border: 0;
  }
  .table-section tbody td.info-cell button {
    min-width: 36px;
    min-height: 36px;
  }
  /* Description cell */
  .table-section tbody td .ticker-desc {
    font-size: var(--fs-mobile-small);
    line-height: 1.5;
    color: var(--dark2);
  }
  .table-section tbody td.weight-cell {
    padding-top: 0.6rem;
    text-align: left;
  }
  /* Proportional weight bar — desktop draws a tiny px-width bar (max 120 px)
     next to the percentage. On mobile we want the bar to span the full card
     width as a track, with the fill matching the weight's share of the
     largest holding. renderTable() exposes this share as the
     `--weight-ratio` custom property (0..1). We render the bar as a single
     linear-gradient (teal up to the ratio stop, marble2 after) so a single
     <div> shows both the track AND the fill — no extra DOM. */
  .table-section tbody td.weight-cell .weight-bar-container {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    justify-content: flex-start;
  }
  .table-section tbody td.weight-cell .weight-bar {
    /* Override the desktop inline width (px) and the desktop max-width cap */
    width: auto !important;
    max-width: none !important;
    height: 8px;
    border-radius: 4px;
    flex: 1 1 auto;
    min-width: 0;
    /* Solid teal fill from 0% to (weight-ratio * 100%); soft marble track
       from there to 100%. AFRM (biggest holding, ratio = 1.0) → all teal.
       USO (ratio ≈ 0.56) → 56% teal then marble track. */
    background: linear-gradient(
      to right,
      var(--teal) 0%,
      var(--teal) calc(var(--weight-ratio, 1) * 100%),
      var(--marble2) calc(var(--weight-ratio, 1) * 100%),
      var(--marble2) 100%
    ) !important;
    opacity: 1 !important;
  }
  .table-section tbody td.weight-cell .weight-pct {
    font-size: var(--fs-mobile-h3);
    font-weight: 800;
    color: var(--dark1);
    white-space: nowrap;
    flex-shrink: 0;
  }
  /* "Descripción en inglés:" pill (Spanish sessions) — gets its own line above the desc */
  .table-section tbody td .ticker-desc em {
    display: block;
    margin-bottom: 0.35rem;
  }
  .ticker-cell { gap: 0.35rem; }
  .ticker-symbol { font-size: 1.1rem; }
  .ticker-segment { font-size: var(--fs-mobile-tiny); }

  /* §3.7.8  Generate Report becomes icon-only in nav */
  #btn-print { padding: 0.5rem 0.65rem; min-width: var(--tap); }
  #btn-print > span[data-i18n] { display: none; }
}


/* ── §3.8  ASSET DETAIL SCREEN ─────────────────────────────────────────────── */
@media (max-width: 1024px) {
  .asset-body { padding: 1.25rem 1rem calc(2rem + var(--safe-bot)); }
  .asset-hero {
    flex-direction: column;
    align-items: stretch;
    gap: 0.85rem;
  }
  .asset-hero-left, .asset-hero-right { width: 100%; }
  .asset-name { font-size: var(--fs-mobile-h1); line-height: 1.18; }
  .asset-hero-meta { gap: 0.5rem; flex-wrap: wrap; }
  .asset-ticker { font-size: var(--fs-mobile-body); }
  .asset-hero-right {
    background: var(--white);
    border: 1px solid var(--marble2);
    border-radius: 12px;
    padding: 0.85rem 1rem;
    text-align: left;
  }
  .asset-price { font-size: 1.5rem; }
  .asset-price-change { font-size: var(--fs-mobile-body); }
  .asset-price-label { font-size: var(--fs-mobile-tiny); }

  .asset-card { padding: 1rem 1rem; border-radius: 12px; }
  .asset-description-card .card-label { font-size: var(--fs-mobile-tiny); }
  .asset-description { font-size: var(--fs-mobile-body); line-height: 1.55; }

  .asset-chart-card .card-head {
    flex-direction: column;
    align-items: stretch;
    gap: 0.75rem;
  }
  .asset-chart-card .card-h { font-size: var(--fs-mobile-h3); }
  .asset-chart-card .card-sub { font-size: var(--fs-mobile-tiny); }
  .window-selector {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    gap: 0.3rem;
    padding-bottom: 0.3rem;
    scrollbar-width: none;
  }
  .window-selector::-webkit-scrollbar { display: none; }
  .window-selector button {
    flex: 0 0 auto;
    scroll-snap-align: start;
    min-height: 36px;
    padding: 0.4rem 0.8rem;
    font-size: var(--fs-mobile-tiny);
  }
  .asset-chart-wrapper { height: 260px; }

  .asset-kpis {
    grid-template-columns: 1fr 1fr;
    gap: 0.6rem;
  }
  .asset-kpi { padding: 0.75rem 0.85rem; }
  .asset-kpi-label { font-size: var(--fs-mobile-tiny); }
  .asset-kpi-value { font-size: 1.2rem; }
  .asset-kpi-sub   { font-size: var(--fs-mobile-tiny); }

  .asset-news-list { gap: 0.5rem; }
  .asset-news-card { padding: 1rem; }
  .asset-news-card .card-h { font-size: var(--fs-mobile-h3); }
  .asset-news-card .card-sub { font-size: var(--fs-mobile-tiny); }
  .asset-news-item {
    min-height: 64px;
    padding: 0.85rem 0;
    border-radius: 0;
  }
  .asset-news-item-title { font-size: var(--fs-mobile-small); line-height: 1.45; }
  .asset-news-item-meta { font-size: var(--fs-mobile-tiny); }
}


/* ── §3.9  SETTINGS SCREEN ─────────────────────────────────────────────────── */
@media (max-width: 1024px) {
  .settings-grid { grid-template-columns: 1fr; gap: 1rem; }
  .settings-card { padding: 1.25rem 1rem; border-radius: 14px; }
  .card-label {
    font-size: var(--fs-mobile-tiny);
    letter-spacing: 0.12em;
  }
}


/* ── §3.10  PLANS SCREEN (mirrors landing pricing) ─────────────────────────── */
@media (max-width: 1024px) {
  .plans-grid { grid-template-columns: 1fr; gap: 1rem; }
  /* Recommended/featured plan first if .plan-card.featured exists */
  .plans-grid .plan-card.featured { order: -1; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   §5 · TOUCH & A11Y — focus rings on keyboard only, tap-target floors
   ═══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 1024px) {
  /* Universal min tap-target for interactive elements (won't shrink existing
     buttons that are already larger — only enforces a floor). The chart range
     buttons and how-to hints opt out — they're set compact above on purpose. */
  button:not(.chart-win-btn):not(.info-hint-pill):not(.info-hint):not(.sip-check), a.btn, .toggle-btn, .chip {
    min-height: var(--tap);
  }
  /* Sector checkboxes: symmetric circles on mobile (the tap floor was stretching
     the 20px box into a tall rounded rectangle). A generous ::before keeps the
     touch target comfortable without enlarging the visual. */
  .sip-check {
    min-height: 0;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    position: relative;
  }
  .sip-check::before { content: ''; position: absolute; inset: -9px; }
  .sip-check svg { width: 15px; height: 15px; }
  /* Visible focus only when navigated by keyboard — touch users don't see
     a residual outline after tapping. */
  a:focus-visible, button:focus-visible,
  input:focus-visible, textarea:focus-visible, select:focus-visible {
    outline: 2px solid var(--gold);
    outline-offset: 2px;
  }
}

/* ── Chart carousel + new charts: mobile overrides ───────────────────── */
@media (max-width: 1024px) {
  .chart-carousel { margin: 1rem 0 1.25rem; }
  .carousel-arrow, .carousel-prev, .carousel-next { display: none; }
  /* Hard-constrain the whole carousel to the viewport. Without min-width:0
     the flex slides keep their content's intrinsic width (the Chart.js canvas
     / the 5-col window-button grid), so a slide balloons far wider than the
     screen and the panel overflows to the right. min-width:0 lets each slide
     collapse to its flex-basis (100% of the track) and everything inside fits. */
  .chart-carousel {
    width: 100%;
    max-width: 100%;
    overflow: hidden;
  }
  .chart-slide {
    padding: 1rem 0.85rem;
    border-radius: 14px;
    min-width: 0;
    max-width: 100%;
    box-sizing: border-box;
  }
  .chart-slide > * { min-width: 0; max-width: 100%; }
  .chart-wrapper { width: 100%; max-width: 100%; min-width: 0; }
  .chart-wrapper canvas { max-width: 100% !important; }
  /* No extra side padding on the track: each slide is full-width and must
     line up flush with the metric cards / table above and below it. Extra
     inset here made the chart panels visibly narrower than everything else
     ("out of size"). The full-width slides still scroll-snap cleanly. */
  .carousel-track {
    width: 100%;
    max-width: 100%;
    gap: 1rem;
    padding: 0;
    scroll-padding-left: 0;
  }
  .chart-disclaimer {
    font-size: var(--fs-mobile-tiny, 0.72rem);
    line-height: 1.5;
    margin-top: 0.75rem;
  }
  /* The treemap slide is the shortest of the three, but the carousel stretches
     every slide to the tallest (the heatmap). Let the treemap fill that height
     so it consumes the dead space below the disclaimer instead of leaving a
     blank gap. height:auto + flex:1 means renderTreemap reads the grown
     clientHeight and draws a correspondingly taller map. */
  .chart-slide[data-slide-key="treemap"] .treemap-wrapper {
    height: auto;
    flex: 1 1 auto;
    min-height: 280px;
  }
  /* Heatmap needs more vertical room on mobile: the column labels are now
     fully vertical (90°) so the header band is taller, and the per-row cells
     still need to stay legible. Clip any sub-pixel overflow to the panel. */
  /* Fill the slide height (like the treemap) so the vertically-centred matrix
     uses the available space instead of leaving a blank gap below the grid. */
  .heatmap-wrapper {
    height: auto;
    flex: 1 1 auto;
    min-height: 320px;
    overflow: hidden;
    max-width: 100%;
  }
  .treemap-tile:hover { transform: none; filter: none; }
  .hm-cell-val { font-size: 10px; }

  /* CRITICAL: the universal tap-target floor (button { min-height: 44px })
     also lands on the heatmap's row/column label buttons, which live inside
     a CSS grid sized to the matrix. A 44-px floor forces each of the N row
     labels taller than its matching cell row, so the labels progressively
     drift down and detach from their rows. Reset the floor for heatmap
     labels — they get their height from the grid track instead. */
  .hm-label, .hm-row, .hm-col {
    min-height: 0;
  }
  .hm-callout {
    font-size: var(--fs-mobile-small, 0.78rem);
    padding: 0.5rem 0.7rem;
  }
  .hm-disabled-title { font-size: var(--fs-mobile-h3, 1rem); }
  .hm-disabled-body  { font-size: var(--fs-mobile-small, 0.78rem); }
  .hm-disabled-icon { width: 30px; height: 30px; }
}

/* ── Glossary hints on small screens ─────────────────────────────────────────
   The popover becomes a centered modal over a blurred backdrop (see
   InfoHint.jsx + .glossary-overlay in quafi.css). Here we only enlarge the "?"
   tap target and keep the icon a true circle (overriding the universal --tap
   floor that otherwise stretches it into an ellipse). */
@media (max-width: 640px) {
  .info-hint {
    width: 18px;
    height: 18px;
    min-width: 18px;
    min-height: 18px;
    font-size: 12px;
  }
  .info-hint::before { inset: -13px; }   /* ~44px tap target */
}

/* ── Sector → Industry picker on small screens ───────────────────────────────
   Single-column industries, taller rows for touch, a taller scroll area. */
@media (max-width: 640px) {
  .sip-summary { padding: 0.8rem 0.85rem; }
  .sip-summary-text { font-size: var(--fs-mobile-body, 0.95rem); }
  .sip-toolbar { flex-wrap: wrap; gap: 8px; }
  .sip-search { flex: 1 1 100%; order: 1; }
  .sip-search input { min-height: 40px; font-size: var(--fs-mobile-body, 0.95rem); }
  .sip-bulk { order: 2; width: 100%; justify-content: flex-end; }
  .sip-bulk button { padding: 6px 4px; font-size: 0.85rem; }
  .sip-list { max-height: 60vh; }
  .sip-row-main { padding-top: 0.7rem; padding-bottom: 0.7rem; }
  .sip-sector-name { font-size: 0.95rem; }
  .sip-industries { grid-template-columns: 1fr; padding: 2px 14px 12px 40px; }
  .sip-ind { padding: 7px 0; font-size: 0.9rem; }
  .sip-ind input { width: 17px; height: 17px; }
}

