@media(max-width: 768px) {
    .hero h1 {
        font-size: 3rem;
    }

    .intro-logo {
        color: var(--brand-red);
        font-size: 5rem;
        letter-spacing: 6px;
    }

    .feature-row,
    .feature-row.reverse {
        flex-direction: column;
        gap: 30px;
        text-align: center;
    }

    .step-badge {
        position: relative;
        top: 0;
        left: 0;
        font-size: 2.5rem;
        display: block;
        margin-bottom: 10px;
    }

    .modal-window {
        padding: 30px 20px;
    }

    .modal-body.content-body {
        flex-direction: column;
    }


    .content-window {
        flex-direction: column;
        height: 90vh;
        overflow: hidden;
        width: 100%;

        overflow-y: scroll;

    }

    /* Cards 1 and 2 — the two modals that stay side-by-side on the desktop.
       Their mobile presentation is UNCHANGED by 1.0.6. */
    .content-preview {
        min-height: 420px;
    }

    /* L15 (1.0.6) — and cards 3, 4 and 5 must not get 420px of image AND a 2:1
       box on a phone. `.content-body.stacked .content-preview` in landing.css
       already outranks the rule above on specificity (0,3,0 beats 0,1,0), so
       this is not what makes it work — it is here so that the interaction is
       visible at the place a future reader will change the 420px, rather than
       being an accident of two files. Keep the two in step. */
    .content-body.stacked .content-preview {
        min-height: 0;
        aspect-ratio: 2 / 1;
    }

    .content-body.stacked .content-details {
        padding: 20px;
    }

    .content-details {
        padding: 20px;
    }

    /* W5.2: one column on a phone — two columns of ~140px break the longer
       titles onto three lines each. The window is already a 90vh scroller here,
       so the block can be taller than it is on the desktop. */
    .listing-titles {
        columns: 1;
    }

    .content-listing {
        max-height: 300px;
    }

    /* S3.2 — Stacked, the X lands on the image rather than on the text, so the
       details do not need to be pushed down. The chip itself still applies. */
    .content-window .content-details {
        padding-top: 20px;
    }

    .question-card {
        padding: 1.5rem;
    }

    .sidebar {
        transform: translateX(-100%);
    }

    .sidebar.open {
        transform: translateX(0);
        box-shadow: 5px 0 20px rgba(0, 0, 0, 0.5);
    }

    .main-content {
        margin-left: 0;
        width: 100%;
    }

    .mobile-menu-btn {
        display: block;
    }

    .modal-body {
        flex-direction: column;
        padding: 1.5rem;
    }

    .modal-left {
        flex: auto;
        width: 100%;
    }

    .modal-image-wrapper {
        width: 200px;
        margin: 0 auto;
    }

    #series-modal .modal-header> div:first-of-type {
        width: 100%;
        max-width: unset;
        max-height: unset;
    }

    /* W4.6 (WDF1-1.8). The desktop strip gives each word 2rem of air either
       side, spent as a 4rem gap because the accent bar is sized from the
       label's border box and must not grow with it. Measured at 390px, that
       tips three labels from 363px to 427px in a 390px viewport and the strip
       starts to scroll — which it did not do before, so it would be a mobile
       regression bought with a desktop improvement. Phones keep the original
       2rem.

       Only the horizontal half is reverted: the 0.75rem above the words is
       vertical, costs no width, and is wanted on every screen. */
    .tab-strip {
        gap: 2rem;
    }

    /* W4.2 (WDF1-4.1 + 4.2) — the mobile hero. -----------------------------
       Owner ruling 2026-08-13 (Q5): "make the art fill the box", applied to
       EVERY hero on mobile rather than only the one that misbehaves.

       Before this block, nothing in this stylesheet touched the portal hero at
       all — `.hero h1` above is the LANDER's hero, a different element.

       Two halves, and they are independent:

       4.2 — the background. `.hero-section` base is `contain` / `left top`
       (quizflix.css). `.hero-section.main-page` already overrides that to
       cover/center, so home, library, search, profile and arcade were already
       right. The series / directory hero is NOT `.main-page`: it keeps
       `contain` + `left top` and sets its banner inline, so a 16:9 banner drew
       a strip in the top-left of the box and left the rest unpainted. THAT is
       the "looks like it's broken" report. Measured at 390px before the change:
       directory `background-size: contain; background-position: 0% 0%`, every
       other hero already `cover` / `50% 50%`.

       4.1 — the height. 🔴 The hero is CONTENT-bound on a phone, not
       min-height-bound, so lowering `min-height` alone would have moved almost
       nothing. Measured at 390x844 (30vh = 253px):

           home        285px   content 285   <- .hero-title wraps to 154px
           profile     366px   content 366   <- title 154 + meta 124 (email)
           directory   270px   content 270
           library ?type=series / search / arcade
                       253px   content 193-208  (at the 30vh floor)

       So the reduction comes off the content — `.hero-title` is 3rem/48px on a
       390px screen, which is what wraps "Welcome Back" onto two lines — and the
       30vh floor comes down with it so the three screens already sitting on it
       actually move.

       ⚠️ Scoped `.hero-section .hero-*` and not bare `.hero-*`: index.html's
       lander uses `.hero-content` too, and this sheet is loaded there. A bare
       rule would restyle the lander — the trap the `.btn` restyle was withdrawn
       over (§2.8).

       ⚠️ `.exercise-hero` (the five game screens) is deliberately excluded. It
       is already `cover`, so 4.2 has nothing to fix there, and its `height:
       30vh` is coupled to a hand-tuned `background-position-y: -59vh` — moving
       one without the other misframes the art. Its titles are short and do not
       wrap, so it does not show the defect either. One selector includes them
       if that is wanted.

       ScrollEffect.Hero (quizflix.logic.helpers.js) clamps its sticky offset to
       the free band above .hero-content and re-measures on resize, so a shorter
       hero needs no JS change. */
    .hero-section:not(.exercise-hero) {
        background-size: cover;
        background-position: center;
        min-height: 20vh;
    }

    .hero-section:not(.exercise-hero) .hero-content {
        /* Bottom only: 2rem -> 1.25rem. The horizontal half stays on
           --container-padding so the hero text still lines up with the rows
           below it.

           🔴 The TOP stays at 2rem deliberately. `.mobile-menu-btn` is
           `position: fixed` at 15..57px in the top-left corner with z-index
           100, and the hero title starts at x=32 — so the hamburger already
           sits ON the title on every portal screen, by 25x25px, and has done
           since before this task. Cutting the top padding to 1.25rem moved the
           title up 12px and took that overlap to 25x37px. That is a
           pre-existing defect this order does not name (and the owner deferred
           the "cluttered headers" item), so it is left exactly as it was found
           rather than half-redesigned here — but it must not be made WORSE by a
           height task either. Keeping the top at 2rem holds the overlap at its
           original 25x25px. Measured both ways. */
        padding: 2rem var(--container-padding) 1.25rem;
    }

    .hero-section:not(.exercise-hero) .hero-title {
        font-size: 2rem;
    }

    .hero-section:not(.exercise-hero) .hero-meta {
        font-size: 0.95rem;
        gap: 8px;
        /* The profile's meta carries the user's e-mail, which is long enough to
           wrap inside its own span and stack the row to 124px. Let the items
           wrap as items instead. */
        flex-wrap: wrap;
        margin-bottom: 0.5rem;
    }

}

