/* ============================================================
   PixelVerse — mobile / touch layer
   ------------------------------------------------------------
   Link this AFTER each page's own <style> block so it wins on
   equal specificity:

     <link rel="stylesheet" href="pixelverse-design-system.css">
     <style> ...page CSS... </style>
     <link rel="stylesheet" href="mobile.css">   <-- last

   Three layers, in order:
     A. touch   (hover: none) — width-independent
     B. compact (<= 900px)    — phones and small tablets
     C. narrow  (<= 560px)    — phones proper
   ...then one block per page.

   Nothing here is desktop-visible: every rule sits in a query.
   ============================================================ */


/* ============================================================
   A. TOUCH LAYER — anything gated behind :hover is unreachable
   on a finger. Keyed off (hover: none), not width, because a
   touch tablet at 1024px has the same problem as a phone.
   ============================================================ */
@media (hover: none) {

  /* --- Controls that only appear on hover -------------------- */
  /* brands.html: delete-brand. brand.html: delete/re-tag asset.
     generate+edit: per-tile download. Each is opacity:0 until
     :hover, i.e. invisible AND untappable on touch. */
  .brand-del,
  .tile-del,
  .tile-edit,
  .tile-dl-btn { opacity: 1 !important; }

  /* brand.html: per-section actions sit at .55 until the group
     is hovered. */
  .sec-act { opacity: 1 !important; }

  /* brand.html: the "click to edit" affordance is the only thing
     announcing that identity cards are editable at all. */
  .edit-hint { opacity: 1 !important; }
  .edit-hint .t { display: inline !important; }

  /* gallery.html: the overlay carries the status tags and the
     تحميل / عرض buttons. Show it, but weight the gradient to the
     bottom and drop the 2-line brief so the picture still reads.
     (The brief is still there in the lightbox.) */
  .tile-overlay {
    opacity: 1;
    background: linear-gradient(to top,
                rgba(30,20,60,.86) 0%,
                rgba(30,20,60,.45) 45%,
                transparent 72%);
  }
  .tile-overlay .tile-brief { display: none; }

  /* --- Sticky-hover artifacts -------------------------------- */
  /* On touch, :hover latches after a tap and stays. Kill the
     transforms so a tapped card does not stay lifted. */
  .btn-primary:hover,
  .btn-outline:hover,
  .btn-danger:hover,
  .btn-danger-outline:hover,
  .lift:hover,
  .tile:hover,
  .brand-card:hover,
  .new-card:hover,
  .lb-dl-btn:hover,
  .lb-btn-dl:hover { transform: none; }

  .tile:hover img { transform: none; }

  /* Soften the grey block the OS paints over a tapped target. */
  a, button, .tile, .brand-card, .new-card,
  .fchip, .combo-opt, .flow-opt, .diff-side, .ebody.clickable {
    -webkit-tap-highlight-color: rgba(126,87,211,.12);
  }
}


/* ============================================================
   B. COMPACT LAYER — <= 900px
   ============================================================ */
