/* ==========================================================================
   layout.css — the application shell: the #app grid, the sticky glass topbar,
   the collapsible sidebar, the independently scrolling main region and the
   history dock.

   WHY a fixed grid instead of document flow: base.css gives <body>
   `overflow:hidden`, so the shell is exactly viewport-high and every region
   owns its own scrollport. That is what makes this read as a desktop window
   rather than a web page — the chrome can never scroll away, and a long
   gallery never pushes the dock off screen.

   WHY no `isolation`/`transform` on #app: the whole app shares ONE stacking
   context so the single --z-* scale in tokens.css actually orders things.
   The overlay roots (#sidebar-scrim, #modal-root, #toast-root, #context-menu,
   #lightbox) are siblings of #app; if #app created a stacking context they
   could only ever be entirely above or entirely below it, and the mobile
   drawer (scrim *under* the sidebar) would be impossible.

   Contract: ARCHITECTURE.md §12 (ids) + §13 (tokens, z-index, states).
   All @media overrides live in responsive.css, which loads last.
   ========================================================================== */

/* ==========================================================================
   Pre-shell chrome
   ========================================================================== */

/* First tab stop. Parked above the viewport until it is focused. */
.skip-link {
  position: fixed;
  top: var(--space-3);
  left: var(--space-3);
  z-index: var(--z-toast);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: var(--accent-contrast);
  font-size: 13px;
  font-weight: 600;
  box-shadow: var(--shadow-3);
  transform: translateY(calc(-100% - var(--space-5)));
  transition: transform var(--dur) var(--ease-out);
}

.skip-link:hover {
  color: var(--accent-contrast);
  text-decoration: none;
}

.skip-link:focus-visible {
  transform: none;
}

.noscript {
  position: fixed;
  inset: var(--space-4) var(--space-4) auto;
  z-index: var(--z-toast);
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--danger);
  border-radius: var(--radius-md);
  background: var(--danger-soft);
  color: var(--text-0);
  font-size: 13px;
  line-height: 1.6;
  box-shadow: var(--shadow-3);
}

/* ==========================================================================
   #app — three rows: topbar / body / history dock
   ========================================================================== */

.app {
  display: grid;
  grid-template-columns: 100%;
  grid-template-rows: var(--topbar-h) minmax(0, 1fr) auto;
  height: 100%;
  overflow: hidden;
}

/* ==========================================================================
   Topbar
   ========================================================================== */

.topbar {
  position: sticky;
  top: 0;
  z-index: var(--z-topbar);
  display: flex;
  align-items: center;
  gap: var(--space-2);
  height: var(--topbar-h);
  min-width: 0;
  padding-inline: var(--space-3);
  background: var(--glass);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border-bottom: 1px solid var(--glass-border);
  box-shadow: var(--shadow-1);
}

.topbar__spacer {
  flex: 1 1 auto;
  min-width: var(--space-2);
}

.topbar__actions {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

/* Chrome buttons read as glyphs, not as controls, until you reach for them.
   Specificity beats components.css' .btn rules regardless of load order. */
.topbar .btn--icon,
.topbar__toggle {
  background: transparent;
  border-color: transparent;
  color: var(--text-1);
  box-shadow: none;
}

.topbar .btn--icon:hover:not(:disabled),
.topbar__toggle:hover:not(:disabled) {
  background: var(--bg-3);
  border-color: var(--border);
  color: var(--text-0);
}

.topbar .btn--icon.is-active {
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
  color: var(--accent);
}

/* ---- Brand ----------------------------------------------------------- */

.brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  padding-inline: var(--space-1);
  user-select: none;
}

.brand__mark {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: var(--radius-sm);
  background: var(--accent-gradient);
  color: var(--accent-contrast);
  box-shadow: var(--shadow-1), 0 0 0 1px var(--glass-border);
}

.brand__title {
  font-size: 14px;
  font-weight: 650;
  letter-spacing: -0.015em;
  white-space: nowrap;
  color: var(--text-0);
}

/* ---- Primary nav (segmented control) --------------------------------- */

.main-nav {
  display: flex;
  align-items: center;
  gap: 2px;
  min-width: 0;
  margin-inline-start: var(--space-3);
  padding: 3px;
  background: color-mix(in srgb, var(--bg-inset) 55%, transparent);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

.nav-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 32px;
  padding-inline: var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--text-1);
  font-size: 13px;
  font-weight: 550;
  white-space: nowrap;
  transition:
    background-color var(--dur-fast) var(--ease),
    color var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease);
}

.nav-btn:hover:not(:disabled) {
  background: var(--bg-3);
  color: var(--text-0);
}

.nav-btn:active:not(:disabled) {
  transform: translateY(1px);
}

.nav-btn.is-active,
.nav-btn[aria-current="page"] {
  background: var(--accent-soft);
  color: var(--accent);
}

