/* The home page - on the website, in the app and in the admin's phone preview
   (2026-10-08). The website's bands and its row layout, moved here from the website's
   base.css and layouts.css so all three surfaces load one sheet and the six themes,
   written against .wx-band / .wx-hero / .wx-pin and the rest, dress the home page
   everywhere. The website loads this right after base.css, where layouts.css was, so
   the order the rules meet each other in is unchanged; its own page framing (the open
   page, natural heights on a desktop) stays in base.css.

   The fixed short/tall module heights start at 900px, so a phone - the app, the
   preview, the website on a phone - is one column of modules at their natural height. */

/* ---------- the bands (from base.css) ---------- */

/* ============================================================================
   Home page bands.

   One layout, restyled five ways. The section heading (.wx-band-head) is the
   element the themes lean on hardest - it appears once per band, so restyling
   that one rule changes the rhythm of the whole page. Everything else here is
   structure and takes its color from the contract.
   ========================================================================== */

/* .wx-home and the slots are laid out in layouts.css, which owns the shapes. */

.wx-band {
    display: grid;
    gap: calc(var(--wx-pad) * 0.6);
}

/* The one line every theme redraws. */
.wx-band-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 14px;
    padding: 6px 10px;
    border: 1px solid var(--wx-line);
    border-radius: var(--wx-radius);
    background: var(--wx-surface-2);
    color: var(--wx-ink);
    min-width: 0;
}

.wx-band-head h2 {
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
    color: inherit;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.wx-band-more,
.wx-band-aside {
    flex: 0 0 auto;
    font-size: 0.82rem;
    color: inherit;
    opacity: 0.85;
    white-space: nowrap;
}

.wx-band-more:hover { opacity: 1; }

/* ---- hero -------------------------------------------------------------- */

.wx-hero {
    position: relative;
    overflow: hidden;
    border-radius: var(--wx-radius);
    /* Without an uploaded image the theme's own colors make the backdrop, so
       a partner who has supplied nothing still gets something composed. */
    background:
        radial-gradient(120% 90% at 20% 15%, var(--wx-signal-soft), transparent 62%),
        linear-gradient(155deg, var(--wx-surface-2), var(--wx-ground));
    display: grid;
    place-items: center;
    min-height: 200px;
    padding: calc(var(--wx-pad) * 1.4) var(--wx-pad);
    text-align: center;
}

.wx-hero-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Only when there is a photograph behind it does the text need a scrim. */
.wx-hero.has-image .wx-hero-in {
    position: relative;
    background: rgba(0, 0, 0, 0.45);
    padding: 18px 22px;
    border-radius: var(--wx-radius);
    color: #fff;
}

.wx-hero.has-image .wx-hero-name,
.wx-hero.has-image .wx-hero-tag { color: #fff; }

.wx-hero-in { display: grid; gap: 8px; justify-items: center; max-width: 46rem; }

.wx-hero-logo { max-height: 84px; width: auto; }

.wx-hero-name {
    margin: 0;
    font-family: var(--wx-font-display);
    font-size: clamp(1.6rem, 4vw, 2.5rem);
    font-weight: 800;
    line-height: 1.1;
    color: var(--wx-ink);
}

.wx-hero-tag {
    margin: 0;
    color: var(--wx-muted);
    font-size: 1.02rem;
    max-width: 52ch;
}

/* ---- pinned post ------------------------------------------------------- */

.wx-pin {
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    gap: var(--wx-pad);
    align-items: center;
    background: var(--wx-surface);
    border: 1px solid var(--wx-line);
    border-radius: var(--wx-radius);
    overflow: hidden;
}

.wx-pin-shot { align-self: stretch; min-height: 220px; }

.wx-pin-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }

.wx-pin-in { display: grid; gap: 10px; padding: var(--wx-pad); min-width: 0; }

.wx-pin-flag {
    justify-self: start;
    font-family: var(--wx-font-data);
    font-size: 0.66rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--wx-signal);
    background: var(--wx-signal-soft);
    border-radius: var(--wx-radius);
    padding: 3px 9px;
}

