/* ==========================================================================
   responsive.css — LOADED LAST, owns every @media rule in the app.

   WHY all breakpoints live in one file: four stylesheets each style a slice of
   the same screen (layout, components, views). If any of them shipped its own
   media query, the winner at a given width would depend on load order *inside*
   a query — untraceable. With one last-loaded file a mobile override always
   wins, and there is exactly one place to look when a width breaks.

   Ladder (max-width, so each step inherits the wider ones):
     1280  desktop-narrow — tighter sidebar, one masonry column fewer
     1024  tablet         — sidebar becomes an off-canvas overlay drawer
      860  small tablet   — explorer side panel drops under the stage
      720  phone          — icon-only nav, 2-up action bar, one-column info
      480  small phone    — single masonry column, tightest padding
   Plus coarse-pointer target sizing, hover-less affordances, safe-area insets,
   and a print sheet that prints the current image alone.
   ========================================================================== */

/* ==========================================================================
   ≤1280px — reclaim horizontal space before anything has to move
   ========================================================================== */

@media (max-width: 1280px) {
  :root { --sidebar-w: 236px; --thumb: 124px; }
  .masonry { --cols: 3; }
  .explorer { grid-template-columns: minmax(0, 1fr) 272px; }
  .chart-grid { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
}

/* ==========================================================================
   ≤1024px — the sidebar leaves the flow and becomes an overlay drawer.

   position:fixed takes it out of the app grid entirely, so whatever column
   layout.css reserved for it collapses to zero and <main> gets the full width
   without either file needing to know about this breakpoint.
   ========================================================================== */

@media (max-width: 1024px) {
  #sidebar {
    position: fixed; top: var(--topbar-h); bottom: 0; left: 0; z-index: var(--z-sidebar);
    /* Never full-bleed: the sliver of scrim is the "tap to dismiss" cue. */
    width: min(86vw, 320px); max-width: none;
    padding-bottom: env(safe-area-inset-bottom, 0px);
    transform: translate3d(-102%, 0, 0);
    border-right: 1px solid var(--border); box-shadow: var(--shadow-3);
    transition: transform var(--dur-slow) var(--ease-out); will-change: transform;
  }
  #sidebar.is-open { transform: none; }
  /* The desktop collapse state is meaningless off-canvas: a 68px drawer shows
     icons with no labels and gives the user no way to widen it. */
  #sidebar.is-collapsed { width: min(86vw, 320px); }

  #sidebar-scrim {
    position: fixed; inset: var(--topbar-h) 0 0; z-index: calc(var(--z-sidebar) - 1);
    background: var(--overlay);
    backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
    opacity: 0; pointer-events: none;
    transition: opacity var(--dur) var(--ease);
  }
  #sidebar-scrim.is-open { opacity: 1; pointer-events: auto; }

  /* Now the only way in or out of the drawer, so it can never be hidden. The
     accented state is keyed off the drawer itself via :has() rather than the
     button's aria-expanded, which ships "true" in the markup and would light
     up on first paint while the drawer is still off-canvas. */
  #btn-toggle-sidebar { display: inline-grid; place-items: center; }
  #app:has(#sidebar.is-open) #btn-toggle-sidebar { color: var(--accent); background: var(--accent-soft); }

  .view__header,
  .view__body,
  .explorer { padding-left: var(--space-5); padding-right: var(--space-5); }
}

/* Belt for the desktop side of that breakpoint: an overlay scrim must never be
   able to sit on top of the app while the sidebar is docked. */
@media (min-width: 1025px) {
  #sidebar-scrim { display: none; }
}

/* ==========================================================================
   ≤860px — the explorer stops being two columns
   ========================================================================== */

