/* Site header: the logo, the refresh button, the faux address bar, the credential
   dropdown behind it, and the site nav.

   THE SOURCE OF TRUTH FOR EVERY defaultcreds.lol SURFACE. The apex site, the guides
   subdomain and the podcast player all load this exact file, and all take their header
   markup from partials/header.html. Edit either one, then run

       .venv/bin/python scripts/build-header.py

   and the change lands on all three. honeypot/tests/test_header.py fails the suite when a
   page has drifted from the partial, so keeping them in step is not anyone's job to
   remember.

   Self-contained on purpose. The three sites ship three different stylesheets with three
   different sets of design tokens, so a header that borrowed each site's tokens would go
   on looking different on each site, which is the thing this file exists to stop. Every
   value the header needs is declared below as --hdr-*, scoped to .site-header so it
   cannot reach the rest of the page, and this file is linked last so it wins the cascade
   against whatever the host stylesheet says.

   --header-height is the one token left unprefixed and on :root, because it is genuinely
   shared: the apex sidebar and main column offset themselves against the header, and
   guides.css sizes its own layout from it. It is defined here and nowhere else.
*/

:root {
  --header-height: 64px;
}

.site-header {
  --hdr-max: 1280px;
  --hdr-color-bg: #121212;
  --hdr-color-bg-elevated: #1e1e1e;
  --hdr-color-bg-hover: #2a2a2a;
  --hdr-color-text: #e5e5e5;
  --hdr-color-text-secondary: #a0a0a0;
  --hdr-color-text-muted: #6b6b6b;
  --hdr-color-border: #2e2e2e;
  --hdr-color-border-strong: #404040;
  --hdr-color-accent: #22c55e;
  --hdr-color-accent-soft: rgba(34, 197, 94, 0.15);
  --hdr-color-success: #34d399;
  /* Orange, not the amber the rest of the palette uses for warnings. The honeypot
     pages already overrode it to this and they are the ones to match. */
  --hdr-color-warning: #fb923c;
  --hdr-font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --hdr-font-mono: 'JetBrains Mono', 'Fira Code', 'SF Mono', Consolas, monospace;
  /* The same size as -sm, on purpose. The group labels and page addresses in the dropdown
     used this token while nothing declared it, so they inherited the dropdown's 0.875rem,
     and that is the size they have always been read at. A smaller declared value would
     shrink them below what the readability floor allows. Phones size the address row down
     on their own, in the max-width: 768px block below. */
  --hdr-text-xs: 0.875rem;
  --hdr-text-sm: 0.875rem;
  --hdr-space-1: 0.25rem;
  --hdr-space-2: 0.5rem;
  --hdr-space-3: 0.75rem;
  --hdr-space-4: 1rem;
  --hdr-space-6: 1.5rem;
  --hdr-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
  --hdr-transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
  --hdr-transition-base: 200ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* --- Site Header --- */
.site-header {
  position: sticky;
  top: 0;
  /* Must out-rank .sidebar (z:100). The faux-URL dropdown (#creds-history) is
     a descendant of this header's stacking context, so whatever z-index the
     dropdown carries is clamped by this root. When the dropdown extends
     downward past the header and overlaps the pinned sidebar, the header
     subtree needs to win the paint order. See AUDIT.md F053. */
  z-index: 110;
  background: var(--hdr-color-bg-elevated);
  border-bottom: 1px solid var(--hdr-color-border);
  height: var(--header-height);
}

/* Square corners, on every surface. The board pages force them with a blanket rule of their
   own (honeypot.css), and /news, the guides and the podcast player have none, so the header
   carries its own, down to the padlocks creds.js draws in the dropdown with rx="2". */
.site-header,
.site-header *,
.site-header *::before,
.site-header *::after {
  border-radius: 0;
}

.site-header svg rect {
  rx: 0;
  ry: 0;
}

.header-content {
  display: flex;
  align-items: center;
  gap: var(--hdr-space-4);
  /* One width on every surface. It used to be 1600 here and 1280 on the honeypot pages,
     which overrode it, so the header ran wider on news, guides and the podcast player
     than on the two pages it was designed against. 1280 is the one that looked right. */
  max-width: var(--hdr-max);
  margin: 0 auto;
  padding: 0 var(--hdr-space-6);
  height: 100%;
}

.logo {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--hdr-color-border);
  background: var(--hdr-color-bg-elevated);
  color: var(--hdr-color-text-secondary);
  text-decoration: none;
  transition: all var(--hdr-transition-fast);
}

.logo:hover {
  background: var(--hdr-color-bg-hover);
  color: var(--hdr-color-text);
  border-color: var(--hdr-color-border-strong);
}