.wx-pin-in h2 {
    margin: 0;
    font-size: 1.5rem;
    line-height: 1.15;
    color: var(--wx-ink);
}

.wx-pin-in p { margin: 0; color: var(--wx-muted); max-width: 56ch; }

.wx-pin-in a.wx-btn { justify-self: start; }

/* One giveaway with the box to itself (GiveawaysBand): the pinned post's shape, as a
   link. The whole card is the link, so the button inside is only its label. */
a.wx-gfeature {
    text-decoration: none;
    color: inherit;
    transition: border-color 120ms ease;
}

a.wx-gfeature:hover,
a.wx-gfeature:focus-visible { border-color: var(--wx-signal); }

.wx-gfeature .wx-btn { justify-self: start; }

/* In a module of fixed height it fills the box - the one row stretches to it, so the
   picture runs to the bottom rather than leaving a strip of card under it. */
.wx-mod .wx-gfeature { height: 100%; grid-template-rows: minmax(0, 1fr); }

/* ---- giveaway cards ---------------------------------------------------- */

.wx-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 12px;
}

.wx-gcard {
    display: flex;
    flex-direction: column;
    background: var(--wx-surface);
    border: 1px solid var(--wx-line);
    border-radius: var(--wx-radius);
    overflow: hidden;
}

/* A card that is a link keeps the card's look, not the browser's idea of one, and
   says it can be opened on hover. Cards that are still plain articles are unaffected. */
a.wx-gcard {
    text-decoration: none;
    color: inherit;
    transition: border-color 120ms ease, transform 120ms ease;
}

a.wx-gcard:hover,
a.wx-gcard:focus-visible {
    border-color: var(--wx-signal);
    transform: translateY(-2px);
}

@media (prefers-reduced-motion: reduce) {
    a.wx-gcard { transition: none; }
    a.wx-gcard:hover, a.wx-gcard:focus-visible { transform: none; }
}

.wx-gcard-shot {
    position: relative;
    aspect-ratio: 4 / 3;
    background: var(--wx-surface-2);
}

.wx-gcard-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Where the card's tag sits - the tag itself is ui.css's .wx-tag. */
.wx-gcard-tag {
    position: absolute;
    top: 8px;
    left: 8px;
}

.wx-gcard-in { padding: 10px 12px 14px; display: grid; gap: 3px; }

.wx-gcard-in h3 {
    margin: 0;
    font-size: 0.98rem;
    line-height: 1.25;
    color: var(--wx-ink);
}

.wx-gcard-prize { margin: 0; color: var(--wx-muted); font-size: 0.85rem; }

.wx-gcard-value {
    margin: 0;
    color: var(--wx-coin);
    font-family: var(--wx-font-data);
    font-size: 0.82rem;
    font-weight: 700;
}

/* ---- game tiles -------------------------------------------------------- */

.wx-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 12px;
}

.wx-tile {
    position: relative;
    background: var(--wx-surface);
    border: 1px solid var(--wx-line);
    border-radius: var(--wx-radius);
    overflow: hidden;
    transition: border-color 0.2s ease;
}

.wx-tile:not(.is-flat):hover { border-color: var(--wx-signal); }

/* A stretched anchor, so the whole tile is one target without nesting the
   card's text inside a link. */
.wx-tile-hit { position: absolute; inset: 0; z-index: 1; }

.wx-tile-shot {
    aspect-ratio: 16 / 9;
    background: var(--wx-surface-2);
    display: grid;
    place-items: center;
    overflow: hidden;
}

.wx-tile-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.wx-tile-shot img.is-icon { width: auto; height: 54%; object-fit: contain; }

.wx-tile-in { padding: 10px 12px 14px; display: grid; gap: 3px; }