@media (max-width: 860px) {
  .explorer { grid-template-columns: minmax(0, 1fr); }
  .image-stage { min-height: clamp(240px, 46vh, 460px); }
  .image-stage__img { max-height: 52vh; }
  .masonry { --cols: 2; }
  .collections-list { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
  .chart-card__canvas { --chart-h: 220px; }
}

/* ==========================================================================
   ≤720px — phone layout
   ========================================================================== */

@media (max-width: 720px) {
  :root { --topbar-h: 52px; --dock-h: 132px; --thumb: 108px; }

  /* Nav collapses to icons. The label stays in the accessibility tree — it is
     hidden visually only, and every nav-btn also carries data-tip. */
  #main-nav { gap: 2px; }
  #main-nav .nav-btn { padding-inline: var(--space-2); }
  #main-nav .nav-btn__label {
    position: absolute; width: 1px; height: 1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }

  /* Two columns beat wrapping: ten equal full-width targets in five rows. */
  .action-bar { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); }
  .action-bar > .btn { width: 100%; justify-content: center; }

  .info-panel__row,
  .settings-row { grid-template-columns: minmax(0, 1fr); }
  .info-panel__row { gap: 0; padding-block: var(--space-2); }
  .settings-row__control {
    grid-column: 1; grid-row: auto; justify-self: stretch; margin-top: var(--space-2);
  }
  .settings-row__control .input,
  .settings-row__control .select { flex: 1 1 auto; min-width: 0; }

  .view__header { align-items: stretch; gap: var(--space-3); padding: var(--space-4) var(--space-4) var(--space-3); }
  .view__body,
  .explorer { padding-left: var(--space-4); padding-right: var(--space-4); }
  .toolbar > .search,
  .toolbar > .field { flex: 1 1 160px; min-width: 0; }

  /* The dock keeps exactly one row, of smaller thumbs. */
  .history-strip__grid { --history-thumb: 82px; padding: var(--space-2) var(--space-4); }

  /* Near-fullscreen sheets: a centred 480px card wastes a phone screen. */
  .modal { width: 100%; max-width: none; max-height: calc(100dvh - var(--topbar-h)); border-radius: var(--radius-lg); }
  .modal__body { max-height: none; }

  /* Full-width toasts. */
  .toast-root { left: var(--space-3); right: var(--space-3); align-items: stretch; }
  .toast { width: 100%; max-width: none; }

  .lightbox { padding: calc(var(--space-8) + var(--space-2)) var(--space-3) var(--space-4); }
  .lightbox__toolbar { gap: 0; padding: var(--space-1); }

  .stat-grid { grid-template-columns: repeat(auto-fit, minmax(124px, 1fr)); }
  .chart-grid { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   ≤480px
   ========================================================================== */

@media (max-width: 480px) {
  .masonry { --cols: 1; }
  .media-grid { grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: var(--space-3); }
  .collections-list { grid-template-columns: minmax(0, 1fr); }
  .view__title { font-size: 18px; }
  .view__subtitle { display: none; }
  #sidebar { width: min(92vw, 320px); }
}

/* ==========================================================================
   Coarse pointers — 44px minimum touch target (WCAG 2.5.8, platform HIGs)
   ========================================================================== */

@media (pointer: coarse) {
  .btn,
  .nav-btn,
  .select,
  .input,
  .menu__item { min-height: 44px; }
  .btn--icon { min-width: 44px; }
  .btn--sm { min-height: 40px; }
  .chip,
  .tag-pill { min-height: 38px; }
  /* Momentum scrolling inside the dock and every scroll region. */
  .scroll-area,
  .history-strip__grid { -webkit-overflow-scrolling: touch; }
}

/* Hover-only affordances have no trigger on touch, so they are always on. */
@media (hover: none) {
  .image-stage__fullscreen,
  .collection-card__actions,
  .thumb__overlay,
  .thumb__actions { opacity: 1; transform: none; }
  /* Press-to-reveal replaces hover-to-reveal for the NSFW veil. */
  .thumb.is-blurred.is-selected .thumb__img,
  .image-stage__img.is-blurred:active { filter: none; }
}

/* ==========================================================================
   Safe-area insets. The viewport meta carries viewport-fit=cover, so the app
   paints edge to edge and has to inset its own chrome around notches, rounded
   corners and the home indicator.
   ========================================================================== */

@supports (padding: env(safe-area-inset-left)) {
  #topbar {
    padding-left: max(var(--space-3), env(safe-area-inset-left));
    padding-right: max(var(--space-3), env(safe-area-inset-right));
  }
  #history-strip { padding-bottom: env(safe-area-inset-bottom); }
  .toast-root { padding-bottom: max(var(--space-3), env(safe-area-inset-bottom)); }
  .lightbox {
    padding-top: max(calc(var(--space-8) + var(--space-4)), env(safe-area-inset-top));
    padding-bottom: max(var(--space-7), env(safe-area-inset-bottom));
    padding-left: max(var(--space-5), env(safe-area-inset-left));
    padding-right: max(var(--space-5), env(safe-area-inset-right));
  }

  @media (max-width: 1024px) {
    #sidebar { padding-left: env(safe-area-inset-left); }
  }
}

/* ==========================================================================
   Print — the current image, nothing else.

   Everything is hidden first, then the single containment chain from <body>
   down to #main-image is re-shown. The five non-explorer views are hidden
   explicitly because forcing .view to display:block would reveal all six.
   ========================================================================== */

@media print {
  html,
  body {
    height: auto; overflow: visible; color: #000;
    background: #fff !important; background-image: none !important;
  }

  #topbar, #sidebar, #sidebar-scrim, #history-strip, #toast-root, #modal-root,
  #context-menu, #lightbox, .skip-link, .view__header, .action-bar,
  .explorer__side, #stage-badges, #btn-fullscreen, #load-progress,
  #image-skeleton, #image-error,
  #view-gallery, #view-favorites, #view-collections, #view-stats, #view-settings {
    display: none !important;
  }

  #app, .app-body, #main, #view-explorer, .explorer, .explorer__main, #image-stage {
    display: block !important;
    width: auto !important; height: auto !important;
    min-height: 0 !important; max-height: none !important;
    margin: 0 !important; padding: 0 !important; overflow: visible !important;
    border: 0 !important; background: none !important; box-shadow: none !important;
  }

  #main-image {
    display: block !important;
    width: auto !important; max-width: 100% !important; max-height: 96vh !important;
    margin: 0 auto !important;
    opacity: 1 !important; filter: none !important;
    animation: none !important; transform: none !important;
    border-radius: 0 !important;
    break-inside: avoid;
  }

  @page { margin: 12mm; }
}
