/* ===========================================================================
   Sale themes + the canonical discounted-price hierarchy.

   Loaded site-wide from base.html, so everything in here is available on every
   public page whether or not a sale is running.

   WHY THE PRICE RULES LIVE HERE (regression this file exists to prevent):
   `.original-price` / `.sale-price` / `.savings-text` / `.price-container` /
   `.price-row` are emitted by the purchase-page package cards. Their ONLY
   stylesheet used to be `static/css/christmas-sale.css` — a December campaign
   file that also carried snowfall, tree decorations and holiday reds. When that
   seasonal file was unlinked to get Christmas off the site, the STRUCTURAL
   price styling went with it, and discounted packages started rendering
   "$4.99 $3.74" as two identically-weighted, unstruck spans with no signal
   about which one the customer actually pays.

   Seasonal decoration and structural hierarchy must not share a stylesheet.
   Decoration is per-theme (the `--sale-theme-*` custom properties below, chosen
   per campaign via the promotion's `theme_key`); hierarchy is universal and
   lives here, un-themed, always loaded.

   Theme classes are declared for BOTH `body.sale-theme-x` (legacy: purchase.html
   sets it on <body>) and bare `.sale-theme-x` so a single banner element can
   carry a theme without repainting the whole page.
   =========================================================================== */

:root {
    --sale-theme-primary: #dc2626;
    --sale-theme-secondary: #b91c1c;
    --sale-theme-accent: #fbbf24;
    --sale-theme-text: #fffaf0;
    --sale-theme-badge-text: #111827;
    --sale-theme-shadow: rgba(220, 38, 38, 0.32);
}

/* NOT widened to a bare `.sale-theme-active`, unlike the named themes below.
   `sale-theme-active` doubles as a STYLING HOOK on individual buy buttons
   (`purchase.html` appends it to `.purchase-btn` / `.btn-premium`, styled at the
   bottom of this file). Declaring the default red custom properties on the bare
   class would re-declare them locally on every such button, overriding the
   named theme inherited from <body> — a summer sale's buttons would silently
   render in the default red while the rest of the page stayed teal. */
body.sale-theme-active {
    --sale-theme-primary: #dc2626;
    --sale-theme-secondary: #b91c1c;
    --sale-theme-accent: #fbbf24;
    --sale-theme-text: #fffaf0;
    --sale-theme-badge-text: #111827;
    --sale-theme-shadow: rgba(220, 38, 38, 0.32);
}

body.sale-theme-christmas,
.sale-theme-christmas {
    --sale-theme-primary: #c41e3a;
    --sale-theme-secondary: #165b33;
    --sale-theme-accent: #ffd700;
    --sale-theme-text: #fffaf0;
    --sale-theme-badge-text: #1f2937;
    --sale-theme-shadow: rgba(196, 30, 58, 0.34);
}

body.sale-theme-halloween,
.sale-theme-halloween {
    --sale-theme-primary: #ea580c;
    --sale-theme-secondary: #4a044e;
    --sale-theme-accent: #facc15;
    --sale-theme-text: #fff7ed;
    --sale-theme-badge-text: #111827;
    --sale-theme-shadow: rgba(234, 88, 12, 0.32);
}

body.sale-theme-black_friday,
.sale-theme-black_friday {
    --sale-theme-primary: #111827;
    --sale-theme-secondary: #374151;
    --sale-theme-accent: #fbbf24;
    --sale-theme-text: #f9fafb;
    --sale-theme-badge-text: #111827;
    --sale-theme-shadow: rgba(17, 24, 39, 0.42);
}

body.sale-theme-summer,
.sale-theme-summer {
    --sale-theme-primary: #0f766e;
    --sale-theme-secondary: #0891b2;
    --sale-theme-accent: #fde047;
    --sale-theme-text: #f0fdfa;
    --sale-theme-badge-text: #164e63;
    --sale-theme-shadow: rgba(8, 145, 178, 0.34);
}

body.sale-theme-memorial_day,
.sale-theme-memorial_day {
    --sale-theme-primary: #1d4ed8;
    --sale-theme-secondary: #dc2626;
    --sale-theme-accent: #f8fafc;
    --sale-theme-text: #ffffff;
    --sale-theme-badge-text: #1e3a8a;
    --sale-theme-shadow: rgba(29, 78, 216, 0.34);
}

body.sale-theme-premium_gold,
.sale-theme-premium_gold {
    --sale-theme-primary: #a16207;
    --sale-theme-secondary: #854d0e;
    --sale-theme-accent: #fde68a;
    --sale-theme-text: #fffbeb;
    --sale-theme-badge-text: #451a03;
    --sale-theme-shadow: rgba(161, 98, 7, 0.34);
}

