/* ============================================================================
   OVERRIDES.CSS  —  @layer app.overrides  —  conditional rules ONLY.

   The last layer, and the narrowest: every rule in this file must sit inside a
   condition — @media, @supports or print. That is the whole reason the layer
   exists. It is where a class declared by an earlier layer is allowed to be
   restyled by its bare name, because "the same component, under a stated
   condition" is not a second owner: it is the same owner, later.

   An unconditional rule here would be an ordinary declaration that happens to
   win everything, which is precisely the habit this stack is meant to remove —
   so `node scripts/check-css.mjs` rejects one.
   ==========================================================================*/

@layer app.overrides {

/* ---------------------------------------------------------------- motion --
   The app has no motion: base.css §19 ends with an UNLAYERED

       *, *::before, *::after { animation: none !important; transition: none !important }

   and that is deliberate, so every transition and keyframe in public/styles/ was
   deleted rather than left to pretend. This block is the single exemption, and
   it earns it by carrying information rather than decoration: the alert's ring
   IS the ten-second dismiss timer that public/app.js is counting down. Frozen,
   it was a full circle that said "waiting" forever, and the `data-paused` state
   the JS sets on hover had no visible effect at all.

   Why it wins without touching base.css: for !important declarations the
   cascade REVERSES layer order and unlayered styles rank lowest. base.css's
   backstop is unlayered, so an important declaration inside any layer — this
   one — outranks it. That is the whole trick, and it is why this is the only
   place in the app where !important is the right tool.

   Anyone who wants the app completely still again deletes this block; nothing
   else depends on it. */
@media (prefers-reduced-motion: no-preference) {
  .alert-ring > circle { animation: alert-ring 10s linear forwards !important; }
  .alert[data-paused] .alert-ring > circle { animation-play-state: paused !important; }
}

@keyframes alert-ring {
  from { stroke-dashoffset: 100.53; }
  to { stroke-dashoffset: 0; }
}

/* --------------------------------------------- the rail on a small screen --
   --bp-md (52rem / 832px). Below this the signed-in shell stops being two
   columns.

   It had no narrow-screen rule at all. `body:has(> .side-nav)` and `.app-shell`
   are `grid-template-columns: var(--side-w) minmax(0, 1fr)` at EVERY width, so
   on a 390px phone the rail took 240px and the page was left 150px — a column
   narrower than the cards inside it, with the app's own content scrolling
   sideways under a rail that filled two thirds of the screen. The review
   console was given exactly this fix (AGENTS.md §14.8) and the app was not;
   this is the same fix, at the app's own breakpoint and in the app's own class
   names.

   One column, and the rail becomes the strip along the top that it already
   knows how to be: the entries are the same pills, laid in a row that scrolls
   horizontally when there are more than fit. */
@media (max-width: 52rem) {
  body:has(> .side-nav),
  .app-shell {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto;
  }

  .side-nav {
    position: static;
    flex-direction: row;
    align-items: center;
    gap: var(--sp-2);
    block-size: auto;
    padding: var(--sp-2) var(--sp-3);
    overflow-x: auto;
    overflow-y: hidden;
    border-inline-end: 0;
    border-block-end: 1px solid var(--glass-border);
  }
  /* The header variant pins the rail below the top bar and sizes it to the
     viewport; neither is true of a strip. */
  body:has(> .app-header) .side-nav {
    inset-block-start: auto;
    block-size: auto;
  }

  .side-head { flex: none; }
  .side-nav > ul {
    flex: 1 1 auto;
    flex-direction: row;
    align-items: center;
    gap: var(--sp-1);
  }
  .side-nav li { flex: none; }
  .side-nav li a,
  .side-nav li button,
  .side-nav li .nav-here { inline-size: auto; }

  /* A nested list cannot be a row: its parent entry still leads there. */
  .side-nav > ul > li > .nav-sub,
  .side-nav .nav-sub-toggle { display: none; }

  /* Both of these push their item to the bottom of a column that no longer
     exists; in a row they would push it off the end. */
  .side-nav li[data-foot="true"] { margin-block-start: 0; }
  .side-nav .site-nav-action {
    margin-block-start: 0;
    padding-block-start: 0;
    padding-inline-start: var(--sp-2);
    border-block-start: 0;
    border-inline-start: 1px solid var(--glass-border);
  }

  /* The toast is offset by the width of a rail that is now above it. */
  body:has(.side-nav) .alert {
    inset-inline-start: 0;
    inline-size: calc(100% - 2 * var(--sp-4));
  }

  /* With the rail gone the page is the whole width, and .page has no inline
     padding of its own — its cards would sit against the glass. */
  .page { padding-inline: var(--sp-4); }
  .page[data-layout="full"] { padding-inline: var(--sp-4); }
}

@media (max-width: 44rem) {
  .app-header-start {
    flex: 1 1 auto;
    min-inline-size: 0;
  }

  .app-header-start .app-row {
    min-inline-size: 0;
    overflow-x: auto;
    overscroll-behavior-inline: contain;
    scrollbar-width: none;
  }
  .app-header-start .app-row::-webkit-scrollbar { display: none; }

  .app-header .app-pill {
    inline-size: var(--nav-item-h);
    justify-content: center;
    padding-inline: 0;
  }
  .app-header .app-pill .nav-label { display: none; }

  .app-menu-email-preview { display: none; }
  .app-account-trigger {
    min-inline-size: var(--nav-item-h);
    justify-content: center;
    padding-inline: var(--sp-1);
  }
}

@media (max-width: 30rem) {

  :root { --nav-h: 3.5rem; }
  .site-nav > nav {
    gap: var(--sp-2);
    padding-inline: var(--sp-3);
  }
  .site-nav a,
  .site-nav button {
    padding-inline: var(--sp-2);
    font-size: var(--fs-xs);
  }

  /* The address is repeated inside the account menu itself. Keeping it in the
     390px header crowds the two real destinations and turns the top bar into a
     truncation demo, so phones show the avatar as the account affordance. */
  .app-menu-email-preview { display: none; }
  .app-header-start { gap: var(--sp-1); }

  main.auth,
  body.auth:not([data-surface="platform-auth"]) {
    place-items: stretch;
    align-content: center;
    padding: var(--sp-5) var(--sp-4);
  }
  body[data-surface="platform-auth"] main.auth > .auth-head,
  body[data-surface="platform-auth"] main.auth > .auth-card {
    inline-size: 100%;
    max-inline-size: none;
  }
  .auth-head,
  .auth-card { max-inline-size: none; }
  .auth-card {
    padding: 0;
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .auth-card::before { display: none; }
  /* The compact operator form remains a real card on mobile; the general
     mobile auth reset must not strip its container or offset the viewport. */
  body.auth[data-surface="super-admin-auth"] {
    padding: 0;
    place-items: center;
  }
  body[data-surface="super-admin-auth"] .auth-card {
    padding: var(--sp-5);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--r-xl);
    box-shadow: var(--sh-sm);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  body::after { opacity: .35; }

  .profile-split { flex-direction: column; }
  .profile-side { margin: 0 var(--sp-4) var(--sp-3); }
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  :root {
    --glass-bg: var(--bg);
    --glass-bar-bg: var(--bg);
    --glass-field-bg: var(--field-bg);
    --glass-alert-bg: var(--red-50);
    --glass-filter: none;
  }

  .alert { background: var(--red-50); }
  .alert[data-tone="ok"] { background: var(--success-bg); }
  .alert[data-tone="info"] { background: var(--info-bg); }
  .profile-card[data-state="empty"] { background: var(--bg-subtle); }
  .avatar-editor { background: var(--bg-subtle); }
}

@media print {
  /* app.overrides is the last layer, so `display: none` wins over the layout
     that put these on the page without needing !important — which, in a layered
     stack, would have inverted the order it is trying to enforce. */
  body > *:not(#main) { display: none; }
  .side-nav,
  .site-nav,
  .page-head .crumbs,
  .page-foot,
  .identity-actions { display: none; }
  .page[data-layout="full"],
  .page { max-inline-size: none; padding: 0; }
  .page-body { display: block; }

  [data-print] {
    max-inline-size: none;
    margin: 0;
    padding: 0;
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  /* The one !important left in public/styles/: `[data-print] *` is (0,1,0) and
     has to beat every component rule inside the printed block, including the
     ones in this same layer. Specificity cannot buy that without naming them
     all. */
  [data-print] * { color: #000 !important; }
}

} /* @layer app.overrides */
