/*
 * Chrome-only layout for the four shells (business/referrer/public/admin)
 * and the /styleguide chassis that reuses them. Component-internal styling
 * lives beside its ViewComponent; this file only covers rail/topbar/tabbar/
 * device-frame layout that doesn't map cleanly onto Tailwind utilities.
 *
 * Every value below is either a design token (tokens.css) or one of the
 * shell-specific dimension constants declared in :root here — no raw
 * literals in component rules. The one unavoidable exception is the
 * @media breakpoints: CSS custom properties cannot appear inside a media
 * query condition, so those pixel values are hand-kept in sync with
 * tokens.css §1.11 (--bp-lg: 1024px, --bp-xl: 1280px, --bp-md: 768px).
 */

:root {
  --shell-rail-w: 226px;             /* business left rail, full */
  --shell-rail-w-collapsed: 72px;    /* business left rail, icon-only */
  --shell-topbar-h: 44px;            /* business top bar row */
  --shell-header-h: 56px;            /* referrer header, both variants */
  --shell-tabbar-h: 64px;            /* referrer bottom tab bar */
  --shell-admin-rail-w: 256px;       /* admin left rail, open */
  --shell-admin-rail-w-folded: 64px; /* admin left rail, folded to icons */
  --shell-admin-content-w: 1200px;   /* admin content column cap */
  --shell-admin-gutter: 32px;        /* admin content gutter, desktop */
  --shell-admin-bar-h: 56px;         /* admin phone top bar */
  --shell-avatar-size: 32px;         /* business user-menu avatar */
  --shell-public-col: 420px;         /* public auth column */
  --shell-landing-col: 1120px;       /* public landing (A1) container */
  --shell-device-w: 375px;           /* styleguide referrer device frame */
  --device-frame-h: 720px;           /* styleguide referrer device frame, fixed height */
}

/* ---------- Business rail ---------- */

.business-rail {
  width: var(--shell-rail-w);
  flex-shrink: 0;
  position: sticky;
  top: var(--space-6);
  height: calc(100dvh - (var(--space-6) * 2));
  display: flex;
  flex-direction: column;
  padding: var(--space-6);
  overflow-y: auto;
}

.business-rail__logo {
  margin-bottom: var(--space-6);
}

.business-rail__logo-img {
  height: var(--space-6);
  width: auto;
}

/* Mark-only lockup for the icon-only rail — hidden at full width, swapped in
   below --bp-xl by the rule further down. */
.business-rail__logo-mark {
  display: none;
  height: var(--space-6);
  width: auto;
}

.business-rail__logo a {
  display: inline-flex;
}

.business-rail__nav {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.business-rail__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  height: var(--control-h);
  padding-inline: var(--space-3);
  border-radius: var(--radius-lg);
  color: var(--color-ink-muted);
  font-size: var(--text-base);
  line-height: var(--text-base--line-height);
  font-weight: 500;
  transition: background-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
}

.business-rail__item:hover {
  background: var(--color-surface-inset);
}

.business-rail__item.is-active {
  background: var(--color-accent-strong);
  color: var(--color-on-accent);
}

.business-rail__icon {
  flex-shrink: 0;
}

/* Not-yet-built surfaces (11 Aug 2026 decision) — de-emphasised, no hover
   affordance, since these are non-interactive spans, not links. */
.business-rail__item--disabled {
  opacity: 0.5;
}

.business-rail__item--disabled:hover {
  background: none;
}

/* Icon-only rail below --bp-xl (1280px) */
@media (max-width: 1279px) {
  .business-rail {
    width: var(--shell-rail-w-collapsed);
    padding-inline: var(--space-2);
  }

  .business-rail__label {
    display: none;
  }

  .business-rail__item {
    justify-content: center;
    padding-inline: 0;
  }

  /* The "Soon" badge is a text label like .business-rail__label — hide it
     alongside that label rather than let it crowd the icon-only rail. */
  .business-rail__item--disabled .ui-badge {
    display: none;
  }

  .business-rail__logo-img {
    display: none;
  }

  .business-rail__logo-mark {
    display: block;
  }

  .business-rail__logo {
    display: flex;
    justify-content: center;
  }
}

