/* The site nav, shared by the storefront and the staff portal.
   ============================================================

   Extracted from site.css so the portal can load it WITHOUT loading the
   storefront's stylesheet. base_site.html links tokens.css, aurora.css and
   the portal-*.css files; it does not link site.css, and it must not - that
   file styles the catalog, the cart, product pages and forms, all of which
   would land on top of Django's admin.

   One partial (templates/partials/site-nav.html) renders both surfaces, so
   one stylesheet dresses both. A second copy of these rules for the portal
   is exactly the drift this arrangement exists to prevent.

   Everything here is prefixed .site-nav*, so nothing in it can reach the
   admin's own furniture. */

/* --- Top navigation ------------------------------------------------------ */
/* One header for every logged-in page, replacing the per-page wordmark. It
   carries its own ground rather than floating on the gradient: white text on
   --glow-red alone sits near the AA boundary (S-G §3). */

.site-nav {
  --site-nav-gutter: var(--gutter, clamp(1rem, 3.5vw, 2.5rem));
  --site-nav-content-max: var(--content-max, 1440px);
  position: sticky;
  top: 0;
  z-index: 5;
  /* The staff portal's header treatment, brought across so the two surfaces
     read as one site: a near-black glass band over the aurora with a
     hairline under it, rather than the light theme's navy slab.

     This is the ONE place backdrop-filter is still allowed. The nav is not a
     windowed panel - it has no aurora showing through a 1px ring to blur -
     so the rule in aurora.css does not bite here. */
  background: rgba(5, 7, 13, 0.72);
  border-bottom: 1px solid var(--hairline);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}

/* Django admin does not carry the storefront's global border-box rule. Keep
   the shared header's dimensions independent of whichever surface includes
   it, especially the account button whose padding otherwise makes the portal
   bar taller than the storefront's. */
.site-nav,
.site-nav * {
  box-sizing: border-box;
}

.site-nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.4rem var(--site-nav-gutter);
  width: min(var(--site-nav-content-max), 100%);
  margin: 0 auto;
  padding: 0.7rem var(--site-nav-gutter);
}

/* The logo, not the word. The wordmark rules below are kept because the mark
   falls back to text if the SVG ever fails to load, and a header that loses
   its only link home is worse than one that loses its styling. */
.site-nav-mark {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 1.35rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #ffffff;
  text-decoration: none;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.45);
}

.site-nav-logo {
  display: block;
  height: 2.2rem;
  width: auto;
  /* The artwork is black line-work on transparent; the nav is dark. Without
     this it is a logo-shaped hole. */
  filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.45));
}

@media (max-width: 40rem) {
  .site-nav-logo {
    height: 1.7rem;
  }

}

/* Sized in the flow rather than by font-size so the icon and its label share a
   baseline whatever the label does. */
.site-nav-icon {
  font-size: 1.05rem;
  line-height: 1;
}

.site-nav-links {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: clamp(0.5rem, 2.5vw, 1.6rem);
}

.site-nav-logout {
  display: inline-flex;
  margin: 0;
}

/* Shared by the two links and the logout submit, so the POST form is
   indistinguishable from its neighbours. */
.site-nav-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.45rem 0.7rem;
  border: 0;
  border-radius: 10px;
  background: none;
  color: var(--muted);
  font-family: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
}

/* The portal's glowing pill, on the storefront's nav. Hover and the current
   page get the same treatment the portal's active sidebar item does, so
   "where I am" looks like one idea across both surfaces. */
.site-nav-link:hover {
  color: var(--ink);
  background: rgba(255, 255, 255, 0.05);
}

/* Any aria-current, not just "page". A link is lit when its SECTION is
   current - Account while you are on /account/security, Catalog while you are
   on a product - and that case carries aria-current="true". Pinning the
   selector to "page" lit the pill only on the section's own front page and
   left every page inside it looking like nowhere. */
.site-nav-link.is-current,
.site-nav-link[aria-current] {
  color: var(--ink);
  background: var(--accent-wash);
  box-shadow: inset 0 0 0 1px rgba(255, 42, 42, 0.35), 0 0 18px var(--edge-glow);
}

.site-nav-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.site-nav-count {
  display: inline-grid;
  place-items: center;
  min-width: 1.35rem;
  padding: 0 0.35rem;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0;
}

