/* ============================================================================
   Chat app, responsive layer. Loaded LAST so it wins on equal specificity.

   Structure, in this order:
     1. Token bands, max-width blocks, widest to narrowest, then the
                             min-width block for the widest screens (placed last
                             so it wins from 1800px up regardless of order).
     2. Structural bands, layout changes that tokens alone cannot express.
     3. Capability queries, pointer/hover, reduced motion, short viewports.

   The single most important breakpoint is 900px: at and below it the shell stops
   being two floating cards side by side and becomes one full-bleed surface with
   the sidebar as an overlay drawer, the way ChatGPT and Claude behave on a
   phone. That number is mirrored in js/chat/mobile.js as MOBILE_QUERY, change
   both together.
   ============================================================================ */

/* ------------------------------------------------------------------- 0. base */

/* The sidebar scrim (created by js/chat/mobile.js) exists only for the overlay
   layout. Outside the mobile band it must be display:none, not merely transparent:
   it is a child of .app, which is a flex row, so an unstyled empty div would still
   be a participating flex item. */
.sidebar-scrim { display: none; }

/* -------------------------------------------------------------- 1. token bands */

@media (max-width: 1399px) {
  :root {
    --sidebar-w: 260px;
    --reading-max: 720px;
  }
}

@media (max-width: 1024px) {
  :root {
    --sidebar-w: 248px;
    --shell-pad: 12px;
    --shell-gap: 12px;
    --reading-max: 680px;
    --reading-pad: 20px;
    --hero-h2: 28px;
    --lib-card-min: 190px;
  }
}

/* Phone / small-tablet shell. Cards give way to one edge-to-edge surface, so the
   shell padding and inter-card gap both collapse to zero. */
@media (max-width: 900px) {
  :root {
    --shell-pad: 0px;
    --shell-gap: 0px;
    --reading-pad: 16px;
    /* Deliberately NOT zeroing --r-xl here. It reads like the obvious way to flatten
       the full-bleed chat surface, but the same token rounds the Settings, search and
       confirm modals, which are still centred cards down to 767px and must keep
       their corners. The surfaces that actually go edge-to-edge (.chat, form,
       #libraryPanel, and the Settings sheet below 767px) set border-radius: 0
       themselves, which is the targeted way to say it. */
    --hero-h2: 26px;
    --hero-sub: 14px;
  }
}

@media (max-width: 767px) {
  :root {
    --reading-pad: 14px;
    --hero-h2: 23px;
    --hero-sub: 13.5px;
    --lib-card-min: 150px;
  }
}

@media (max-width: 479px) {
  :root {
    --sidebar-w: min(300px, 86vw);
    --reading-pad: 12px;
    --sp-6: 20px;
    --hero-h2: 21px;
    --hero-sub: 13px;
  }
}

/* Widest screens. A min-width query placed after every max-width block above, so
   it wins from 1800px up regardless of source order. */
@media (min-width: 1800px) {
  :root {
    --shell-pad: 22px;
    --shell-gap: 20px;
    --sidebar-w: 300px;
    --reading-max: 840px;
    --reading-pad: 32px;
    --hero-h2: 36px;
    --hero-sub: 15.5px;
  }
}

/* --------------------------------------------------------- 2. structural bands */

/* ---- desktop shell: one sidebar toggle, never two ----------------------- */
@media (min-width: 901px) {
  /* When the sidebar is collapsed here it is replaced by the icon rail, and the
     rail carries its own #railToggle. The base rule in chat-messages.css reveals
     the chat header's #toggleSidebar for the collapsed state, which is right on a
     phone (there is no rail) but makes a second, redundant control sit a few pixels
     from the rail's own on desktop. */
  body.sidebar-collapsed #toggleSidebar { display: none; }
}

/* ---- tablet: the drawer stops stealing layout width ---------------------- */
@media (max-width: 1024px) {
  /* Below this the artifact drawer covers the chat instead of pushing it aside.
     Reserving --drawer-w of body padding at this size squeezed the reading column
     to a sliver. */
  body:has(.drawer.open) { padding-right: 0; }
  .drawer { width: min(560px, 92vw); }
}