/* Off-canvas rail below --bp-lg (1024px) */
@media (max-width: 1023px) {
  .rail-drawer {
    position: fixed;
    inset: 0;
    z-index: var(--z-drawer);
    pointer-events: none;
  }

  .rail-scrim {
    position: absolute;
    inset: 0;
    background: var(--color-overlay);
    opacity: 0;
    transition: opacity var(--duration-base) var(--ease-out);
    pointer-events: none;
  }

  .business-rail {
    position: fixed;
    top: var(--space-4);
    left: var(--space-4);
    bottom: var(--space-4);
    height: auto;
    width: var(--shell-rail-w);
    transform: translateX(calc(-100% - var(--space-4)));
    transition: transform var(--duration-slow) var(--ease-out);
    pointer-events: auto;
  }

  .business-rail__label {
    display: block;
  }

  .business-rail__item {
    justify-content: flex-start;
    padding-inline: var(--space-3);
  }

  .business-rail__logo-img {
    display: block;
  }

  .business-rail__logo-mark {
    display: none;
  }

  .business-rail__logo {
    display: block;
  }

  .rail-drawer.is-open .rail-scrim {
    opacity: 1;
    pointer-events: auto;
  }

  .rail-drawer.is-open .business-rail {
    transform: translateX(0);
  }
}

@media (min-width: 1024px) {
  .business-rail-toggle {
    display: none;
  }
}

/* ---------- Business top bar ---------- */

.business-topbar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--shell-topbar-h);
}

.business-topbar__search {
  flex: 1;
  max-width: var(--bp-sm);
}

/* The search pill stops growing at --bp-sm, so the bell and user menu have
   to be pushed to the end of the row explicitly — otherwise they sit
   directly against the pill, adrift in the middle of the bar. */
.business-topbar__actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-inline-start: auto;
}

.business-topbar__avatar {
  width: var(--shell-avatar-size);
  height: var(--shell-avatar-size);
  border-radius: var(--radius-round);
  object-fit: cover;
  background: var(--color-surface-inset);
  flex-shrink: 0;
}

/* ---------- Referrer shell ---------- */

.referrer-shell {
  width: 100%;
  max-width: var(--bp-sm);
  margin-inline: auto;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  position: relative;
}

/* Native-gated override: inside the Hotwire Native shell there's no web
   header/tab bar competing for viewport, and the native chrome already
   owns the full screen, so forcing a full 100dvh column here just makes
   the content phantom-scroll by nothing. Additive next to the base rule
   above rather than edited in place, so the web behaviour is untouched. */
.turbo-native .referrer-shell {
  min-height: auto;
}

/*
 * Above --bp-md (768px) the shell centres as a deliberate glass "device" —
 * below that it is plain full-bleed mobile content, so the glass recipe is
 * applied here (scoped to the breakpoint) rather than via the shared
 * .surface-glass class, which would also paint it at mobile widths.
 */
@media (min-width: 768px) {
  .referrer-shell {
    min-height: auto;
    margin-block: var(--space-12);
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: var(--color-surface);
    backdrop-filter: blur(var(--glass-blur));
    -webkit-backdrop-filter: blur(var(--glass-blur));
    border: var(--border-glass);
    box-shadow: var(--shadow-md);
  }

  .perf-lite .referrer-shell {
    background: var(--color-surface-solid);
  }
}

@media (min-width: 768px) {
  @supports not (backdrop-filter: blur(1px)) {
    .referrer-shell {
      background: var(--color-surface-solid);
    }
  }
}

.referrer-header {
  height: var(--shell-header-h);
  padding-inline: var(--space-4);
  padding-top: env(safe-area-inset-top);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  position: relative;
}

.referrer-header--back {
  justify-content: center;
}

.referrer-header.is-scrolled {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  box-shadow: var(--shadow-sm);
}

.referrer-header__back {
  position: absolute;
  left: var(--space-4);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--control-h);
  height: var(--control-h);
  border-radius: var(--radius-round);
  color: var(--color-ink);
  flex-shrink: 0;
}