.site-nav-notifications {
  position: relative;
}

/* Cart and Alerts are compact status actions: their aria-label supplies the
   name while the UI stays to an icon and, when non-zero, a number badge. */
.site-nav-icon-only {
  padding: 0.55rem 0.7rem;
}

.site-nav-icon-only .site-nav-icon {
  font-size: 1.25rem;
}

/* Narrow: the mark and the search take the first row and the actions spread
   across the second. No overflow at 320px, and no JS to open anything.

   THE ACTIONS HAVE TO FIT THAT ONE ROW. A staff account carries five of them
   and the widest is "Staff Portal"; at the desktop size that row wraps again
   somewhere under 700px, and a nav three rows tall pushes the page it labels
   off the screen. Two steps, in this order:

   1. Tighten. Type, tracking, padding and gap all come down together and the
      type is tied to the viewport, so the row keeps shrinking to meet the
      screen rather than snapping at one breakpoint. A shopper - three items,
      no portal - never gets near the floor of the clamp.
   2. Only once tightening runs out, drop the labels to icons. That is the
      second block, and it is a LAST resort: an icon-only nav is a guessing
      game, which is why the words are held onto for as long as they fit. */
@media (max-width: 700px) {
  .site-nav-inner {
    justify-content: center;
    padding-block: 0.55rem;
  }

  .site-nav-links {
    width: 100%;
    /* around, not between: the end items keep an edge margin, so at the
       icon-only size the row does not read as two items pinned to the
       corners with a hole in the middle. */
    justify-content: space-around;
    flex-wrap: nowrap;
    gap: 0.15rem;
  }

  .site-nav-link {
    font-size: clamp(0.6rem, 1.85vw, 0.74rem);
    letter-spacing: 0.02em;
    gap: 0.3rem;
    padding: 0.45rem 0.4rem;
    /* Five items sharing one row means five chances to wrap a two-word
       label onto a second line and take the whole header with it. */
    white-space: nowrap;
  }

  /* The search's half of this lives with the rest of the search rules at the
     foot of the file. It has to: those rules come later, a media query adds
     no specificity, and .site-nav-search input's width would win from there
     however narrow the screen got. */
}

/* Below this the five labels cannot be made small enough to fit and still be
   read, so they go. Visually - the span stays in the accessibility tree, so
   every link keeps its name. */
@media (max-width: 440px) {
  .site-nav-label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }

  /* The tap target was the label's width; without it the icon has to carry
     the 44px on its own. */
  .site-nav-link {
    padding: 0.55rem 0.7rem;
  }

  .site-nav-icon {
    font-size: 1.25rem;
  }

  /* Nothing left to sit beside, so it rides the corner of the cart icon
     instead of pushing it out of line with the others. */
  .site-nav-count {
    min-width: 1.1rem;
    margin-left: -0.35rem;
    align-self: flex-start;
    font-size: 0.62rem;
  }
}


/* --- Nav search ---------------------------------------------------------- */

.site-nav-search {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-left: auto;
  padding: 0.3rem 0.5rem 0.3rem 0.75rem;
  background: var(--surface-tile);
  border: 1px solid var(--hairline);
  border-radius: 999px;
}

.site-nav-search-results {
  position: absolute;
  top: calc(100% + 0.65rem);
  right: 0;
  z-index: 12;
  width: min(26rem, calc(100vw - 2 * var(--gutter)));
  max-height: min(32rem, 70vh);
  overflow-y: auto;
  padding: 0.5rem;
  border: 1px solid var(--hairline);
  border-radius: 14px;
  background: var(--surface-float);
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.5), 0 0 22px var(--edge-glow);
}

.site-nav-search-results[hidden] {
  display: none;
}

.site-nav-search-list {
  display: grid;
  gap: 0.4rem;
}

.site-nav-search-card {
  display: grid;
  grid-template-columns: 3.4rem minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.7rem;
  min-width: 0;
  padding: 0.55rem;
  border: 1px solid transparent;
  border-radius: 10px;
  background: var(--surface-tile);
  color: var(--ink);
  text-decoration: none;
}

.site-nav-search-card:hover,
.site-nav-search-card:focus-visible {
  border-color: var(--accent);
  background: var(--accent-wash);
  outline: none;
}

