/* ── Swoop arc (experimental alternative supergraphic) ───────────────────────
   An alternative to the fixed top-right corner arc in home.css: a ribbon that
   enters from the lower left, runs behind the game tiles, and exits the top.

   This file is only loaded by public/index.html. Loading it is what swaps the
   two marks — remove the <link> and <script> from the homepage <head> and the
   original corner arc returns untouched. See public/arc-swoop.js.

   Sizing, viewBox and the band paths are all set by the script; everything
   here is presentation only. */

.arc-swoop {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 0;
    pointer-events: none;
    /* The bands are generated as polylines that can sit slightly outside the
       viewBox at the very ends; don't clip them. */
    overflow: visible;
}

.arc-swoop path {
    fill: none;
    stroke-linecap: butt;
    stroke-linejoin: round;
    /* pathLength="1" is set on each band, so the whole curve is one dash unit
       and the offset can be animated from fully-hidden (1) to fully-drawn (0). */
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
}

/* Final resting state — also what a resize redraw lands on, so the reveal
   never replays after the initial load. */
.arc-swoop.is-static path {
    stroke-dashoffset: 0;
}

.arc-swoop.is-drawing path {
    animation: arc-swoop-draw 1.4s cubic-bezier(.22, .61, .36, 1) forwards;
}

@keyframes arc-swoop-draw {
    from { stroke-dashoffset: 1; }
    to   { stroke-dashoffset: 0; }
}

/* Above the mobile breakpoint the swoop replaces the corner arc. */
@media (min-width: 769px) {
    .arc {
        display: none;
    }
}

/* Below it the cards stack vertically, so a horizontal run "behind the tiles"
   has no meaning — fall back to the original corner arc. The script also skips
   building the SVG at these widths; this is belt and braces. */
@media (max-width: 768px) {
    .arc-swoop {
        display: none;
    }
}

/* ── Cards lit by the passing ribbon ─────────────────────────────────────────
   The script sets data-arc-cards="armed" on <html> synchronously, before first
   paint, then lights each card as the ribbon slips under it. The attribute is
   only ever set on desktop with motion allowed, and is removed again once the
   sequence finishes or a safety timer fires — so every other path (mobile, no
   JS, a thrown error, reduced motion) leaves the cards plainly visible.

   One card is deliberately spared so the page is never blank, and it has to be
   the one the ribbon reaches FIRST or it would sit lit on its own while the
   sweep happened elsewhere. The ribbon now enters bottom-right, so that is the
   LAST card in the grid — it used to be the first, back when the ribbon came in
   from the bottom left. computeTriggers() skips the same card; the two must
   agree. */
@media (min-width: 769px) {
    :root[data-arc-cards="armed"] .game-card:not(:last-child) {
        opacity: 0;
        transform: translateY(14px);
    }

    :root[data-arc-cards="armed"] .game-card:not(:last-child).is-lit {
        opacity: 1;
        transform: none;
        transition: opacity .5s ease-out, transform .5s cubic-bezier(.22, .61, .36, 1);
    }
}

/* ── Footer scrim ────────────────────────────────────────────────────────────
   The ribbon enters through the footer, and the footer's muted --text-label
   drops to ~1.15 contrast where it crosses the orange band — unreadable. A flat
   translucent wash isn't enough (88% still only reaches ~3.5), so this fades to
   FULLY opaque before the text band: transparent at the top edge, so the ribbon
   is still seen sliding underneath, solid by the time it reaches the type,
   which restores the 4.57 the text has on the plain page.

   Filling with --page-bg is what makes it invisible: .footer is only as wide as
   .page, but a page-coloured fill has no discernible edge against the page. */
@media (min-width: 769px) {
    .footer {
        /* Solid by 30%: the highest text in the footer starts at ~32%. */
        background: linear-gradient(to bottom, transparent 0, var(--page-bg) 30%);
    }
}

/* ── Eyebrow bar shadow ──────────────────────────────────────────────────────
   The ribbon leaves through the top of the page and is cut dead by the sticky
   eyebrow bar's hard bottom edge. A soft shadow gives it something to slide
   under, echoing the way the footer scrim catches it at the other end.

   Kept at every width — unlike the footer scrim, this reads as ordinary sticky
   header polish, and on mobile it softens the corner arc the same way. Split by
   theme because a shadow tuned for cream disappears on the dark page, following
   the --shadow-card pattern in home.css. */
.sticker-strip {
    box-shadow: 0 4px 14px rgba(43, 43, 40, .22);
}

:root[data-theme="dark"] .sticker-strip {
    box-shadow: 0 4px 16px rgba(0, 0, 0, .45);
}

@media (prefers-reduced-motion: reduce) {
    .arc-swoop path {
        stroke-dashoffset: 0;
    }

    .arc-swoop.is-drawing path {
        animation: none;
    }

    /* Belt and braces — arm() already declines to hide anything here. Must
       match the hiding selector above, or reduced motion would stop overriding
       it. */
    :root[data-arc-cards="armed"] .game-card:not(:last-child) {
        opacity: 1;
        transform: none;
        transition: none;
    }
}