/* ---- phone shell -------------------------------------------------------- */
@media (max-width: 900px) {
  /* .app is the positioning context for the overlay sidebar. */
  .app { position: relative; }

  /* .chat is no longer a card at ANY width (it has no radius or shadow to cancel --
     see the block above .chat in chat-messages.css), so the override that used to be
     here would now be restating the default. `form` is likewise transparent and
     unrounded everywhere. Both removed rather than left as no-ops, so this band keeps
     saying only what actually changes on a phone. */

  /* Sidebar becomes an overlay drawer that slides in over the chat, with a scrim
     behind it. It is `position: absolute` inside .app rather than fixed so it
     cannot be dragged around by iOS's rubber-band scroll. */
  .sidebar {
    position: absolute; top: 0; left: 0; bottom: 0; height: auto;
    width: var(--sidebar-w);
    z-index: 45;
    margin: 0;
    border-radius: 0 var(--r) var(--r) 0;
    box-shadow: 8px 0 32px rgba(10, 10, 10, 0.28);
    padding-left: var(--safe-l);
    visibility: visible;
    transition: transform 0.26s var(--ease), visibility 0s;
  }
  /* Slide rather than margin-shift: a negative margin still participates in flex
     layout and dragged the chat panel sideways with it.
     `visibility: hidden`, held until the slide finishes, is what guarantees a
     closed drawer cannot swallow a tap meant for the chat underneath, relying on
     the transform alone leaves it hit-testable for the whole 260ms, and fully
     interactive if the transition never runs at all. */
  .sidebar.hidden {
    margin-left: 0;
    transform: translateX(-101%);
    visibility: hidden;
    transition: transform 0.26s var(--ease), visibility 0s 0.26s;
  }

  /* Scrim. One element, driven purely by the sidebar's own state, so no extra
     bookkeeping is needed to keep the two in sync. */
  .sidebar-scrim {
    display: block;
    position: absolute; inset: 0; z-index: 40;
    background: rgba(10, 10, 10, 0.42);
    opacity: 1; transition: opacity 0.24s var(--ease);
  }
  body.sidebar-collapsed .sidebar-scrim { opacity: 0; pointer-events: none; }

  /* Neither resize handle makes sense without a mouse. */
  .sidebar-resizer, .drawer-resizer { display: none !important; }

  /* The icon rail is a desktop affordance; the header hamburger replaces it. */
  .rail { display: none !important; }
  #toggleSidebar { display: grid; }

  /* ...and the header hamburger is then the ONLY sidebar toggle. The markup has
     three of them, one per state, and exactly one may ever be on screen:
     #sidebarToggleTop inside the sidebar, #railToggle in the collapsed rail, and
     #toggleSidebar in the chat header. Here the sidebar is an overlay dismissed by
     the scrim, Escape, or picking a conversation, so the in-sidebar collapse button
     would be a second control for the same thing sitting right next to the first. */
  .sidebar-toptools #sidebarToggleTop { display: none; }

  /* Full-screen artifact drawer and Library, a 620px side panel on a 390px
     screen is just a full-screen panel with a broken edge. */
  .drawer { width: 100%; border-left: none; }
  body:has(.drawer.open) { padding-right: 0; }
  /* `body.sidebar-collapsed .drawer#libraryPanel` is repeated here on purpose: that
     selector in chat-drawer.css offsets the panel by the icon rail's width, and it
     outranks a bare `.drawer#libraryPanel` on specificity (one more class and an
     element), so source order alone would not beat it. Matching its specificity is
     what lets this win, otherwise the Library sits 60px off the left edge on a
     phone, where there is no rail to make room for. */
  .drawer#libraryPanel,
  .drawer#libraryPanel.open,
  body.sidebar-collapsed .drawer#libraryPanel {
    top: 0; bottom: 0; left: 0; right: 0; width: auto; height: auto;
    border-radius: 0; box-shadow: none;
  }
  .drawer#libraryPanel:not(.open) { transform: translateX(100%); }

  /* Overlays span the viewport now that there is no permanent sidebar column. */
  .search-modal,
  body.sidebar-collapsed .search-modal { left: 0; padding-top: 8vh; }

  /* Respect the notch and the home indicator. */
  .drawer-head { padding-left: max(var(--drawer-pad-x), var(--safe-l)); padding-right: max(var(--drawer-pad-x), var(--safe-r)); }
  .drawer-body { padding-bottom: max(var(--drawer-pad-x), var(--safe-b)); }

  /* Give the composer room above the iOS home indicator. */
  form { padding-bottom: calc(14px + var(--safe-b)); }

  /* A user bubble may take nearly the full width; the 20% reserved gutter was
     costing more than the visual asymmetry gained. */
  .row.user { max-width: 92%; }
  .row { margin-top: 20px; }

  /* Stack the artifact card so a long title never squeezes the buttons to zero. */
  /* .artifact-card { flex-wrap: wrap; } */
  /* .artifact-meta { flex-basis: 100%; } */
  /* .artifact-btns { width: 100%; } */
  .artifact-btns .view { flex: 1; justify-content: center; }

  /* Same for the two notice cards, which were space-between rows. */
  .notice-session { flex-direction: column; align-items: stretch; max-width: none; }
  .notice-session-btn { align-self: flex-start; }
  .notice-graceful, .lead-form { max-width: none; }

  /* Quick-prompt cards: one per row reads far better than two cramped columns. A
     single grid column, since .chips is a grid now -- the `flex: 1 1 100%` that used to
     be here stopped meaning anything the moment the container stopped being flex, and
     would have silently left the cards in two columns. `max-width: none` lifts the
     desktop two-column cap so one card spans the full width.
     The gap is NOT overridden. This band used to tighten it to --sp-2 (8px) on the
     reasoning that a full-width single column reads as a list and lists sit closer
     together; the specified spacing is 16 either way, so 16 applies at every width. */
  .empty .chips { grid-template-columns: 1fr; max-width: none; }
  .empty .chip { padding: var(--sp-3); }

  /* Let follow-up chips wrap instead of forcing horizontal overflow. text-align:left
     because a wrapped chip is now two ragged lines: centred, the shorter second line sits
     mid-pill and reads as a caption rather than a continuation of the sentence. */
  .followup-chips .chip { white-space: normal; text-align: left; }

  /* Tighter chrome. */
  header { min-height: 52px; padding: 8px 10px; }
  .messages { padding-top: 18px; }
  /* Tighten the panel inset via the shared token so the header moves with the body.
     Setting .drawer-body alone here is what used to knock the panel title 4px out of
     line with its own content. */
  :root { --drawer-pad-x: 14px; }
  .chart-box { height: 260px; }

  /* ---- Library ---------------------------------------------------------- */
  /* The panel is already full-screen (above); this is its inner chrome. */
  .library-toolbar { gap: 8px; margin-bottom: 10px; }
  .library-filter-row { margin-bottom: 12px; }
  .library-grid { gap: 12px; }
  .library-card-foot { padding: 9px 11px; }
  .library-empty { padding: 32px 16px; }

  /* ---- Settings --------------------------------------------------------- */
  /* Both dialog titles step down together, matching the shared rule in chat-drawer.css. */
  #settingsTitle, #libraryPanel .drawer-title { font-size: 20px; }
}

