/*
    THE PAGE HEADER'S OWN STYLESHEET.

    Everything Components/Shared/PageHeader.razor needs and nothing else, in its own file rather than
    a section of utilities.css: the component, its stylesheet and its behaviour are one thing that
    ten screens wear, and a shared utility file is where a rule goes to be edited by somebody who has
    never opened the component. Its behaviour is js/ui/page-header.js.

    FIVE ROWS IN A FIXED ORDER - the way out, the name and its states, what can be done to it, what
    it measures, the way across - and then the page underneath. Cost of a page hand-rolling its own
    instead, which is what nine project screens used to do: five different title sizes for one
    project name, the actions level with the back link on one screen and level with the subtitle on
    the next, and the primary button moving under the pointer every time somebody walked the strip.

    NO SURFACE OF ITS OWN, and it must not grow one. The well is the page and the raised surface is
    for the cards below; a box around the header made a project the one screen in the product with a
    card inside a card, bounding nothing a reader was asking about. A title is not a container.

    WHAT IT DOES NOT OWN. .sv-back, .sv-btn, .sv-badge and .sv-project-nav are utilities several
    unrelated screens set, so they stay in utilities.css and this file composes them. Copying one in
    here to make the header self-contained would be the dual-presence defect wearing a tidy name.
*/

.sv-pagehead {
  min-width: 0;
}

/* ── The band ────────────────────────────────────────────────────────────────
   THE ROWS ARE STICKY AND THE BODY IS NOT, which is why they are wrapped. A sticky element sticks
   whole: with the body inside it the page would pin to the top of the window and scroll nothing.

   IT SITS UNDER THE SHELL'S UTILITY BAR, at that bar's own height, so the two stack into one
   continuous block of chrome. --sv-topbar-height rather than the number, because the shell owns
   that measurement and this file must not be a second place it is written down.

   IT BREAKS OUT OF THE WELL'S PADDING, so its rule reaches both edges of the main column and the
   band reads as chrome rather than as a card the page happens to start with. It pulls by exactly
   what .sv-content pushed - the well states its gutter as a custom property for this reason, and
   redefines it below the shell's breakpoint, so the pull follows with nothing having to remember.

   TRANSLUCENT WITH A BLUR, matching the bar above it: at full opacity a figure sliding underneath
   vanishes at a hard line, which reads as content being clipped rather than scrolled.
   ────────────────────────────────────────────────────────────────────────── */

.sv-pagehead__bar {
  position: sticky;
  top: var(--sv-topbar-height);

  /* ABOVE THE UTILITY BAR'S OWN 20, because the way back is drawn by this band and painted into
     that one - see .sv-pagehead__back. The two never overlap otherwise: this sticks at exactly the
     height of the bar above it, so nothing but that one child ever enters its band. */
  z-index: 21;

  margin: calc(var(--sv-space-5) * -1) calc(var(--sv-well-gutter) * -1) 0;
  padding: var(--sv-space-3) var(--sv-well-gutter) 0;
  background: color-mix(in srgb, var(--sv-bg) 94%, transparent);
  backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--sv-border);
}

/* NOTHING IS CENTRED AND NOTHING IS CAPPED. The gutter is the only horizontal measurement the app
   well has: the band runs the full width of the main column so its rule is the boundary of the
   chrome, and every row inside it, the page under it and the utility bar above it are all inset by
   that one number. That is what puts them on a single left edge - a maximum width would have to be
   restated by each of the three, and each of them spends the gutter in a different place. */

/* THE WAY BACK, DRAWN BY THE PAGE AND PAINTED INTO THE BAR ABOVE IT. It belongs on the utility row,
   beside who is signed in, and it cannot be RENDERED there: the shell is a layout, layouts render
   statically, and a layout cannot know a page's back destination. A Blazor section will not carry
   it either - the static shell and the page's circuit are two render trees and two scopes.

   So it stays in the page's own markup, where the destination is declared, and is positioned one
   band up. The sticky band is its containing block, so it travels with it: pinned or in flow, it
   lands on the utility row either way. Out of flow, it also stops reserving a row - which is twenty
   pixels of chrome back, and the rule it used to reserve for (the title starting at the same pixel
   whether or not there is a link) now holds because there is nothing in the flow to differ. */
.sv-pagehead__back {
  position: absolute;
  top: calc(var(--sv-topbar-height) * -1);
  left: var(--sv-well-gutter);
  height: var(--sv-topbar-height);
  display: flex;
  align-items: center;
}

.sv-pagehead__back > .sv-back {
  margin-bottom: 0;
}