.referrer-header__title {
  font-size: var(--text-base);
  line-height: var(--text-base--line-height);
  font-weight: 600;
  color: var(--color-ink);
  text-align: center;
  /* NV-04: truncates to one line with an ellipsis rather than wrapping
     under the absolutely-positioned back button / action slot. Reserves
     the same width on both sides regardless of whether the action slot
     is actually present, so the title never re-centres when it appears. */
  max-width: calc(100% - ((var(--control-h) + var(--space-4)) * 2));
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.referrer-header__action {
  position: absolute;
  right: var(--space-4);
}

/* No side padding at phone widths: every referrer page already wraps itself
   in p-4, and this plus the layout's own gutter stacked three 16px gutters —
   48px a side, a 306px column on a 402px phone, which read as the whole UI
   being zoomed out. The page's p-4 is the one phone gutter. Inside the
   ≥768px device frame the extra inset is kept, where it reads as the frame's
   margin rather than lost width. */
.referrer-content {
  flex: 1;
  padding-top: var(--space-4);
  padding-bottom: calc(var(--shell-tabbar-h) + var(--space-4) + env(safe-area-inset-bottom));
}

/* Below 768px the referrer shell has no surface of its own (outside the
   styleguide's device frame), so pages sit on the bare canvas and
   inset-tinted fields vanish into it. Fields here get
   the solid fill; cards inside reset it (forms.css). */
@media (max-width: 767px) {
  .referrer-content {
    --fm-control-bg: var(--color-surface-solid);
  }
}

@media (min-width: 768px) {
  .referrer-content {
    padding-inline: var(--space-4);
  }
}

/* Native-gated override: the bottom padding above reserves space for the
   web .referrer-tabbar, which the native shell never renders — left in
   place it's a dead gap sitting above the native tab bar. Additive next to
   the base rule, not an edit to it, so the web layout is untouched. */
.turbo-native .referrer-content {
  padding-bottom: var(--space-4);
}

.referrer-tabbar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: var(--z-nav);
  height: calc(var(--shell-tabbar-h) + env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
  display: flex;
  border-top: var(--border-glass);
}

@media (min-width: 768px) {
  .referrer-tabbar {
    position: absolute;
  }
}

.referrer-tabbar__item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-height: var(--tap-min);
  color: var(--color-ink-muted);
}

.referrer-tabbar__item.is-active {
  color: var(--color-accent-strong);
}

.referrer-tabbar__label {
  font-size: var(--text-2xs);
  line-height: var(--text-2xs--line-height);
}

/* Not-yet-built surfaces (11 Aug 2026 decision). The badge stacks UNDER the
   label rather than beside it: four tabs share 375px, so a label and a pill
   side by side overflow their tab and collide with the neighbouring labels.
   Verified live at 375px — an inline row is visibly broken there. */
.referrer-tabbar__label-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  max-width: 100%;
  min-width: 0;
}

.referrer-tabbar__item--disabled {
  opacity: 0.5;
}

/*
 * ---------- Native-only ----------
 * Audit 4.9: iOS shows its "Copy"/"Save Image" callout on a long-press of a
 * link or image, which reads as a broken context menu inside a native app
 * that has no page to view source of. Scoped to links and images only —
 * inputs and textareas are deliberately excluded, or text selection in form
 * fields would break with them. Inert on the web, where that callout is
 * expected browser behaviour.
 */

.turbo-native a,
.turbo-native img {
  -webkit-touch-callout: none;
}

/* ---------- Public shell ---------- */

.public-shell {
  width: 100%;
  max-width: var(--shell-public-col);
  margin-inline: auto;
}

/* ---------- Admin shell ----------
 *
 * A left rail (shared/admin/_rail) beside a content column capped at
 * --shell-admin-content-w and left-aligned. The rail is pinned full-height to
 * the window's left edge; each page's Ui::PageHeaderComponent bar is sticky
 * at the top of the column. Its brand row and the page header bar share one
 * height (--space-16), so their two bottom rules meet as one line.
 *
 * From --bp-lg the rail is open (--shell-admin-rail-w) or folded to an icon
 * rail (--shell-admin-rail-w-folded). The server renders .admin-shell
 * [data-nav] from the browser's cookie: "open" and "rail" are a choice and
 * hold at every width; "auto" (no choice yet) folds below --bp-xl and opens
 * from it. admin_rail_controller.js only ever flips the attribute, so the
 * first paint is right without it.
 *
 * Below --bp-lg the rail is hidden; shared/admin/_mobile_bar's sticky top
 * bar opens the same nav in a drawer, always open.
 */

