/* ============================================================================
   responsive.css — the shared device layer, loaded last on every page.
   ============================================================================

   Each page here grew its own breakpoints: fourteen different widths across
   seventeen stylesheets, several pages carrying a single `@media` and nothing
   below it. The result was a set of designs that were pixel-exact on the
   author's monitor and approximate everywhere else.

   This file doesn't restyle anything. It sits underneath the page CSS and fixes
   the things that are structural rather than decorative — the ones that make a
   layout wrong on a device rather than merely different:

     * one breakpoint scale, so pages reflow at the same widths as each other;
     * fluid gutters and type, so there are no dead zones between breakpoints;
     * the mobile-browser viewport (dvh), notch/home-indicator safe areas;
     * wide content (tables, chart rows) scrolls in its own box instead of
       pushing the page sideways;
     * touch targets and iOS's focus-zoom rule on coarse pointers;
     * an upper bound, so the layout doesn't stretch to nothing on a 4K panel.

   Load order matters: this must come after the page's own stylesheet. Rules are
   kept at low specificity so a page can still override any of them deliberately.

   BREAKPOINTS (max-width unless noted)
     420px   small phones          — iPhone SE / mini, 320–420 CSS px
     560px   phones                — the standard portrait phone
     768px   large phones/tablets  — portrait iPad, phablets, split view
     1024px  tablets landscape     — iPad landscape, small laptops
     1099px  sidebar overlay edge  — matches nav.css; do not change alone
     1280px  laptops
     1600px+ large desktop (min-width)
   ========================================================================== */

/* ---------------------------------------------------------------------------
   1. Tokens — every fluid value in one place.
   `clamp(min, preferred, max)` removes the awkwardness between breakpoints:
   the gutter shrinks smoothly from desktop to phone instead of stepping down
   at one arbitrary width and staying wrong either side of it.
   --------------------------------------------------------------------------- */
:root {
    /* Page gutter: 14px on a small phone → 22px from ~700px up. */
    --pad-x: clamp(0.875rem, 0.55rem + 1.6vw, 1.375rem);
    /* Vertical rhythm above the first block and below the last. */
    --pad-top: clamp(1.25rem, 0.6rem + 2.6vw, 2.25rem);
    --pad-bottom: clamp(3rem, 2rem + 4vw, 5rem);
    /* Gap between cards in a grid. */
    --gap: clamp(0.625rem, 0.4rem + 1.1vw, 1.125rem);
    /* Card corner radius — tighter on phones, where a big radius eats content. */
    --card-radius: clamp(0.75rem, 0.5rem + 0.8vw, 1.125rem);
    /* Minimum comfortable hit area on touch screens (Apple HIG / Material). */
    --tap: 44px;
    /* Safe-area insets: 0 everywhere except notched/gesture-bar devices. */
    --safe-top: env(safe-area-inset-top, 0px);
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    --safe-left: env(safe-area-inset-left, 0px);
    --safe-right: env(safe-area-inset-right, 0px);
}

/* ---------------------------------------------------------------------------
   2. Foundation
   --------------------------------------------------------------------------- */

/* Inherited border-box: pages that already set it are unaffected; pages that
   forgot stop miscomputing widths once padding is added. */
html {
    box-sizing: border-box;
    /* Stop iOS Safari inflating text in landscape. */
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}
*,
*::before,
*::after {
    box-sizing: inherit;
}

/* `overflow-x: clip` rather than `hidden`: hidden creates a scroll container,
   which silently breaks `position: sticky` on descendants. clip does not.
   Wrapped in :where() so it carries zero specificity — this file loads last, and
   a page with a legitimately wider-than-viewport layout (the option chain) must
   be able to opt out with a plain `html, body` rule of its own. */
:where(html, body) {
    overflow-x: clip;
}
html,
body {
    /* Honour the notch in landscape, where the inset is horizontal. */
    padding-left: var(--safe-left);
    padding-right: var(--safe-right);
}

/* Nothing may exceed the viewport. A single oversized image or embed is all it
   takes to give the whole page a horizontal scrollbar on a phone. */
img,
svg,
video,
canvas,
iframe,
embed,
object {
    max-width: 100%;
}
img,
svg,
video,
canvas {
    height: auto;
}

/* Grid and flex items default to `min-width: auto`, meaning they refuse to
   shrink below their content's intrinsic width — one long unbroken number or a
   fixed-width child is enough to push a card wider than the phone it's on. This
   is the single most common source of mobile overflow in this app, so the
   shared containers opt out of it explicitly. */
