/**
 * plugins/themes/soilweb/styles/site-header.css
 *
 * THE site header, for every page that is not the public frontend: the OJS
 * backend layout (dashboards, submission wizard, workflow, settings, admin)
 * and the /cabinet pages. Markup: templates/soilweb/site-header.tpl.
 *
 * Why plain CSS and not Tailwind
 * -----------------------------
 * The public header (templates/frontend/components/header.tpl) is written in
 * Tailwind utilities, and the OJS **backend context does not load Tailwind** —
 * only fonts.css, backend-palette.css and backend.css. A utility class there
 * is not "mostly fine", it is INERT, which fails in the worst direction:
 * `hidden` stops hiding, `w-5 h-5` stops constraining, and an <svg> with a
 * viewBox and no width paints at its intrinsic 960px. So every rule the shared
 * header needs is spelled out here, and this file is registered in BOTH
 * contexts (see SoilWebThemePlugin::init) so the cabinet and the backend get
 * byte-identical chrome.
 *
 * Values are the same design tokens the public header compiles to
 * (theme/tailwind.config.js): forest-deep #0D211B, primary #01261F,
 * sprout-vibrant #27AE60, on-surface-variant #414846, label-caps
 * 12px/16px/0.1em/700, headline-md Montserrat 24px.
 *
 * No JavaScript of its own. js/main.js is frontend-only, and inside the backend
 * any listener it attached to this markup would be dropped the moment Vue
 * mounts #app and re-renders its subtree — so the language panel opens on
 * :hover/:focus-within in CSS alone, which is also the no-JS fallback the
 * public header ships.
 *
 * The one exception is the scrolled state at the end of this file: it reads
 * `html.is-scrolled`, which js/scroll-state.js sets. That file is the ONE
 * script registered in the backend context too (see SoilWebThemePlugin::init),
 * precisely because it writes to <html> — outside #app, so a Vue re-render
 * cannot wipe it — and its listener is on `window`, not on the header. If it
 * never runs, the bar simply never elevates: purely cosmetic, and every
 * disclosure above still works.
 */

:root {
    /* 80px, not the public header's 75px: /cabinet's sticky rail offsets and
       qa/tests/cabinet-fidelity.spec.js are both keyed to an 80px topbar, and
       the 5px is imperceptible next to matching identity, type and controls.
       Kept at 80px on mobile too — that same test asserts the height at 390px. */
    --swh-h: 80px;
    --swh-max: 1280px;
    --swh-pad: 32px;

    --swh-paper: #FFFFFF;
    --swh-forest: #0D211B;
    --swh-primary: #01261F;
    --swh-sprout: #27AE60;
    /* Nav label colour on hover and for the current page. NOT the mockup's
       secondary-fixed-dim (#7adaa1): that pale green is 1.7:1 on paper-white
       and the mockup only ever paints it over the dark hero. This is the same
       #006d41 the public header now uses. */
    --swh-secondary: #006D41;
    --swh-ink: #1A1C1F;
    --swh-ink-soft: #414846;
    --swh-hairline: rgba(13, 33, 27, .10);
    --swh-outline: rgba(193, 200, 196, .30);
    --swh-low: #F3F3F7;
    --swh-shadow: 0 8px 32px rgba(13, 33, 27, .08);

    /* The bar's own motion, matching the public header (src/theme.css) and the
       mockup it came from. */
    --swh-ease: cubic-bezier(.4, 0, .2, 1);
    --swh-dur: .3s;

    --swh-body: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --swh-display: 'Montserrat', system-ui, sans-serif;
}

/* ===================================================================== *
 * The bar
 * ===================================================================== */
