/* Shared by the Jinja pages and the NiceGUI account/admin pages.
 * The header markup lives in templates/_header.html and is rendered by
 * both, so there is exactly one definition of how a header looks.
 * Per-tenant colours arrive as CSS custom properties from the page. */
* { box-sizing: border-box; }
    /* Long unbroken strings - a URL in an error, a call number - must wrap
       rather than push the page sideways. */
    body, .card, .meta { overflow-wrap: anywhere; }
    /* Sticky footer: the body fills the viewport and the footer is pushed to
       the bottom when the content is short, rather than floating mid-page. */
    html { min-height: 100%; }
    body {
      min-height: 100dvh; display: flex; flex-direction: column;
      /* Room for the fixed header and footer; the fallbacks cover a
         no-JavaScript load. */
      padding-top: var(--header-h, 64px);
      padding-bottom: var(--footer-h, 4.5rem);
      margin: 0; background: var(--canvas); color: var(--ink);
      font: 16px/1.6 var(--font);
      -webkit-font-smoothing: antialiased;
      font-feature-settings: "cv05" 1; /* Inter: single-storey l, clearer at small sizes */
    }
    h1, h2, h3, .display {
      font-family: var(--font-display);
      font-weight: 600; letter-spacing: -0.01em; line-height: 1.25;
    }
    /* Bibliographic titles read as the content they are, not as UI chrome. */
    .record-title {
      font-family: var(--font-display); font-size: 1.075rem; font-weight: 600;
      letter-spacing: -0.005em; text-decoration: none; display: inline-block;
      margin-bottom: .15rem;
    }
    .record-title:hover { text-decoration: underline; }
    .meta { font-size: .8125rem; color: var(--muted); font-variant-numeric: tabular-nums; }
    a { color: var(--link); }
    /* One header height across every page - public, account and admin. The
       account header sets the same value in pages/layout.py; changing one means
       changing both. min-height, not height, so the narrow layout can still
       drop the search box onto a second row. */
    header.site {
      background: var(--brand); color: var(--brand-ink); padding: 0 1rem;
      border-bottom: 1px solid var(--line);
      min-height: 64px; display: flex; align-items: center;
      /* Fixed for the same reason as the footer: it stays visible while
         scrolling. The body reserves --header-h, measured by static/chrome.js,
         because the header wraps to two rows on narrow screens. */
      position: fixed; top: 0; left: 0; right: 0; z-index: 21;
    }
    /* Three zones: identity left, search centred in the row, account links
       right. A grid rather than flex, so the middle stays optically centred
       even though the two sides are different widths. */
    header.site .bar {
      display: grid; gap: 1rem; width: 100%;
      /* The middle track is sized here, not by the search box: with an `auto`
         column a percentage width on the child resolves against a
         content-sized track, so the box silently stayed at its content width.
         Sides stay `auto` so they keep their content width - 1fr let them
         collapse and the wordmark wrapped to one letter per line. The middle
         grows to 1040px only if there is room. */
      grid-template-columns: auto minmax(0, 1040px) auto; align-items: center;
    }
    header.site .bar > .wordmark { justify-self: start; white-space: nowrap; }
    header.site .bar > .searchbox { width: 100%; }
    header.site .bar > .account-nav { justify-self: end; }
    /* Too narrow for three abreast: identity and links share the top row, the
       search box takes a full-width row of its own beneath them. */
    @media (max-width: 720px) {
      header.site { padding: .6rem 1rem; }
      header.site .bar { grid-template-columns: 1fr auto; }
      header.site .bar > .searchbox {
        grid-row: 2; grid-column: 1 / -1; width: 100%;
      }
    }
    header.site a { color: var(--brand-ink); text-decoration: none; font-weight: 600; }
    /* :focus-visible only - a mouse click should not ring every header link,
       just tabbing to it. Negative offset on .seg-item because .seg clips
       with overflow:hidden; an outward ring there was invisible, clipped by
       the very edge the segmented control sits against. */
    header.site a:focus-visible, header.site .seg-item:focus-visible {
      outline: 2px solid var(--brand-ink); outline-offset: 2px; border-radius: 2px;
    }
    header.site .seg-item:focus-visible {
      outline-offset: -2px; position: relative; z-index: 1;
    }
    /* Visually hidden until it receives keyboard focus - the first tab stop on
       every page, so tangentbordsanvändare need not tab through the whole
       header before reaching the content. */
    .skip-link {
      position: absolute; left: -9999px; top: 0; z-index: 100;
      background: var(--surface); color: var(--ink);
      padding: .6rem 1rem; border-radius: 0 0 var(--radius) 0;
      font: 600 .9rem var(--font);
    }
    .skip-link:focus { left: 0; }
    header.site .wordmark { font-family: var(--font-display); font-size: 1.15rem;
      letter-spacing: -0.01em; display: flex; align-items: center; }
    header.site .logo { max-height: 34px; width: auto; display: block;
      margin-right: .55rem; }
    .account-nav { display: flex; gap: .9rem; align-items: center; white-space: nowrap; }
    header.site .account-nav a { font-weight: 600; font-size: .9rem; }
    .langs { display: inline-flex; gap: .4rem; align-items: center; }
    .langs .globe { opacity: .7; flex-shrink: 0; }
    .seg {
      display: inline-flex; overflow: hidden;
      border: 1px solid color-mix(in srgb, var(--brand-ink) 25%, transparent);
      border-radius: var(--radius);
    }
    header.site .account-nav .seg-item {
      font: 600 .72rem var(--font); letter-spacing: .03em;
      padding: .2rem .45rem; line-height: 1.5;
      color: color-mix(in srgb, var(--brand-ink) 65%, transparent);
      text-decoration: none;
    }
    header.site .account-nav a.seg-item:hover {
      background: color-mix(in srgb, var(--brand-ink) 10%, transparent);
      color: var(--brand-ink);
    }
    header.site .account-nav .seg-item.current {
      background: var(--link); color: #fff;
    }
    .visually-hidden {
      position: absolute; width: 1px; height: 1px; overflow: hidden;
      clip-path: inset(50%); white-space: nowrap;
    }
    /* Same mark, size, colour and round flat-button behaviour as the sign-out
       control in the account area, so the header does not change shape when you
       cross between them. */
    .account-nav .icon-link {
      display: inline-flex; align-items: center; justify-content: center;
      width: 40px; height: 40px; border-radius: 50%;
      color: var(--link);
    }
    .account-nav .icon-link:hover { background: color-mix(in srgb, var(--link) 12%, transparent); }
    .searchbox { display: flex; gap: .5rem; }
    .searchbox input {
      flex: 1; min-width: 0;
      padding: .55rem .75rem; border-radius: var(--radius);
      font: 400 1rem var(--font); color: var(--ink);
      /* The field has to read as a field against the header, whatever colour a
         tenant picks for it: a tinted ground and a border mixed from the ink,
         rather than the near-white --line, which vanished on a white header. */
      background: var(--canvas);
      border: 1px solid color-mix(in srgb, var(--ink) 28%, transparent);
    }
    .searchbox input::placeholder { color: color-mix(in srgb, var(--ink) 55%, transparent); }
    .searchbox input:focus-visible {
      outline: 2px solid var(--link); outline-offset: 1px;
      background: var(--surface);
    }
    /* Scoped away from Quasar's controls: a bare `button` rule restyles
       every NiceGUI widget on the account and admin pages. */
    main.page button, header.site button, .btn {
      padding: .55rem .9rem; border: 0; border-radius: var(--radius);
      background: var(--accent); color: #fff; cursor: pointer;
      font: 600 .9rem var(--font); letter-spacing: .01em;
      text-decoration: none; display: inline-block;
    }
    a.btn, a.btn:hover { color: #fff; text-decoration: none; }
    /* Scoped: NiceGUI's page element is <main class="q-page">, so a bare
       `main` selector constrained the account and admin pages to 1100px
       and pulled their header in with them. */
    main.page {
      max-width: 1100px; margin: 0 auto; padding: 1.25rem 1rem 3rem;
      width: 100%; flex: 1 0 auto;
    }
    html, body { max-width: 100%; overflow-x: hidden; }
    /* Results come first in the DOM so mobile shows them without scrolling past
       the facet list; on desktop the sidebar is placed back on the left. */
    .layout { display: grid; grid-template-columns: 1fr; gap: 1rem; }
    .facets > summary {
      cursor: pointer; padding: .6rem .8rem; background: var(--surface);
      border: 1px solid var(--line); border-radius: var(--radius); font-weight: 600;
    }
    @media (min-width: 761px) {
      .layout { grid-template-columns: 240px 1fr; gap: 1.5rem; }
      .layout > aside { grid-column: 1; grid-row: 1; }
      .layout > div { grid-column: 2; grid-row: 1; }
      /* <details> renders open by default (see the template); on desktop the
         disclosure control is simply hidden. CSS cannot re-open a closed
         <details> in Chrome, so the open attribute has to come from the markup. */
      .facets > summary { display: none; }
    }
    .card {
      background: var(--surface); border: 1px solid var(--line);
      border-radius: var(--radius); padding: 1rem; margin-bottom: .75rem;
    }
    .muted { color: var(--muted); font-size: .875rem; }
    .facet li { font-variant-numeric: tabular-nums; }
    .facet h2 { font-family: var(--font); font-size: .6875rem; text-transform: uppercase;
      letter-spacing: .08em; font-weight: 600; color: var(--muted); margin: 0 0 .4rem; }
    .facet ul { list-style: none; margin: 0 0 1.25rem; padding: 0; }
    .facet li { margin: .15rem 0; font-size: .9rem; }
    /* Facet values are navigation, not emphasis: keep them in body ink so the
       accent colour stays meaningful on titles and actions. */
    .facet a { text-decoration: none; color: var(--ink); }
    .facet a:hover { color: var(--link); text-decoration: underline; }
    .facet .applied { font-weight: 700; color: var(--link); }
    .pill {
      display: inline-block; background: var(--canvas); border: 1px solid var(--line);
      border-radius: 999px; padding: .1rem .6rem; font-size: .75rem; color: var(--muted);
      margin-right: .3rem;
    }
    .htmx-request #results { opacity: .5; transition: opacity .1s; }

/* Account tabs: the centre zone on account pages, where public pages put the
   search box. Plain links, so the account header needs no JavaScript and uses
   the same markup as everything else. */
.tabs { display: inline-flex; gap: .25rem; justify-self: center; }
.tabs .tab {
  font: 600 .9rem var(--font); text-decoration: none;
  /* 65%, not 60%: measured 4.18:1 for the Sunet theme and 4.26:1 for the
     default navy theme against WCAG 1.4.3's 4.5:1 floor - both clear 65%. */
  color: color-mix(in srgb, var(--brand-ink) 65%, transparent);
  padding: .3rem .6rem; border-radius: var(--radius);
  border-bottom: 2px solid transparent;
}
.tabs .tab:hover { color: var(--brand-ink); }
.tabs .tab.current {
  color: var(--brand-ink); border-bottom-color: var(--link);
  border-bottom-left-radius: 0; border-bottom-right-radius: 0;
}
header.site .wordmark .suffix {
  font: 400 .8rem var(--font); opacity: .7; margin-left: .4rem;
}

/* Status text (form errors, admin outcome messages). Fixed literal colours,
   not theme tokens - these are semantic (error/success/warning), not brand -
   with a lightened dark-mode variant each, since the light values measured
   2.5-2.8:1 against the dark --surface. */
.status-error { color: #b91c1c; }
.status-success { color: #2f6b46; }
.status-warning { color: #8a5a12; }
@media (prefers-color-scheme: dark) {
  .status-error { color: #d57777; }
  .status-success { color: #789f87; }
  .status-warning { color: #ad8c59; }
}

/* Dark mode lightens --link only for body-text uses (record titles, footer
   links, the applied-facet marker), scoped to main.page/.site-footer so it
   never reaches header.site - .seg-item.current and .icon-link put --link on
   a background there, where lightening it would wreck the white-text
   contrast instead of helping it (the same trap as the --accent buttons,
   which is why --accent is not touched here either).
   45% white: measured 5.86:1 (default theme) and 6.99:1 (Sunet) against the
   dark --surface, both clear of WCAG 1.4.3's 4.5:1 - a tenant's own link
   colour was never guaranteed that against a canvas it was not chosen for. */
@media (prefers-color-scheme: dark) {
  /* :not(.btn): a.btn keeps the hardcoded white-on-accent pairing below -
     without the exclusion this rule's higher specificity (an extra type
     selector) overrode it, leaving "Beställ"/"Request" at 2.47:1. */
  main.page a:not(.btn), .site-footer .footer-links a, .facet .applied,
  body .logo-pick, body .logo-remove,
  /* The header now darkens too (see --brand/--brand-ink above), so its own
     use of --link as a foreground colour needs the same lightening -
     .seg-item.current and the account-nav sign-out icon are still fine
     unlit because --link is there a *background* under white text, not
     text on top of the (now dark) header. */
  header.site .account-nav .icon-link {
    color: color-mix(in srgb, var(--link) 45%, white);
  }
  /* body .logo-pick, not .logo-pick: apply_theme()'s inline <style> block
     sets the unconditional colour on the same class and loads after this
     stylesheet, so equal specificity would let it win regardless of the
     media query. The extra type selector breaks the tie. */
  body .logo-pick { border-color: color-mix(in srgb, var(--link) 45%, white); }
}

/* Footer, shared by both frontends. Sits below the content rather than being
   fixed: a library's opening hours should not eat a phone screen. */
.site-footer {
  /* Fixed, so it stays visible while scrolling. `sticky` cannot do this for a
     last child: it has no room below it inside its parent to travel, so it
     never pins. Being fixed takes it out of the flow, so the body reserves
     --footer-h (measured by static/footer.js) to keep content clear of it. */
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
  border-top: 1px solid var(--line);
  background: var(--surface);
  margin-top: 2rem;
  padding: 1.25rem 1rem;
}
.footer-inner {
  max-width: 1100px; margin: 0 auto;
  display: flex; flex-wrap: wrap; gap: .6rem 2rem;
  align-items: baseline; justify-content: space-between;
}
.footer-text {
  white-space: pre-wrap;
  font-size: .85rem; color: var(--muted); max-width: 60ch;
}
.footer-links { display: flex; flex-wrap: wrap; gap: 1rem; }
.footer-links a { font-size: .85rem; color: var(--link); text-decoration: none; }
.footer-links a:hover { text-decoration: underline; }

/* Real heading elements in the NiceGUI account/admin pages (see
   pages/layout.py:heading()), styled to match the plain-text section titles
   they replace rather than picking up h1-h3's serif display font - these are
   UI chrome, not bibliographic titles. */
.section-heading {
  font-family: var(--font); font-weight: 600; font-size: 1rem;
  line-height: 1.4; letter-spacing: normal; margin: 0;
}