.wx-tile-in h3 { margin: 0; font-size: 0.96rem; color: var(--wx-ink); }
.wx-tile-in p { margin: 0; color: var(--wx-muted); font-size: 0.82rem; }

/* ---- posts ------------------------------------------------------------- */

.wx-posts {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 12px;
}

.wx-post {
    display: flex;
    flex-direction: column;
    background: var(--wx-surface);
    border: 1px solid var(--wx-line);
    border-radius: var(--wx-radius);
    overflow: hidden;
}

/* overflow: hidden is what holds the 16:9 - without it a portrait picture stretched
   its box taller than its neighbors'. */
.wx-post-shot { aspect-ratio: 16 / 9; background: var(--wx-surface-2); overflow: hidden; }
.wx-post-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }

.wx-post-in { padding: 10px 12px 12px; display: grid; gap: 5px; min-width: 0; }

.wx-post-in h3 {
    margin: 0;
    font-size: 0.95rem;
    line-height: 1.3;
    color: var(--wx-ink);
}

/* Two lines, then stop - posts are imported, so their length is not ours to
   rely on. */
.wx-post-text {
    margin: 0;
    color: var(--wx-muted);
    font-size: 0.84rem;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.wx-post-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    color: var(--wx-muted-dim);
    font-size: 0.74rem;
    font-family: var(--wx-font-data);
}

/* ---- winners ----------------------------------------------------------- */

.wx-winners {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 10px;
}

.wx-winner {
    display: flex;
    align-items: center;
    gap: 10px;
    background: var(--wx-surface);
    border: 1px solid var(--wx-line);
    border-radius: var(--wx-radius);
    padding: 9px 11px;
    min-width: 0;
}

.wx-winner-shot {
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    border-radius: var(--wx-radius);
    overflow: hidden;
    background: var(--wx-surface-2);
}

.wx-winner-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }

.wx-winner-in { display: grid; gap: 1px; min-width: 0; }

.wx-winner-who { font-weight: 700; color: var(--wx-ink); font-size: 0.88rem; }

.wx-winner-what {
    color: var(--wx-muted);
    font-size: 0.8rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.wx-winner-when {
    color: var(--wx-muted-dim);
    font-size: 0.72rem;
    font-family: var(--wx-font-data);
}

/* ---- points ------------------------------------------------------------ */

.wx-points {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
    gap: var(--wx-pad);
    align-items: center;
    background: var(--wx-surface);
    border: 1px solid var(--wx-line);
    border-radius: var(--wx-radius);
    padding: var(--wx-pad);
}

.wx-tally { display: flex; gap: 10px; flex-wrap: wrap; }

.wx-tally-cell {
    flex: 1 1 90px;
    display: grid;
    gap: 1px;
    padding: 11px 13px;
    background: var(--wx-surface-2);
    border-radius: var(--wx-radius);
}

.wx-tally-n {
    font-family: var(--wx-font-data);
    font-variant-numeric: tabular-nums;
    font-size: 1.4rem;
    font-weight: 700;
    color: var(--wx-coin);
    line-height: 1.1;
}

.wx-tally-l {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--wx-muted-dim);
}

.wx-points-cta { display: grid; gap: 11px; justify-items: start; }
.wx-points-cta p { margin: 0; color: var(--wx-muted); }

/* Signed out: what an account gets them - an icon, a line in bold, a line under it. */
.wx-perks { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.wx-perks li { display: flex; gap: 12px; align-items: flex-start; }
.wx-perks i { flex: none; width: 1.25rem; margin-top: 3px; text-align: center; color: var(--wx-signal); }
.wx-perks span { color: var(--wx-muted); font-size: 0.86rem; line-height: 1.4; }
.wx-perks b { display: block; color: var(--wx-ink); font-size: 0.95rem; }

.wx-earn { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; }

.wx-earn li {
    display: flex;
    gap: 10px;
    align-items: baseline;
    color: var(--wx-muted);
    font-size: 0.86rem;
}

.wx-earn-k {
    flex: 0 0 62px;
    font-family: var(--wx-font-data);
    font-size: 0.7rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--wx-signal);
}