.admin-shell {
  --admin-rail-current: var(--shell-admin-rail-w);
  display: grid;
  grid-template-columns: var(--admin-rail-current) minmax(0, 1fr);
  align-items: start;
  min-height: 100dvh;
  transition: grid-template-columns var(--duration-base) var(--ease-out);
}

.admin-shell[data-nav="rail"] {
  --admin-rail-current: var(--shell-admin-rail-w-folded);
}

@media (width >= 1024px) and (width < 1280px) {
  .admin-shell[data-nav="auto"] {
    --admin-rail-current: var(--shell-admin-rail-w-folded);
  }
}

@media (prefers-reduced-motion: reduce) {
  .admin-shell {
    transition: none;
  }
}

.admin-rail {
  position: sticky;
  top: 0;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--color-surface-solid);
  border-right: var(--border-hairline);
}

.admin-rail__brand {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  height: var(--space-16);
  padding-inline: var(--space-5) var(--space-3);
  border-bottom: var(--border-hairline);
}

.admin-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  border-radius: var(--radius-xs);
  color: inherit;
  text-decoration: none;
}

.admin-brand__logo,
.admin-brand__mark {
  display: block;
  height: var(--space-6);
  width: auto;
}

.admin-brand__tag {
  padding: calc(var(--space-1) / 2) var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--color-surface-sunken);
  font-size: var(--text-2xs);
  line-height: var(--text-2xs--line-height);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

/* panel-left-close sits at the brand row's end while the rail is open;
   folded, panel-left-open is the only thing in the slot. */
.admin-rail__toggle {
  flex: none;
  margin-inline-start: auto;
  color: var(--color-ink-soft);
}

.admin-rail__toggle:hover {
  color: var(--color-ink);
}

.admin-rail .admin-rail__toggle--open {
  display: none;
}

.admin-rail__nav {
  flex: 1 1 auto;
  overflow-x: hidden;
  overflow-y: auto;
  padding: var(--space-4) var(--space-3);
}

.admin-rail__foot {
  flex: none;
  padding: var(--space-4);
  border-top: var(--border-hairline);
}

.admin-rail__foot:not(:has(*)) {
  display: none;
}

/* The nav itself — shared by the rail and the drawer. Groups are lists with
   a hairline between them, no headings. */

.admin-nav {
  display: flex;
  flex-direction: column;
}

.admin-nav__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin: 0;
  padding: 0;
  list-style: none;
}

.admin-nav__list + .admin-nav__list {
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: var(--border-hairline);
}

.admin-nav__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--space-10);
  padding-inline: var(--space-3);
  border-radius: var(--radius-lg);
  color: var(--color-ink-muted);
  font-size: var(--text-sm);
  line-height: var(--text-sm--line-height);
  font-weight: 500;
  white-space: nowrap;
  text-decoration: none;
  transition: background-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
}

.admin-nav__item:hover {
  background: var(--color-surface-inset-solid);
  color: var(--color-ink);
}

.admin-nav__item:focus-visible {
  outline: 2px solid var(--color-accent-pressed);
  outline-offset: 0;
}

/* Current: the accent's soft fill with the pressed accent for the words and
   the icon (--color-accent-strong is AA on white, not on this fill) — quieter than a filled pill, and it lets the icon carry the
   accent the way the rest of the rail's icons carry the tertiary ink. */
.admin-nav__item.is-active {
  background: var(--color-accent-100);
  color: var(--color-accent-pressed);
}

/* Icons: 20px Lucide, tertiary at rest, accent when current. The wrapper
   anchors the folded rail's unread dot to the icon's corner. */
.admin-nav__icon {
  position: relative;
  flex-shrink: 0;
  display: inline-flex;
  color: var(--color-ink-soft);
}