.card,
.fl-grid > *,
.ln-results > *,
.grid > *,
.cards > * {
    min-width: 0;
}

/* Long symbols, URLs and headlines break instead of stretching their container. */
h1, h2, h3, h4, h5, h6, p, li, td, th, dd, dt, figcaption, label, button, a {
    overflow-wrap: break-word;
}

/* ---------------------------------------------------------------------------
   3. Viewport height
   `100vh` on mobile means "the viewport with the address bar hidden", so a
   full-height element is taller than the screen until you scroll — the sidebar
   loses its footer behind the browser chrome. `dvh` is the live value.
   Guarded by @supports so older browsers keep the vh fallback already in place.
   --------------------------------------------------------------------------- */
@supports (height: 100dvh) {
    .sidebar {
        height: 100dvh;
    }
}

/* The sidebar is fixed and full-height, so it owns the top notch and the bottom
   gesture bar on iOS. Without this the brand sits under the notch in landscape
   and the last nav item under the home indicator. */
.sidebar {
    padding-top: var(--safe-top);
    padding-bottom: var(--safe-bottom);
    /* Momentum scrolling for the nav list on iOS. */
    -webkit-overflow-scrolling: touch;
    /* A scroll gesture in the sidebar shouldn't scroll the page behind it. */
    overscroll-behavior: contain;
}

/* ---------------------------------------------------------------------------
   4. The shared page container
   `.wrap` is the layout container on every page (screener.css defines it, six
   pages widen it). Here it only gets fluid gutters — the max-width each page
   chose is left alone.
   --------------------------------------------------------------------------- */
.wrap {
    padding-left: var(--pad-x);
    padding-right: var(--pad-x);
    padding-top: var(--pad-top);
    padding-bottom: var(--pad-bottom);
    /* Below its max-width the container is simply the viewport, minus gutters. */
    width: 100%;
}

/* ---------------------------------------------------------------------------
   5. Wide content scrolls in its own box
   A market app is full of tables that are legitimately wider than a phone. The
   fix is never to squeeze them — it's to let them scroll horizontally inside
   their own container while the page itself stays put.
   --------------------------------------------------------------------------- */
.cs-table-wrap,
.table-responsive,
.table-scroll,
.card > table,
.jr-table-card > table {
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    /* Contain the swipe: at the end of the table, don't start swiping the page
       (or trigger the browser's back gesture). */
    overscroll-behavior-x: contain;
}

/* Give the scroll a visible affordance rather than leaving users to guess. */
.cs-table-wrap::-webkit-scrollbar,
.table-responsive::-webkit-scrollbar,
.table-scroll::-webkit-scrollbar {
    height: 6px;
}
.cs-table-wrap::-webkit-scrollbar-thumb,
.table-responsive::-webkit-scrollbar-thumb,
.table-scroll::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.16);
    border-radius: 999px;
}

/* Tables keep their intrinsic column widths inside that scroller instead of
   collapsing into unreadable slivers. */
@media (max-width: 768px) {
    .cs-table,
    .jr-table,
    .wl-table,
    table.table {
        /* A sensible reading width; the wrapper scrolls past it. */
        min-width: 520px;
    }
    /* …unless the table has been explicitly built to reflow. */
    .table-stack,
    .table-stack table {
        min-width: 0;
    }
}

/* ---------------------------------------------------------------------------
   6. Touch and pointer
   Applied only where the primary pointer is coarse, so a mouse-driven desktop
   keeps its tighter, denser controls.
   --------------------------------------------------------------------------- */
@media (pointer: coarse) {
    /* Anything clickable gets a real hit area. min-height (not height) so it
       can still grow with its content. */
    button,
    [role="button"],
    .btn,
    .tab,
    .sb-link,
    .pill,
    input[type="submit"],
    input[type="button"],
    select {
        min-height: var(--tap);
    }

    /* iOS zooms the viewport when focusing an input whose font-size is under
       16px — and never zooms back out. This is the whole fix. */
    input,
    select,
    textarea {
        font-size: max(16px, 1em);
    }

    /* Hover styles latch on touch (they stick until you tap elsewhere), which
       reads as a stuck highlight. Neutralise the transform-based ones. */
    .card:hover,
    .sb-featured:hover {
        transform: none;
    }
}

