/* =====================================================================
 * components.css  —  Shared UI components built on tokens.css
 * ---------------------------------------------------------------------
 * LOADED FROM: App/View/main-base.html, after tokens.css and BEFORE
 * {% block css %} — so a page-level sheet can override a component, and
 * so css/style.css (which loads last) still wins on ties, matching the
 * precedence order the codebase already relies on.
 *
 * SCOPE: only NEW components introduced by the UI refresh. Existing
 * component CSS stays where it is — moving declarations between sheets
 * would change the cascade (see the ordering note in main-base.html).
 *
 * This is also the one place allowed to use the --space-* scale. The
 * legacy sheets keep their ad-hoc spacing; retrofitting them would shift
 * pixels for no theming benefit.
 *
 * Populated by:
 *   Phase 2 — .section-tabs (sticky section navigation)
 *   Phase 3 — .section-head (section heading component)
 *   Phase 4 — .skeleton, .state-empty, .state-error (loading vocabulary)
 * ===================================================================== */

/* =====================================================================
 * .section-tabs  —  sticky section navigation for the birth-chart page
 * ---------------------------------------------------------------------
 * Replaces the fixed circular .floating-nav-buttons stack.
 *
 * ONLY THIS BAR IS STICKY. main-header.twig deliberately scrolls away:
 * it is .navbar-expand-lg, so below 992px it collapses to a hamburger and
 * grows to ~200px when opened. A sticky element that changes height while
 * stuck causes content jumps and invalidates scroll-padding-top. On a
 * 667px-tall phone two stacked bars would also eat ~16% of a viewport
 * whose entire job is showing wide tables and 500x375 charts.
 *
 * MUST be a direct child of <body>, OUTSIDE <div id="content">.
 * position: sticky fails silently if ANY ancestor has overflow other than
 * visible, and this page has six such ancestors (.basic-details-container,
 * .mahadasha-section, .ld-card, .astro-canvas-cell-outer,
 * #houseActivationContainer, .guide-offcanvas .offcanvas-body).
 * ===================================================================== */

.section-tabs {
    position: sticky;
    top: 0;
    z-index: var(--z-tabbar);
    background: var(--surface-card);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow-xs);
}

.section-tabs__inner {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    height: var(--tabbar-h);
    padding: 0 var(--space-3);
    max-width: 1600px;
    margin: 0 auto;
}

/* Absorbs the old #floatingChartNameTag: the chart name IS the
   "where am I" information this bar should carry. */
.section-tabs__title {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--ink);
    white-space: nowrap;
    max-width: 22ch;
    overflow: hidden;
    text-overflow: ellipsis;
    flex-shrink: 0;
}

.section-tabs__title i {
    color: var(--brand-600);
}

.section-tabs__back {
    color: var(--ink-subtle);
    text-decoration: none;
    font-size: 0.875rem;
    flex-shrink: 0;
    padding: var(--space-1);
    border-radius: var(--radius-sm);
}

.section-tabs__back:hover {
    color: var(--brand-700);
    background: var(--brand-a06);
}

/* Horizontal scroll strip. Reuses the .ai-quick-prompts idiom already in
   birth-chart.css so the codebase has one scroll-strip pattern, not two. */
.section-tabs__list {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    list-style: none;
    margin: 0;
    padding: 0;
    overflow-x: auto;
    scrollbar-width: none;
    -ms-overflow-style: none;
    scroll-snap-type: x proximity;
    flex: 1 1 auto;
    min-width: 0;
    -webkit-overflow-scrolling: touch;
}

.section-tabs__list::-webkit-scrollbar {
    display: none;
}

.section-tabs__tab {
    display: block;
    white-space: nowrap;
    scroll-snap-align: start;
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-pill);
    font-size: 0.8125rem;
    font-weight: 500;
    line-height: 1.6;
    color: var(--ink-muted);
    text-decoration: none;
    transition: background-color var(--transition-fast), color var(--transition-fast);
}

.section-tabs__tab:hover {
    color: var(--brand-700);
    background: var(--brand-a08);
    text-decoration: none;
}

.section-tabs__tab.is-active {
    color: var(--ink-on-brand);
    background: var(--brand-600);
}

/* Edge fade: a sticky pseudo-element gradient rather than mask-image,
   which still needs -webkit- on older Safari and has known bugs on
   overflow:auto containers. */
.section-tabs__fade {
    position: sticky;
    right: 0;
    flex: 0 0 24px;
    align-self: stretch;
    margin-left: -24px;
    pointer-events: none;
    background: linear-gradient(to right, transparent, var(--surface-card));
}