.admin-nav__item:hover .admin-nav__icon {
  color: var(--color-ink);
}

.admin-nav__item.is-active .admin-nav__icon {
  color: var(--color-accent-pressed);
}

.admin-nav__dot {
  display: none;
  position: absolute;
  top: calc(var(--space-1) / -2);
  right: calc(var(--space-1) / -2);
  width: var(--space-2);
  height: var(--space-2);
  border-radius: var(--radius-round);
  background: var(--color-accent-strong);
  box-shadow: 0 0 0 2px var(--color-surface-solid);
}

.admin-nav__label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.admin-nav__count {
  flex-shrink: 0;
  min-width: var(--space-5);
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--color-surface-sunken);
  font-size: var(--text-xs);
  line-height: var(--space-5);
  font-weight: 600;
  font-variant-numeric: var(--numeric-tabular);
  text-align: center;
  color: var(--color-ink);
}

.admin-nav__item.is-active .admin-nav__count {
  background: var(--color-surface-solid);
  color: var(--color-accent-pressed);
}

/* The folded rail's label bubble (admin_rail_controller.js puts it in the
   top layer and measures it beside its item). The UA's [popover] box is
   neutralised so the inline top/left land where they are aimed. */
.admin-rail-tip {
  position: fixed;
  inset: auto;
  z-index: var(--z-popover);
  margin: 0;
  padding: var(--space-1) var(--space-2);
  border: var(--border-hairline);
  border-color: var(--color-border-strong);
  border-radius: var(--radius-xs);
  background: var(--color-surface-solid);
  box-shadow: var(--shadow-sm);
  color: var(--color-ink);
  font-size: var(--text-xs);
  line-height: var(--text-xs--line-height);
  font-weight: 500;
  white-space: nowrap;
  pointer-events: none;
}

.admin-rail-tip[hidden] {
  display: none;
}

/* The signed-in admin and Sign out — rail foot and drawer foot. */