.site-nav-search-card img {
  display: block;
  width: 3.4rem;
  height: 3.4rem;
  object-fit: contain;
  border-radius: 8px;
  background: var(--surface);
}

.site-nav-search-copy {
  min-width: 0;
}

.site-nav-search-name,
.site-nav-search-meta {
  display: block;
}

.site-nav-search-name {
  overflow: hidden;
  font-size: 0.84rem;
  font-weight: 700;
  line-height: 1.25;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.site-nav-search-meta {
  margin-top: 0.2rem;
  overflow: hidden;
  color: var(--muted);
  font-size: 0.7rem;
  line-height: 1.25;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.site-nav-search-price {
  color: var(--ink);
  font-size: 0.76rem;
  font-weight: 700;
  white-space: nowrap;
}

.site-nav-search-sale {
  display: block;
  color: var(--accent);
  font-size: 0.62rem;
  text-align: right;
}

.site-nav-search-status {
  margin: 0;
  padding: 0.7rem 0.55rem;
  color: var(--muted);
  font-size: 0.76rem;
}

.site-nav-search-list:not(:empty) + .site-nav-search-status:empty {
  display: none;
}

.site-nav-search input {
  width: clamp(140px, 22vw, 280px);
  border: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 0.86rem;
}

.site-nav-search input::placeholder {
  color: var(--muted);
}

.site-nav-search input:focus {
  outline: none;
}

.site-nav-search:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 18px var(--edge-glow);
}

.site-nav-search button {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}

/* Narrow: the search shares row one with the mark and takes what is left of
   it rather than its desktop width.

   BOTH min-widths matter and neither is redundant. The one on the form is
   what lets a flex item shrink past its content at all; the one on the input
   is what stops the input's own intrinsic size - a text field is about twenty
   characters wide before anyone touches it - from setting the floor. Without
   them the 140px in the clamp above is a hard minimum, the mark and the
   search stop fitting one row somewhere around 340px, and the header goes
   three rows tall on the narrowest phones. */
@media (max-width: 700px) {
  /* Basis ZERO, not auto, and that is the whole trick. Flexbox decides where
     to wrap from the hypothetical main size - the basis - and only shrinks
     what is left on the line afterwards. With basis auto the search asks for
     its content width first, the mark plus that ask exceeds a 360px screen,
     and the line breaks before shrinking is ever consulted. At zero it asks
     for nothing, never causes a break, and grows into whatever the mark
     leaves behind. */
  .site-nav-search {
    flex: 1 1 0;
    min-width: 0;
    margin-left: 0;
  }

  .site-nav-search input {
    width: 100%;
    min-width: 0;
  }
}

@media (max-width: 440px) {
  .site-nav-search-card {
    grid-template-columns: 3rem minmax(0, 1fr);
  }

  .site-nav-search-card img {
    width: 3rem;
    height: 3rem;
  }

  .site-nav-search-price {
    grid-column: 2;
    justify-self: start;
  }

  .site-nav-search-sale {
    display: inline;
    margin-right: 0.35rem;
  }
}

.site-nav-search button:hover {
  color: var(--accent);
}

/* --- Storefront navigation refresh ------------------------------------- */
/* Desktop keeps the primary destinations centered. On storefront phones the
   same destinations become a bottom dock; the top bar retains identity,
   Cart, staff access, and the account menu. The portal uses the same clean
   three-column hierarchy, but its rail already owns narrow-screen navigation. */

.site-nav:not(.site-nav--portal) .site-nav-inner,
.site-nav--portal .site-nav-inner {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  flex-wrap: nowrap;
  gap: clamp(0.65rem, 2vw, 1.5rem);
  padding-block: 0.65rem;
}

.site-nav:not(.site-nav--portal) .site-nav-links,
.site-nav--portal .site-nav-links {
  justify-content: center;
  gap: clamp(0.15rem, 1.2vw, 0.75rem);
}

.site-nav:not(.site-nav--portal) .site-nav-link,
.site-nav--portal .site-nav-link {
  gap: 0.42rem;
  padding: 0.58rem 0.72rem;
  letter-spacing: 0.035em;
  text-transform: none;
}

/* The admin root font is 90% of the storefront root. Fixed component sizes
   here keep the one shared header physically identical on both surfaces
   without changing typography anywhere else in Django admin. */
.site-nav--portal .site-nav-logo {
  height: 35.2px;
}

.site-nav--portal .site-nav-link,
.site-nav--portal .site-nav-account-button {
  font-size: 12.8px;
}

.site-nav--portal .site-nav-icon {
  font-size: 16.8px;
}

.site-nav--portal .site-nav-account-button {
  min-height: 40px;
  padding: 7.2px 10.4px;
}

@media (max-width: 40rem) {
  .site-nav--portal .site-nav-logo {
    height: 27.2px;
  }
}

/* --- The middle column never wraps ---------------------------------------
   The grid above gives the links a `minmax(0, 1fr)` track, and .site-nav-links
   inherited `flex-wrap: wrap` from the base rule near the top of this file.
   Between 761px - where the desktop row is still shown - and about 1215px,
   where six labelled links plus the mark plus a staff account's utilities
   first fit on one line, the row wrapped to two and three rows. The header
   grew to ~190px, and because the mark and the utilities stay vertically
   centred in a taller row, the links appeared to spill over the logo. Every
   laptop between those widths saw it.

   Wrapping is never the answer for this row, so: nowrap, then the same
   two-step the narrow rules below already use - tighten, and only when
   tightening runs out, drop the words. The thresholds are measured against
   the widest case, a staff account: six primary links plus Staff Portal.
   A shopper has fewer and simply reaches each step with room to spare.

   Storefront only. The portal carries two links and its own rail, so it has
   no crowding to solve and keeps its labels at every width. */

.site-nav:not(.site-nav--portal) .site-nav-links,
.site-nav--portal .site-nav-links {
  flex-wrap: nowrap;
}

.site-nav:not(.site-nav--portal) .site-nav-link,
.site-nav--portal .site-nav-link {
  white-space: nowrap;
}

/* Step 1: the utilities give up their words before the destinations do.
   "Staff Portal" is the single widest label in the header and the least
   needed - it sits beside a toolbox icon, and the people who use it use it
   daily. */
@media (max-width: 1280px) {
  .site-nav:not(.site-nav--portal) .site-nav-utility-label .site-nav-label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }
}