.section-tabs__action {
    flex-shrink: 0;
    border: 1px solid var(--border-brand-soft);
    background: var(--surface-card);
    color: var(--brand-700);
    font-size: 0.8125rem;
    font-weight: 500;
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-pill);
    white-space: nowrap;
    text-decoration: none; /* also used on <a> (Sandbox link) */
}

.section-tabs__action:hover {
    background: var(--brand-a08);
    color: var(--brand-700);
}

@media (max-width: 767.98px) {

    /* The name costs ~120px of a budget the tabs need more. */
    .section-tabs__title,
    .section-tabs__back {
        display: none;
    }
}

@media print {
    .section-tabs {
        display: none;
    }
}

/* Keeps section headings clear of the sticky bar on anchor jumps.
   scroll-padding-top (not a JS offset) so it also covers browser
   find-in-page and scrollIntoView, which a JS offset would miss.
   This replaces the ad-hoc #vimshottari-dasha-heading rule in style.css. */
html {
    scroll-padding-top: calc(var(--tabbar-h) + 12px);
    scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior: auto;
    }
}

/* =====================================================================
 * Loading / empty / error vocabulary
 * ---------------------------------------------------------------------
 * Before this, the whole app had exactly TWO empty-state strings, both
 * hand-written inline in birthChartInit.js. Four major render targets
 * (#astroTableContainer, #astroGridSvgContainer, #astroCanvasContainer,
 * #detailedDashaTable) had no loading, empty or error state at all: they
 * were blank for ~1s, then populated - or blank forever if a render threw.
 *
 * HOW SKELETONS CLEAR THEMSELVES
 * Every renderer overwrites its container with a full `innerHTML =`
 * assignment (astroChart.js:248/425, app2.js:71, dasha.js:62,
 * houseActivation.js:182, birthChartInit.js). So skeleton markup placed
 * INSIDE a container is destroyed by the successful render - no teardown
 * code, no cleanup pass. That is what makes this cheap.
 *
 * The watchdog in birthChartInit.js is what stops a thrown render from
 * leaving an infinite shimmer, which would be worse than the blank box it
 * replaced: it promises something that is never coming.
 * ===================================================================== */

.skeleton {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    width: 100%;
}

.skeleton__line,
.skeleton__block {
    position: relative;
    overflow: hidden;
    background: var(--neutral-200);
    border-radius: var(--radius-sm);
}

.skeleton__line {
    height: 0.75rem;
    width: var(--w, 100%);
}

.skeleton__block {
    height: var(--h, 120px);
    width: 100%;
    border-radius: var(--radius-md);
}

/* transform, not background-position: compositor-only, so it costs no
   layout or paint per frame. This page is simultaneously rendering 9+
   Raphael SVG charts, where main-thread animation shows up as jank. */
@media (prefers-reduced-motion: no-preference) {

    .skeleton__line::after,
    .skeleton__block::after {
        content: '';
        position: absolute;
        inset: 0;
        transform: translateX(-100%);
        background: linear-gradient(90deg,
                transparent,
                rgba(var(--white-rgb), 0.65),
                transparent);
        animation: sk-shimmer 1.4s infinite;
    }
}

@keyframes sk-shimmer {
    to {
        transform: translateX(100%);
    }
}

.skeleton__row {
    display: flex;
    gap: var(--space-2);
}

.skeleton__row>.skeleton__line {
    flex: 1 1 0;
}

@media print {
    .skeleton {
        display: none;
    }
}

/* ── Terminal states ────────────────────────────────────────────────── */
.state-empty,
.state-error {
    padding: var(--space-5) var(--space-4);
    text-align: center;
    font-size: 0.8125rem;
    border-radius: var(--radius-md);
}

.state-empty {
    color: var(--ink-subtle);
    background: var(--surface-muted);
}

.state-error {
    color: var(--danger-fg);
    background: var(--danger-bg);
    border: 1px solid var(--tier-1-bg);
}

.state-error__title {
    font-weight: 600;
    display: block;
    margin-bottom: var(--space-1);
}

.state-error__hint {
    color: var(--ink-muted);
    font-size: 0.75rem;
}