@media (max-width: 900px) {

  /* --- Global -------------------------------------------------
     100vh on iOS Safari measures the *large* viewport, so a
     100vh box hides ~90px behind the browser chrome. dvh tracks
     the visible box. background-attachment:fixed forces a
     full-page repaint on every scroll frame on iOS. */
  html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
  body {
    min-height: 100vh;
    min-height: 100dvh;
    background-attachment: scroll;
  }

  .container { padding: 0 16px; }
  section { padding: 32px 0; }

  h1 { font-size: 2rem; line-height: 1.35; }
  .section-title { font-size: 1.5rem; }
  .card-title { font-size: 1.35rem; }

  /* 40px of padding each side leaves 262px of a 390px screen. */
  .card { padding: 24px 18px; }
  .card-glow { inset: -10px; border-radius: 28px; }

  /* 16px/32px padding at 1.1rem makes a two-word Arabic button
     ~180px wide — four of them cannot share a row. */
  .btn {
    padding: 11px 18px;
    font-size: .95rem;
    min-height: 44px;
    justify-content: center;
  }

  /* --- iOS zoom-on-focus ---------------------------------------
     Safari zooms the whole page when a focused field computes
     under 16px, and does not zoom back out. Every field in the
     app was 11.5–15.2px. */
  .input, .textarea, .select,
  .combo-input, .composer-input, .name-input,
  input, textarea, select { font-size: 16px; }

  /* Two fields were sized around a small font; give them room. */
  .sw-item input[type=text] { width: 92px; padding: 5px 4px; }
  .toolbar .select { min-width: 0; width: 100%; }

  /* --- Scroll affordance ---------------------------------------
     The design system hides every scrollbar globally (`* {
     scrollbar-width: none }`). On desktop that is a style choice;
     on a phone it means a 9-column table or a filmstrip looks
     like static content. Restore it on the containers that
     actually scroll. */
  .table-scroll, .upload-previews, .lb-inner, .modal,
  .details-modal, .combo-menu, .brand-menu-pop {
    scrollbar-width: thin;
    scrollbar-color: rgba(126,87,211,.35) transparent;
  }
  .table-scroll::-webkit-scrollbar,
  .upload-previews::-webkit-scrollbar,
  .lb-inner::-webkit-scrollbar,
  .modal::-webkit-scrollbar,
  .details-modal::-webkit-scrollbar { display: block; width: 4px; height: 4px; }
  .table-scroll::-webkit-scrollbar-thumb,
  .upload-previews::-webkit-scrollbar-thumb,
  .lb-inner::-webkit-scrollbar-thumb,
  .modal::-webkit-scrollbar-thumb,
  .details-modal::-webkit-scrollbar-thumb {
    background: rgba(126,87,211,.35); border-radius: 999px;
  }

  /* --- Shared header (brands / brand / gallery) ----------------
     `justify-content: space-between` with no wrap and up to four
     .btn children needs ~600px. Below that the nav was clipped
     by body{overflow-x:hidden} and خروج became unreachable.
     Give the nav its own full-width row that scrolls sideways.
     `display`/`gap` need !important: both are inline attributes
     on the <nav> in the markup. */
  header.bar {
    flex-wrap: wrap;
    gap: 10px;
    padding: 14px 0;
  }
  header.bar .logo { font-size: 1.15rem; }
  /* Wrap, do not scroll. A sideways-scrolling nav looked tidy but hid half
     the app: measured on a 411px phone the row needed 484px, so المعرض sat
     at x=-15 and خروج at x=-86 and you had to know to swipe for them.
     Wrapping to a second line keeps every destination on screen, and this
     header is not sticky so the extra height just scrolls away. */
  header.bar nav {
    display: flex !important;
    gap: 8px !important;
    flex: 1 1 100%;
    flex-wrap: wrap;
    row-gap: 8px;
  }
  header.bar nav > * { flex: 0 1 auto; }
  header.bar nav .btn {
    padding: 9px 14px;
    font-size: .88rem;
    min-height: 44px;
  }

  /* --- Modals ---------------------------------------------------
     Action rows are written as inline style="display:flex" with
     no wrap; at 270px of modal interior "إنشاء ومتابعة" + "إلغاء"
     overflowed and the status/error text was pushed off-screen.
     flex-wrap is not in the inline attribute, so this lands. */
  .overlay { padding: 14px; }
  .overlay .card > div,
  .overlay .modal > div { flex-wrap: wrap; }
  .overlay .btn { flex: 1 1 auto; }
  .modal, .details-modal {
    max-height: 88vh;
    max-height: 88dvh;
    overflow-y: auto;
  }

  /* --- Tap targets ---------------------------------------------
     44px is the floor. These were 16–34px. */
  .tile-del, .tile-edit, .brand-del, .x-btn,
  .tile-dl-btn, .lb-close {
    width: 40px; height: 40px;
  }
  .sw-item .x-btn { width: 26px; height: 26px; }
  .tile-edit { inset-inline-end: 54px; }
  .fchip, .sec-act, .add-btn, .lb-btn { min-height: 44px; }
  /* Two buttons sharing a 165px tile — height is what matters here. */
  .tile-btn { min-height: 38px; }
}