/* ROW 2 - the name, AND THE ACTIONS ARE PART OF IT. ALIGNED ON THE TITLE'S BASELINE, which is the
   only anchor that does not move: the name block is a title plus whatever the identity strip holds,
   so it is one line tall on a screen whose strip is a run of facts and two on a screen whose strip
   is a sentence. Centred, the primary action floated by half the difference; bottom-aligned it sat
   level with the sentence rather than with the name. A flex container's baseline is its first
   item's, so this is the h1's baseline against the first button's - the rule this component exists
   to hold, written as one declaration. The title takes the slack so a long name wraps rather than
   pushing the buttons off the edge. */
.sv-pagehead__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sv-space-4);
  flex-wrap: wrap;
}

/* THE TITLE AND ITS FACTS SHARE A BASELINE. Centred, a 10px uppercase label beside a 27px heading
   rides high enough to read as a superscript - the same reason .sv-supply__fact is baseline-set. */
.sv-pagehead__name {
  flex: 1 1 auto;
  display: flex;
  align-items: baseline;
  gap: var(--sv-space-3);
  flex-wrap: wrap;
  min-width: 0;
}

/* THE PAGE TITLE IS THE HEADER'S, NOT THE SCALE'S. .sv-h1 is 30px and stays 30px - the marketing
   pages and the printed sheet are set on it. A project name at the top of an instrument sits a step
   down from that: it shares its line with a run of facts and a row of controls, and at 30px it was
   the loudest thing on a screen whose subject is the figures underneath. */
.sv-pagehead__name > .sv-h1 {
  font: 700 27px/1.1 var(--sv-font-sans);
  letter-spacing: -0.02em;
}

/* THE STATE IS CENTRED ON THE TITLE, and align-self has to say so here. .sv-badge sets
   align-self: flex-start for the flex COLUMN case - where it stops a pill stretching the width of
   a card - and that declaration wins over the container's align-items, so a badge on a title line
   hung from the top of a 34px heading with the word beside it sitting six pixels lower.

   THE STATUS MARK IS CENTRED FOR A DIFFERENT REASON AND NEEDS THE SAME LINE. The row is
   baseline-set, and a wordless control has no baseline worth aligning to - the browser falls back
   to the bottom edge of its box, which hangs a dot below the foot of a 27px name. */
.sv-pagehead__name > .sv-badge,
.sv-pagehead__name > .sv-statuspick,
.sv-pagehead__name > .sv-menu--status {
  align-self: center;
}

/* What can be done to this subject, opposite its name. Kept short by the caller: one primary, at
   most one more beside it, and the rest behind the overflow menu below. */
.sv-pagehead__actions {
  display: flex;
  align-items: center;
  gap: var(--sv-space-2);
  flex: none;
}

/* WHY TWO CONTROLS HAVE APPEARED ON A ROW THAT USUALLY HOLDS THREE.

   A form whose Save is pinned to the top of the page needs to say what the Save is for, or the
   button reads as a control that was always there and the reader learns nothing from it arriving.
   The words are the point; the button beside them is what to do about it.

   AMBER, WHICH IS THIS PRODUCT'S ONE COLOUR FOR "SOMETHING IS WAITING ON YOU", and the same tone the
   badge on a tab uses. NOT red: nothing is wrong, and a form with an edit in it is the ordinary
   state of a form somebody is filling in.

   SENTENCE CASE IN THE SANS FACE, not the mono eyebrow. The eyebrow labels a control; this is a
   statement about the page, which is the same distinction the filter row's own count draws. */
.sv-pagehead__dirty {
  flex: none;
  padding: 3px var(--sv-space-3);
  border: 1px solid var(--sv-accent-underline);
  border-radius: var(--sv-radius-pill);
  background: var(--sv-accent-badge);
  color: var(--sv-accent);
  font: 500 11px/1.5 var(--sv-font-sans);
  white-space: nowrap;
}

/* THE IDENTITY STRIP - what this subject measures, in one line, in the mono face because every item
   in it is a measured value or a count. Separated by a middot rather than by a rule, because these
   are facets of one thing and not a list of several.

   ON THE TITLE'S OWN LINE, which is what it is a child of the name block for. A run of short facts
   is a caption on the name; given a row of its own it cost every screen in the product about thirty
   pixels of chrome before a reader had got to anything.

   A STRIP CARRYING PROSE STILL DROPS BELOW THE NAME, and this decides that from what is in it
   rather than from a parameter every caller has to remember - twenty-four of the forty-four screens
   put a summary sentence here, and a sentence set beside a 27px heading reads as a subtitle to it.
   :has() is the whole rule: flex-basis: 100% takes the strip to its own line inside the name block,
   where it wraps against the title rather than against the actions. */