.sale-banner {
    background: linear-gradient(135deg, var(--sale-theme-primary) 0%, var(--sale-theme-secondary) 100%);
    color: var(--sale-theme-text);
    border: 1px solid color-mix(in srgb, var(--sale-theme-accent) 35%, transparent);
    border-bottom: 3px solid var(--sale-theme-accent);
    border-radius: 18px;
    box-shadow: 0 20px 48px var(--sale-theme-shadow);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.95rem 1.15rem;
    margin: 0 auto 1.5rem;
    max-width: 1100px;
}

.sale-timer {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    color: color-mix(in srgb, var(--sale-theme-text) 88%, white);
    font-size: 0.92rem;
    white-space: nowrap;
}

.sale-timer-label {
    color: color-mix(in srgb, var(--sale-theme-text) 72%, white);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-size: 0.72rem;
    font-weight: 700;
}

.sale-timer-value {
    color: var(--sale-theme-accent);
    font-weight: 800;
}

/* Discount badge on a package card.
   Colour comes from the campaign theme; GEOMETRY is universal and lives here.
   The geometry half (position/padding/radius/size/z-index) previously existed
   ONLY in the orphaned christmas-sale.css, so once that file was unlinked the
   badge stopped being pinned to the card corner and rendered as a full-width
   gradient block mid-card. `purchase.html`'s `.sale-badge.subscriber-sale-badge`
   rule still assumes this base (its `max-width: 90%` and `animation: none` only
   make sense against an absolutely-positioned, animated badge). */
.sale-badge {
    position: absolute;
    top: -10px;
    right: -10px;
    z-index: 10;
    padding: 8px 16px;
    border-radius: 20px;
    font-size: 0.9rem;
    font-weight: 700;
    max-width: calc(100% - 12px);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    background: linear-gradient(135deg, var(--sale-theme-accent) 0%, color-mix(in srgb, var(--sale-theme-accent) 75%, white) 100%);
    color: var(--sale-theme-badge-text);
    box-shadow: 0 8px 22px color-mix(in srgb, var(--sale-theme-accent) 30%, transparent);
}

/* The badge sits at a negative offset, so on a narrow phone it must not be the
   thing that widens the card and starts a horizontal scroll. */
@media (max-width: 430px) {
    .sale-badge {
        top: -6px;
        right: -4px;
        padding: 5px 10px;
        font-size: 0.75rem;
    }
}

.purchase-btn.sale-theme-active,
.btn-premium.sale-theme-active {
    background: linear-gradient(135deg, var(--sale-theme-primary) 0%, var(--sale-theme-secondary) 100%);
    border: 2px solid var(--sale-theme-accent);
    color: var(--sale-theme-text) !important;
    box-shadow: 0 12px 26px var(--sale-theme-shadow);
}

.purchase-btn.sale-theme-active:hover,
.btn-premium.sale-theme-active:hover {
    filter: brightness(1.06);
    transform: translateY(-1px);
}

@media (max-width: 768px) {
    .sale-banner {
        flex-direction: column;
        align-items: flex-start;
        padding: 0.85rem 0.95rem;
    }

    .sale-timer {
        white-space: normal;
    }
}

/* ===========================================================================
   CANONICAL DISCOUNTED-PRICE HIERARCHY  (was / now / you save)

   Rescued from the orphaned `christmas-sale.css` and de-seasonalised. Nothing
   below references a theme colour: a struck price must read identically in a
   Christmas, summer or unthemed sale, in greyscale, and in Reader mode.

   Three redundant signals distinguish "was" from "now", so no single one is
   load-bearing:
     1. STRUCTURE  — the old price is marked up as <s>, so the strikethrough is
                     the browser's own UA default and survives this stylesheet
                     failing to load entirely.
     2. SIZE/WEIGHT— the old price is smaller and lighter; the payable price is
                     the largest, heaviest number in the card.
     3. TEXT       — visually-hidden "was"/"now" labels for screen readers and
                     a visible "Save $X" line.
   Colour is deliberately NOT one of the three (colour-blind + greyscale).
   =========================================================================== */

.price-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.15rem;
    min-width: 0;
    overflow: hidden;
}

.price-row {
    display: flex;
    align-items: baseline;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.15rem 0.5rem;
    min-width: 0;
    max-width: 100%;
}

/* `s.original-price` (and the legacy bare `.original-price` span, still emitted
   by older markup) — de-emphasised and struck. `text-decoration-*` longhands are
   set explicitly because several component stylesheets reset `text-decoration`
   on descendants of a card link. */
.original-price,
s.original-price {
    font-size: 0.85rem;
    font-weight: 500;
    opacity: 0.62;
    text-decoration: line-through;
    text-decoration-thickness: 2px;
    text-decoration-skip-ink: none;
    white-space: nowrap;
    min-width: 0;
}