/* Step 2: the account name follows, and the destinations tighten. */
@media (max-width: 1200px) {
  .site-nav:not(.site-nav--portal) .site-nav-account-name {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }

  .site-nav:not(.site-nav--portal) .site-nav-account-button {
    width: 2.5rem;
    justify-content: center;
    padding-inline: 0.45rem;
  }

  .site-nav:not(.site-nav--portal) .site-nav-account-chevron {
    display: none;
  }

  .site-nav:not(.site-nav--portal) .site-nav-link {
    gap: 0.32rem;
    padding: 0.5rem 0.45rem;
    font-size: 0.74rem;
  }
}

/* Step 3, and only now: the destinations lose their labels. Visually - the
   span stays in the accessibility tree, so every link keeps its name, the
   same bargain the 440px rule above strikes. */
@media (max-width: 980px) {
  .site-nav:not(.site-nav--portal) .site-nav-links .site-nav-label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }

  /* The tap target was the label's width; the icon has to carry it alone. */
  .site-nav:not(.site-nav--portal) .site-nav-links .site-nav-link {
    padding: 0.55rem 0.6rem;
  }

  .site-nav:not(.site-nav--portal) .site-nav-links .site-nav-icon {
    font-size: 1.2rem;
  }

  /* Nothing left to sit beside, so it rides the corner of its icon. */
  .site-nav:not(.site-nav--portal) .site-nav-links .site-nav-count {
    min-width: 1.1rem;
    margin-left: -0.4rem;
    align-self: flex-start;
    font-size: 0.62rem;
  }
}

.site-nav-utilities {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.25rem;
}

.site-nav-account {
  position: relative;
}

.site-nav-account summary {
  list-style: none;
}

.site-nav-account summary::-webkit-details-marker {
  display: none;
}

.site-nav-account-button {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 2.5rem;
  padding: 0.45rem 0.65rem;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--ink);
  font-size: 0.8rem;
  font-weight: 600;
  cursor: pointer;
}

.site-nav-account-button:hover,
.site-nav-account[open] .site-nav-account-button,
.site-nav-account.is-current .site-nav-account-button {
  background: var(--accent-wash);
}

.site-nav-account-button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.site-nav-account-chevron {
  font-size: 0.7rem;
  transition: transform 160ms ease;
}