/* ---- phone: Settings becomes a full-screen sheet ------------------------- */
/* A 560px centred card on a 390px screen is a full-screen panel with 10px gutters
   and pointless rounded corners. Worse, `place-items: center` fights the on-screen
   keyboard: focusing the Instructions textarea shrinks the visual viewport and the
   whole modal jumps. Anchoring it to the top edge as a sheet, the pattern ChatGPT
   and Claude both use, fixes the layout and the keyboard behaviour together. */
@media (max-width: 767px) {
  /* padding: 0 cancels the composer keep-out reservation from chat-overlays.css. That
     reservation exists so a CENTRED card cannot cover the input; a full-screen sheet
     covers the input on purpose, and leaving the padding in place would inset the sheet
     from the screen edges and reintroduce the gutters this band exists to remove. */
  .settings-modal { place-items: stretch; padding: 0; }
  .settings-box {
    width: 100%; max-width: none;
    height: 100dvh; max-height: none;
    border: none; border-radius: 0;
    /* The centred card animated in with a translate+scale; a sheet should not. */
    transform: none;
  }
  .settings-modal.open .settings-box { transform: none; }

  /* Header stays put while the body scrolls under it. */
  .settings-box .drawer-head {
    position: sticky; top: 0; z-index: 1;
    background: var(--panel);
    padding-left: max(18px, var(--safe-l));
    padding-right: max(18px, var(--safe-r));
  }
  .settings-box .drawer-body {
    padding: 6px max(18px, var(--safe-l)) calc(24px + var(--safe-b)) max(18px, var(--safe-r));
  }
  .settings-row { padding: 16px 0; }
}