/* ---- app promo --------------------------------------------------------- */

.wx-promo {
    background:
        radial-gradient(110% 140% at 88% 12%, var(--wx-signal-soft), transparent 60%),
        var(--wx-surface);
    border: 1px solid var(--wx-line);
    border-radius: var(--wx-radius);
    padding: var(--wx-pad);
}

.wx-promo-in { display: grid; gap: 13px; max-width: 44rem; }
.wx-promo-in p { margin: 0; color: var(--wx-muted); font-size: 0.95rem; }
.wx-promo-links { display: flex; gap: 10px; flex-wrap: wrap; }

/* ---- narrow ------------------------------------------------------------ */

@media (max-width: 720px) {
    .wx-pin,
    .wx-points {
        grid-template-columns: 1fr;
    }

    .wx-pin-shot { min-height: 170px; }
}

/* The grand prize is the one the partner is promoting, so it reads first. */
.wx-gcard.is-grand { border-color: var(--wx-signal); }

/* Cards on the home page that are links: the same card, plus a hand and a lift. */
a.wx-post, a.wx-winner, a.wx-tally-cell { color: inherit; text-decoration: none; cursor: pointer; }
a.wx-post:hover, a.wx-winner:hover, a.wx-tally-cell:hover { border-color: var(--wx-signal); }
a.wx-tally-cell:hover { background: var(--wx-signal-soft); }

/* A Giveaways module's entry packs - "Get Entries for ..." - under the prizes. Small
   cards in a row that wraps: how many entries, and the price the store charges. */
.wx-packs { display: grid; gap: 8px; margin-top: 12px; }

.wx-packs-h { margin: 0; font-size: 0.95rem; color: var(--wx-ink); }

.wx-packs-list { display: flex; flex-wrap: wrap; gap: 8px; }

.wx-pack {
    display: grid;
    gap: 2px;
    min-width: 120px;
    padding: 8px 12px;
    background: var(--wx-surface);
    border: 1px solid var(--wx-line);
    border-radius: var(--wx-radius);
    color: inherit;
    text-decoration: none;
    transition: border-color 120ms ease;
}

.wx-pack:hover, .wx-pack:focus-visible { border-color: var(--wx-signal); }

.wx-pack-n { font-weight: 700; color: var(--wx-ink); }

.wx-pack-price { font-family: var(--wx-font-data); font-size: 0.85rem; color: var(--wx-coin); }

/* ---- the cover ------------------------------------------------------------ */

.wx-hero-logo { display: none; }

@media (min-width: 900px) {
    :where(.wx-home.is-wide) .wx-mod[data-module="Hero"] .wx-hero { min-height: 440px; }
}

.wx-hero-tag {
    font-family: var(--wx-font-display);
    font-size: clamp(2.2rem, 5vw, 4.2rem);
    line-height: 1.04;
    letter-spacing: -0.02em;
    color: var(--wx-ink);
    max-width: 16ch;
}

@media (max-width: 899px) {
    .wx-hero-tag { font-size: clamp(2rem, 9vw, 2.8rem); }
}

/* ---------- the row layout (from layouts.css) ---------- */

/* ============================================================================
   Home page layouts.

   Structure only - every color, face and radius still comes from the theme
   contract. A page is rows of one, two or three columns (PageLayout), each column
   a slot holding modules stacked.

   Two rules hold this together:

   Slots are containers. A module sizes itself against the space it was given
   rather than the viewport, because a rail is narrow on a 27" monitor too. Any
   module that adapts must use container queries, not media queries.

   The narrow-screen order is declared, not inherited. Each cell carries its place
   in its row's stack (--stack), so what a phone shows first is a decision rather
   than an accident of source order. A gutter on the left is the case that proves
   it: drawn first and stacked second.
   ========================================================================== */

