.header {
  background-color: var(--color-bg);
  border-block-end: 1px solid var(--color-subtle);
  position: sticky;
  inset-block-start: 0;
  transition: transform 250ms ease;
  z-index: 40;
}

/* Auto-hide (TOP-style): the header-reveal controller hides this past the
   header's height, showing it again only at the very top. */
.header--hidden {
  transform: translateY(-100%);
}

/* The mobile sheet is a child of the header, so a hidden header would drag it
   off-screen with it. Outranks .header--hidden by specificity. */
.header:has(.header__menu[open]) {
  transform: none;
}

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

/* The top bar carries ONLY "use the product" links (Профессии · Практика ·
   Библиотека · Калькуляторы) — everything "about the project" lives in the
   footer. ONE exception, and only in the mobile sheet: a guest gets О проекте
   + Частые вопросы (.header__menu-guest). The rule guards the DESKTOP row,
   where space is scarce and the footer is one scroll away; in the sheet the
   footer is a whole catalog away and it's a guest's only nav. Inline nav shows
   ≥1024px; below that it collapses behind the hamburger so the row never
   wraps — nowrap is enforced in both compact blocks as a safety valve. */
.header__nav {
  align-items: center;
  column-gap: 1.5rem;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  min-block-size: var(--header-height);
  padding-block: 0.75rem;
  row-gap: var(--block-space-half);
}

.header__brand {
  margin-inline-end: auto;
}

/* Grouping via spacing, no dividers: nav words keep 1.5rem air; search +
   account read as one tight cluster, separated by the menu's trailing margin. */
.header__right {
  align-items: center;
  column-gap: 0.75rem;
  display: flex;
  row-gap: var(--block-space-half);
}

.header__menu {
  margin-inline-end: 0.75rem;
}

/* Icon-only search entry (Writebook pattern) — a quiet glyph among the nav
   words, always visible even when the nav collapses into the hamburger. */
.header__search {
  align-items: center;
  color: var(--color-ink);
  display: inline-flex;
  padding: 0.3rem;
}

.header__search .icon {
  block-size: 1.3rem;
  inline-size: 1.3rem;
}

.header__search[aria-current="page"] {
  color: var(--color-link);
}

/* Palette wrapper only scopes the Stimulus controller; the link must stay a
   direct flex item of .header__right. */
.header__palette {
  display: contents;
}

/* Desktop: the <details> disclosure is "transparent" — the toggle is hidden and
   the panel always renders as the inline nav row (overriding the UA rule that
   hides a closed <details>'s content). */
.header__menu-toggle {
  display: none;
}

.header__menu-panel {
  align-items: center;
  column-gap: 1.5rem;
  display: flex;
  flex-wrap: wrap;
  row-gap: var(--block-space-half);
}

/* The UA hides a closed <details>' content instantly via ::details-content
   (content-visibility). Turn that off at every width: the desktop inline row
   must show while the <details> is closed, and the mobile dropdown's exit
   animation needs the content to survive until the fade finishes — hiding is
   ours, via the panel's display rule in the ≤819px block below. */
.header__menu::details-content {
  content-visibility: visible;
}

/* Desktop default: account section, guest orientation group, the drawer's ✕,
   its brand slot and the signup row are hidden (the inline nav row, the CTA
   pill and the popover button are used instead). */
.header__menu-account,
.header__menu-guest,
.header__menu-close,
.brand.header__menu-brand, /* must outgun .brand's display, declared below */
.header__menu-signup {
  display: none;
}

.brand {
  --brand-mark-height: 1.3em;
  align-items: center;
  color: var(--color-ink);
  column-gap: 0.5rem;
  display: inline-flex;
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  text-decoration: none;
  text-transform: none;
}

/* Brand lockup: the RJ45 mark "plugs into" the wordmark. The mark scales with
   the wordmark via an em-based height; the source PNG is far larger than any
   render size, so it stays crisp on hi-dpi. */