.logo:focus-visible {
  outline: 2px solid var(--hdr-color-accent);
  outline-offset: 2px;
}

.logo-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  stroke-width: 2;
}

.refresh-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  margin: 0;
  border: 1px solid var(--hdr-color-border);
  background: var(--hdr-color-bg-elevated);
  color: var(--hdr-color-text-secondary);
  cursor: pointer;
  transition: all var(--hdr-transition-fast);
  font-family: inherit;
  font-size: inherit;
}

.refresh-btn:hover {
  background: var(--hdr-color-bg-hover);
  color: var(--hdr-color-text);
  border-color: var(--hdr-color-border-strong);
}

.refresh-btn:active {
  background: var(--hdr-color-bg);
}

.refresh-btn:focus-visible {
  outline: 2px solid var(--hdr-color-accent);
  outline-offset: 2px;
}

.refresh-btn svg {
  width: 18px;
  height: 18px;
  color: inherit;
  stroke: currentColor;
}

.address-bar-wrapper {
  position: relative;
  flex: 1;
  max-width: 600px;
  /* min-width: auto would be the min-content width of the faux URL, and
     creds.js picks a random pair up to ~590px wide. With the nav competing
     for the row that refused to shrink and pushed the header past the
     viewport between 769 and 1024px. The .url-text ellipsis handles the
     overflow once the wrapper is allowed to shrink. */
  min-width: 0;
}

.faux-url {
  display: flex;
  align-items: center;
  gap: var(--hdr-space-2);
  font-family: var(--hdr-font-mono);
  font-size: var(--hdr-text-sm);
  padding: var(--hdr-space-2) var(--hdr-space-3);
  background: var(--hdr-color-bg-elevated);
  border: 1px solid var(--hdr-color-border);
  cursor: pointer;
  transition: all var(--hdr-transition-base);
  user-select: none;
  /* No floor. A 280px minimum here outgrew its wrapper, which shrinks with the row, and
     between 769 and 960px the bar ran underneath the nav: at 769px it reached 175px into the
     links. The URL ellipsises instead (.url-text). */
  min-width: 0;
  position: relative;
  z-index: 1;
}

.faux-url:hover {
  background: var(--hdr-color-bg-hover);
  border-color: var(--hdr-color-border-strong);
}

.faux-url:focus,
.faux-url[aria-expanded="true"] {
  outline: none;
  border-color: var(--hdr-color-accent);
  box-shadow: 0 0 0 3px var(--hdr-color-accent-soft);
  background: var(--hdr-color-bg);
}

.faux-url[aria-expanded="true"] {
  border-bottom-color: transparent;
}

.address-bar-icon {
  flex-shrink: 0;
  color: var(--hdr-color-success);
  opacity: 0.8;
}

.url-text {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.address-bar-dropdown-icon {
  flex-shrink: 0;
  color: var(--hdr-color-text-muted);
  opacity: 0.6;
  transition: transform var(--hdr-transition-fast);
}

.faux-url[aria-expanded="true"] .address-bar-dropdown-icon {
  transform: rotate(180deg);
  opacity: 1;
}

.url-protocol { color: var(--hdr-color-accent); }
.url-creds { color: var(--hdr-color-text-secondary); }
.url-password { color: var(--hdr-color-warning); }
.url-host { color: var(--hdr-color-success); }
/* The path used to borrow .url-creds, which coloured it as though it were part of the
   credential. It is the only true part of the address, so it gets the plain text colour. */
.url-path { color: var(--hdr-color-text); }

/* --- Site Nav --- */
/* Palette-only, no radii: the honeypot pages' hard rules apply to this block unchanged, so
   no other page needs an exception for it. */
.site-nav {
  display: flex;
  align-items: center;
  gap: 20px;
  margin-left: auto;
  flex-shrink: 0;
}

.site-nav a {
  display: inline-flex;
  align-items: center;
  height: 40px;
  padding: 0 2px;
  font-family: var(--hdr-font-sans);
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--hdr-color-text-secondary);
  text-decoration: none;
  white-space: nowrap;
}

/* text-decoration again because the podcast player's stylesheet underlines a:hover, with a
   selector that ties with the one above and so leaves it to the order the sheets load in. */
.site-nav a:hover {
  color: var(--hdr-color-text);
  text-decoration: none;
}

/* Any value of aria-current: "page" on the page the link leads to, "true" on a page inside
   its section (an attack page under Attacks, a guide under Guides).
   The mark is a flat fill, never an underline, a bar or a line in the accent colour. The
   padding makes the fill a block around the label rather than a tint behind its letters, and
   the negative margin gives the extra width back: the link takes exactly the room in the row
   that every other link does (2px either side of its text), so nothing in the nav moves from
   one page to the next. No link carries a border, not even a transparent one: a transparent
   border is drawn in forced-colours mode, which would put a line under every label. */