.wx-home {
    display: grid;
    gap: var(--wx-mod-gap);
}

.wx-slot {
    display: grid;
    gap: var(--wx-mod-gap);
    align-content: start;
    min-width: 0;

    /* What lets a module know how much room it actually has. */
    container-type: inline-size;
}

/* On a phone a cell with nothing in it gives its space back. On a wide screen it
   keeps it - it is a column of its row, and hiding it would slide the next column
   into its place. Not :empty - the markup leaves whitespace inside the element, so
   :empty never matches; :has(*) asks the question that was meant. */
@media (max-width: 899px) {
    .wx-slot:not(:has(*)) {
        display: none;
    }
}

/* ---- heights ----------------------------------------------------------- */

/* Every module sits in a box of one of two heights on a wide screen - short, or
   tall, which is exactly two shorts and the gap between them - so columns line up
   whatever is in them: two shorts side by side, two talls, or a tall beside two
   stacked shorts (Frank, 2026-10-01). The height does not change with the width; a
   module rearranges itself to fit (container queries on .wx-slot). A phone stacks
   everything at its natural height, so none of this applies below 900px.

   220, not 260: measured on WAY-EZ (2026-10-02), the most any short module needed was
   216 (the hero) - the streak 186, the balances 158 - and the tallest list in a tall box
   450, inside the 475 this makes it. At 260 every short row ended in a band of nothing. */
.wx-home {
    /* How far past a clipping box a card's solid edge may hang - see .wx-mod below.
       The deepest theme edge is Playbook's 9px offset plus its 3px spread. */
    --wx-edge-room: 12px;
    --wx-mod-gap: calc(var(--wx-pad) * 1.6);
    --wx-short: 220px;
    --wx-tall: calc(var(--wx-short) * 2 + var(--wx-mod-gap));
}

/* A module with nothing to show - the streak for a visitor - takes no room. */
.wx-mod:not(:has(*)) {
    display: none;
}