/* ============================================================
   C. NARROW LAYER — <= 560px
   ============================================================ */
@media (max-width: 560px) {
  h1 { font-size: 1.75rem; }
  .card { padding: 20px 16px; }
  .container { padding: 0 14px; }
}


/* ============================================================
   PAGE: login.html
   ============================================================ */
@media (max-width: 900px) {
  .login-wrap {
    min-height: 100vh;
    min-height: 100dvh;
    padding: 24px 14px;
  }
  .login-card { padding: 28px 20px; }
  .login-card .logo { font-size: 1.5rem; }
}


/* ============================================================
   PAGE: brands.html
   ============================================================ */
@media (max-width: 900px) {
  .page-head { margin: 20px 0 24px; }
  .page-head h1 { font-size: 1.9rem; }
  .page-head > .btn { width: 100%; }

  /* minmax(280px,1fr) overflows a 320px viewport once the
     container padding is taken out. */
  .brand-grid { grid-template-columns: 1fr; gap: 16px; }
  .brand-card .body { padding: 18px; }
  .brand-card h3 { font-size: 1.3rem; }
  .new-card { min-height: 150px; }

  /* The card itself navigates on tap, so the delete button (now
     always visible, see layer A) needs to sit clear of it. */
  .brand-del { top: 10px; inset-inline-end: 10px; }
}


/* ============================================================
   PAGE: brand.html
   ============================================================ */
@media (max-width: 900px) {
  /* 48px/44px padding leaves 254px of a 390px screen, and the
     three decorative cubes are absolutely positioned across the
     leftmost 144px of it — straight through the wrapped title. */
  .hero { padding: 26px 20px; margin-bottom: 26px; }
  .hero h1 { font-size: 1.8rem; }
  .cube { display: none; }
  .name-input { font-size: 1.6rem; padding: 8px 12px; }

  /* 5 buttons at desktop size = 5 stacked rows. Two per row. */
  .hero-actions { gap: 8px; }
  .hero-actions .btn { flex: 1 1 calc(50% - 4px); padding: 10px 8px; font-size: .88rem; }

  /* .sec-actions has flex-wrap, but its parent .sec-head does
     not — so the whole actions block was one unbreakable flex
     item and its last button was clipped. */
  .sec-head { flex-wrap: wrap; row-gap: 10px; }
  .sec-head h2 { font-size: 1.2rem; }
  .sec-actions { margin-inline-start: 0; flex: 1 1 100%; }

  .identity { gap: 14px; margin-bottom: 32px; }
  .ifield { padding: 18px 16px; }
  .ifield .value { font-size: 1.05rem; }
  .swatch .chip-color { width: 46px; height: 46px; }

  /* Uploaded-file rows: name + type select + section select each
     want their own line at this width. */
  .file-row { gap: 8px; }
  .file-row .name { flex: 1 1 100%; }
  .file-row .select { flex: 1 1 auto; max-width: none !important; }
}


/* ============================================================
   PAGE: identity.html
   ============================================================ */
@media (max-width: 900px) {
  .id-head { margin: 10px 0 16px; }
  .id-head h1 { font-size: 1.7rem; }
  .steps { gap: 6px; margin-bottom: 16px; }
  .step { padding: 6px 10px 6px 12px; font-size: .82rem; }

  /* Optional fields: two columns of inputs leave ~140px each on a phone. */
  .two { grid-template-columns: 1fr; gap: 0; }
  .logo-zone { gap: 14px; padding: 14px; }
  .logo-zone .thumb { width: 68px; height: 68px; }
  .actions .btn { flex: 1 1 100%; }

  /* The chat keeps its own scroll; on a phone it gets most of the screen. */
  .chat-messages { padding: 14px; max-height: 64dvh; }
  .bubble { max-width: 88%; }
  .bubble.has-proposal { max-width: 100%; width: 100%; }
  .proposal { padding: 14px; }
  .p-tagline { font-size: 1.3rem; }
  .p-grid { grid-template-columns: 1fr; }
  .p-actions .btn { flex: 1 1 100%; }
  .linkish { min-height: 44px; }

  /* Hero beside a stacked pair is unreadable at 375px: one column. */
  .board { grid-template-columns: 1fr; grid-template-areas: "hero" "social" "lifestyle"; }
  .board-actions .btn { flex: 1 1 100%; }
}