.sv-pagehead__meta {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--sv-space-2);
  color: var(--sv-text-tertiary);
}

.sv-pagehead__meta:has(p) {
  flex-basis: 100%;
  margin-top: var(--sv-space-1);
}

/* THE STRIP PUNCTUATES ITSELF, so a caller lists facts and never types a separator. Twenty-seven
   middots were written by hand across ten screens, each one a chance to leave one out, put two in,
   or forget the aria-hidden that keeps it out of the reading order.

   ONE FACT IS ONE CHILD. A value and the word that qualifies it - "3 MPPT", "2 members" - are one
   fact in two spans, so they go in a wrapper; anything left loose gets punctuated as though it were
   a fact of its own, which is exactly the mistake this replaces.

   The middot is plain content rather than the `content: "\00B7" / ""` form that would hide it from
   a screen reader: that syntax is not old enough to rely on, and an unsupported `content` throws
   the whole declaration away in silence - which here means no punctuation at all, on the browsers
   least likely to be the ones we test. A middot read aloud is the cheaper failure. */
.sv-pagehead__meta > * + *::before {
  content: "\00B7";
  margin-right: var(--sv-space-2);
  color: var(--sv-text-faint);
}

/* A fact in more than one span, so the strip counts it once. */
.sv-pagehead__fact {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* A page whose summary is a sentence rather than a strip of measured facts sets it as prose. The
   face is set here rather than by every caller repeating two utility classes on its own paragraph:
   twenty-one screens were doing exactly that, and one of them getting it wrong would look like a
   decision. */
.sv-pagehead__meta > p {
  margin: 0;
  font: 400 13px/1.45 var(--sv-font-sans);
  color: var(--sv-text-secondary);
}

.sv-pagehead__meta > .sv-mono,
.sv-pagehead__fact > .sv-mono {
  font: 400 12px/1.4 var(--sv-font-mono);
  color: var(--sv-text-secondary);
}

/* ROW 3 - the way across, and it is the LAST thing in the band, so the band's own rule is the
   strip's rule. The strip carries one of its own everywhere else it is drawn; inside here that
   would be a second hairline one pixel under the first. */
/* THE LAST ROW IN THE BAND OWNS THE GAP UNDER IT, and on a page with no section strip that row is
   the title's.

   The band states no bottom padding, because on every screen inside a project the strip is the last
   row and its own tabs are the footing. A SIDEBAR DESTINATION HAS NO STRIP - the projects list, the
   library, the schedules, every staff console - so the title row ends the band; and the head is
   baseline-set, so the primary action beside the title hangs below the title's own box and lands on
   the rule with a pixel to spare. Thirty-five screens draw a header with no strip, so this is one
   rule rather than a bottom padding each of them remembers.

   `:last-child` rather than a parameter the caller passes: whether there is a strip is a fact about
   the markup, and asking a page to declare it twice is the second declaration that goes stale. */
.sv-pagehead__head:last-child {
  padding-bottom: var(--sv-space-3);
}

.sv-pagehead__nav {
  margin-top: var(--sv-space-3);
}

.sv-pagehead__nav .sv-project-nav {
  margin-top: 0;
  border-bottom: 0;
}

/* UNLESS THE READ-ONLY BANNER IS RIDING WITH IT. The banner comes after the strip, so with the
   strip's own rule gone the tabs would be underlined by nothing and the band's rule would be
   forty pixels below them, under a notice. Where there is a banner the strip keeps its footing. */
.sv-pagehead__nav:has(.sv-alert) .sv-project-nav {
  border-bottom: 1px solid var(--sv-border);
}

.sv-pagehead__nav .sv-alert {
  margin-top: var(--sv-space-4);
  margin-bottom: var(--sv-space-3);
}

/* THE PAGE ITSELF, outside the band because the band is sticky and a page is not. The header
   carries it so the strip has something to be the footing OF. */
.sv-pagehead__body:not(:empty) {
  margin-top: var(--sv-space-5);
}

/* AND THE STEP FROM ONE BLOCK OF THE PAGE TO THE NEXT, which is the same step. The header is the
   first block and what the page draws under it is the rest, so the body states that gap once -
   rather than nineteen cards across nine screens each stating it, and a block that renders only
   sometimes takes its gap with it, which a sibling holding a margin cannot.

   A MARGIN RATHER THAN A FLEX GAP, deliberately. Adjacent margins collapse, so a block already
   stating one of its own keeps the larger of the two; a gap would land on top of it and stand that
   one block twice as far down the page as its neighbours. */
.sv-pagehead__body > * + * {
  margin-top: var(--sv-space-5);
}

/* ── The header's overflow menu ────────────────────────────────────────────
   WHERE THE REST OF THE ACTIONS GO. Six equal buttons opposite a title is a row with no primary
   action in it, so anything past the second one drops in here.

   THE SKIN ONLY. The open state is a class js/ui/page-header.js toggles on the container, which
   names that class in its own data-sv-menu attribute - which is what lets the account block in the
   top bar wear a completely different skin on the same mechanism. Never MudMenu: opening a menu
   changes nothing the server owns, so it does not go on the circuit.
   ───────────────────────────────────────────────────────────────────────── */

.sv-menu {
  position: relative;
  display: inline-flex;
  flex: none;
}

/* ONE ICON BOX, sized like every other icon control in the product - which means SQUARE, at the
   height .sv-btn states. That box is .sv-btn--icon in utilities.css, worn by the trigger in the
   markup; it is not restated here, because a second copy of a shape is how two controls in one row
   come to be different sizes. */

.sv-menu__panel {
  display: none;
  position: absolute;
  top: calc(100% + var(--sv-space-2));
  right: 0;
  z-index: 40;
  flex-direction: column;
  min-width: 168px;
  padding: var(--sv-space-1);
  background: var(--sv-bg-raised);
  border: 1px solid var(--sv-border);
  border-radius: var(--sv-radius-card);
  box-shadow: var(--sv-shadow-panel);
}

.sv-menu--open .sv-menu__panel {
  display: flex;
}

/* HOW MANY OF THE THINGS BEHIND THIS TRIGGER ARE SET, said quietly.

   NOT `.sv-tab-badge`, which is the one place a data screen shouts: filled amber, answering "is
   anybody waiting on me" from across a room. This answers "how many of these did I leave on" to
   somebody whose eyes are already on the button, and wearing the alert it read as a queue on a
   screen that has none. Mono because it is a count, tertiary because the word beside it is the
   thing being pressed. */
.sv-menu__count {
  margin-left: 6px;
  font: 500 11px/1 var(--sv-font-mono);
  color: var(--sv-text-tertiary);
}

/* AN ITEM IS A BUTTON OR A LINK and reads identically either way. An export is a navigation the
   browser does better than we can, so it is a real anchor with a download attribute - and an
   anchor arrives underlined and in the link colour unless it is told otherwise. */
.sv-menu__item {
  display: block;
  width: 100%;
  padding: 7px var(--sv-space-2);
  border: 0;
  border-radius: var(--sv-radius-control);
  background: none;
  color: var(--sv-text);
  font: 400 13px/1.4 var(--sv-font-sans);
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

.sv-menu__item:hover {
  background: var(--sv-bg-overlay);
  color: var(--sv-text);
  text-decoration: none;
}

.sv-menu__item--danger {
  color: var(--sv-danger-ink);
}

.sv-menu__item--danger:hover {
  color: var(--sv-danger-ink);
}

/* ── The status chip's menu ────────────────────────────────────────────────
   THE SECOND BORROWER OF THE MECHANISM, and it declares itself one. The account block in the top
   bar was the first; this is a badge on the title line that moves the project on. Only the skin is
   here - where the panel hangs, and that its items are pills rather than words.

   IT DROPS FROM THE LEFT, because it does. The overflow menu is the last control in a row at the
   right of the header and hangs back from its own right edge; this one is the first thing after
   the title at the far left, and a panel right-aligned to it opens backwards underneath the name.
   ───────────────────────────────────────────────────────────────────────── */

.sv-menu--status .sv-menu__panel {
  right: auto;
  left: 0;

  /* THE PANEL IS THE MEASURE, NOT ITS LONGEST SENTENCE. The note underneath is prose and would set
     its own width given the chance; capped here, it wraps inside a panel whose width is settled by
     the states above it, which is the part a reader is choosing from. */
  min-width: 214px;
  max-width: 268px;
}

/* AN OPEN CONTROL STAYS LIT, so it and the panel below read as one object rather than as a menu
   that happens to be near some words. The properties are .sv-statuspick's in utilities.css and are
   only restated under the open class, which belongs to this family: the module toggles it, and
   utilities.css declaring it would be the shared stylesheet owning half of a mechanism it cannot
   see. */
.sv-menu--status.sv-menu--open .sv-statuspick {
  border-color: var(--sv-border);
  background: var(--sv-bg-overlay);
}

.sv-menu--status.sv-menu--open .sv-statuspick__caret {
  opacity: 1;
}

/* AN ITEM THAT IS A DOT AND A WORD, exactly as the control it fills is. A menu is the one place a
   whole lifecycle is seen at once, which makes it the one place the palette can be learnt - so the
   colour is carried, but in the same register as the trigger rather than in a second one. Drawn as
   pills the eight rows were eight different widths, and a list of ragged capsules is harder to
   read down than a column of dots. */
.sv-menu__item--status {
  display: flex;
  align-items: center;

  /* A BUTTON MADE A FLEX CONTAINER CENTRES ITS OWN CONTENTS, and the browser's own sheet is where
     that comes from - text-align on the item does not reach a flex line. Left unsaid, eight rows of
     dot-and-word sat centred on a panel sized by the longest of them, so the dots ran down a curve
     instead of a column, which is the one thing a list of states has to do. */
  justify-content: flex-start;

  gap: 9px;
}

/* WHERE THE PROJECT IS NOW, marked rather than dropped. Removed from the list the menu would be a
   different height and a different shape on every project, and the state somebody is moving away
   from is the one they are checking themselves against. */
.sv-menu__item--current {
  background: var(--sv-bg-overlay);
}

/* WHAT THE THING BEING PICKED DRIVES, under the rule that separates it from the picking. It is the
   FieldHelp sentence that used to sit behind the mark on a form field, and it is set at the size
   help is set at everywhere else - a definition read once, not a label read every time. The measure
   is capped because a panel sized by its longest sentence is a panel the width of the screen. */
.sv-menu__note {
  margin: var(--sv-space-1) 0 0;
  padding: var(--sv-space-2);
  border-top: 1px solid var(--sv-border-subtle);
  color: var(--sv-text-tertiary);
  font: 400 11px/1.5 var(--sv-font-sans);
  white-space: normal;
}

/* ── Below the shell's breakpoint ─────────────────────────────────────────────
   THE HEADER STACKS RATHER THAN WRAPPING ITS BUTTONS OFF THE EDGE, and the primary action takes the
   width it has - a form long enough to scroll puts its own submit button on a screen the person
   filling it in cannot see, which is the whole reason the action is up here. 1000px is the shell's
   own breakpoint, stated in utilities.css where the sidebar becomes a drawer; the two move together.
   ────────────────────────────────────────────────────────────────────────────── */

@media (max-width: 1000px) {
  /* THE BAND PULLS BY WHAT THE WELL PUSHED, and the well's vertical padding steps down at this
     width while its gutter does so through the custom property the band already reads. Only the
     top pull has to be restated.

     AND IT STOPS STICKING. The head stacks at this width - the title, then the actions at full
     width, then the strip - so a band that stays put would hold a third of a phone's screen for
     chrome the reader has already read. Sticking is what a wide screen can afford. */
  .sv-pagehead__bar {
    position: static;
    margin-top: calc(var(--sv-space-4) * -1);
  }

  /* THE WAY BACK COMES BACK INTO THE FLOW. The utility row's left end is the drawer's opener at
     this width, and the band is no longer positioned for anything to be painted out of. */
  .sv-pagehead__back {
    position: static;
    height: auto;
    min-height: 12px;
    margin-bottom: var(--sv-space-2);
  }

  .sv-pagehead__head {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sv-space-3);
  }

  .sv-pagehead__actions {
    flex-wrap: wrap;
    width: 100%;
  }
}

/* ── On paper ─────────────────────────────────────────────────────────────────
   A CONTROL IS NOT FOR READING. The grid-application pack and the production report both print from
   a page that wears this header, and a way back, a row of buttons and a strip of tabs printed onto
   a document somebody files with a distributor are three things that mean nothing there. The name
   and what the subject measures do print - they are what the sheet is about.
   ────────────────────────────────────────────────────────────────────────────── */

@media print {
  .sv-pagehead__back,
  .sv-pagehead__actions,
  .sv-pagehead__nav {
    display: none;
  }

  /* A SHEET HAS NO SCROLL FOR ANYTHING TO STICK TO, and a translucent band with a blur behind it
     is a renderer's guess at what is underneath. The band goes back to being an ordinary block,
     and its rule goes with the controls it was ruling off. */
  .sv-pagehead__bar {
    position: static;
    margin: 0;
    padding: 0;
    background: none;
    backdrop-filter: none;
    border-bottom: 0;
  }

  .sv-pagehead__body:not(:empty) {
    margin-top: var(--sv-space-4);
  }
}