@media (min-width: 900px) {
    /* Clipped, but with room past the edge for a theme's solid card edge - Playbook draws
       its border as a shadow hanging up to 12px below each card (0 9px 0 3px), and the
       modules are sized to fit their rows exactly, so a plain overflow: hidden sliced it
       flat at the bottom of every list module (2026-10-19, the third time). The edge
       hangs into the gap between modules instead. Where overflow-clip-margin isn't
       supported it clips at the edge, as before. e2e/tests/signed-in/edges.spec.ts
       checks it. */
    :where(.wx-home.is-wide) .wx-mod {
        display: flex;
        flex-direction: column;
        min-width: 0;
        overflow: hidden;
        overflow: clip;
        overflow-clip-margin: var(--wx-edge-room);
    }

    :where(.wx-home.is-wide) .wx-mod > * {
        flex: 1 1 auto;
        min-height: 0;
    }

    :where(.wx-home.is-wide) .wx-mod[data-height="short"] { height: var(--wx-short); }
    :where(.wx-home.is-wide) .wx-mod[data-height="tall"] { height: var(--wx-tall); }

    /* ---- fitting the box --------------------------------------------------
       Every module fills its box, at full, half or third width. A band keeps its
       heading and gives the rest to its body; a list in a band shows the whole cards
       that fit and no part of the next one (wxFit.js hides the rest - its heading's
       "See All" has them). The narrow arrangements key off the slot's width, which is
       what each module is given. */

    :where(.wx-home.is-wide) .wx-mod > .wx-band {
        display: flex;
        flex-direction: column;
    }

    :where(.wx-home.is-wide) .wx-mod > .wx-band > :not(.wx-band-head) {
        flex: 1 1 auto;
        min-height: 0;
        overflow: hidden;
        overflow: clip;
        overflow-clip-margin: var(--wx-edge-room);
        align-content: start;
    }

    /* A Giveaways module's entry packs keep their natural height at the foot; the
       giveaways above give way. */
    :where(.wx-home.is-wide) .wx-mod > .wx-band > .wx-packs { flex: none; }

    /* A list keeps every card its natural height. In a box of fixed height the grid
       would otherwise shrink its rows to fit and squash every card - the text cut
       off inside each - instead of letting the ones that don't fit fall past the
       bottom, where wxFit.js finds them. */
    :where(.wx-home.is-wide) .wx-mod :is(.wx-posts, .wx-cards, .wx-tiles, .wx-winners, .product-grid) {
        grid-auto-rows: max-content;
        align-content: start;
    }

    :where(.wx-home.is-wide) .wx-mod :is(.wx-posts, .wx-cards, .wx-tiles, .wx-winners, .product-grid) > * {
        flex-shrink: 0;
    }

    /* Compact cards in a tall box: narrower columns, and the picture and the title
       without the paragraph under it - so the count a partner set fits. Six posts or
       six games at half width is three across and two down; at the store page's or
       the feed's own size two big cards were all a half-width box could hold. */
    /* 150, not 170: three across has to fit half width with a theme's own gap - Slate
       spaces cards 22px apart, and 3 x 170 + 44 is wider than a half-width box (546px
       at 1280), so it fell to two across and a tall box held one row (2026-10-02). */
    :where(.wx-home.is-wide) .wx-mod[data-height="tall"] .wx-posts, :where(.wx-home.is-wide) .wx-mod[data-height="tall"] .wx-tiles, :where(.wx-home.is-wide) .wx-mod[data-height="tall"] .product-grid {
        grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    }

    :where(.wx-home.is-wide) .wx-mod[data-height="tall"] :is(.wx-post-text, .wx-tile-in p, .product-info .desc) {
        display: none;
    }

    /* One card size for posts and games: the same picture, and the same room under it
       - two lines of title and the line under those - so two tall modules side by side
       have rows that match (Frank, 2026-10-01). */
    :where(.wx-home.is-wide) .wx-mod[data-height="tall"] :is(.wx-post-in, .wx-tile-in) {
        box-sizing: border-box;
        height: 82px;
        align-content: start;
        overflow: hidden;
    }

    :where(.wx-home.is-wide) .wx-mod[data-height="tall"] :is(.wx-post-in h3, .wx-tile-in h3) {
        font-size: 0.86rem;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
    }

    /* The hero fills the box; its photograph crops to it. */
    :where(.wx-home.is-wide) .wx-mod > .wx-hero { min-height: 0; height: 100%; }

    /* The streak and the balances sit in the middle of a box that is taller than
       they need. */
    :where(.wx-home.is-wide) .wx-mod > .vs { height: 100%; align-content: center; }
    :where(.wx-home.is-wide) .wx-mod > .wx-band > .wx-points { height: 100%; align-content: center; }

    /* A pinned post fills its box: picture and words side by side. */
    :where(.wx-home.is-wide) .wx-mod > .wx-pin { height: 100%; }
    :where(.wx-home.is-wide) .wx-mod > .wx-pin .wx-pin-shot { min-height: 0; }

    /* Text that runs past its box fades out rather than stopping mid-line. */
    :where(.wx-home.is-wide) .wx-mod > .wx-textblock { height: 100%; overflow: hidden; }
    :where(.wx-home.is-wide) .wx-mod > .wx-textblock.is-clipped {
        -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 48px), transparent);
        mask-image: linear-gradient(to bottom, #000 calc(100% - 48px), transparent);
    }

    /* A third: one product to a row, and a square picture would make that one card
       taller than the box. A landscape crop keeps at least one in it. */
    @container (max-width: 520px) {
        :where(.wx-home.is-wide) .wx-mod .product-grid .product-image img, :where(.wx-home.is-wide) .wx-mod .product-grid .product-noimage {
            aspect-ratio: 4 / 3;
            object-fit: cover;
        }
    }

    /* Half or a third: the balances alone - the ways to earn need the room. */
    @container (max-width: 760px) {
        :where(.wx-home.is-wide) .wx-mod[data-height="short"] .wx-points { grid-template-columns: minmax(0, 1fr); }
        :where(.wx-home.is-wide) .wx-mod[data-height="short"] .wx-earn { display: none; }
    }

    /* A short pinned post in a narrow column has no room for its picture. */
    @container (max-width: 520px) {
        :where(.wx-home.is-wide) .wx-mod[data-height="short"] .wx-pin { grid-template-columns: minmax(0, 1fr); }
        :where(.wx-home.is-wide) .wx-mod[data-height="short"] .wx-pin-shot { display: none; }
    }

    /* A tall pinned post in a narrow column: picture above, words below. */
    @container (max-width: 520px) {
        :where(.wx-home.is-wide) .wx-mod[data-height="tall"] .wx-pin {
            grid-template-columns: minmax(0, 1fr);
            grid-template-rows: minmax(0, 1fr) auto;
        }
    }
}

