/* ==========================================================================
   mobile.css — global responsive behaviour for Lesson Loom
   --------------------------------------------------------------------------
   Added 2026-09-18 alongside the removal of the "Desktop Browser Required"
   interstitial (components/mobile_device_block.html), which previously hid
   every authenticated page below 1024px.

   RULE FOR EDITING THIS FILE: every declaration lives inside a
   `@media` block. Nothing outside section 1 may apply at desktop widths, so
   the desktop layout stays exactly as it was and this file can be deleted
   wholesale to revert. Section 1 is the only unscoped part; its rules are
   overflow guards that are inert unless content actually overflows.
   ========================================================================== */


/* --------------------------------------------------------------------------
   1. Overflow containment  (ALL-WIDTHS — inert unless content overflows)
   -------------------------------------------------------------------------- */

/* Media must never be able to push the page wider than the viewport. */
img,
video,
canvas,
svg:not(.keep-intrinsic-size) {
    max-width: 100%;
}

img,
video {
    height: auto;
}

/* Preformatted blocks (prompt dumps, JSON, logs) scroll rather than stretch. */
pre {
    max-width: 100%;
    overflow-x: auto;
}


/* --------------------------------------------------------------------------
   2. Phones and small tablets  (< 1024px — the old cut-off for the block)
   -------------------------------------------------------------------------- */