header.swh {
    position: sticky;
    top: 0;
    /* Horizontal pin as well as vertical, plus a viewport clamp. Core's backend
       stretches the whole page past a phone viewport on its own — body carries
       min-width:fit-content and the submissions table is ~930px, so the document
       scrolls sideways with core's header too (measured: deleting this header
       from a live 390px dashboard leaves the overflow byte-identical at 864px;
       see qa/DEFECTS.md D-HDR-1). As a block child of that stretched page the bar
       inherited its 1254px width, which pushed the locale switcher, the task and
       notification bells and the CTA off screen — core's own .app__header had the
       same fault. `left: 0` pins the bar to the viewport's left edge during that
       horizontal scroll; the clamp keeps it exactly as wide as what is visible,
       so every control stays reachable.

       max-width, NOT width. `width: 100vw` would be a bug: 100vw includes the
       classic vertical scrollbar, so on the many backend pages that DO fit it
       would make the bar wider than the content box and introduce a horizontal
       scrollbar of its own. A max-width can only ever shrink a box, so on a page
       that fits this line does nothing at all. */
    left: 0;
    max-width: 100vw;
    z-index: 50;
    display: block;
    /* --swh-h is the height of the WHOLE bar, hairline included. Without
       border-box the 1px border-bottom is added on top of min-height and the
       bar measures 81px, which fails cabinet-fidelity's exact TOPBAR_H check. */
    box-sizing: border-box;
    min-height: var(--swh-h);
    padding: 0;
    background: rgba(255, 255, 255, .92);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--swh-hairline);
    box-shadow: 0 1px 2px rgba(13, 33, 27, .05);
    font-family: var(--swh-body);
    color: var(--swh-ink);
}
/* backend.css gives .app__header its own 32px inline padding and a flex row;
   the inner element owns both now, so neutralise them (0,2,1 beats 0,1,0). */
header.swh.app__header {
    padding-inline: 0;
    gap: 0;
    font-size: 1rem;
}

.swh__inner {
    display: flex;
    align-items: center;
    gap: 16px;
    width: 100%;
    max-width: var(--swh-max);
    /* Content row = bar height less the hairline, so the two add up to
       exactly --swh-h rather than one pixel more. */
    min-height: calc(var(--swh-h) - 1px);
    margin-inline: auto;
    padding-inline: var(--swh-pad);
    box-sizing: border-box;
}

.swh__sr {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ===================================================================== *
 * Brand — the flexible element in the row, exactly as on the public site:
 * it is what gives way when a long ru/uz nav needs the space.
 * ===================================================================== */
.swh__brand {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
    flex: 1 1 auto;
}
header.swh .swh__wordmark {
    flex-shrink: 0;
    font-family: var(--swh-display);
    font-size: 24px;
    line-height: 32px;
    font-weight: 700;
    letter-spacing: -.02em;
    color: var(--swh-primary);
    text-decoration: none;
    transition: color .2s;
}
header.swh .swh__wordmark:hover,
header.swh .swh__wordmark:focus-visible { color: var(--swh-sprout); }

/* The institute's emblem, ahead of the wordmark — same order as the public
   header. Its size is declared HERE and not on the element: this bar is
   rendered in the backend too, which loads no Tailwind, so a `h-10` class
   would be inert and the <img> would paint at its natural 264px and push the
   whole row off the bar. The public header's pair (h-10, md:h-12) is matched
   with a two-step rule so the two bars agree at every breakpoint. */
.swh__brandLogo {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
    text-decoration: none;
}
.swh__brandLogo > img {
    display: block;
    height: 40px;
    width: auto;
}
@media (min-width: 768px) {
    .swh__brandLogo > img { height: 48px; }
}

/* ===================================================================== *
 * Primary nav — same items as the public header (it is the same
 * NavigationMenu), same label-caps type, same sprout underline on hover.
 * shrink-0 so nowrap labels never paint over the actions.
 * ===================================================================== */
.swh__nav { display: flex; align-items: center; flex-shrink: 0; }

.swh__navList {
    display: flex;
    align-items: center;
    gap: 20px;
    margin: 0;
    padding: 0;
    list-style: none;
}
@media (min-width: 1536px) { .swh__navList { gap: 28px; } }

.swh__navItem { position: relative; list-style: none; }

header.swh .swh__navItem > a {
    display: block;
    white-space: nowrap;
    /* transparent top border balances the active/hover underline, so marking
       an item never shifts the row by 2px (the public header's trick). */
    border-block: 2px solid transparent;
    padding-block: 4px;
    font-family: var(--swh-body);
    font-size: 12px;
    line-height: 16px;
    letter-spacing: .1em;
    font-weight: 700;
    text-transform: uppercase;
    color: var(--swh-ink-soft);
    text-decoration: none;
    transition: color var(--swh-dur) var(--swh-ease),
                border-color var(--swh-dur) var(--swh-ease);
}
header.swh .swh__navItem > a:hover,
header.swh .swh__navItem > a:focus-visible,
header.swh .swh__navItem.is-current > a,
header.swh .swh__navItem > a[aria-current="page"] {
    color: var(--swh-secondary);
    border-bottom-color: var(--swh-sprout);
}

/* Second level: hover/focus flyout, same geometry and motion as the public
   header's.

   The panel is the <ul>. Radius, border and shadow belong to one box rather
   than to a stack of <li>s styled to look like a box — which is what this
   file used to do, and it could only ever approximate the mockup's corners.

   The 8px gap under the trigger is inside neither the item nor the panel, so
   a pointer crossing it would leave the hover target and the panel would shut
   before it could be reached. The ::before bridge spans exactly that 8px. */
.swh__navItem > ul {
    position: absolute;
    inset-inline-start: 0;
    top: 100%;
    margin: 8px 0 0;
    min-width: 14rem;
    padding: 8px 0;
    list-style: none;
    z-index: 60;
    background: var(--swh-paper);
    border: 1px solid var(--swh-outline);
    border-radius: 8px;
    box-shadow: var(--swh-shadow);
    visibility: hidden;
    opacity: 0;
    transform: translateY(8px);
    /* visibility is delayed, not toggled: flipping it outright would cut the
       fade-out dead, and transitioning it without a delay would hold the panel
       on screen for 150ms after the fade. */
    transition: opacity var(--swh-dur) var(--swh-ease),
                transform var(--swh-dur) var(--swh-ease),
                visibility 0s linear var(--swh-dur);
}
.swh__navItem > ul::before {
    content: '';
    position: absolute;
    inset-inline: 0;
    top: -8px;
    height: 8px;
}
.swh__navItem:hover > ul,
.swh__navItem:focus-within > ul {
    visibility: visible;
    opacity: 1;
    transform: translateY(0);
    /* Opening zeroes the delay; it does not restate the transitions, which are
       the panel's own (above). The one thing the open state has to change is
       that `visibility` flips NOW instead of .3s from now. */
    transition-delay: 0s;
}

.swh__navItem > ul > li {
    display: block;
}
header.swh .swh__navItem > ul > li > a {
    display: block;
    padding: 8px 16px;
    border: 0;
    font-size: 14px;
    line-height: 20px;
    letter-spacing: 0;
    font-weight: 400;
    text-transform: none;
    color: var(--swh-ink);
    text-decoration: none;
    transition: background-color .15s, color .15s;
}
header.swh .swh__navItem > ul > li > a:hover {
    background: var(--swh-low);
    color: var(--swh-secondary);
}

/* ===================================================================== *
 * Actions
 * ===================================================================== */
.swh__actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}
@media (min-width: 768px) { .swh__actions { gap: 12px; } }