.site-nav-account[open] .site-nav-account-chevron {
  transform: rotate(180deg);
}

.site-nav-account-menu {
  position: absolute;
  top: calc(100% + 0.55rem);
  right: 0;
  z-index: 20;
  width: 13.5rem;
  padding: 0.45rem;
  border: 1px solid var(--hairline);
  border-radius: 12px;
  background: var(--surface-float);
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.52);
}

.site-nav-account-menu a,
.site-nav-account-menu button {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  padding: 0.7rem 0.75rem;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 0.82rem;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.site-nav-account-menu a:hover,
.site-nav-account-menu a:focus-visible,
.site-nav-account-menu button:hover,
.site-nav-account-menu button:focus-visible {
  background: var(--accent-wash);
  outline: none;
}

.site-nav-account-menu form {
  margin: 0;
}

.site-nav-mobile {
  display: none;
}

@media (max-width: 760px) {
  .site-nav:not(.site-nav--portal) .site-nav-inner,
  .site-nav--portal .site-nav-inner {
    grid-template-columns: minmax(0, 1fr) auto;
    justify-content: initial;
    padding-inline: var(--site-nav-gutter);
  }

  .site-nav:not(.site-nav--portal) .site-nav-links,
  .site-nav--portal .site-nav-links {
    display: none;
  }

  .site-nav-utility-label .site-nav-label,
  .site-nav-account-name {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }

  .site-nav-account-button {
    width: 2.5rem;
    justify-content: center;
    padding-inline: 0.45rem;
  }

  .site-nav--portal .site-nav-account-button {
    width: 40px;
  }

  .site-nav-account-chevron {
    display: none;
  }

  .site-nav-mobile {
    position: fixed;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 15;
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    border-top: 1px solid var(--hairline);
    background: rgba(5, 7, 13, 0.94);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
  }

  .site-nav-mobile a {
    position: relative;
    display: grid;
    justify-items: center;
    gap: 0.25rem;
    min-width: 0;
    padding: 0.7rem 0.25rem calc(0.72rem + env(safe-area-inset-bottom));
    color: var(--muted);
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.025em;
    text-decoration: none;
  }

  .site-nav-mobile a > i {
    font-size: 1.25rem;
  }

  .site-nav-mobile a[aria-current] {
    color: var(--ink);
    background: var(--accent-wash);
  }

  .site-nav-mobile-count {
    position: absolute;
    top: 0.35rem;
    left: calc(50% + 0.35rem);
    display: grid;
    place-items: center;
    min-width: 1.05rem;
    height: 1.05rem;
    padding: 0 0.2rem;
    border-radius: 999px;
    background: var(--accent);
    color: var(--accent-ink);
    font-size: 0.58rem;
    font-weight: 700;
  }
}

@media (prefers-reduced-motion: reduce) {
  .site-nav-account-chevron {
    transition: none;
  }
}

/* --- The installed app has no browser chrome to sit on -------------------- */

/* In a browser tab, Safari's own toolbar occupies the bottom of the screen and
   the mobile nav rests on it. Added to the home screen there is nothing there,
   and the nav's tap targets end up in the strip iOS reserves for the
   home-indicator swipe - so reaching for "Orders" pulls the app to the
   background instead (Greg, 2026-08-15, iPhone).

   The `env(safe-area-inset-bottom)` already in the padding above does NOT
   cover this on its own: env() resolves to zero unless the page asks for
   `viewport-fit=cover`, and this site deliberately does not. Asking for it
   would hand the whole layout responsibility for every inset on every screen
   - the top nav would slide under the status bar the same day - to fix one
   bar at the bottom. So the inset stays in the calc for the day that changes,
   and the fixed cushion is what actually does the work today.

   Scoped to display-mode: standalone, which is exactly the condition that
   causes it. A browser tab is untouched, so the ordinary mobile site cannot
   regress from this. */
@media (display-mode: standalone) {
  .site-nav-mobile a {
    padding-bottom: calc(0.72rem + 1.25rem + env(safe-area-inset-bottom));
  }
}

/* The two docks have the same problem in the same strip, and their rule lives
   in site.css - which base.html loads AFTER this file, so an override written
   here would lose on source order and do nothing at all. It is at the bottom
   of site.css beside the rules it is overriding. */