/* --- W4B.2 + W4B.3 (WDF1-3.3) — the per-library row size -------------------
   🔴 This is the application's FIRST min-width block. Every other rule in this
   sheet, and in every other sheet, is max-width — the desktop sizing IS the base
   stylesheet — so nothing here can reach the 768px and 600px blocks above, and
   nothing in them can reach this. That is deliberate and it is the whole of
   WDF1-3.2 (owner ruling, Q12): below 1024px every screen renders exactly as it
   did before this task, with no exception carved out for it.

   WHAT SCALES, and why it is one custom property rather than three copies of the
   rules: --row-scale multiplies the card, its art, the gap between cards, the
   row title and the gaps between rows (owner ruling, Q11 — the row is 50%
   SHORTER, not just its cards). A fourth size is then one declaration.

   WHAT DOES NOT SCALE — owner ruling 2026-08-13: the words. Taken literally a
   50% card carries a 7.6px title and 6.4px meta, and 5px / 4.2px at Small, which
   is not a smaller card but an unreadable one. The type floors at 11px (card)
   and 16px (row title). The art dominates the height, so the row still lands at
   ~51% and ~38% rather than exactly 50% and 33% — the ruling's intent, measured.

   WHERE IT APPLIES — Series, Movies and Games only (owner ruling, Q13). The hook
   is the data-row-size attribute, which quizflix.render.logic.js sets ONLY on a
   ?type= library screen and arcade.js sets on the arcade. Home is a different
   container (#home-rows) and the unfiltered library gets no attribute at all, so
   neither can be reached by anything here even though the unfiltered library
   shares this id. Search results and the directory's season rows are different
   containers again.

   🔴 The art height MUST be written at this specificity. The base rule is
   ID-scoped (#library-rows > section.category-row > ... > img in quizflix.css),
   so a .series-card img rule loses to it and the two screens that matter most
   would not move. The attribute selector is what wins here, not the file order.

   The [data-row-size] rule below is a floor for --row-scale: an attribute
   holding something unexpected renders at today's size rather than collapsing a
   calc() to nothing. scalarPreference() already refuses to store a fourth value;
   this is the same promise made twice. */