/* Backstop for EVERY icon in the bar, applied before the per-control rules
   below can refine it. The failure this guards against is not subtle: the
   backend context loads no Tailwind, so the `w-5 h-5` in the markup does
   nothing, and an <svg viewBox="0 -960 960 960"> with no intrinsic size paints
   960px wide and shoves the whole header off screen. Any icon added here later
   is therefore sized whether or not someone remembers to write a rule for it.
   Deliberately narrow: only svg that is a DIRECT child of one of our own
   controls, so core's Vue chrome (top-nav-actions, the journal-switcher
   <dropdown>) keeps the sizing backend.css gives it. */
header.swh .swh__actions > * > svg,
header.swh .swh__brand > * > svg { width: 20px; height: 20px; flex: 0 0 auto; }

/* Icon buttons. Sizes are declared on the <svg> itself, per element type:
   the markup's `class` attribute carries Tailwind names that are inert in the
   backend, and an unsized <svg viewBox="0 -960 960 960"> paints 960px wide.
   Scoped to our own controls so core's Vue chrome (top-nav-actions) keeps its
   own sizing. */
header.swh .swh__iconBtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    padding: 0;
    border: 0;
    border-radius: 9999px;
    background: transparent;
    color: var(--swh-ink-soft);
    text-decoration: none;
    cursor: pointer;
    transition: color .2s, background-color .2s;
}
header.swh .swh__iconBtn:hover {
    color: var(--swh-sprout);
    background: var(--swh-low);
}
header.swh .swh__iconBtn > svg { width: 20px; height: 20px; fill: currentColor; }