/* Keyboard focus stays visible everywhere — a visible ring is the only way to
   navigate this app without a mouse. :focus-visible means pointer users never
   see it. */
:focus-visible {
    outline: 2px solid #8b5cf6;
    outline-offset: 2px;
    border-radius: 4px;
}

/* ---------------------------------------------------------------------------
   7. Breakpoints — one scale, applied to the shared primitives
   --------------------------------------------------------------------------- */

/* Tablets and small laptops: cards stop trying to hold four columns. */
@media (max-width: 1024px) {
    .grid-4 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* Large phones / portrait tablets. */
@media (max-width: 768px) {
    .grid-3,
    .grid-4 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    /* Header rows stop being one line and wrap sensibly. */
    .card-head,
    .cs-head,
    .top {
        flex-wrap: wrap;
        gap: 0.5rem;
    }
}

/* Phones: single column, everything full width. */
@media (max-width: 560px) {
    .grid-2,
    .grid-3,
    .grid-4 {
        grid-template-columns: minmax(0, 1fr);
    }

    .card {
        border-radius: var(--card-radius);
    }

    /* A row of controls becomes a stack of full-width controls rather than a
       cramped line of 60px buttons. */
    .btn-row,
    .controls,
    .filters {
        flex-direction: column;
        align-items: stretch;
    }
    .btn-row > *,
    .controls > *,
    .filters > * {
        width: 100%;
    }

    /* Tab strips scroll rather than wrapping into three ragged rows. */
    .tabs,
    .tab-row,
    .cat-tabs {
        display: flex;
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior-x: contain;
        scrollbar-width: none;
    }
    .tabs::-webkit-scrollbar,
    .tab-row::-webkit-scrollbar,
    .cat-tabs::-webkit-scrollbar {
        display: none;
    }
    .tabs > *,
    .tab-row > *,
    .cat-tabs > * {
        flex: 0 0 auto;
    }

    /* Headline type: big hero sizes chosen for a monitor are shouty on a 360px
       screen. Cap them rather than restyling. */
    .hero-title {
        font-size: clamp(1.5rem, 6.5vw, 2rem);
        line-height: 1.15;
    }
    .hero-sub {
        font-size: clamp(0.875rem, 3.4vw, 1rem);
    }
}

/* Small phones (≤420px): the tightest real device still worth supporting. */
@media (max-width: 420px) {
    /* Reclaim the gutter — at 320px CSS px every pixel of content matters. */
    :root {
        --pad-x: 0.75rem;
    }
    /* Numbers stay on one line; tabular figures stop them jittering as they tick. */
    .mono,
    .cs-num {
        font-variant-numeric: tabular-nums;
        letter-spacing: -0.01em;
    }
    /* Badges and pills wrap instead of forcing the row wider than the screen. */
    .badge,
    .pill,
    .brand-tag {
        white-space: normal;
    }
}

/* Landscape phones: very little height, so trim vertical padding rather than
   letting a hero eat the entire screen. */
@media (max-height: 480px) and (orientation: landscape) {
    :root {
        --pad-top: 0.75rem;
        --pad-bottom: 1.5rem;
    }
    .hero {
        padding-top: 0.5rem;
        padding-bottom: 0.25rem;
    }
}

/* Large desktop: stop the layout dissolving into a thin ribbon of content with
   two feet of empty background either side. Pages that set their own wider
   max-width keep it — this only lifts the 1120px default. */
@media (min-width: 1600px) {
    :root {
        --pad-x: 2rem;
    }
    .wrap {
        max-width: min(1440px, 92vw);
    }
}

/* ---------------------------------------------------------------------------
   8. Preferences
   --------------------------------------------------------------------------- */

/* Respect a system-level request for less motion: kill the decorative loops
   (the sidebar sheen, aurora drift, pulsing badges) and collapse transitions to
   near-instant. Not zero — `0.01ms` keeps transitionend handlers firing, so
   JS that waits on an animation doesn't hang. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* Print / PDF: drop the app chrome and the dark theme so a printed page is
   readable and doesn't burn a cartridge on the background gradient. */
@media print {
    .sidebar,
    .nav-backdrop,
    .nav-toggle,
    .aurora,
    .disclaimer {
        display: none !important;
    }
    html,
    body {
        background: #fff !important;
        color: #000 !important;
    }
    .wrap {
        max-width: none;
        padding: 0;
    }
    .card {
        break-inside: avoid;
        border: 1px solid #ccc;
        box-shadow: none;
    }
}