/* ============================================================
   PAGE: gallery.html
   ============================================================ */
@media (max-width: 900px) {
  .page-head { flex-wrap: wrap; }
  .page-head h1 { font-size: 1.7rem; }
  .toolbar { gap: 10px; margin-bottom: 22px; }
  /* `.toolbar .select` is (0,2,0) and beats the bare `select` rule in the
     compact layer, so the 15.2px zoom trigger has to be cleared here. */
  .toolbar .select { flex: 1 1 100%; font-size: 16px; min-height: 44px; }
  .filter-chips { flex: 1 1 100%; }

  /* Lightbox: the <=800px rule stacks it to a column and removes
     max-height, but .lb-img-wrap keeps a 300px floor and the
     panel adds 220px — taller than an iPhone SE viewport, with
     no scroll container. Let the whole thing scroll instead. */
  .lb-scrim { padding: 0; align-items: stretch; }
  .lb-inner {
    max-height: 100vh;
    max-height: 100dvh;
    overflow-y: auto;
    border-radius: 0;
  }
  .lb-img-wrap { min-height: 200px; }
  .lb-img-wrap img { max-height: 58vh; max-height: 58dvh; }
  .lb-panel { max-height: none; padding: 20px 16px 24px; }

  /* margin-top:auto pushed the download button below the fold of
     a 220px panel whose scrollbar was hidden. */
  .lb-dl-btn { margin-top: 8px; }

  .lb-close {
    top: 10px; left: 10px;
    background: rgba(0,0,0,.45);
  }

  .empty { padding: 48px 16px; }
}

@media (max-width: 560px) {
  .gallery-grid { gap: 10px; }
  .tile-overlay { padding: 10px; }
  .tile-actions { gap: 6px; margin-top: 6px; }
  .tile-btn { font-size: .78rem; padding: 7px 0; }
}


/* ============================================================
   PAGE: generate.html + edit.html — the focused app shell
   ------------------------------------------------------------
   These two pages are a fixed-size desktop "window": the body
   centres a min(1400px,97vw) x min(900px,95vh) rounded box with
   overflow:hidden. On a phone that box is still centred, still
   rounded, and its docked composer sits behind the browser
   chrome. Below 900px it becomes a full-bleed app screen:
   header / scrolling stage / docked composer, sized in dvh.

   Scoped to body.app-shell — these two pages carry that class,
   and the flat background below must not reach the pastel
   gradient the content pages use.
   ============================================================ */