/* Language switcher — CSS-only disclosure (see the file header). */
.swh__lang { position: relative; }
header.swh .swh__langToggle {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 8px 10px;
    border: 0;
    border-radius: 9999px;
    background: transparent;
    font-family: var(--swh-body);
    font-size: 12px;
    line-height: 16px;
    letter-spacing: .1em;
    font-weight: 700;
    text-transform: uppercase;
    color: var(--swh-ink-soft);
    cursor: pointer;
    transition: color .2s, background-color .2s;
}
header.swh .swh__langToggle:hover,
.swh__lang:focus-within .swh__langToggle {
    color: var(--swh-sprout);
    background: var(--swh-low);
}
header.swh .swh__langToggle > svg { width: 18px; height: 18px; fill: currentColor; }
header.swh .swh__langToggle > svg.swh__chevron { width: 16px; height: 16px; }

.swh__langMenu,
.swh__userMenu {
    position: absolute;
    inset-inline-end: 0;
    top: 100%;
    margin: 8px 0 0;
    padding: 8px 0;
    min-width: 11rem;
    list-style: none;
    background: var(--swh-paper);
    border: 1px solid var(--swh-outline);
    border-radius: 8px;
    box-shadow: var(--swh-shadow);
    z-index: 60;
    /* Same disclosure language as the nav flyouts above: hidden by
       `visibility`, not `display`, so the panel can animate — and so its links
       still leave the tab order while it is closed. */
    visibility: hidden;
    opacity: 0;
    transform: translateY(8px);
    transition: opacity var(--swh-dur) var(--swh-ease),
                transform var(--swh-dur) var(--swh-ease),
                visibility 0s linear var(--swh-dur);
}
.swh__langMenu::before,
.swh__userMenu::before {
    content: '';
    position: absolute;
    inset-inline: 0;
    top: -8px;
    height: 8px;
}
.swh__userMenu { min-width: 13rem; max-width: 18rem; }
.swh__lang:hover .swh__langMenu,
.swh__lang:focus-within .swh__langMenu,
.swh__user:hover .swh__userMenu,
.swh__user:focus-within .swh__userMenu {
    visibility: visible;
    opacity: 1;
    transform: translateY(0);
    /* As on the flyouts above: the open state zeroes the delay and inherits the
       transitions from the panel's own rule. */
    transition-delay: 0s;
}

header.swh .swh__langMenu a,
header.swh .swh__userList a {
    display: block;
    padding: 8px 16px;
    border: 0;
    font-size: 14px;
    line-height: 20px;
    letter-spacing: 0;
    font-weight: 400;
    text-transform: none;
    white-space: nowrap;
    color: var(--swh-ink);
    text-decoration: none;
    transition: background-color .15s, color .15s;
}
header.swh .swh__langMenu a:hover,
header.swh .swh__userList a:hover {
    background: var(--swh-low);
    color: var(--swh-secondary);
}
header.swh .swh__langMenu a[aria-current] {
    background: var(--swh-low);
    color: var(--swh-secondary);
    font-weight: 600;
}
.swh__userList, .swh__userList ul {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    list-style: none;
}
.swh__userItem { list-style: none; }
header.swh .swh__userList > .swh__userItem > ul > li > a {
    padding-inline-start: 32px;
    color: var(--swh-ink-soft);
}

/* Sign-in (only reachable on a cabinet page opened without a session) */
header.swh .swh__signin {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 20px;
    border: 2px solid rgba(1, 38, 31, .10);
    border-radius: 12px;
    background: transparent;
    font-size: 12px;
    line-height: 16px;
    letter-spacing: .1em;
    font-weight: 700;
    text-transform: uppercase;
    color: var(--swh-primary);
    text-decoration: none;
    box-shadow: 0 1px 2px rgba(13, 33, 27, .05);
    white-space: nowrap;
    transition: all var(--swh-dur) var(--swh-ease);
}
header.swh .swh__signin:hover {
    border-color: var(--swh-sprout);
    background: var(--swh-primary);
    color: #FFFFFF;
    transform: scale(1.05);
}
header.swh .swh__signin:active {
    transform: scale(.95);
}
header.swh .swh__signin > svg { width: 18px; height: 18px; fill: currentColor; }

