/* AppShell layout. Tokens come from tokens.css; nothing hardcoded here. */

@layer layout {
  /* Scoped list-reset on the AppShell nav — the global rule was removed
     because Safari VoiceOver strips list semantics from <ul> when
     list-style: none is applied. Content lists (ingredients, instructions)
     keep their default markers and AT semantics. */
  .app-shell__nav {
    list-style: none;
    padding: 0;
    margin: 0;
  }

  body {
    display: grid;
    min-height: 100dvh;
    grid-template-columns: 1fr;
    grid-template-rows: 1fr auto;
  }

  /* ----- Icons (shared across sidebar + tabbar) ----- */
  .icon {
    width: 24px;
    height: 24px;
    display: block;
    flex-shrink: 0;
  }

  .app-shell__sidebar { display: none; }

  .app-shell__main {
    /* min-width: 0 lets this grid item shrink below its content's
       intrinsic width — without it a long unbroken title or a wide
       child pushes the main column past the viewport (the systemic
       overflow root from the meal-planning retrospect 6C). */
    min-width: 0;
    padding: var(--space-page);
    padding-block-end: calc(var(--tab-bar-height) + var(--space-6));
  }

  /* Shared content-column primitive. Centers a content column and caps
     its width at one of the --content-* tiers. A surface picks its tier
     by setting --page-shell-max — either via a modifier class below or
     a per-surface override of the custom property. Default tier is the
     wide --content-max. Surfaces stop hand-declaring the
     `margin:0 auto; width:100%` + literal-width trio.

     Additive in PR1: defined here, applied by no surface yet — surface
     migration is PR2. */
  .page-shell {
    --page-shell-max: var(--content-max);
    inline-size: 100%;
    max-inline-size: var(--page-shell-max);
    margin-inline: auto;
  }
  .page-shell--narrow { --page-shell-max: var(--content-narrow); }
  .page-shell--form { --page-shell-max: var(--content-form); }

  /* ----- Mobile bottom tab bar ----- */
  .app-shell__tabbar {
    position: fixed;
    inset-block-end: 0;
    inset-inline: 0;
    height: var(--tab-bar-height);
    display: grid;
    /* Five tabs: Explore, Add, Saved, Plan, Profile. */
    grid-template-columns: repeat(5, 1fr);
    background: color-mix(in oklch, var(--md-surface-container-low) 92%, transparent);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-block-start: 1px solid color-mix(in oklch, var(--md-border-muted) 70%, transparent);
    z-index: 10;
    padding-block-end: env(safe-area-inset-bottom);
  }

  .app-shell__tab {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-1);
    font-size: 10px;
    font-weight: 500;
    color: var(--md-on-surface-variant);
    transition: color var(--motion-spring-fast-effects-duration) var(--motion-spring-fast-effects);

    &.is-active { color: var(--md-primary); }
    &:hover { color: var(--md-on-surface); }
    &.is-active:hover { color: var(--md-primary); }
  }

  .app-shell__tab .icon { width: 22px; height: 22px; }

  /* Auth shell: full-viewport, single-cell layout for pages whose root
     content uses .signin or .signin-sent. Detected via :has() so handlers
     and templates don't need to opt in. The page block does its own
     flex centering. The :has() selector's specificity (0,1,1) beats the
     desktop `body` rule below (0,0,1) at all viewports, so no per-media
     duplication is needed. */
  body:has(.signin, .signin-sent) {
    grid-template-columns: 1fr;
    grid-template-rows: 1fr;
  }
  body:has(.signin, .signin-sent) :is(.app-shell__sidebar, .app-shell__tabbar) {
    display: none;
  }
  body:has(.signin, .signin-sent) .app-shell__main { padding: 0; }

  /* ----- Desktop sidebar ----- */
  @media (min-width: 1024px) {
    body {
      grid-template-columns: var(--sidebar-width) 1fr;
      grid-template-rows: 1fr;
    }

    .app-shell__sidebar {
      display: flex;
      flex-direction: column;
      align-items: center;
      padding: var(--space-6) 0;
      gap: var(--space-8);
      border-inline-end: 1px solid color-mix(in oklch, var(--md-border-muted) 70%, transparent);
      background: var(--md-surface-container-low);
      /* Pin to the viewport instead of stretching with row 1. Row 1 grows
         to the tallest grid item (main), so without these the rail (and
         its flex:1 nav) stretched the full page height — visible on long
         pages like /recipes. align-self:start opts out of the default
         grid stretch; sticky keeps it in view while main scrolls. */
      position: sticky;
      inset-block-start: 0;
      block-size: 100dvh;
      align-self: start;
    }

    .app-shell__logo {
      display: flex;
      align-items: center;
      justify-content: center;
      /* Sized to the prototype's 44x44 + 14px radius to read against
         the 112px rail. The 80px-tuned 40x40 was too small after the
         rail bump. */
      width: 44px;
      height: 44px;
      border-radius: 14px;
      transition: opacity var(--motion-spring-fast-effects-duration) var(--motion-spring-fast-effects);
    }
    .app-shell__logo:hover { opacity: 0.8; }
    .app-shell__logo .mascot { width: 32px; height: 32px; }

    .app-shell__nav {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: var(--space-2);
      flex: 1;
      width: 100%;
    }

    .app-shell__nav-item {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 48px;
      height: 48px;
      border-radius: var(--radius-lg);
      color: var(--md-on-surface-variant);
      transition:
        color var(--motion-spring-fast-effects-duration) var(--motion-spring-fast-effects),
        background-color var(--motion-spring-fast-effects-duration) var(--motion-spring-fast-effects);

      &:hover {
        color: var(--md-on-surface);
        background: var(--md-surface-container);
      }
      /* Bible 10.2(h) wider-rail pattern: --md-primary-container pill fills
         the 48px nav-item with on-primary-container glyph. Active hover
         pinned against hover-flip per nora's PR-prep punch list #6. */
      &.is-active {
        color: var(--md-on-primary-container);
        background: var(--md-primary-container);
      }
      &.is-active:hover {
        color: var(--md-on-primary-container);
        background: var(--md-primary-container);
      }
    }

    .app-shell__nav-item:focus-visible {
      outline: none;
      box-shadow: var(--focus-ring);
    }

    /* Hide the text label on desktop — icon + tooltip carry the meaning,
       matching the legacy app shell. Mobile keeps the label below the icon. */
    .app-shell__nav-label {
      position: absolute;
      width: 1px;
      height: 1px;
      padding: 0;
      margin: 0;
      overflow: hidden;
      clip: rect(0, 0, 0, 0);
      white-space: nowrap;
      border: 0;
    }

    .app-shell__nav-spacer { flex: 1; }

    .app-shell__main {
      padding: var(--space-section) var(--space-page);
    }

    .app-shell__tabbar { display: none; }
  }
}