.admin-identity {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.admin-identity__who {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}

.admin-identity__who .ui-avatar {
  flex-shrink: 0;
}

.admin-identity__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.admin-identity__name,
.admin-identity__email {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.admin-identity__name {
  font-size: var(--text-sm);
  line-height: var(--text-sm--line-height);
  font-weight: 600;
  color: var(--color-ink);
}

.admin-identity__email {
  font-size: var(--text-xs);
  line-height: var(--text-xs--line-height);
  color: var(--color-ink-muted);
}

/* Centres the ghost button's icon under the 32px avatar above it. */
.admin-identity__sign-out .ui-button {
  margin-inline-start: calc(var(--space-2) * -1);
}

/* The folded rail. Two copies of one rule set: the chosen fold holds at
   every width (the rail is display: none below --bp-lg anyway), the default
   one only below --bp-xl. Edit both together. */

.admin-shell[data-nav="rail"] .admin-rail__brand {
  justify-content: center;
  padding-inline: 0;
}

.admin-shell[data-nav="rail"] .admin-rail .admin-brand,
.admin-shell[data-nav="rail"] .admin-rail__toggle--close,
.admin-shell[data-nav="rail"] .admin-rail .admin-nav__label,
.admin-shell[data-nav="rail"] .admin-rail .admin-nav__count,
.admin-shell[data-nav="rail"] .admin-rail .admin-identity__text {
  display: none;
}

.admin-shell[data-nav="rail"] .admin-rail__toggle--open {
  display: inline-flex;
  margin-inline: 0;
}

.admin-shell[data-nav="rail"] .admin-rail .admin-nav__item {
  justify-content: center;
  gap: 0;
  padding-inline: 0;
}

.admin-shell[data-nav="rail"] .admin-rail .admin-nav__dot {
  display: block;
}

.admin-shell[data-nav="rail"] .admin-rail__foot {
  padding-inline: var(--space-3);
}

.admin-shell[data-nav="rail"] .admin-rail .admin-identity {
  align-items: center;
}

.admin-shell[data-nav="rail"] .admin-rail .admin-identity__sign-out .ui-button {
  margin-inline-start: 0;
}

/* Sign out keeps its words for screen readers; the tooltip shows them. */
.admin-shell[data-nav="rail"] .admin-rail .admin-identity__sign-out .ui-button__label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@media (width < 1280px) {
  .admin-shell[data-nav="auto"] .admin-rail__brand {
    justify-content: center;
    padding-inline: 0;
  }

  .admin-shell[data-nav="auto"] .admin-rail .admin-brand,
  .admin-shell[data-nav="auto"] .admin-rail__toggle--close,
  .admin-shell[data-nav="auto"] .admin-rail .admin-nav__label,
  .admin-shell[data-nav="auto"] .admin-rail .admin-nav__count,
  .admin-shell[data-nav="auto"] .admin-rail .admin-identity__text {
    display: none;
  }

  .admin-shell[data-nav="auto"] .admin-rail__toggle--open {
    display: inline-flex;
    margin-inline: 0;
  }

  .admin-shell[data-nav="auto"] .admin-rail .admin-nav__item {
    justify-content: center;
    gap: 0;
    padding-inline: 0;
  }

  .admin-shell[data-nav="auto"] .admin-rail .admin-nav__dot {
    display: block;
  }

  .admin-shell[data-nav="auto"] .admin-rail__foot {
    padding-inline: var(--space-3);
  }

  .admin-shell[data-nav="auto"] .admin-rail .admin-identity {
    align-items: center;
  }

  .admin-shell[data-nav="auto"] .admin-rail .admin-identity__sign-out .ui-button {
    margin-inline-start: 0;
  }

  /* Sign out keeps its words for screen readers; the tooltip shows them. */
  .admin-shell[data-nav="auto"] .admin-rail .admin-identity__sign-out .ui-button__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* Main column. overflow-x: clip (not hidden — that would make a scroll
   container and unpin the sticky header) keeps the page header's
   full-bleed rule from scrolling the page sideways. */

.admin-shell__main {
  min-width: 0;
  overflow-x: clip;
}

.admin-shell__content {
  --page-gutter: var(--shell-admin-gutter);
  max-width: calc(var(--shell-admin-content-w) + (var(--page-gutter) * 2));
  padding: var(--space-8) var(--page-gutter) var(--space-12);
}

/* A page header opens the page itself; only header-less pages (the
   styleguide's admin shell) need the top inset. */
.admin-shell__content:has(> .ui-page-header:first-child) {
  padding-top: 0;
}

/* Phone top bar — hidden from --bp-lg up, where the rail shows. */

.admin-mobile-bar {
  display: none;
}

@media (max-width: 1023px) {
  .admin-shell {
    grid-template-columns: minmax(0, 1fr);
  }

  .admin-rail {
    display: none;
  }

  .admin-mobile-bar {
    position: sticky;
    top: 0;
    z-index: var(--z-nav);
    display: flex;
    align-items: center;
    gap: var(--space-3);
    height: var(--shell-admin-bar-h);
    padding-inline: var(--space-4) var(--space-2);
    background: var(--color-surface-solid);
    border-bottom: var(--border-hairline);
  }


  .admin-mobile-bar__menu {
    margin-inline-start: auto;
  }

  .admin-shell__content {
    --page-gutter: var(--space-4);
    padding-top: var(--space-4);
  }

  .admin-shell__content:has(> .ui-page-header:first-child) {
    padding-top: 0;
  }
}

/* ---------- Fixed frame (a list page) ----------
 *
 * From --bp-lg a page whose content holds an .admin-frame stops the window
 * scrolling: the column is exactly the window's height, the header and the
 * band hold still, and .admin-frame__region is the one scroller — focusable
 * and labelled by the page (role="region"), so the keyboard can scroll it.
 * Menus open in the top layer, never inside it. The frame takes the full
 * width beside the rail rather than the 1200px reading column: a table is
 * the one thing that wants it.
 *
 * Below --bp-lg, or in a window under 640px tall (where the header and band
 * would leave the list a sliver), the window scrolls as on any other page
 * and the region is only a wrapper. admin_frame_controller.js keeps the
 * region's scroll position across a visit to a row and Back.
 */

.admin-frame {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  min-height: 0;
}

/* The band: the one thing that needs an admin, then the figures. */
.admin-band {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.admin-band__need {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding-inline-start: var(--space-4);
  border-inline-start: 2px solid var(--color-warning);
}

.admin-band__eyebrow {
  margin: 0;
  font-size: var(--text-xs);
  line-height: var(--text-xs--line-height);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-warning-ink);
}

.admin-band__title {
  margin: 0;
  font-size: var(--text-lg);
  line-height: var(--text-lg--line-height);
  font-weight: 600;
  color: var(--color-ink);
}

.admin-band__meta {
  margin: 0;
  font-size: var(--text-sm);
  line-height: var(--text-sm--line-height);
  color: var(--color-ink-muted);
}

.admin-band__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  margin-top: var(--space-2);
}

.admin-frame__region:focus-visible {
  outline: 2px solid var(--color-accent-pressed);
  outline-offset: 2px;
}

@media (min-width: 1024px) and (min-height: 640px) {
  .admin-shell__content:has(> .admin-frame) {
    display: flex;
    flex-direction: column;
    height: 100dvh;
    max-width: none;
    padding-bottom: 0;
  }

  .admin-shell__content > .admin-frame {
    flex: 1 1 auto;
  }

  .admin-frame__region {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    overscroll-behavior: contain;
    padding-bottom: var(--space-6);
  }

  /* The table's own sideways scroller would trap its sticky header row;
     inside the frame the region scrolls both ways instead. */
  .admin-frame__region .ui-table__table-wrap {
    overflow: visible;
  }

  /* A reference or a date broken over two lines is harder to scan than a
     region that scrolls sideways. */
  .admin-frame__region .ui-table__td {
    white-space: nowrap;
  }

  .admin-frame__region .ui-table__th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--color-bg);
    box-shadow: inset 0 -1px 0 var(--color-border);
  }
}