/* Primary CTA — the public header's .btn-primary, spelled out. */
header.swh .swh__cta {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 24px;
    border: 0;
    border-bottom: 2px solid var(--swh-sprout);
    border-radius: 8px;
    background: var(--swh-forest);
    font-size: 12px;
    line-height: 16px;
    letter-spacing: .1em;
    font-weight: 700;
    text-transform: uppercase;
    color: #FFFFFF;
    text-decoration: none;
    white-space: nowrap;
    transition: opacity .2s, box-shadow .2s;
}
header.swh .swh__cta:hover,
header.swh .swh__cta:focus-visible {
    opacity: .9;
    color: #FFFFFF;
    box-shadow: 0 4px 20px rgba(13, 33, 27, .04);
}

/* Focus ring — one visible state for every control in the bar. */
header.swh a:focus-visible,
header.swh button:focus-visible {
    outline: 2px solid var(--swh-sprout);
    outline-offset: 2px;
    border-radius: 4px;
}

/* Core Vue chrome kept in the bar: journal switcher, notifications, profile.
   They are the backend's only route to tasks/profile/logout, so they stay —
   just recoloured onto the paper-white bar. */
header.swh .app__headerAction,
header.swh .app__contexts { flex-shrink: 0; }
header.swh .app__headerAction > a,
header.swh .app__headerAction > button,
header.swh .pkpDropdown__button { color: var(--swh-ink-soft); }
header.swh .app__headerAction > a:hover,
header.swh .app__headerAction > button:hover { color: var(--swh-sprout); }

/* ===================================================================== *
 * Scrolled state.
 *
 * js/scroll-state.js puts `is-scrolled` on <html>; js/main.js is frontend-only
 * so this file needs its own registration for the backend context (see
 * SoilWebThemePlugin::init).
 *
 * The bar animates its shadow and background and NOT its height, unlike the
 * public header. This bar is `position: sticky`, so it is in flow: shortening
 * it by 16px would drag everything below it up by 16px in the middle of a
 * scroll — visible as a jump, and it would break the 80px topbar that
 * qa/tests/cabinet-fidelity.spec.js asserts as TOPBAR_H. The backdrop is only
 * 92% opaque, so the elevation still reads.
 * ===================================================================== */
header.swh {
    transition: box-shadow var(--swh-dur) var(--swh-ease),
                background-color var(--swh-dur) var(--swh-ease);
}
html.is-scrolled header.swh {
    background: rgba(255, 255, 255, .97);
    box-shadow: var(--swh-shadow);
}

/* ===================================================================== *
 * Responsive — the same breakpoints as the public header (xl for the nav,
 * lg for the CTA, sm for search). The nav has no hamburger drawer here:
 * a drawer needs JS, and both internal surfaces already ship their own
 * navigation (the backend's side rail, the cabinet's disclosure nav).
 * ===================================================================== */
@media (max-width: 1279px) { .swh__nav { display: none; } }
@media (max-width: 1023px) { header.swh .swh__cta { display: none; } }
@media (max-width: 767px) {
    .swh__inner { padding-inline: 20px; gap: 8px; }
    header.swh .swh__wordmark { font-size: 20px; }
}
@media (max-width: 639px) {
    header.swh .swh__search,
    header.swh .swh__signin { display: none; }
}

/* ===================================================================== *
 * Reduced motion — the whole set of transitions in this file switched off
 * at once, matching src/theme.css. The disclosures still open: `visibility`
 * flips instantly, so the state changes and only the journey to it is gone.
 * ===================================================================== */
@media (prefers-reduced-motion: reduce) {
    /* Base selectors only, and `!important` is what makes that enough: it
       outranks the open-state declarations (`:hover`, `:focus-within`) however
       specific they are, so listing those here as well would be a second copy
       of the same switch. */
    header.swh,
    .swh__navItem > ul,
    .swh__langMenu,
    .swh__userMenu,
    .swh__signin {
        transition: none !important;
    }

    .swh__navItem > ul,
    .swh__navItem:hover > ul,
    .swh__navItem:focus-within > ul,
    .swh__langMenu,
    .swh__lang:hover .swh__langMenu,
    .swh__lang:focus-within .swh__langMenu,
    .swh__userMenu,
    .swh__user:hover .swh__userMenu,
    .swh__user:focus-within .swh__userMenu {
        transform: none;
    }

    /* A hover transform is motion even when it cannot be animated: the sign-in
       button keeps its colour change and loses the 1.05 scale. */
    header.swh .swh__signin:hover,
    header.swh .swh__signin:active {
        transform: none;
    }
}