.sale-price {
    font-size: 1.5rem;
    font-weight: 800;
    line-height: 1.1;
    white-space: nowrap;
    min-width: 0;
}

.savings-text {
    font-size: 0.8rem;
    font-weight: 700;
    opacity: 0.9;
    max-width: 100%;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Screen-reader-only "was"/"now" qualifiers. The struck <s> conveys
   supersession structurally, but "was $4.99, now $3.74" is what actually gets
   announced clearly, and it is the only cue that survives a stylesheet-free
   render where both numbers are plain text. */
.price-sr-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Narrow phones (360 / 390 / 414 CSS px): the was/now pair stacks rather than
   letting a long "$1,234.56" pair force the card wider than its grid track. */
@media (max-width: 430px) {
    .sale-price {
        font-size: 1.3rem;
    }

    .original-price,
    s.original-price {
        font-size: 0.8rem;
    }
}

/* ===========================================================================
   SITE SALE BANNER — server-rendered, theme-carrying, countdown-bearing.
   Used by index.html (homepage) and shop.html. Scoped by a `.sale-theme-*`
   class ON THE BANNER ITSELF, so a themed sale never has to repaint the page.
   =========================================================================== */

.site-sale-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    min-width: 0;
    overflow: hidden;
    max-width: 1100px;
    margin: 0 auto 1.25rem;
    padding: 0.7rem 1rem;
    border-radius: 12px;
    border: 1px solid color-mix(in srgb, var(--sale-theme-accent) 32%, transparent);
    border-left: 4px solid var(--sale-theme-accent);
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--sale-theme-primary) 26%, transparent) 0%,
        color-mix(in srgb, var(--sale-theme-secondary) 20%, transparent) 100%);
    color: var(--sale-theme-text);
}

.site-sale-banner__main {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.35rem 0.6rem;
    min-width: 0;
}

.site-sale-banner__title {
    font-weight: 800;
    font-size: 0.98rem;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    /* Two lines max on a phone, then ellipsis — a long campaign name must never
       push the countdown off the card. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

.site-sale-banner__sub {
    font-size: 0.82rem;
    opacity: 0.85;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.site-sale-banner__timer {
    display: inline-flex;
    align-items: baseline;
    gap: 0.4rem;
    flex-shrink: 0;
    min-width: 0;
    font-size: 0.85rem;
}

.site-sale-banner__timer-label {
    text-transform: uppercase;
    letter-spacing: 0.07em;
    font-size: 0.66rem;
    font-weight: 700;
    opacity: 0.75;
}

.site-sale-banner__timer-value {
    color: var(--sale-theme-accent);
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    white-space: nowrap;
}

.site-sale-banner__cta {
    flex-shrink: 0;
    /* inline-flex + centring so a min-height floor grows the hit area rather
       than leaving the label pinned to the top of a taller pill. */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.35rem 0.8rem;
    border-radius: 999px;
    background: var(--sale-theme-accent);
    color: var(--sale-theme-badge-text);
    font-weight: 800;
    font-size: 0.8rem;
    text-decoration: none;
    white-space: nowrap;
}

/* Touch devices: the only CTA on the site's highest-traffic sale surface
   measured 29px tall in headless Chromium at 360/390/414px — under every
   touch-target guideline. Gated on pointer:coarse so the desktop banner keeps
   its compact chrome. */
@media (pointer: coarse) {
    .site-sale-banner__cta {
        min-height: 44px;
        padding-inline: 1rem;
    }
}

.site-sale-banner__cta:hover {
    filter: brightness(1.07);
    text-decoration: none;
}

/* The countdown driver (static/js/sale-countdown.js) sets this on the host once
   the window closes, so an open tab never shows a dead sale or a 00:00:00. */
.site-sale-banner[hidden],
.sale-countdown-expired {
    display: none !important;
}

@media (max-width: 640px) {
    .site-sale-banner {
        flex-direction: column;
        align-items: flex-start;
        gap: 0.4rem;
        padding: 0.65rem 0.8rem;
    }

    /* The sub-line carries the actual OFFER ("Up to 40% off every Dream Coin
       pack this weekend"), so hiding it on phones dropped the substance of the
       promotion on the surface most visitors see. It is kept and clamped to two
       lines instead: the base rule's `white-space: nowrap` (which is what made
       it look unusable in a narrow column — nowrap is not rescued by
       `min-width: 0`) is released here so it can actually wrap. */
    .site-sale-banner__sub {
        white-space: normal;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
        text-overflow: clip;
    }

    .site-sale-banner__cta {
        align-self: stretch;
        text-align: center;
    }
}