.site-nav a[aria-current] {
  padding: 0 8px;
  margin: 0 -6px;
  color: var(--hdr-color-accent);
  background: var(--hdr-color-accent-soft);
}

.site-nav a:focus-visible {
  outline: 2px solid var(--hdr-color-accent);
  outline-offset: 2px;
}

/* Where six labels do not fit, the two other sites (scripts/build-header.py NARROW_HIDDEN)
   leave the inline nav. They stay in the address-bar dropdown, which lists every page at
   every width. Measured in Chromium and Firefox:
   - Beside the address bar (above 768px) the six take 505px in Inter, which leaves the bar
     under 280px below a 960px viewport. So they go from just above 768px to below 960px.
   - On their own row under the bar (768px and down) the six labels are 379px of Inter, and
     409px of DejaVu Sans, the widest fallback a reader without Inter is likely to get. The
     row is the viewport less 32px of padding, so from 480px there are at least 7px between
     labels in either font. Below 480px they go.
   The bounds are fractional because a viewport can be: browser zoom and display scaling
   give widths such as 768.18px. With integer bounds that width matched neither the phone
   layout's (max-width: 768px) nor (min-width: 769px), so all six sat beside an address bar
   squeezed to 141px. 768.02px and the .98s follow Bootstrap: .01 trips a rounding bug in
   Safari (https://bugs.webkit.org/show_bug.cgi?id=178261). */
@media (max-width: 479.98px), (min-width: 768.02px) and (max-width: 959.98px) {
  .site-nav .site-nav__more {
    display: none;
  }
}


/* --- Credentials History Dropdown --- */
.creds-history {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  width: 100%;
  background: var(--hdr-color-bg-elevated);
  border: 1px solid var(--hdr-color-accent);
  border-top: none;
  box-shadow: var(--hdr-shadow-lg);
  font-family: var(--hdr-font-mono);
  font-size: var(--hdr-text-sm);
  /* Never taller than the screen below the bar, so every entry can be scrolled to inside
     the list: the header is sticky, and a list running off the bottom of the viewport
     cannot be reached by scrolling the page. dvh where it exists, for phones whose
     toolbars change the visible height. */
  max-height: min(400px, calc(100vh - 72px));
  max-height: min(400px, calc(100dvh - 72px));
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  z-index: 201;
  /* Can't use var(--hdr-transition-base) here: it expands to "200ms cubic-
     bezier(...)", and combining that with ease-out would put two timing
     functions in the shorthand, making the whole declaration invalid and
     the animation a no-op. Duration written explicitly to match. */
  animation: slideDown 200ms ease-out;
  margin-top: -1px;
}