.brand__mark {
  display: block;
  height: var(--brand-mark-height);
  width: auto;
}

.nav__link {
  font-size: 0.9rem;
  position: relative;
}

/* Nav icons exist for the mobile dropdown (they match the palette tiles);
   the desktop inline row stays words-only. */
.nav__link .icon {
  display: none;
}

/* "You are here" — quiet cue via weight + brightness, no underline. */
.nav__link[aria-current="page"] {
  color: var(--color-ink);
  font-weight: 600;
}

/* Off-screen holder for the shared hand-drawn <path> (referenced via <use>). */
.svg-defs {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* Hand-drawn underline that draws itself in on hover/focus of a desktop nav word
   (CodeMyUI technique: one shared <path>, reused per link via <use>, revealed by
   animating stroke-dashoffset — a big absolute dash sidesteps the non-scaling-stroke
   marching artifact). Same blue + hand-drawn language as the hero underline.
   Absolute, so it never shifts the row; hidden on the mobile sheet below. */
.nav__link .nav__underline {
  display: block;
  position: absolute;
  left: 0;
  inline-size: 100%;
  block-size: 0.6em;
  inset-block-end: -0.26em;
  overflow: visible;
  pointer-events: none;
  stroke: var(--color-link);
  stroke-width: 2;
  stroke-dasharray: 650;
  stroke-dashoffset: 650;
}

.nav__link:hover .nav__underline,
.nav__link:focus-visible .nav__underline {
  stroke-dashoffset: 0;
}

@media (prefers-reduced-motion: no-preference) {
  .nav__link .nav__underline {
    transition: stroke-dashoffset 420ms ease-out;
  }
}

/* Identity header inside the hamburger dropdown — mobile-only (desktop shows
   it in the account popover instead). Scoped selector: it must outrank
   .account-menu__header's display:flex, which the element also carries. */
.header__menu-panel .header__menu-identity {
  display: none;
}

/* ── Account menu (Fizzy-style hub): one name button, one popover ────── */
.account-menu-button {
  align-items: center;
  background: none;
  position: relative; /* anchors the corner notify-dot */
  border: 1px solid var(--color-subtle);
  border-radius: 999px;
  color: var(--color-ink);
  cursor: pointer;
  display: inline-flex;
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  gap: 0.35em;
  padding: 0.35em 0.9em;
  transition: border-color 150ms ease, background-color 150ms ease;

  .icon {
    block-size: 0.9em;
    color: var(--color-subtle-dark);
    inline-size: 0.9em;
  }

  .avatar {
    --avatar-size: 1.4rem;
  }

  @media (any-hover: hover) {
    &:hover {
      background-color: var(--color-subtle-light);
      border-color: var(--color-subtle-dark);
    }
  }
}

/* Native popover: the top layer ignores ancestors, so it positions against
   the viewport — but the button sits at the right edge of the centered 72rem
   .container, not of the viewport. Mirror the container math
   ((100vw - max-width) / 2 + its padding per breakpoint) so the menu hangs
   under the button at any window width. */
.account-menu {
  background-color: var(--color-subtle-light);
  border: 1px solid var(--color-subtle);
  border-radius: 0.75em;
  box-shadow:
    0 12px 32px -8px oklch(var(--lch-always-black) / 0.5),
    0 4px 8px -4px oklch(var(--lch-always-black) / 0.4);
  color: var(--color-ink);
  inset: 3.9rem max(1rem, calc((100vw - 72rem) / 2 + 1rem)) auto auto;
  margin: 0;
  min-inline-size: 15rem;
  padding: var(--block-space-half);
  position: fixed;
  transform-origin: top right; /* grows out from under its trigger, not the centre */

  @media (min-width: 640px) {
    inset-inline-end: max(1.5rem, calc((100vw - 72rem) / 2 + 1.5rem));
  }

  @media (min-width: 1024px) {
    inset-inline-end: max(2rem, calc((100vw - 72rem) / 2 + 2rem));
  }
}

.account-menu__header {
  align-items: center;
  border-block-end: 1px solid var(--color-subtle);
  display: flex;
  gap: 0.6rem;
  margin-block: 0 var(--block-space-half);
  padding: var(--block-space-half) 0.6rem 0.75rem;

  .avatar {
    --avatar-size: 2.25rem;
  }
}

.account-menu__identity {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-inline-size: 0;
}

.account-menu__name {
  align-items: center;
  display: flex;
  font-weight: 600;
  gap: 0.4rem;
}

/* The quiet role mark (Эксперт/Администратор) — visible only to its owner,
   inside the opened menu; deliberately not in the always-on header chrome. */
.account-menu__role {
  font-size: 0.65rem;
}

.account-menu__email {
  color: var(--color-subtle-dark);
  font-size: 0.8rem;
}

.account-menu__nav {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}

.account-menu__link {
  align-items: center;
  background: none;
  border: 0;
  border-radius: 0.5em;
  color: var(--color-subtle-dark);
  cursor: pointer;
  display: flex;
  font: inherit;
  font-size: 0.9rem;
  gap: 0.6rem;
  inline-size: 100%;
  padding: var(--block-space-half) 0.6rem;
  text-align: start;
  text-decoration: none;
  transition: background-color 150ms ease, color 150ms ease;

  .icon {
    block-size: 1.05rem;
    inline-size: 1.05rem;
  }

  @media (any-hover: hover) {
    &:hover {
      background-color: var(--color-subtle);
      color: var(--color-ink);
    }
  }
}

/* The admin/editor workspace link: first in the list, brighter than the personal
   items, with a hairline separating work from personal.

   The hairline FLOATS in the gap below the row instead of being the row's border.
   As a border it sat inside the hover fill and forced square bottom corners, so the
   fill came out lopsided — taller at the bottom (padding was 0.5rem/0.65rem),
   rounded on top, cut off underneath. The row is now the same symmetric pill as
   every other item, and the rule is a separator between groups, which is what it
   means. Same treatment for sign-out below, which had the mirror-image defect. */
.account-menu__link--work,
.account-menu__signout {
  position: relative;

  &::after {
    background-color: var(--color-subtle);
    block-size: 1px;
    content: "";
    inset-inline: 0;
    position: absolute;
  }
}

.account-menu__link--work {
  color: var(--color-ink);
  font-weight: 600;
  margin-block-end: 0.75rem;

  /* Centred in the gap it owns: its own margin plus the nav's row gap. */
  &::after {
    inset-block-end: -0.4375rem;
  }
}

/* button_to wraps sign-out in a form. Grid, so the single button stretches to the
   row's width in BOTH menus instead of shrinking to its label — the rows size
   themselves off their container, and a plain block form leaves the button
   content-width. */
.account-menu .button_to,
.header__menu-account .button_to {
  display: grid;
}

/* Sign-out sits after a hairline, like Fizzy's bottom row. */
.account-menu__signout {
  margin-block-start: 0.75rem;

  &::after {
    inset-block-start: -0.375rem;
  }
}

/* ── Mobile (≤819px): the nav collapses behind ONE menu ─────────────────
   Two quiet glyphs (search, ☰) + the CTA. The hamburger dropdown carries
   everything — identity header, nav, personal links — styled with the same
   row component as the desktop popover, so both read as one menu. This block
   stays LAST in the file: its overrides must win by source order. */
@media (max-width: 1023px) {
  /* Below the width where the full inline nav comfortably fits, collapse the
     nav words behind the hamburger — one clean row that can never wrap onto a
     second line. The brand wordmark STAYS here (there's room and it anchors the
     identity); only true phones drop it (the narrower block at the file's end). */
  .header__nav {
    column-gap: 0.6rem;
    flex-wrap: nowrap;
  }
  .header__right {
    column-gap: 0.5rem;
    flex-wrap: nowrap;
  }
  .header__cta.btn--small {
    white-space: nowrap;
  }

  /* Signed-in: the avatar button hides — the hamburger is the one account
     surface on mobile (its dropdown opens with the identity header). */
  .account-menu-button {
    display: none;
  }

  .header__menu {
    margin-inline-end: 0; /* the desktop words↔utilities separator has no job here */
    order: 1;             /* push the hamburger to the far-right corner, after the CTA */
    position: relative;
  }

  /* A bare glyph, same quiet treatment as the search icon next to it. */
  .header__menu-toggle {
    align-items: center;
    color: var(--color-ink);
    cursor: pointer;
    display: inline-flex;
    justify-content: center;
    list-style: none;
    padding: 0.3rem;
    position: relative; /* anchors the corner notify-dot */
  }
  .header__menu-toggle::-webkit-details-marker { display: none; }

  /* Open, the ✕ floating in the strip lands almost exactly on the veiled
     hamburger — hide the glyph while its job is taken. */
  .header__menu[open] .header__menu-toggle :is(.icon, .notify-dot) {
    opacity: 0;
  }
  .header__menu-toggle .icon {
    block-size: 1.4rem;
    inline-size: 1.4rem;
  }

  /* The sheet's ✕ sets the house rule — every touch control clears 44px. The
     compact header's three controls keep their quiet 30–33px look; an invisible
     overlay extends the hit area to the standard. */
  .header__search,
  .header__cta {
    position: relative;
  }
  .header__search::after,
  .header__menu-toggle::after {
    content: "";
    inset: -7px;
    position: absolute;
  }
  /* The CTA is already wide; growing it sideways would eat the search icon's
     share of the gap between them. */
  .header__cta::after {
    content: "";
    inset: -7px 0;
    position: absolute;
  }

  /* A full-height left drawer — The Odin Project's off-canvas menu
     (Overlays::DrawerComponent), adopted 2026-07-26 over the earlier bottom
     sheet. Same modal anatomy (veil, scroll-lock, ✕); the geometry trades the
     bottom sheet's thumb-arc reach for the app-drawer pattern every mobile
     user already knows. A ~4.5rem strip of the page stays visible and
     tappable on the right (TOP's `mr-16`), so the page never fully vanishes. */
  /* Geometry and spacing lifted verbatim from TOP's off-canvas menu:
     w-full max-w-xs (20rem) with an mr-16 (4rem) strip; the panel itself is
     flat — no border, no shadow, the veil does the separation. pt-3 pb-4,
     rows spaced by space-y-1. */
  .header__menu-panel {
    align-items: stretch;
    background-color: var(--color-subtle-light);
    flex-direction: column;
    /* A height-capped column must not wrap — flex would spill the overflow
       into a second column instead of scrolling it. */
    flex-wrap: nowrap;
    inline-size: min(20rem, calc(100vw - 4rem));
    inset-block: 0;
    inset-inline-start: 0;
    overflow-y: auto;
    padding: max(0.75rem, env(safe-area-inset-top)) 0
             max(1rem, env(safe-area-inset-bottom));
    position: fixed;
    row-gap: 0.25rem;
    z-index: 50;
  }

  /* The ✕ is a direct <details> child now (not inside the panel), so the
     closed state must hide it explicitly too. */
  .header__menu:not([open]) :is(.header__menu-panel, .header__menu-close) {
    display: none;
  }

  /* The inline nav's "Admin" context badge would stretch into a full-width banner
     here, and the identity row already names the role. Scoped to that badge alone:
     as a blanket `.badge` rule it also hid the role mark in the identity row, so
     the drawer and the popover disagreed about the same markup. */
  .header__menu-panel .header__context-badge {
    display: none;
  }

  /* The drawer slides in from the left edge it's anchored to (TOP's
     -translate-x-full → translate-x-0) — one straight slide, nothing scaled.
     allow-discrete holds `display` until the exit slide finishes. Gated on
     reduced-motion so the base transform never strands the menu. */
  @media (prefers-reduced-motion: no-preference) {
    .header__menu-panel {
      opacity: 0;
      transform: translateX(-100%);
      transition: var(--sheet-duration, 200ms) ease-in-out allow-discrete;
      transition-property: display, opacity, transform;
    }

    .header__menu[open] .header__menu-panel {
      opacity: 1;
      transform: translateX(0);
    }

    @starting-style {
      .header__menu[open] .header__menu-panel {
        opacity: 0;
        transform: translateX(-100%);
      }
    }
  }

  /* Backdrop — what turns the sheet into a mode instead of a floating block.
     It hangs off the SUMMARY on purpose: a click on it targets the toggle
     itself, so the native <details> flips shut. Hanging it off .header__menu
     would read as "inside" to the details controller's outside-click check and
     the sheet would never close. */
  .header__menu-toggle::before {
    /* TOP's veil verbatim: a plain dark:bg-black/70, no blur. */
    background-color: oklch(var(--lch-always-black) / 0.7);
    content: "";
    display: none;
    inset: 0;
    opacity: 0;
    position: fixed;
    z-index: 45;
  }

  .header__menu[open] .header__menu-toggle::before {
    display: block;
    opacity: 1;
  }

  @media (prefers-reduced-motion: no-preference) {
    .header__menu-toggle::before {
      /* TOP: transition-opacity ease-linear duration-200 */
      transition: var(--sheet-duration, 200ms) linear allow-discrete;
      transition-property: display, opacity;
    }

    @starting-style {
      .header__menu[open] .header__menu-toggle::before {
        opacity: 0;
      }
    }
  }

  /* TOP's close button verbatim: floats in the 4rem strip right of the panel
     (`absolute left-full top-0 w-16 justify-center pt-5`), white ✕ h-6 w-6,
     p-2.5 tap padding. Fixed to the viewport; a closed <details> hides it. */
  .header__menu-close {
    align-items: flex-start;
    background: none;
    border: 0;
    color: var(--color-ink);
    cursor: pointer;
    display: flex;
    inline-size: 4rem;
    inset-block-start: 0;
    inset-inline-start: min(20rem, calc(100vw - 4rem));
    justify-content: center;
    /* pt-5 on the strip minus the button's -m-2.5: icon lands 1.25rem down. */
    padding: 0.625rem 0 0;
    position: fixed;
    z-index: 50;
  }

  .header__menu-close .icon {
    block-size: 1.5rem;
    box-sizing: content-box;
    inline-size: 1.5rem;
    padding: 0.625rem;
  }

  /* TOP's logo slot: px-4 column, then nav mt-3 — but the full brand
     (mark + wordmark), reusing the header's .brand component. Guest only; a
     signed-in reader gets the identity row in this slot instead. */
  .brand.header__menu-brand {
    --brand-mark-height: 1.75rem;
    align-self: start;
    display: flex;
    margin: 0 1rem 0.75rem;
  }

  /* The ✕ lives in the strip now, not over the panel — the identity row only
     needs the same px-4 column as the logo slot. */
  .header__menu-panel .header__menu-identity {
    padding-inline: 1rem;
  }

  /* The page must not scroll under an open sheet — pure CSS, no controller. */
  html:has(.header__menu[open]) {
    overflow: hidden;
  }

  .header__menu-panel .header__menu-identity {
    display: flex;
  }

  /* Nav rows take the popover's row component: icon + label, same metrics —
     one visual language across the sheet, the popover and the palette.
     No [open] qualifier: the styles must hold during the exit fade too. */
  .header__menu-panel .nav__link {
    align-items: center;
    color: var(--color-subtle-dark);
    display: flex;
    font-size: 0.9rem;
    gap: 0.6rem;
    padding: var(--block-space-half) 0.6rem;
    transition: background-color 150ms ease, color 150ms ease;
  }
  .header__menu-panel .nav__link .icon {
    block-size: 1.05rem;
    display: block;
    inline-size: 1.05rem;
  }
  /* The hover underline is a desktop affordance — keep it out of the touch sheet. */
  .header__menu-panel .nav__link .nav__underline {
    display: none;
  }

  /* TOP's Nav::ItemComponent verbatim: rows are `px-2 py-2 text-base
     font-medium` inside a `px-2` container — square corners, fill inset
     0.5rem from the drawer edges, text starting at 1rem. Icons at their
     native 24px (w-6 h-6) with the mr-4 gap; scaling them down was what made
     them thin. */
  /* Rows run edge to edge, text indented by padding — the same anatomy the identity
     row and the guest pair already use ("sheds the row inset to run full width like
     the group dividers"). An inset pill instead gave the row three different left
     edges — divider at 0, fill at 0.5rem, icon at 1rem — which is what read as
     lopsided. Full-bleed, every horizontal edge in the sheet lines up.
     inline-size: auto (not the base row's 100%) so a row can't outgrow its column. */
  .header__menu-panel :is(.nav__link, .account-menu__link) {
    border-radius: 0;
    font-size: 1rem;
    font-weight: 500;
    gap: var(--block-space);
    inline-size: auto;
    margin-inline: 0;
    padding: var(--block-space-half) 1rem;
  }
  /* One tone quieter than the label (TOP: icon text-gray-400 vs label
     gray-300) — the icon accompanies, the word leads. Hover and the active
     row lift it back to the row's colour. */
  .header__menu-panel :is(.nav__link, .account-menu__link) .icon {
    block-size: 1.5rem;
    color: var(--color-disabled);
    inline-size: 1.5rem;
  }
  .header__menu-panel .nav__link[aria-current="page"] .icon {
    color: inherit;
  }
  @media (any-hover: hover) {
    .header__menu-panel :is(.nav__link, .account-menu__link):hover .icon {
      color: inherit;
    }
  }
  /* TOP's Nav::ItemComponent states: the active row is a filled pill
     (dark:bg-gray-700/60), hover fills quieter — hierarchy by fill, not
     just weight. */
  .header__menu-panel .nav__link[aria-current="page"] {
    background-color: oklch(var(--lch-gray) / 0.4);
    color: var(--color-ink);
    font-weight: 600;
  }

  @media (any-hover: hover) {
    .header__menu-panel :is(.nav__link, .account-menu__link):hover {
      background-color: oklch(var(--lch-gray) / 0.25);
      color: var(--color-ink);
    }
  }

  /* Account section under a hairline, ending with sign-out — same anatomy
     as the desktop popover. */
  /* TOP's group divider: a full-width hr with my-4 — 1rem of air on both
     sides of the hairline. */
  .header__menu-account,
  .header__menu-guest {
    border-block-start: 1px solid var(--color-subtle);
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    margin-block-start: var(--block-space);
    padding-block-start: var(--block-space);
  }

  /* The shared partial nests the rows in their own <nav>; the sheet keeps its
     roomier row rhythm rather than inheriting the popover's tighter one. */
  .header__menu-account .account-menu__nav {
    gap: 0.25rem;
  }


  /* TOP's guest pair (Get started + Sign in) sits under the last divider —
     the signup row opens the group and carries the hairline, which sheds the
     row inset to run full width like the group dividers (TOP's hr). */
  .header__menu-panel .header__menu-signup {
    border-block-start: 1px solid var(--color-subtle);
    display: flex;
    margin-block-start: var(--block-space);
    margin-inline: 0;
    padding-block-start: var(--block-space);
    padding-inline: 1rem;
  }

}

/* True phones: the wordmark would crowd the row beside search + CTA + ☰, so drop
   it and let the enlarged RJ45 mark stand as the identity. Stays LAST so it wins
   over the medium block above at these widths. */
@media (max-width: 599px) {
  .header__brand {
    --brand-mark-height: 1.7em;
  }
  .header__brand .brand__text {
    display: none;
  }
}