/* The filter menu's form (Ui::FilterMenuComponent on a list page). */
.admin-filter-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.admin-filter-form__group {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0;
  padding: var(--space-4) 0 0;
  border: 0;
  border-top: var(--border-hairline);
}

.admin-filter-form__legend {
  float: left;
  margin: 0 0 var(--space-2);
  padding: 0;
  font-size: var(--text-xs);
  line-height: var(--text-xs--line-height);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

.admin-filter-form__options {
  clear: both;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2) var(--space-4);
}

.admin-filter-form__actions {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding-top: var(--space-4);
  border-top: var(--border-hairline);
}

/* ---------- Detail page ----------
 *
 * Two columns from --bp-lg: the record's facts and documents on the left in
 * hairline sections, and a right rail of what an admin can still do, with
 * anything destructive as a quiet danger button at its foot. The rail comes
 * second in the source, so on a phone the facts lead and the actions follow.
 * No cards: sections are divided by hairlines alone.
 */

.admin-detail {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-8);
  align-items: start;
}

.admin-detail__main {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.admin-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding-block: var(--space-6);
  border-top: var(--border-hairline);
}

.admin-section:first-child {
  padding-top: 0;
  border-top: 0;
}

.admin-section__title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  font-size: var(--text-base);
  line-height: var(--text-base--line-height);
  font-weight: 600;
  color: var(--color-ink);
}

/* A record's facts read across the column rather than down it. */
.admin-section .ui-details-list {
  grid-template-columns: repeat(auto-fill, minmax(calc(var(--space-12) * 4), 1fr));
}

.admin-section__lede {
  margin: 0;
  max-width: 65ch;
  font-size: var(--text-sm);
  line-height: var(--text-sm--line-height);
  color: var(--color-ink-muted);
}

.admin-detail__rail {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding-top: var(--space-6);
  border-top: var(--border-hairline);
}

.admin-detail__rail-block {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-block: var(--space-5);
  border-top: var(--border-hairline);
}

.admin-detail__rail-block:first-child {
  padding-top: 0;
  border-top: 0;
}