/* Underline anchors the active tab even when the tint is subtle. */
.nav-btn.is-active::after,
.nav-btn[aria-current="page"]::after {
  content: "";
  position: absolute;
  bottom: 3px;
  left: 50%;
  width: 16px;
  height: 2px;
  translate: -50% 0;
  border-radius: var(--radius-full);
  background: var(--accent);
}

/* ---- Connection status ------------------------------------------------
   The dot inherits `currentColor` from .api-status, so one colour swap
   re-tints dot + text + the glow-pulse halo (which is currentColor-based). */

.api-status {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 28px;
  padding-inline: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--bg-inset) 55%, transparent);
  color: var(--success);
  white-space: nowrap;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}

.api-status__dot {
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: var(--radius-full);
  background: currentColor;
}

.api-status__text {
  font-size: 12px;
  font-weight: 550;
  color: var(--text-1);
}

/* Both hooks are honoured: the .is-* state convention (§13) and a
   data-status attribute, so whichever ui/topbar.js emits, this paints. */
.api-status.is-loading,
.api-status[data-status="loading"] { color: var(--warning); }
.api-status.is-error,
.api-status[data-status="error"] { color: var(--danger); }
.api-status.is-disabled,
.api-status[data-status="offline"] { color: var(--text-2); }
.api-status[data-status="ok"] { color: var(--success); }

.api-status.is-loading .api-status__dot,
.api-status[data-status="loading"] .api-status__dot {
  animation: glow-pulse 2.2s var(--ease-out) infinite;
}

/* ---- Topbar glyph pairs ----------------------------------------------
   Both glyphs ship in the markup; CSS decides which one is real. */

.topbar .icon--pause,
:root[data-theme="light"] #btn-theme .icon--sun,
:root:not([data-theme="light"]) #btn-theme .icon--moon {
  display: none;
}

#btn-slideshow[aria-pressed="true"] .icon--play,
#btn-slideshow.is-active .icon--play {
  display: none;
}

#btn-slideshow[aria-pressed="true"] .icon--pause,
#btn-slideshow.is-active .icon--pause {
  display: block;
}

#btn-slideshow[aria-pressed="true"],
#btn-slideshow.is-active {
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
  color: var(--accent);
}

/* ==========================================================================
   Body row — sidebar + main
   ========================================================================== */

.app-body {
  display: flex;
  min-width: 0;
  min-height: 0;
}

/* ==========================================================================
   Sidebar
   ========================================================================== */

.sidebar {
  position: relative;
  z-index: var(--z-sidebar);
  display: flex;
  flex-direction: column;
  flex: 0 0 auto;
  width: var(--sidebar-w);
  min-width: 0;
  background: var(--bg-1);
  border-inline-end: 1px solid var(--border);
  transition:
    width var(--dur-slow) var(--ease-out),
    transform var(--dur-slow) var(--ease-out);
}

.sidebar__scroll {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  padding: var(--space-4) var(--space-3) var(--space-5);
}

.sidebar__section {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-width: 0;
}

.api-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.tag-list,
.search-history {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  min-width: 0;
}

/* Recent searches only earn their gap once something is in them. */
.search-history:empty,
.api-list:empty,
.tag-list:empty {
  display: none;
}

.sidebar__actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(78px, 1fr));
  gap: var(--space-2);
}

.sidebar__footer {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-3);
  border-top: 1px solid var(--border);
  background: color-mix(in srgb, var(--bg-inset) 50%, transparent);
}

.sidebar__storage {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 12px;
}

.sidebar__storage .icon {
  width: 16px;
  height: 16px;
}

/* ---- Collapsed rail ---------------------------------------------------
   Hook: `.is-collapsed` on #sidebar (the §13 state convention). The
   `.is-sidebar-collapsed` alias on #app is accepted as well so ui/sidebar.js
   may flag either node. :is() keeps the specificity of the id-free compound
   high enough to beat base.css without repeating every selector twice. */

.sidebar.is-collapsed,
.is-sidebar-collapsed .sidebar {
  width: var(--sidebar-w-collapsed);
}

/* Labels, headers, search field and footer copy all fold away. */
:is(.sidebar.is-collapsed, .is-sidebar-collapsed .sidebar) .section-title,
:is(.sidebar.is-collapsed, .is-sidebar-collapsed .sidebar) .search,
:is(.sidebar.is-collapsed, .is-sidebar-collapsed .sidebar) .search-history,
:is(.sidebar.is-collapsed, .is-sidebar-collapsed .sidebar) .tag-list,
:is(.sidebar.is-collapsed, .is-sidebar-collapsed .sidebar) .empty-state,
:is(.sidebar.is-collapsed, .is-sidebar-collapsed .sidebar) .sidebar__storage,
:is(.sidebar.is-collapsed, .is-sidebar-collapsed .sidebar) .switch__text {
  display: none;
}