@media (max-width: 1023px) {

    /* --- 2a. Typography & wrapping ------------------------------------- */

    /* Unbroken strings — emails, URLs, API keys, filenames, job ids — are the
       single most common cause of a page scrolling sideways.

       This MUST stay `break-word`, never `anywhere`. The two look
       interchangeable and are not: `anywhere` also shrinks the element's
       intrinsic *min-content* width, which is what flex and grid use to decide
       how far a child may be squeezed. Applying it to `.badge` let a squeezed
       badge collapse to one character wide and render "Completed" as a vertical
       column of letters on the lesson-history cards. `break-word` still breaks
       a long word that would otherwise overflow, but leaves min-content alone,
       so a badge keeps its width and the real fix stays where it belongs — in
       the flex container that was squeezing it. */
    body {
        overflow-wrap: break-word;
        word-wrap: break-word;
    }

    .break-anywhere {
        overflow-wrap: anywhere;
    }

    /* Badges and pills state a short, fixed label. They must never be the thing
       that gives way when a row runs out of room — wrap the row instead. */
    .badge {
        white-space: nowrap;
        flex-shrink: 0;
    }

    /* Display headings set for a 1440px canvas are far too large on a phone.
       NOTE the `body` prefix on these: the Tailwind Play CDN injects its
       utilities into a <style> block at runtime, so we cannot rely on source
       order to win a tie. `body .text-5xl` (0,1,1) beats `.text-5xl` (0,1,0)
       whichever order they land in. Responsive variants are untouched —
       `lg:text-5xl` compiles to a different class name. */
    body .text-7xl { font-size: 2.75rem;  line-height: 1.1; }
    body .text-6xl { font-size: 2.5rem;   line-height: 1.1; }
    body .text-5xl { font-size: 2.125rem; line-height: 1.15; }
    body .text-4xl { font-size: 1.875rem; line-height: 1.2; }
    body .text-3xl { font-size: 1.5rem;   line-height: 1.25; }


    /* --- 2b. Form controls --------------------------------------------- */

    /* iOS Safari zooms the whole viewport when a focused control has a
       computed font-size below 16px, and never zooms back out. This is the
       cause of the "page is suddenly huge and off-centre after I tap a box"
       behaviour. 16px is the documented threshold. */
    input,
    select,
    textarea,
    .input,
    .select,
    .textarea,
    .input-sm,
    .select-sm,
    .textarea-sm,
    .input-xs,
    .select-xs {
        font-size: 16px !important;
    }

    /* Inputs default to a browser-chosen intrinsic width (~20 chars) which
       overflows narrow cards; make them fill their container instead. */
    .input,
    .select,
    .textarea,
    input[type="text"],
    input[type="email"],
    input[type="password"],
    input[type="number"],
    input[type="search"],
    input[type="url"],
    input[type="date"],
    input[type="time"],
    select,
    textarea {
        max-width: 100%;
    }

    /* Date/time inputs on iOS have a fixed intrinsic width that overflows. */
    input[type="date"],
    input[type="time"],
    input[type="datetime-local"] {
        min-width: 0;
        width: 100%;
    }

    /* DaisyUI's `.label` is `justify-content: space-between`, so a field label
       and its `.label-text-alt` hint share one row. That reads fine when the
       hint is short ("per lesson") and badly when it is not — "Special
       Instructions" and "Any specific requirements or focus areas" each wrapped
       to two lines and interleaved, looking like two competing labels.
       Allowing the row to wrap keeps short pairs side by side and drops a long
       hint onto its own line instead. */
    .label {
        flex-wrap: wrap;
        gap: 0.125rem 0.5rem;
    }


    /* --- 2c. Touch targets ---------------------------------------------- */

    /* WCAG 2.2 target-size minimum. DaisyUI's btn-xs/btn-sm and icon-only
       ghost buttons fall well under this. */
    .btn:not(.btn-link),
    .tab,
    .menu li > a,
    .menu li > button,
    .dropdown-content li > a,
    button.link {
        min-height: 2.5rem;
    }

    .btn-circle,
    .btn-square {
        min-width: 2.5rem;
    }

    /* Checkboxes and radios are routinely 16px, which is hard to hit. */
    .checkbox,
    .radio,
    input[type="checkbox"],
    input[type="radio"] {
        min-width: 1.25rem;
        min-height: 1.25rem;
    }

    /* DaisyUI toggles render 43x22 here. The ones in the cookie-settings modal
       are not wrapped in a label, so the switch itself is the only tap target
       and 22px is too short to hit reliably.

       The selector must out-specify the `input[type="checkbox"]` rule above:
       a DaisyUI toggle IS an input[type=checkbox], and (0,1,1) beat a bare
       `.toggle` (0,1,0), silently pinning these back to 20px. */
    input[type="checkbox"].toggle,
    .toggle {
        min-width: 3rem;
        min-height: 1.75rem;
    }


    /* --- 2d. Tables ------------------------------------------------------ */

    /* Any table inside a scroll container keeps its columns readable rather
       than collapsing them into unreadable slivers. Templates wrap tables in
       .overflow-x-auto; this makes the wrapper actually do something by
       stopping the table shrinking to fit.
       Specificity note: many of these tables carry `w-full` (.table.w-full =
       0,2,0), so the selector needs two classes plus the element to win. */
    .overflow-x-auto > table.table,
    .overflow-auto > table.table,
    .overflow-x-auto > table,
    .overflow-auto > table {
        min-width: 100%;
        width: max-content;
    }

    .overflow-x-auto,
    .overflow-auto {
        -webkit-overflow-scrolling: touch;
    }

    /* A table with no wrapper at all still must not widen the page. */
    table {
        max-width: 100%;
    }

    .table :where(th, td) {
        padding-left: 0.5rem;
        padding-right: 0.5rem;
        font-size: 0.8125rem;
    }

    /* Opt-in: turn a table into stacked cards, one per row.
       Horizontal scrolling keeps a table *usable*, but a five-column table in a
       262px window is still a five-column table — the subject column collapses
       to a couple of words per line and the last column sits off-screen. For
       short, read-mostly lists a stacked card per row is simply the right shape
       on a phone.

       To use: add `table-stack` to the <table> and `data-label="…"` to each
       <td> that should show a label. A <td> with no data-label (an actions
       cell) renders without one. */
    table.table-stack thead {
        display: none;
    }

    table.table-stack,
    table.table-stack tbody,
    table.table-stack tr,
    table.table-stack td {
        display: block;
        width: 100%;
    }

    table.table-stack tr {
        border: 1px solid var(--fallback-bc, rgba(0, 0, 0, 0.15));
        border-radius: 0.75rem;
        padding: 0.75rem 0.875rem;
        margin-bottom: 0.75rem;
    }

    table.table-stack td {
        border: 0;
        padding: 0.2rem 0;
        display: flex;
        gap: 0.5rem;
        align-items: baseline;
        justify-content: space-between;
    }

    table.table-stack td[data-label]::before {
        content: attr(data-label);
        font-weight: 600;
        opacity: 0.6;
        flex: 0 0 auto;
        font-size: 0.75rem;
        text-transform: uppercase;
        letter-spacing: 0.02em;
    }

    /* The first cell reads as the row's title rather than a labelled field. */
    table.table-stack td:first-child {
        display: block;
        font-size: 0.95rem;
        font-weight: 600;
        margin-bottom: 0.25rem;
    }

    table.table-stack td:first-child::before {
        content: none;
    }


    /* --- 2e. Modals ------------------------------------------------------ */

    /* max-width is capped because page markup sets max-w-3xl/5xl/7xl via
       Tailwind utilities, which beat DaisyUI's own 32rem and are all wider
       than a phone. The height cap matters just as much: a modal taller than
       the viewport put its action buttons below the fold with no way to
       scroll to them.

       `width` is deliberately NOT forced here. DaisyUI already sizes the box
       (91.67% for modal-middle, 100% for modal-bottom) and those fit fine; an
       earlier version forced `width: calc(100vw - 1.5rem)` and broke every
       bottom-sheet modal — see the .modal-bottom block below.

       Padding is also not touched — teacher/progress_modal.html uses `p-0`
       with its own internal layout. */
    .modal-box {
        max-width: calc(100vw - 1.5rem) !important;
        max-height: calc(100vh - 2rem);
        max-height: calc(100dvh - 2rem); /* dvh excludes the iOS URL bar */
        overflow-y: auto;
    }

    /* Bottom-sheet modals (`modal modal-bottom sm:modal-middle` — the tutorial
       video, progress, queued-job, day-detail, schedule-settings and
       image-cache fullscreen modals).

       `.modal-bottom` is `place-items: end`, which sets BOTH align- and
       justify-items to `end`. DaisyUI makes that harmless by giving the box
       `width: 100%`, so "justify to the end" has nothing to move. Narrow the
       box at all and it stops being harmless: the sheet detaches from the left
       edge and hangs off the right, which is exactly what it did. Restore full
       width, square off the bottom corners so it reads as a sheet rather than
       a card jammed into the corner, and keep the action row clear of the iOS
       home indicator. */
    .modal-bottom .modal-box {
        width: 100% !important;
        max-width: 100% !important;
        border-bottom-left-radius: 0;
        border-bottom-right-radius: 0;
        padding-bottom: calc(1.25rem + env(safe-area-inset-bottom, 0px));
    }

    .modal-action {
        flex-wrap: wrap;
        gap: 0.5rem;
    }

    .modal-action .btn {
        flex: 1 1 auto;
    }


    /* --- 2f. Layout primitives ------------------------------------------- */

    /* DaisyUI stats render side by side and overflow; stack them. */
    .stats:not(.stats-vertical) {
        display: grid;
        grid-auto-flow: row;
        width: 100%;
    }

    .stat {
        padding: 0.75rem 1rem;
    }

    .stat-value {
        font-size: 1.5rem;
    }

    /* Horizontal tab strips scroll instead of wrapping into a tall block. */
    .tabs:not(.tabs-vertical) {
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;
    }

    .tabs:not(.tabs-vertical)::-webkit-scrollbar {
        display: none;
    }

    .tabs .tab {
        flex: 0 0 auto;
    }

    /* NOTE: no blanket `.card-body { padding }` rule here on purpose. Templates
       set their own (`card-body p-2`, `p-3`, `p-4`), and a same-specificity
       rule would win or lose depending on where the Tailwind CDN injected its
       styles — sometimes making padding *larger* than the template asked for.
       Page-level gutters are reclaimed in base.html instead. */

    /* Button groups stack rather than squash. */
    .btn-group:not(.btn-group-horizontal) {
        flex-wrap: wrap;
    }

    /* Safety net for one-off inline `width: NNNpx` in page markup.
       NOTE: this deliberately does NOT try to rein in inline `min-width`.
       Per CSS 2.1 §10.4 min-width wins over max-width, so `max-width: 100%`
       cannot shrink an element that carries `min-width: 400px` — the element
       stays 400px and the page still scrolls sideways. Inline min-widths have
       to be capped at source; the three in lesson_preview.html now use
       `min(Npx, 100%)`. If you add another, do the same. */
    [style*="width:"] {
        max-width: 100%;
    }


    /* --- 2g. Decorative background glyphs --------------------------------- */

    /* The dashboard, pricing page, login, register and whiteboard login each
       scatter 8–16 absolutely-positioned glyphs behind the content. They are
       pleasant behind a wide canvas and pure clutter behind a phone-width
       column, where several land directly under the text. */
    .bg-decoration,
    .pricing-decoration {
        display: none;
    }

    /* The gradient full-bleed wrapper (dashboard, create-plan, history,
       schedule, whiteboards, resources, profile, billing, billing success)
       reserves 2rem top and bottom for the decorations that are now hidden. */
    .full-bleed-bg {
        padding: 1rem 0;
    }


    /* --- 2h. Floating furniture ------------------------------------------ */

    /* The background-task panel is w-80 (320px) anchored right; on a 320px
       phone it hangs off the left edge. */
    #task-manager-panel {
        width: calc(100vw - 2rem) !important;
        max-width: 24rem;
    }

    /* The completion banner is a 3-column flex row that squashes to nothing. */
    #notification-banner-container .flex.items-center.justify-between {
        flex-direction: column;
        align-items: stretch;
        gap: 0.5rem;
    }
}


/* --------------------------------------------------------------------------
   3. Narrow phones (<= 480px) — the tightest case
   -------------------------------------------------------------------------- */
@media (max-width: 480px) {

    /* Stacked, full-width buttons are easier to hit than a squashed row. */
    .btn-block-mobile {
        display: flex;
        width: 100%;
    }

    /* DaisyUI joins (search box + button) break rather than overflow. */
    .join:not(.join-vertical) {
        flex-wrap: wrap;
    }

    .join:not(.join-vertical) > * {
        flex: 1 1 auto;
    }
}


/* --------------------------------------------------------------------------
   4. Landscape phones — vertical space is the scarce resource
   -------------------------------------------------------------------------- */
@media (max-height: 480px) and (orientation: landscape) {
    .modal-box {
        max-height: calc(100vh - 1rem);
        max-height: calc(100dvh - 1rem);
    }

    .navbar {
        min-height: 3rem;
    }
}


/* --------------------------------------------------------------------------
   5. Print — unchanged behaviour, kept here so it survives a CSS reshuffle
   -------------------------------------------------------------------------- */
@media print {
    .no-print,
    #task-manager,
    #notification-banner-container,
    #cookie-consent-banner {
        display: none !important;
    }
}