@keyframes slideDown {
  from {
    opacity: 0;
    transform: translateY(-8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.creds-history:not([hidden]) {
  display: block;
}

/* --- Pages group: the real destinations, above the joke credentials ---
   A browser's address bar drops down to history. This one drops down to history AND to
   somewhere you can actually go, which is the one place the joke and the navigation can
   sit together without either getting in the way. These are real anchors, rendered into
   the markup by scripts/build-header.py, so they work with scripting off. */
.creds-group {
  margin: 0;
  padding: var(--hdr-space-3) var(--hdr-space-4) var(--hdr-space-2);
  font-size: var(--hdr-text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--hdr-color-text-muted);
  background: var(--hdr-color-bg);
  border-bottom: 1px solid var(--hdr-color-border);
  user-select: none;
}

.creds-page {
  display: flex;
  align-items: baseline;
  gap: var(--hdr-space-3);
  padding: var(--hdr-space-3) var(--hdr-space-4);
  text-decoration: none;
  border-bottom: 1px solid var(--hdr-color-border);
  transition: background var(--hdr-transition-fast);
}

/* text-decoration again for the podcast player's a:hover underline, which outranks the
   rule above. */
.creds-page:hover,
.creds-page:focus-visible {
  background: var(--hdr-color-bg-hover);
  text-decoration: none;
}

/* The keyboard focus ring the nav links and the buttons have. Left out, the browser drew its
   own around every entry, the current page's included: Firefox's is its accent blue. Drawn
   inside the entry, because the list scrolls and clips anything outside its own edges. */
.creds-page:focus-visible,
.history-item:focus-visible {
  outline: 2px solid var(--hdr-color-accent);
  outline-offset: -2px;
}

/* The mark for where you are is this flat fill and the green label, the same fill as the
   nav's. Not a tick glyph: the row is a URL in a monospace address bar, and a glyph in the
   text would read as part of the address. Not a border or a bar either: a selected item is
   a filled block of colour. The grey line under the row is every row's separator. */
.creds-page[aria-current] {
  background: var(--hdr-color-accent-soft);
}

.creds-page[aria-current] .creds-page-label {
  color: var(--hdr-color-accent);
}

.creds-page-label {
  flex: 0 0 auto;
  min-width: 5.5rem;
  font-family: var(--hdr-font-sans);
  font-size: var(--hdr-text-sm);
  color: var(--hdr-color-text);
}

.creds-page-url {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--hdr-text-xs);
}

.history-item {
  display: flex;
  align-items: center;
  gap: var(--hdr-space-3);
  padding: var(--hdr-space-3) var(--hdr-space-4);
  cursor: pointer;
  transition: background var(--hdr-transition-fast);
  border-bottom: 1px solid var(--hdr-color-border);
  position: relative;
}

.history-item:last-child {
  border-bottom: none;
}

.history-item:hover {
  background: var(--hdr-color-bg-hover);
}

.history-item:active {
  background: var(--hdr-color-accent-soft);
}

.history-item-icon {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  color: var(--hdr-color-text-muted);
  opacity: 0.6;
}

.history-item-content {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.history-item-time {
  flex-shrink: 0;
  font-size: 10px;
  color: var(--hdr-color-text-muted);
  opacity: 0.7;
  margin-left: auto;
  padding-left: var(--hdr-space-2);
}

@media (max-width: 768px) {
  /* Side by side, the label's fixed column leaves the URL about 60px, which ellipsises to
     "https:…" and tells you nothing. Stacked, the URL gets the whole width, which is the
     only reason it is in the list. */
  .creds-page {
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
  }

  .creds-page-label {
    min-width: 0;
  }

  /* The dropdown is only as wide as the address bar, and on a phone that is about 180px.
     "https://" costs a third of it and carries no information the other four rows do not
     already repeat, so the host and path get the space instead. */
  .creds-page-url .url-protocol {
    display: none;
  }

  /* And a size down from there, which is what gets "defaultcreds.lol/sessions", the
     longest of the six, inside the width without an ellipsis. The label above it
     already carries the meaning, so this row only has to stay readable. */
  .creds-page-url {
    font-size: 0.6875rem;
  }

  :root {
    --header-height: 56px;
  }

  .header-content {
    padding: 0 var(--hdr-space-4);
  }

  /* The nav wraps onto its own strip under the header row: a line, then the 40px links.
     The header loses its fixed height so the strip fits; the first row keeps 56px via
     the 8px vertical margins on its children. */
  .site-header {
    height: auto;
    min-height: var(--header-height);
  }

  .header-content {
    flex-wrap: wrap;
    height: auto;
    row-gap: 0;
  }

  .header-content > :not(.site-nav) {
    margin-top: 8px;
    margin-bottom: 8px;
  }

  .site-nav {
    flex-basis: calc(100% + 2 * var(--hdr-space-4));
    justify-content: space-between;
    gap: 0;
    /* As tall as the 40px links plus the line above them. A fixed 40px, under the
       border-box sizing every host stylesheet sets, gave the line one of the links' pixels:
       each link stood half a pixel proud of the strip at both edges, and the current
       link's fill ran over both grey lines. */
    height: auto;
    margin: 0 calc(-1 * var(--hdr-space-4));
    padding: 0 var(--hdr-space-4);
    border-top: 1px solid var(--hdr-color-border);
  }

  .site-nav a {
    font-size: 12px;
  }

  /* A narrower fill on this row, still 2px either side of the text in the row's layout.
     Spread across a 320px screen in DejaVu Sans Bold, the widest fallback a reader without
     Inter is likely to get, four labels sit under 4px apart, and the 6px the fill reaches out
     beside the address bar would run into the next label. 3px stays clear of it. */
  .site-nav a[aria-current] {
    padding: 0 5px;
    margin: 0 -3px;
  }

  .faux-url {
    font-size: 11px;
    padding: var(--hdr-space-1) var(--hdr-space-2);
  }

  .address-bar-wrapper {
    max-width: 200px;
    margin: 0 var(--hdr-space-2);
  }

  .address-bar-icon,
  .address-bar-dropdown-icon {
    display: none;
  }
}

/* Previously in honeypot.css, where it applied to two pages out of seven. It is part of how
   the header behaves, so it belongs with the rest of it. .is-busy is set by the apex board's
   own script; elsewhere it is simply never set. */
.refresh-btn.is-busy svg {
  animation: hdr-refresh-spin 600ms linear 1;
}

@keyframes hdr-refresh-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .refresh-btn.is-busy svg {
    animation: none;
  }
}