:is(.sidebar.is-collapsed, .is-sidebar-collapsed .sidebar) .sidebar__scroll {
  gap: var(--space-4);
  padding-inline: var(--space-2);
  align-items: center;
}

:is(.sidebar.is-collapsed, .is-sidebar-collapsed .sidebar) .sidebar__actions {
  grid-template-columns: 1fr;
  width: 100%;
}

/* Icons centre; text children collapse. .btn__ripple is excluded because it
   is the decorative overlay, not a label. */
:is(.sidebar.is-collapsed, .is-sidebar-collapsed .sidebar) .btn {
  width: 40px;
  min-width: 40px;
  padding-inline: 0;
  justify-content: center;
  margin-inline: auto;
}

:is(.sidebar.is-collapsed, .is-sidebar-collapsed .sidebar) .btn > span:not(.btn__ripple) {
  display: none;
}

:is(.sidebar.is-collapsed, .is-sidebar-collapsed .sidebar) .sidebar__footer {
  align-items: center;
}

:is(.sidebar.is-collapsed, .is-sidebar-collapsed .sidebar) .switch {
  gap: 0;
}

/* ==========================================================================
   Main + views
   ========================================================================== */

.main {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  scrollbar-gutter: stable;
}

/* main is focused programmatically by the skip link; keep the ring inside so
   it never paints a 2px box around the entire content area. */
.main:focus-visible {
  outline-offset: -3px;
}

.view {
  display: none;
}

/* Overrides the plain fade in animations.css: the extra 10px of travel is
   what sells a view switch as navigation instead of a repaint. */
.view--active {
  display: block;
  animation: fade-in-up var(--dur-slow) var(--ease-out) both;
}

/* ==========================================================================
   History dock
   Collapsing animates `height`, which is the one property that can actually
   move the grid row; the head stays put and the strip closes underneath it.
   ========================================================================== */

.history-strip {
  position: relative;
  z-index: var(--z-dock);
  display: flex;
  flex-direction: column;
  height: var(--dock-h);
  overflow: hidden;
  background: var(--glass);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border-top: 1px solid var(--glass-border);
  transition: height var(--dur-slow) var(--ease-out);
}

/* 41px = the 40px head + the 1px border-top inside the border box. */
.history-strip.is-collapsed {
  height: 41px;
}

/* visibility (not opacity) so collapsed thumbnails leave the tab order. */
.history-strip.is-collapsed .history-strip__grid,
.history-strip.is-collapsed .empty-state {
  visibility: hidden;
}

.history-strip__head {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  height: 40px;
  padding-inline: var(--space-3);
}

.history-strip__spacer {
  flex: 1 1 auto;
}

.history-strip__title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-1);
  user-select: none;
}

.history-strip__title .icon {
  width: 16px;
  height: 16px;
  color: var(--text-2);
}

/* Chevron points where the click will take the dock. */
.history-strip__toggle .icon--chevron {
  transform: rotate(90deg);
  transition: transform var(--dur) var(--ease);
}

.history-strip.is-collapsed .history-strip__toggle .icon--chevron {
  transform: rotate(-90deg);
}

/* A single horizontally scrolling row. Overrides .scroll-area's
   `overflow-x: hidden` from base.css. */
.history-strip__grid {
  flex: 1 1 auto;
  display: flex;
  align-items: stretch;
  gap: var(--space-2);
  min-height: 0;
  padding: 0 var(--space-3) var(--space-3);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
}

.history-strip__grid > * {
  flex: 0 0 auto;
  height: 100%;
  scroll-snap-align: start;
}

/* Square tiles derived from the row height rather than --thumb, so the dock
   is one clean band at any height. Beats components.css' `.thumb`. */
.history-strip__grid > .thumb {
  width: auto;
  aspect-ratio: 1;
}

/* ==========================================================================
   Overlay layering
   Siblings of #app, ordered purely by the --z-* scale. Each one stays hidden
   until it is opened, and accepts EITHER signal — the `.is-open` state class
   or `aria-hidden="false"` — so the visual state can never contradict the
   accessibility state.
   ========================================================================== */

.sidebar-scrim {
  position: fixed;
  inset: 0;
  /* Deliberately one step under the sidebar: the drawer must sit on top of
     its own scrim, and both must cover main and the dock. */
  z-index: calc(var(--z-sidebar) - 1);
  background: var(--overlay);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition:
    opacity var(--dur) var(--ease),
    visibility var(--dur) var(--ease);
}

.sidebar-scrim.is-open,
.sidebar-scrim[aria-hidden="false"] {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}

.lightbox {
  position: fixed;
  inset: 0;
  z-index: var(--z-lightbox);
}

.lightbox:not(.is-open):not([aria-hidden="false"]) {
  display: none;
}