/* ---- rows ------------------------------------------------------------- */

/* A page is rows the partner built (PageLayout), each a shape. (wx-layout-row, not
   wx-row: that is ui.css's list row, and sharing the name hid every list row on the
   website with no module in it - the cart's entries list among them.) On a wide screen a
   row's columns are its shape's widths - the 2:1 of a gutter, halves, thirds; a
   gutter is a third, as the old rail was. */
.wx-layout-row {
    display: grid;
    gap: var(--wx-mod-gap);
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
}

/* A row with nothing to show in any of its cells gives its space back. */
.wx-layout-row:not(:has(.wx-mod > *)) {
    display: none;
}

@media (min-width: 900px) {
    :where(.wx-home.is-wide) .wx-layout-row[data-shape="two-split"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    :where(.wx-home.is-wide) .wx-layout-row[data-shape="gutter-right"] { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
    :where(.wx-home.is-wide) .wx-layout-row[data-shape="gutter-left"] { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }
    :where(.wx-home.is-wide) .wx-layout-row[data-shape="three"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ---- narrow ------------------------------------------------------------ */

/* One column, in each row's stack order: left to right, except that a gutter on the
   left comes after its wide column - nobody scrolls past a sidebar to reach the shop.
   The order is the cell's own --stack (RowShapes.StackOrder), not source order. */
@media (max-width: 899px) {
    .wx-layout-row {
        display: flex;
        flex-direction: column;
        /* Full width - the wide screen's align-items: start would shrink each cell
           to its content here. */
        align-items: stretch;
    }

    .wx-layout-row > .wx-slot { order: var(--stack, 0); }
}

/* ---- modules in a narrow slot ------------------------------------------ */

/* A rail is about a third of the shell. Everything that lays out in columns
   has to collapse against the slot, not the window. */
@container (max-width: 460px) {
    .product-grid,
    .wx-cards,
    .wx-tiles,
    .wx-posts,
    .wx-winners {
        grid-template-columns: minmax(0, 1fr);
    }

    .wx-pin,
    .wx-points {
        grid-template-columns: minmax(0, 1fr);
    }

    .wx-pin-shot {
        min-height: 150px;
    }

    /* The hero carries less weight in a rail than across the page. */
    .wx-hero {
        min-height: 150px;
    }

    .wx-hero-name {
        font-size: clamp(1.2rem, 6cqi, 1.8rem);
    }
}

@container (min-width: 461px) and (max-width: 700px) {
    .product-grid,
    .wx-cards,
    .wx-tiles,
    .wx-posts {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* ---- text module ------------------------------------------------------- */

.wx-textblock {
    display: grid;
    gap: 10px;
    justify-items: start;
    background: var(--wx-surface);
    border: 1px solid var(--wx-line);
    border-radius: var(--wx-radius);
    padding: var(--wx-pad);
}

.wx-textblock h2 {
    margin: 0;
    font-size: 1.25rem;
    line-height: 1.2;
    color: var(--wx-ink);
}

/* Line breaks the partner typed survive without any of it being markup. */
.wx-textblock p {
    margin: 0;
    color: var(--wx-muted);
    white-space: pre-wrap;
    max-width: 62ch;
}

/* A card wxFit.js found past the bottom of its module's box. */
.wx-fit-out { display: none !important; }


/* ---------- a phone, whatever the window ----------
   The app and the admin's phone preview - a phone-sized frame in a wide window - get
   the phone's rules above by the screen's own flag (is-app), not the window's width
   (2026-10-08: the preview drew the desktop grid in a phone and the cards overran). */

.wx-home.is-app .wx-pin, .wx-home.is-app .wx-points {
        grid-template-columns: 1fr;
    }

    .wx-home.is-app .wx-pin-shot { min-height: 170px; }

.wx-home.is-app .wx-hero-tag { font-size: clamp(2rem, 9vw, 2.8rem); }

.wx-home.is-app .wx-slot:not(:has(*)) {
        display: none;
    }

.wx-home.is-app .wx-layout-row {
        display: flex;
        flex-direction: column;
        /* Full width - the wide screen's align-items: start would shrink each cell
           to its content here. */
        align-items: stretch;
    }

    .wx-home.is-app .wx-layout-row > .wx-slot { order: var(--stack, 0); }

/* The screen owns its scrolling in the app, inside the chrome, with the app's inset. */
.wx-home.is-app {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-y: contain;
    padding: 14px 14px 32px;
    --wx-mod-gap: 22px;
}

/* Products on the app's home: two to a row with room between them (2026-10-08) - one
   to a row they filled the screen, and a theme's offset shadow (Playbook's) closed the
   gap so the cards read as overlapping. */
.wx-home.is-app .product-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 22px 12px;
    padding: 0 0 6px;
}

.wx-home.is-app .product-grid .product-info .desc { display: none; }
.wx-home.is-app .product-grid .product-purchase { flex-wrap: wrap; font-size: 0.9rem; }

/* The same sizing the website gets from Bootstrap - see store.css. */
.wx-home.is-app,
.wx-home.is-app * {
    box-sizing: border-box;
}

/* The Ad module (2026-10-18): one ad, drawn like the other bands' cards so the theme
   dresses it. The whole tile is the link. Short puts the picture beside the words;
   Tall stacks them with the picture on top. */
.wx-adtile {
    display: block;
    height: 100%;
    color: inherit;
    text-decoration: none;
    background: var(--wx-surface);
    border: 1px solid var(--wx-line);
    border-radius: var(--wx-radius);
    overflow: hidden;
}

.wx-adtile-in {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
    height: 100%;
}

.wx-adtile-img {
    width: 100%;
    height: 100%;
    min-height: 140px;
    object-fit: cover;
    display: block;
}

.wx-adtile-text {
    display: grid;
    align-content: center;
    justify-items: start;
    gap: 8px;
    padding: var(--wx-pad);
}

.wx-adtile-tag {
    font-size: 0.72rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--wx-muted);
}

.wx-adtile-head {
    font-size: 1.2rem;
    line-height: 1.2;
    font-weight: 700;
    color: var(--wx-ink);
}

.wx-adtile-line {
    color: var(--wx-muted);
    max-width: 52ch;
}

.wx-adtile-in:not(:has(.wx-adtile-img)) { grid-template-columns: 1fr; }

.wx-mod[data-height="tall"] .wx-adtile-in { grid-template-columns: 1fr; grid-template-rows: minmax(0, 1fr) auto; }
.wx-mod[data-height="tall"] .wx-adtile-img { min-height: 200px; }

/* A phone stacks it, picture on top, at its natural height. */
.wx-home.is-app .wx-adtile-in { grid-template-columns: 1fr; }
.wx-home.is-app .wx-adtile-img { aspect-ratio: 16 / 9; height: auto; min-height: 0; }