.admin-detail__rail-heading {
  margin: 0;
  font-size: var(--text-xs);
  line-height: var(--text-xs--line-height);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

.admin-detail__rail-lead {
  margin: 0;
  font-size: var(--text-sm);
  line-height: var(--text-sm--line-height);
  font-weight: 600;
  color: var(--color-ink);
}

.admin-detail__rail-note {
  margin: 0;
  font-size: var(--text-sm);
  line-height: var(--text-sm--line-height);
  color: var(--color-ink-muted);
}

@media (min-width: 1024px) {
  .admin-detail {
    grid-template-columns: minmax(0, 1fr) calc(var(--space-12) * 6);
    gap: var(--space-12);
  }

  .admin-detail__rail {
    position: sticky;
    top: calc(var(--space-16) + var(--space-6));
    padding-top: 0;
    padding-inline-start: var(--space-8);
    border-top: 0;
    border-inline-start: var(--border-hairline);
  }
}

/* Focus scrolled into view (Safari, Firefox) clears the sticky page header. */
@media (min-width: 1024px) {
  html:has(.admin-shell) {
    scroll-padding-top: calc(var(--space-16) + var(--space-4));
  }
}

/* The drawer — Ui::ModalComponent (variant: :drawer, side: :start). */

.admin-drawer .ui-modal__panel {
  max-width: calc(var(--shell-admin-rail-w) + var(--space-10));
  padding: var(--space-4);
}

.admin-drawer .ui-modal__header {
  align-items: center;
  margin-bottom: var(--space-2);
  padding-inline-start: var(--space-3);
}

.admin-drawer .ui-modal__title {
  font-size: var(--text-base);
  line-height: var(--text-base--line-height);
}

.admin-drawer .ui-modal__body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}

.admin-drawer__body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-6);
}

.admin-drawer__foot {
  padding-top: var(--space-4);
  padding-bottom: env(safe-area-inset-bottom);
  border-top: var(--border-hairline);
}

/*
 * ---------- Styleguide device frame ----------
 * The /styleguide referrer preview (?shell=referrer) always renders as a
 * 375px phone frame, regardless of viewport — unlike the production
 * referrer shell, whose glass "device" treatment only kicks in above
 * --bp-md. This overrides .referrer-shell unconditionally.
 */

.referrer-shell.styleguide-device-frame {
  max-width: var(--shell-device-w);
  height: var(--device-frame-h);
  max-height: var(--device-frame-h);
  margin-block: var(--space-12);
  border-radius: var(--radius-lg);
  overflow-y: auto;
  background: var(--color-surface);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: var(--border-glass);
  box-shadow: var(--shadow-md);
}

.perf-lite .referrer-shell.styleguide-device-frame {
  background: var(--color-surface-solid);
}

/* The frame is phone-sized but sits in a desktop viewport, so the ≥768px
   content inset would apply inside it — show the phone's single gutter. */
.referrer-shell.styleguide-device-frame .referrer-content {
  padding-inline: 0;
}

/*
 * The frame itself scrolls internally (the styleguide page's content is far
 * taller than one phone screen) while the tab bar stays pinned to the
 * frame's own bottom edge, not the real document's — `position: absolute`
 * from the base referrer-tabbar rule would otherwise sink to the bottom of
 * the full scrollable content instead of staying visible. `sticky` keeps it
 * pinned against this element's own scrolling box (its nearest scrolling
 * ancestor) as that box scrolls.
 */
.referrer-shell.styleguide-device-frame .referrer-tabbar {
  position: sticky;
}

/*
 * Mirrors page: comparisons must show the WHOLE screen, like the Figma
 * export beside them — a fixed-height scrolling frame would crop the
 * sticky CTA, activity feed and anything else below the first fold.
 */
.referrer-shell.styleguide-device-frame--full {
  height: auto;
  max-height: none;
  overflow-y: visible;
}

/*
 * NV-03 styleguide exhibit (_nv03_tabbar.html.erb) — the base
 * .referrer-tabbar rule is `position: fixed` below --bp-md and only
 * switches to `absolute` (relative to the exhibit's 375px frame) above it,
 * so the exhibit only rendered its absolute-in-frame presentation
 * correctly at one particular viewport width. `.is-exhibit` on the frame
 * forces `absolute` unconditionally, so the tabbar stays contained in the
 * frame regardless of the actual browser viewport width.
 */
.is-exhibit .referrer-tabbar {
  position: absolute;
}