@media (min-width: 1024px) {

    #library-rows[data-row-size] {
        --row-scale: 1;
    }

    #library-rows[data-row-size="medium"] {
        --row-scale: 0.5;
    }

    #library-rows[data-row-size="small"] {
        --row-scale: 0.33;
    }

    /* The card: width and height together, so the art stays square (Q11). */
    #library-rows[data-row-size] .series-card {
        flex: 0 0 calc(240px * var(--row-scale));
    }

    #library-rows[data-row-size] > section.category-row > div.row-canvas > div.scroll-container > div.series-card > img {
        height: calc(240px * var(--row-scale));
    }

    /* Half-size cards a full 24px apart would read as a sparse row rather than a
       small one, and it is what would stop "twice as many titles fit across"
       from being true.

       The other two are measured additions, not guesses: with only the gap
       scaled, a Medium row came out at 56% and a Small row at 44% instead of the
       ruling's 50 and 33. The 1rem below the cards is a fixed 16px of row height
       at every size, and the 125px min-height (quizflix.styles.css) becomes the
       FLOOR at Small, where a card is only ~112px tall — the row stopped
       shrinking before the cards did. Both are the row's own vertical space,
       which Q11 says scales. */
    #library-rows[data-row-size] .scroll-container {
        gap: calc(var(--gap-size) * var(--row-scale));
        padding-bottom: calc(1rem * var(--row-scale));
        min-height: calc(125px * var(--row-scale));
    }

    /* The card's own text: the box scales, the words floor. */
    #library-rows[data-row-size] .card-details {
        padding: calc(10px * var(--row-scale));
    }

    #library-rows[data-row-size] .card-details .card-title {
        font-size: max(11px, calc(0.95rem * var(--row-scale)));
    }

    #library-rows[data-row-size] .card-meta {
        font-size: max(11px, calc(0.8rem * var(--row-scale)));
    }

    /* The row around the cards — this is the half of Q11 that makes the ROW
       shorter rather than only the things in it. */
    #library-rows[data-row-size] .row-title {
        font-size: max(16px, calc(30px * var(--row-scale)));
        margin-bottom: calc(1rem * var(--row-scale));
    }

    #library-rows[data-row-size] .category-row {
        margin: calc(1rem * var(--row-scale)) auto calc(3rem * var(--row-scale));
    }
}

@media (max-width: 600px) {
    .modal-header {
        flex-direction: column;
        align-items: center;
        text-align: center;
    }

    .modal-content {
        margin: 10% auto;
        padding: 1rem;
    }
}