/* ---- small phones ------------------------------------------------------- */
@media (max-width: 479px) {
  /* Wrap the Library toolbar: search + sort side by side left ~90px for the input. */
  .library-toolbar { flex-wrap: wrap; }
  .library-toolbar .search-field { flex-basis: 100%; }
  .library-sort { flex: 1; justify-content: center; }

  /* Stack the appearance/font-size segmented controls' icon+label tighter so three
     options still fit without the labels truncating. */
  .segmented button { padding: 8px 0; font-size: 11px; gap: 4px; }
  .segmented button svg { width: 16px; height: 16px; }
  .settings-row label { margin-bottom: 10px; }

  /* The filter pills scroll horizontally rather than stacking into three rows. */
  .library-filter-row {
    flex-wrap: nowrap; overflow-x: auto; margin-inline: calc(-1 * var(--sp-1));
    padding-inline: var(--sp-1); scrollbar-width: none;
  }
  .library-filter-row::-webkit-scrollbar { display: none; }

  :root { --lib-card-min: 132px; }
  .library-card-thumb { height: 96px; }
  .library-card-cover svg { width: 26px; height: 26px; }

  /* Modals go near-full-width with a small breathing margin. Settings is exempt:
     it is a full-screen sheet from 767px down (above). */
  .modal-box { width: calc(100vw - 24px); padding: 18px 18px 16px; }
  .search-box { width: calc(100vw - 20px); }
  .search-modal { padding-top: 6vh; }

  /* Stack the delete-confirm actions so both buttons are comfortably tappable. */
  .modal-actions { flex-direction: column-reverse; }
  .modal-actions button { width: 100%; padding: 12px 18px; }

  /* The lead-capture row is an email field plus a Send button, too tight side
     by side under ~360px. Stacks instead: input, then Send, then Skip.
     `align-items: stretch` overrides the base rule's `flex-start` (chat-messages.css) --
     that base value exists so `.lead-actions` (Send+Skip) doesn't stretch the input taller
     on desktop, but here the column IS the point: input and `.lead-actions` both need to
     fill the row's width so Send can be full-width. `.lead-actions` itself stays a
     column with `align-items: center` (unchanged), so once it stretches to the full row
     width, Skip centres across that full width -- reading as a centred secondary link
     under a full-width primary button, which is the standard mobile pairing. */
  .lead-form .lead-row { flex-direction: column; align-items: stretch; }
  .lead-form .lead-send { width: 100%; padding: 11px 17px; }

  .chart-box { height: 220px; }
  .drawer-body .chart-box.drawer-chart { height: min(56dvh, 380px); }

  /* Wide artifact tables scroll in their own box instead of widening the page. */
  .artifact-table { display: block; overflow-x: auto; white-space: nowrap; }
}

/* ------------------------------------------------------- 3. capability queries */

/* Touch input: grow hit targets to the ~44px Apple/Google both recommend, and
   drop the hover-only affordances that either never fire or stick on tap. */
@media (hover: none), (pointer: coarse) {
  :root { --tap: 44px; }

  .icon-btn { min-width: var(--tap); min-height: var(--tap); }
  .conv { padding-block: 12px; }
  .sidebar-nav-item { padding-block: 12px; }
  .field { --send-size: 40px; }
  .lib-pill { padding-block: 9px; }
  .msg-actions button { padding: 9px; }
  .conv .kebab { padding: 8px; }

  /* Hover tooltips have no dismissal on touch, they latch on after a tap and
     sit over the UI. The buttons all carry aria-label, so nothing is lost. */
  .tip::after { display: none; }

  /* These reveal-on-hover controls are unreachable by touch, so show them
     permanently instead. */
  .msg-actions,
  .conv .kebab,
  .code-copy,
  .library-card-expand { opacity: 1; }

  /* ...but the expand button's own hover label still has no way to be dismissed. */
  .library-card-expand::after { display: none; }

  /* Remove lift-on-hover transforms: on touch they fire on tap and read as jitter. */
  .artifact-card:hover, .library-card:hover, .followup-chips .chip:hover { transform: none; }
}

/* Landscape phones and short windows: the hero's fixed vertical rhythm does not
   fit, and the composer needs to keep priority over decoration. */
@media (max-height: 560px) {
  /* --hero-h2 alone now: the star is sized in `em` off the heading, so shrinking the
     heading shrinks the mark with it. There is also no `.empty .big { display: none }`
     here any more -- that rule hid the standalone block star to reclaim vertical space,
     and an inline star inside the heading costs no extra vertical space to reclaim. */
  :root { --hero-h2: 20px; }
  /* Retune the TOKEN, not `gap` directly: .hero-sub subtracts --empty-gap to sit 6px
     under the heading, so setting gap here alone would zero that spacing out. */
  .empty { --empty-gap: 10px; padding: 12px 0; }
  .messages { padding-top: 12px; }
  header { min-height: 46px; }
  .chart-box { height: 200px; }
}

/* iOS Safari zooms the page whenever a focused field's text is under 16px, and
   never zooms back out. The composer and every other text entry therefore get a
   hard 16px floor on touch devices, this is a platform constraint, not a design
   choice, so it is scoped to pointer: coarse and leaves desktop typography be. */
@media (pointer: coarse) {
  textarea, .ghost,
  input[type="text"], input[type="email"], input[type="search"],
  .settings-instructions, .conv-rename, .search-field input {
    font-size: 16px;
  }
}

/* Composer metrics are tokens on .field (see css/chat-composer.css), so a phone
   only retunes the numbers, the textarea, the ghost overlay stacked on it and the
   send button all re-derive from them and cannot fall out of sync. */
@media (max-width: 479px) {
  /* --pad-y on :root so --field-h (chat-base.css) re-derives with it and the search
     fields shrink in step with the composer; the rest are composer-only metrics. */
  :root { --pad-y: 13px; }
  .field { --pad-x: 16px; --send-gap: 6px; --send-lead: 8px; }
  /* Tab-to-accept needs a keyboard; the hint is noise on a phone. */
  .ghost .tab-hint { display: none; }
}