/* =====================================================================
 * .section-head  —  section heading
 * ---------------------------------------------------------------------
 * Replaces ~12 identical full-width teal gradient bars on the birth-chart
 * page. When every section is emphasized, none is: the bars gave a ten-
 * section page ten equally loud headings and no hierarchy, and they spent
 * the brand color on decoration rather than on state.
 *
 * Three tiers now do what one bar did:
 *   L1  .card-header.bg-gradient-primary  page/card headers - still filled
 *   L2  .section-head                     the nine major sections
 *   L3  .section-head--sub                nested + JS-injected headings
 *
 * Teal is freed up for meaning: the active tab, the current dasha row,
 * a selected planet.
 *
 * .bg-gradient-primary is NOT renamed or deleted. astroChart.js injects
 * that class name as a string, and astro.html / astro2.html are out of
 * scope for this pass. It stays defined in style.css, token-backed; we
 * only stop applying it to plain section headings.
 * ===================================================================== */

.section-head {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
    margin: var(--space-6) 0 var(--space-3);
    padding-bottom: var(--space-2);
    border-bottom: 1px solid var(--border);
}

/* An accent mark, not a bar: enough to anchor the eye, not enough to
   compete with the content below it. */
.section-head::before {
    content: '';
    flex: 0 0 3px;
    align-self: stretch;
    min-height: 1.15rem;
    background: var(--gradient-brand);
    border-radius: var(--radius-pill);
}

.section-head__title {
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--ink);
    margin: 0;
    flex: 0 1 auto;
}

.section-head__meta {
    font-size: 0.75rem;
    color: var(--ink-subtle);
    margin: 0;
    flex: 1 1 auto;
    min-width: 0;
}

.section-head__actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: 0 0 auto;
    margin-left: auto;
}

/* L3 — nested headings and the table titles astroChart.js emits. */
.section-head--sub {
    display: block;
    margin: var(--space-4) 0 var(--space-2);
    padding: 0;
    border: 0;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-subtle);
}

.section-head--sub::before {
    display: none;
}

@media (max-width: 575.98px) {
    .section-head {
        margin-top: var(--space-5);
        flex-wrap: wrap;
    }

    .section-head__actions {
        margin-left: 0;
        width: 100%;
    }
}

/* =====================================================================
 * Data density
 * ---------------------------------------------------------------------
 * Applied to the birth-chart tables, which are read against the chart
 * rather than skimmed. Two things matter most: the header staying visible
 * while you scan down, and numbers lining up so magnitudes are comparable
 * at a glance.
 * ===================================================================== */

/* Numerals in the same column share a width, so degrees, durations and
   dates align vertically instead of wobbling by glyph. */
.tabular,
.antardasha-table .date-range,
.antardasha-table .duration-compact,
.ps-score,
.compat-sav-val,
.bcd-deg {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* Sticky header for tables inside a scroll container.
   Applied via .table-sticky-head on a wrapper with its own max-height. */
.table-sticky-head {
    overflow: auto;
    max-height: var(--sticky-table-h, 70vh);
}

.table-sticky-head thead th {
    position: sticky;
    top: 0;
    z-index: 1;
}

/* ── Horizontal chart rails ─────────────────────────────────────────────
 * The page previously explained these to the user twice, with a
 * "Scroll sideways to see all charts" note under each rail. A scroll
 * affordance the interface has to apologise for in prose is a missing
 * affordance. Snap points plus an edge fade say the same thing visually.
 *
 * NOTE: style.css only stacks the canvases vertically (and sets
 * `overflow: visible !important`) in @media print. On phones the rail
 * stays horizontally scrollable.
 *
 * Snap is limited to mouse/trackpad input. Each chart is nearly as wide as
 * a phone screen, so on touch the snap fights the swipe and the zoom
 * buttons (which move every snap point). The input-device query, unlike a
 * max-width one, also covers phones using "Desktop site" mode.
 * -------------------------------------------------------------------- */
@media (hover: hover) and (pointer: fine) {
    .chakra-chart-scroll {
        scroll-snap-type: x proximity;
        scroll-padding-left: var(--space-2);
    }

    .chakra-chart-scroll .astro-canvas-cell-outer {
        scroll-snap-align: start;
    }
}

/* The fade sits on a wrapper so it does not scroll away with the content. */
.chart-rail {
    position: relative;
}

.chart-rail::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 32px;
    pointer-events: none;
    background: linear-gradient(to right, transparent, var(--surface-page));
}

@media (max-width: 991.98px) {

    /* style.css stacks the canvases vertically here, so a horizontal
       fade would point at nothing. */
    .chart-rail::after {
        display: none;
    }
}

@media print {
    .chart-rail::after {
        display: none;
    }
}