@media (max-width: 900px) {
  body.app-shell {
    display: block;
    padding: 0;
    background: #eef2fa;
  }
  .gen-shell {
    width: 100%;
    height: 100vh;
    height: 100dvh;
    max-height: none;
    margin: 0;
    border-radius: 0;
    box-shadow: none;
  }

  /* --- Header: one row, never two ------------------------------
     Wrapping was stealing height from the stage. The brand pill
     is the only elastic element; everything else is fixed. */
  .gen-bar {
    flex-wrap: nowrap;
    gap: 8px;
    padding: 6px 12px;
    min-height: 52px;
  }
  .gen-bar .logo { display: none; }          /* keep the mark, drop the wordmark */
  .gen-bar > a:first-child { flex: 0 0 auto; }
  .gen-nav {
    flex-wrap: nowrap;
    gap: 6px;
    min-width: 0;
    flex: 1 1 auto;
    justify-content: flex-end;
  }
  .brand-ctx { min-width: 0; flex: 1 1 auto; }
  .brand-pill {
    max-width: none;
    width: 100%;
    min-width: 0;
    padding: 8px 10px;
  }
  .brand-pill-k { display: none; }           /* the "علامة:" prefix */
  .gen-nav .btn { padding: 8px 10px; font-size: .8rem; min-height: 44px; }
  .brand-pill { min-height: 44px; }
  .credit-pill { padding: 6px 10px 6px 6px; flex-shrink: 0; }

  /* Anchored popovers start near the edge in RTL; let them use
     the available width instead of overhanging it. */
  .brand-menu-pop {
    min-width: 0;
    width: max-content;
    max-width: min(88vw, 320px);
    inset-inline-start: auto;
    inset-inline-end: 0;
  }

  /* --- Stage ---------------------------------------------------- */
  .gen-stage { padding: 8px 12px 0; gap: 10px; }

  /* The 360px floor plus a grown composer overflowed the shell.
     And `height:100%; width:auto; aspect-ratio:4/3` resolved the
     width from the height, then clamped it with max-width:100% —
     silently breaking the ratio. Drive it from the width. */
  /* #result-section is flex:1;min-height:0 and .canvas-wrap has a 190px
     floor, so on a short phone the stage squeezed the section to 141px
     while the canvas held 190px — and painted 49px down over the gallery
     tiles. That is the thumbnail that appeared to sit on the canvas.
     Give the section the same floor so the stage scrolls instead. */
  .canvas-wrap { min-height: 190px; }
  #result-section { min-height: 190px; }
  /* Desktop pins the canvas to 4/3 and drives the width from the height.
     On a portrait phone that both breaks the ratio (width:auto resolved
     from the height, then clamped by max-width:100%) and wastes most of
     the screen — and the content here is usually 1:1 or 9:16. Let it
     fill the stage instead; the image inside is already fit-to-box via
     max-width/max-height, so any orientation letterboxes correctly. */
  .canvas {
    width: 100%;
    height: 100%;
    max-height: none;
    aspect-ratio: auto;
    border-radius: 16px;
  }
  .stage-empty { padding: 18px; gap: 10px; }
  .stage-empty-title { font-size: 1rem; }
  .stage-empty-sub { font-size: .85rem; }

  /* The filmstrip now restores history, so it is a real strip rather than a
     one-off. At 84px it fits 4 per row and the (always-visible on touch)
     40px download button swallows half of each thumbnail. Three per row
     keeps the button tappable AND proportionate. */
  .gen-stage #gallery { grid-template-columns: repeat(auto-fill, minmax(108px, 1fr)); gap: 8px; }

  /* --- Composer -------------------------------------------------
     Docked, and capped so it can never squeeze the canvas out of
     the shell — past the cap it scrolls internally instead. */
  .composer { padding: 4px 10px 8px; }
  .composer-inner { padding: 8px 10px; gap: 6px; border-radius: 16px; }
  /* NO overflow/max-height here, deliberately. .combo-menu opens upward out
     of this box, and any `overflow` on an ancestor clips an absolutely
     positioned descendant — so a scroll cap here silently amputated the top
     of every options list, leaving the last two entries looking like the
     whole list AND making the rest untappable. The composer does not need a
     cap: .gen-stage is flex:1/min-height:0 and scrolls, so it yields the
     space instead. */
  .comp-fields { gap: 8px; }

  /* Each option gets its own full-width row: `width:210px` +
     `flex-shrink:0` could not compress and forced overflow. */
  #brief-details { gap: 8px; padding: 8px 0 2px; }
  .comp-row { flex: 1 1 100%; }
  .combo { width: auto; flex: 1 1 auto; min-width: 0; }
  .comp-label { min-width: 62px; }

  /* The options list opens upward, into the space the keyboard does not
     cover — good — but a fixed 190px menu is taller than the whole stage
     once the keyboard is up, and .gen-shell{overflow:hidden} clips the
     overspill into an unreadable sliver. Size it against the live
     viewport so it always fits what is actually on screen. */
  /* Taller than the desktop 190px now that picking no longer costs half the
     screen to a keyboard — but still tied to the viewport, so it shrinks
     again on the rare occasion the keyboard IS up. */
  /* 30dvh, not 45: the menu opens upward out of the composer, so on a
     keyboard-shrunk viewport a taller box overruns the top of the shell and
     .gen-shell{overflow:hidden} eats the difference. The sticky write row
     below means height is no longer what keeps that row reachable anyway. */
  .combo-menu { max-width: 100%; max-height: min(260px, 30dvh); }
  .combo-opt { white-space: normal; padding: 11px 12px; }

  /* Options scroll; the write row does not. A real footer, not a sticky
     overlay — as an overlay it covered the last option, which was then
     unreachable until the user guessed to scroll. */
  /* Must be `.combo.open .combo-menu` — the page sets `display:block` at that
     same specificity when the menu opens, and a bare `.combo-menu` loses to
     it, leaving the footer to overflow out of the hidden box. */
  .combo.open .combo-menu { display: flex; flex-direction: column; overflow: hidden; }
  .combo-list { flex: 1 1 auto; overflow-y: auto; min-height: 0; }

  /* The "type your own" row: an action, not a value. Separated so it does not
     read as one more preset, and always visible — it is the only way to reach
     the keyboard for this field. */
  .combo-opt.combo-write {
    flex-shrink: 0;
    background: #fff;
    border-top: 1px dashed #ece7fb;
    margin-top: 4px;
    color: var(--core-purple);
    font-weight: 800;
    font-size: .85rem;
  }

  /* content-type and goal are free-text boxes, so the caret is the only
     way to reach their preset list — and it was a 19x21 target. The
     input already reserves 30px of inline-end padding, so widening the
     hit area does not cover any text. */
  .combo-input { min-height: 44px; padding-inline-end: 42px; }
  .combo-caret {
    inset-inline-end: 0;
    width: 40px;
    height: 40px;
    padding: 0;
    display: grid;
    place-items: center;
  }

  /* أسلوب: عادي / ملهم / إبداعي — 29px tall, and their only explanation
     lives in a title="" tooltip that touch never shows. */
  .mode-btn { min-height: 40px; padding: 8px 14px; }

  /* Two-up on one row is right; they just need to be tappable. */
  .flow-switch { gap: 6px; }
  .flow-opt { padding: 8px 10px; }
  .flow-opt .d { font-size: .68rem; }

  /* attach(nowrap label) + 240px preview tray + textarea + button
     needed ~400px inside a ~300px row. The page's own 720px rule sets
     flex-wrap, but nothing wraps: the textarea has no min-width, so it
     just collapsed to a ~60px sliver while the other two kept their
     size. Give the input its own full-width row above the actions. */
  .comp-prompt { padding: 6px; gap: 8px; row-gap: 6px; }
  .comp-prompt .composer-input {
    flex: 1 1 100%;
    order: -1;
    padding: 4px 4px 2px;
  }
  .attach-btn { flex: 1 1 auto; min-width: 0; padding: 8px 10px; min-height: 44px; justify-content: center; }
  /* nowrap label + a nowrap CTA in the same row cannot both hold their
     width; let the longer label ellipsis rather than run under its
     sibling. */
  .attach-add { font-size: .78rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .upload-previews { max-width: 96px; }
  .comp-prompt .btn { flex: 1 1 auto; padding: 10px 16px; font-size: .9rem; min-height: 44px; white-space: nowrap; }
  .composer-input { font-size: 16px; max-height: 84px; }

  /* "أفكار الذكاء" hides the brief, leaving a two-item action bar:
     "＋ إرفاق صورة المنتج" (~170px) beside "✦ اقترح أفكاراً" (~150px)
     does not fit 300px. Stack them — the attach zone is a dashed
     drop target and reads better full-width anyway. */
  .comp-prompt.no-brief { flex-wrap: wrap; }
  .comp-prompt.no-brief .attach-btn,
  .comp-prompt.no-brief .btn { flex: 1 1 100%; }

  /* Removing an attached image was a 16x16 target. */
  .upload-thumb .rm { width: 22px; height: 22px; font-size: .8rem; }

  /* --- Lightbox (generate/edit share this one) ------------------ */
  .overlay .lb-actions { flex-wrap: wrap; justify-content: center; }
  .lb-btn { padding: 12px 22px; min-height: 44px; }
}

@media (max-width: 560px) {
  .gen-bar { padding: 6px 10px; }
  .gen-stage { padding: 6px 10px 0; }
  .comp-label { font-size: .74rem; min-width: 56px; }
}

/* Portrait phone with the keyboard up: short AND narrow at once. While
   typing, the composer is the thing being looked at — so let the fields
   have the room, drop the canvas to a stub, and stop the internal scroll
   that was slicing a row in half. A real portrait phone is ~650px+ tall,
   so only an open keyboard reaches this. */
@media (max-width: 600px) and (max-height: 560px) {
  .gen-bar { min-height: 44px; padding: 4px 10px; }
  .canvas-wrap, #result-section { min-height: 96px; }
  .composer { padding: 3px 8px 6px; }
  .composer-inner { padding: 6px 9px; gap: 5px; }
  #brief-details { gap: 6px; padding: 6px 0 2px; }
}


/* A phone turned landscape is ~390px tall. The shell is still a fixed
   100dvh flex column, so the header + a 42dvh composer would leave the
   stage almost nothing. Tighten both, and let the options row go two-up
   since width is what landscape has to spare.

   min-width:600px is load-bearing, not decoration. generate/edit set
   interactive-widget=resizes-content, so opening the keyboard shrinks the
   LAYOUT viewport - a 432x936 phone becomes 432x430 while typing, which
   satisfies max-height:500px on its own. Without a width floor these
   landscape rules fire in portrait mid-keystroke and put two option rows
   on one 432px line, where they overlap. Orientation/aspect-ratio queries
   do not help: at 432x430 the viewport is technically landscape. A real
   phone in landscape is >=600px wide; a portrait one with the keyboard up
   never is. */
@media (max-width: 900px) and (max-height: 500px) and (min-width: 600px) {
  .gen-bar { min-height: 44px; padding: 4px 10px; }
  .gen-stage { padding: 6px 10px 0; }
  .canvas-wrap { min-height: 120px; }
  .comp-fields { max-height: 26dvh; }
  .composer { padding: 3px 8px 6px; }
  .composer-inner { padding: 6px 8px; }
  .comp-row { flex: 1 1 calc(50% - 6px); }
  .comp-prompt .composer-input { max-height: 56px; }
  /* The one-line description under each flow option is the first thing
     to go when vertical space is the scarce resource — but dropping it
     collapses the button to 32px, so hold a floor and centre the label. */
  .flow-opt { padding: 6px 10px; min-height: 38px; justify-content: center; }
  .flow-opt .d { display: none; }
  .stage-empty-sub { display: none; }
}


/* ============================================================
   PAGE: admin.html  (English + LTR, operator-only)
   Lowest priority — its tables already scroll and its drawer
   already collapses. This just makes them legible.
   ============================================================ */
@media (max-width: 900px) {
  .drawer { padding: 20px 16px; }
  .tabs { gap: 6px; }
  .tabs button { padding: 9px 12px; font-size: .85rem; }
  /* The chart's 11px ticks sit in a 900-unit viewBox, so a 390px-wide
     SVG renders them at ~5px. Hold it at a legible width and let it
     scroll sideways rather than hiding an operator's data. */
  .chart-wrap { overflow-x: auto; }
  .chart-wrap svg { width: 620px; min-width: 620px; max-width: none; }
}
