/* Site chrome: header, nav, footer, and the mobile tab bar.
 *
 * These follow the Waste Footprint Calculator exactly. The two products sit next to each other and
 * a user moving between them should not feel they have crossed into a different company: white
 * sticky header, the Kolekt mark on the left, navy nav that goes yellow on hover and green when
 * active, and a quiet transparent footer rather than a heavy dark bar. */

.page-header {
    position: sticky;
    top: 0;
    z-index: var(--z-sticky);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-4);
    padding: var(--sp-4) var(--sp-6);
    background-color: var(--color-surface);
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
}

.page-header__left,
.page-header__right { display: flex; align-items: center; gap: var(--sp-2); }

/* Only one thing in this row is allowed to give ground, and it is the greeting. A flex item's
   default min-width is auto, so without this the left group keeps its full content width and the
   nav is what gets pushed off the edge - which is why the greeting used to be hidden outright
   instead of shortened. The lockup opts out: a truncated brand is not a brand. */
.page-header__left { min-width: 0; }
.page-header__brand { flex-shrink: 0; }

/* One number drives the whole lockup. --brand-h is local to this block rather than a token: it is
 * a measurement of one component, and tokens.css is the only :root in the project. */
.page-header__brand {
    --brand-h: 2.25rem;
    /* Proportional, not var(--sp-2): the two halves of one word have to keep their spacing when
       the lockup steps down, or the gap grows visibly wider than the letters beside it. */
    display: inline-flex; align-items: center; gap: calc(var(--brand-h) * 0.22);
    color: var(--c-navy); font-weight: 600; text-decoration: none;
}
.page-header__brand:hover { text-decoration: none; }

/* Height fixed to the header; width auto keeps the aspect ratio (264x256, near square). */
.page-header__logo { display: block; flex: 0 0 auto; height: var(--brand-h); width: auto; }

/* KOLEKT EXCHANGE, both words in the project's own font.
 *
 * The artwork's wordmark is a condensed face this project does not ship, so drawing KOLEKT and
 * typing EXCHANGE put two typefaces on two baselines beside each other. Typing both is the only
 * way they are one font, one size, one colour and one baseline by construction rather than by
 * measurement - and the mark still carries the brand.
 *
 * 0.62 of the lockup height is a cap height that matches the mark's optical weight; line-height:1
 * because the default leading would make the text box taller than the mark and push the header
 * open. */
.page-header__brand-name {
    font-size: calc(var(--brand-h) * 0.62);
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.02em;
    white-space: nowrap;
    color: var(--c-navy);
}

.page-header__nav { display: flex; align-items: center; gap: var(--sp-2); }
.page-header__nav[hidden] { display: none; }

.page-header__nav-link {
    font-family: inherit;
    font-size: var(--fs-300);
    font-weight: 500;
    color: var(--c-navy);
    text-decoration: none;
    padding: var(--sp-2) var(--sp-3);
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.2s ease, color 0.2s ease;
}
.page-header__nav-link:hover {
    background: var(--c-yellow);
    color: var(--c-navy);
    text-decoration: none;
}
.page-header__nav-link--active {
    background: var(--c-green);
    color: var(--c-navy);
    font-weight: 700;
}

/* --- Hamburger -----------------------------------------------------------
 * Hidden above the breakpoint, where the nav is already on screen and a control offering to
 * reveal it would be a lie. Below it, this is the way to the full list of destinations. */
.page-header__burger {
    display: none;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    /* 44px: the smallest target a thumb hits reliably, and the floor in WCAG 2.2 SC 2.5.8. */
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    color: var(--c-navy);
    cursor: pointer;
    transition: background-color var(--dur-fast) ease;
}
/* Companion guard: the rule above is display:none already, but the media query turns it into
   inline-flex - which would beat the user agent's [hidden] rule without this. */
.page-header__burger[hidden] { display: none; }
.page-header__burger:hover { background: var(--c-yellow); }
.page-header__burger:focus-visible { outline: 3px solid var(--c-blue); outline-offset: 2px; }
/* Open state carries the same yellow as a hovered nav link, so the button reads as "active"
   rather than as one more outlined box while the panel is down. */
.page-header.is-nav-open .page-header__burger { background: var(--c-yellow); }

.page-header__burger-icon {
    display: block;
    width: 1.5rem;
    height: 1.5rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
}
.page-header__burger-icon[hidden] { display: none; }
/* Bars turn into a cross while the panel is down: the button is a toggle, so it has to say which
   way it will go. Swapped in CSS and not with el.hidden because the state itself is a class. */
.page-header__burger-icon--close { display: none; }
.page-header.is-nav-open .page-header__burger-icon--open { display: none; }
.page-header.is-nav-open .page-header__burger-icon--close { display: block; }

.site-main { flex: 1 0 auto; padding: var(--sp-6) 0; }

/* Quiet by design: the footer carries a line of text, not a slab of colour. */
.footer { background: transparent; }
.footer__inner {
    max-width: var(--container);
    margin: 0 auto;
    padding: var(--sp-5) var(--sp-4);
    text-align: center;
}
.footer__text {
    margin: 0;
    font-weight: 500;
    font-size: var(--fs-200);
    color: var(--c-navy);
}

/* --- Bottom tab bar ------------------------------------------------------
 * The narrow-screen dock. Three to five of the role's own destinations, big enough for a thumb,
 * always where the thumb already is - which is the whole "it feels like an app" of it.
 *
 * The comment that used to sit here said a bottom bar means two navigations to keep in step and
 * that the one at the bottom knows less than the one at the top. Both were true of the old one,
 * because it was written out by hand. This one has no links in the markup at all: header.js clones
 * the header's own links into it, so there is still exactly one list of destinations in the
 * product and the bar cannot fall behind it. What the bar shows less of is deliberate - it is the
 * shortcut, and the hamburger beside the brand still opens the complete list at every width.
 *
 * Same layer as the sticky header: it is the same kind of chrome. Tips (--z-tip) and toasts
 * (--z-toast) sit above it by the scale, and both are also lifted clear of it - see the token. */
.bottom-nav {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: var(--z-sticky);
    display: none;
    background: var(--color-surface);
    border-top: 1px solid var(--color-border);
    box-shadow: 0 -1px 3px rgba(11, 45, 68, 0.08);
    /* The iOS home indicator strip. viewport-fit=cover in base.html is what makes env() non-zero. */
    padding-bottom: env(safe-area-inset-bottom);
}
/* Companion guard: the media query below turns this into display:block, which would beat the user
   agent's [hidden] rule - and the bar is rendered hidden until header.js has put tabs in it. */
.bottom-nav[hidden] { display: none; }

.bottom-nav__list {
    display: flex;
    margin: 0;
    padding: 0;
    list-style: none;
}
.bottom-nav__list[hidden] { display: none; }

/* Equal thirds, quarters or fifths. flex-basis 0 rather than auto so a long label cannot steal
   width from its neighbours; min-width 0 is what lets the label ellipsis instead of pushing. */
.bottom-nav__item { flex: 1 1 0; min-width: 0; }

.bottom-nav__link {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    /* 52px + the 1px border is the height reserved by --bottom-nav-h below; keep them together.
       The padding is deliberately smaller than it looks like it should be: icon + gap + label comes
       to 37px, so min-height is what decides the box and the reserve stays exact. At sp-2 the
       content measured 53.2px, min-height stopped governing, and the page reserved a pixel less
       than the bar actually took. */
    min-height: 3.25rem;
    padding: var(--sp-1);
    color: var(--c-navy);
    font-size: 0.6875rem;
    font-weight: 500;
    line-height: 1.2;
    text-decoration: none;
    /* A tap on a tab should not paint a selection over the label. */
    -webkit-tap-highlight-color: transparent;
}
.bottom-nav__link[hidden] { display: none; }
/* Guarded, because the bar only exists on the devices least likely to have a pointer: a touch
   browser that synthesises hover leaves the tapped tab yellow until you tap somewhere else, which
   reads as the current page and contradicts the tab that really is current. */
@media (hover: hover) {
    .bottom-nav__link:hover { background: var(--c-yellow); }
}
.bottom-nav__link:hover { text-decoration: none; }
/* Inset, because an outline outside the tab would be clipped by the bar's own edge. */
.bottom-nav__link:focus-visible { outline: 3px solid var(--c-blue); outline-offset: -3px; }

.bottom-nav__icon {
    display: block;
    flex: 0 0 auto;
    width: 1.375rem;
    height: 1.375rem;
    /* Set here and not in the sprite: a <use> instance inherits from the element that uses it, so
       presentation attributes written on the sprite never arrive. currentColor is also what makes
       the active tab's icon go green with its label, from one declaration. */
    fill: none;
    stroke: currentColor;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.bottom-nav__icon[hidden] { display: none; }

/* Last resort only - the labels are chosen short in header.html. Clipping beats a two-line tab
   that makes the bar taller than the height the page reserved for it. */
.bottom-nav__label {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The header marks its current link with a filled green pill. A pill across a whole tab would be a
   slab, so the same green becomes a top indicator plus the text colour. Green-dark on white, not
   the brand green: #AFCA0B as 11px text is 1.9:1. */
.bottom-nav__link--active {
    color: var(--c-green-dark);
    font-weight: 700;
    box-shadow: inset 0 3px 0 var(--c-green);
}

/* The sprite itself draws nothing. Taken out of flow as well as sized to zero, because an inline
   <svg> is a replaced element and still claims a line box. */
.bottom-nav__sprite {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
}

/* The page has to stop above a fixed bar, or its last row sits under one. --bottom-nav-h is 0px
   unless the media query below raised it, so this rule is free on a desktop and free on a phone
   whose role had nothing to tab. */
body.is-bottom-nav { padding-bottom: var(--bottom-nav-h); }

/* The lockup is the widest fixed thing in the header. At 2.25rem the mark plus EXCHANGE measures
   about 306px and only 298px is free on a 390px screen, so both halves step down together rather
   than the text wrapping under the mark. Same breakpoint as the disclosure below, deliberately:
   one width at which the header changes shape, not two. */
@media (max-width: 1100px) {
    .page-header__brand { --brand-h: 1.75rem; }
}

/* Every destination is reachable at every width. Below the breakpoint the header nav becomes a
 * disclosure panel behind the hamburger - the FULL list, nothing dropped - and the three to five
 * this role uses most are also docked at the bottom.
 *
 * The threshold was 760px, and the header overflowed the page at every width between there and
 * 1024px: at 768px the operator's inline nav pushed the document 256px sideways, the brand lock
 * sat on top of the first link and Log out ran off the right edge. Nothing caught it because the
 * browser runs measure 390px and 1400px and nothing in between - a tablet was simply never
 * looked at. mobile.js now sweeps 390, 768 and 1025.
 *
 * The number is 1100 and the measurement is 1030 (scripts/browser/header-width.js: the operator
 * header, the one with the most links, overflows by 6px at 1025 and is clean from 1030). The 70px
 * is deliberate headroom, not slop. Six pixels is not a margin - it is a coincidence, and this
 * breakpoint has now been wrong twice for exactly that reason: a renamed link or one more
 * destination eats it silently, and the failure shows up as a page that scrolls sideways rather
 * than as anything anyone would think to look for. Between 1030 and 1100 the disclosure panel is
 * doing no harm: it lists every link the role has. Re-run the script after touching the nav. */
@media (max-width: 1100px) {
    .page-header {
        padding: var(--sp-3) var(--sp-4);
        flex-wrap: wrap;
        row-gap: var(--sp-2);
    }
    /* Shares the top row with the burger now, so it takes the space that is left rather than the
       whole width. min-width:0 lets the brand name shrink instead of pushing the button off. */
    .page-header__left { flex: 1 1 auto; min-width: 0; }
    .page-header__burger { display: inline-flex; }

    /* Closed by default, and a full-width stack when open.
     *
     * This was a wrapping row of links, which was itself a fix for an overflow-x:auto strip that
     * had Chain links, Payouts and Profile off the right edge with no scrollbar and no hint. The
     * wrap fixed the hiding but cost a phone three rows of chrome above every page. A disclosure
     * costs one tap and keeps the promise the wrap was making: the panel lists EVERY link this
     * role has, including the ones already docked at the bottom.
     *
     * display and not el.hidden, because hidden is not width-aware: a nav left hidden by a tap on
     * a phone would still be hidden after a rotation to landscape, with the button that could
     * bring it back now hidden by CSS. The class is inert outside this media query. */
    .page-header__nav {
        flex: 1 1 100%;
        display: none;
        flex-direction: column;
        align-items: stretch;
        gap: var(--sp-1);
        margin-top: var(--sp-1);
        padding-top: var(--sp-2);
        border-top: 1px solid var(--color-border);
        /* A long panel scrolls inside itself rather than making a sticky header taller than the
           viewport. Visible and vertical, so nothing is hidden without saying so. */
        max-height: calc(100vh - 8rem);
        overflow-y: auto;
    }
    .page-header.is-nav-open .page-header__nav { display: flex; }
    /* Companion guard, and it needs this specificity: the rule above (0,2,1) would otherwise beat
       the global .page-header__nav[hidden] (0,1,1) and an el.hidden nav would show while open. */
    .page-header.is-nav-open .page-header__nav[hidden] { display: none; }

    /* Full-width rows in a panel: 44px targets, and the hit area spans the panel. */
    .page-header__nav-link { padding: var(--sp-3); font-size: var(--fs-300); }

    .bottom-nav { display: block; }
    /* The bar's own height, and the only place it is written down. Everything that has to clear
       the bar reads this one variable: the page below, the toast stack and the info-tip bubble. */
    body.is-bottom-nav { --bottom-nav-h: calc(3.25rem + 1px + env(safe-area-inset-bottom)); }
}

/* base.css already drops the header when printing; the bar is the same chrome and a certificate is
   a thing people print. The reserve goes with it, or the last page carries 53px of blank paper. */
@media print {
    .bottom-nav { display: none !important; }
    body.is-bottom-nav { padding-bottom: 0; }
}

/* --- Page head -----------------------------------------------------------
 * The page title, and on the right whatever this page lets you DO.
 *
 * Twelve templates carried this as a copy-pasted inline style. As a class it can finally have the
 * [hidden] companion an inline display:flex can never have - the trap base.css already documents.
 * Navigation moved to the header nav, so what is left in this row is only ever an action. */
.page-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--sp-3);
    margin-bottom: var(--sp-5);
}
/* Companion guard: the rule above is display:flex, so [hidden] alone would not hide it. */
.page-head[hidden] { display: none; }

/* The heading's own bottom margin fought the row's gap and pushed the buttons off centre.
   The row owns the spacing now - which also matters because the explanatory paragraph that
   used to supply the separation below is going away. */
.page-head > h1,
.page-head > h2 { margin-bottom: 0; }

.page-head__actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.page-head__actions[hidden] { display: none; }

/* --- Field grids ---------------------------------------------------------
 * Two or three form fields side by side, collapsing to one column when they no longer fit.
 *
 * These were inline `grid-template-columns: 1fr 1fr`. A 1fr track has a min-content floor, and an
 * <input> does not shrink below its intrinsic width - so at 390px the second column simply pushed
 * off the right edge and took the whole page with it. Measured: 152px of sideways scroll on the
 * proof form, 27px on the profile. auto-fit does the collapsing for us, so no breakpoint has to be
 * kept in step with the field count. */
.field-grid {
    display: grid;
    gap: var(--sp-4);
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
}
.field-grid[hidden] { display: none; }

/* Three-up on a wide screen; same collapse. */
.field-grid--tight { grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); }

/* Named for its page, because it carries column widths rather than a shape - the house rule after
   a .split-row name collision once turned a table into a stack. One date on the left, a pair of
   them on the right: an equal split starves the pair (it needs 328px) so the right column is given
   the slack. Below the breakpoint the row is one column and the pair has the whole width. */
.proof-date-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1.45fr); }
@media (max-width: 760px) {
    .proof-date-row { grid-template-columns: minmax(0, 1fr); }
}

/* The admin's reference-data forms: five short fields in a row, packed tighter than a two-field
   form because none of them holds a sentence. */
.field-grid--compact {
    gap: var(--sp-3);
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
}

/* --- Row and grid primitives ---------------------------------------------
 * What was left of the copy-pasted `style="display:flex"` in the page templates after .page-head
 * took the title rows.
 *
 * Same reason .page-head exists, and it is the whole point of moving these: an INLINE display rule
 * can never be paired with the [hidden]{display:none} companion this codebase requires, because
 * there is no selector to hang the companion on. The day a script sets .hidden on one of these
 * rows it would stay on screen, and the bug would read as a broken script rather than as a missing
 * CSS rule. As classes they finally have somewhere to put the guard.
 *
 * One class per SHAPE, not per call site - so a modifier here is only ever a real difference in
 * how the row behaves, never a place that happened to want a different number. */

/* A record's top line: what it IS on the left, what you can DO with it on the right. Wraps rather
   than squeezing, because the right-hand side is a button cluster and buttons do not shrink. */
.split-row {
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--sp-3);
}
/* Companion guard: the rule above is display:flex, so [hidden] alone would not hide it. */
.split-row[hidden] { display: none; }

/* The certificate's footer line. flex-end because the QR block has to sit level with the LAST
   line of the text beside it rather than with its first, and the wider gap because at that size
   the two columns read as one paragraph at sp-3. */
.split-row--end { align-items: flex-end; gap: var(--sp-5); }

/* A cluster of buttons - the only thing left in these rows now that navigation lives in the
   header. Stretch is the default and is right here: sibling buttons on one line share a height. */
.btn-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2);
}
.btn-row[hidden] { display: none; }

/* Top-aligned where the cluster holds something that is NOT a button - an info tip, a note - and
   stretching it to the tallest item on the line would pull it off the buttons' own line. */
.btn-row--top { align-items: flex-start; }

/* Centred where the cluster mixes a line of text with the buttons acting on it. */
.btn-row--center { align-items: center; }

/* Deliberately one line. The staff review queue puts three fixed verbs side by side and a wrap
   there would restack the queue's most-used control mid-scroll. */
.btn-row--nowrap { flex-wrap: nowrap; align-items: flex-start; }

/* Form fields side by side, wrapping whole when they no longer fit. Unlike .field-grid this keeps
   each field at its own width instead of forcing equal tracks - it is for a short field beside a
   long one, not for a matched pair. */
.form-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-3);
}
.form-row[hidden] { display: none; }

/* Bottoms aligned, for a field standing next to the button that acts on it: the button has no
   label above it, so aligning tops would leave it floating a label's height too high. */
.form-row--baseline { align-items: flex-end; }

/* Two inputs that are one answer - a from/to period. No wrap: split across two lines they stop
   reading as a range. */
/* Two controls sharing a column - and they WRAP rather than overflow it.
 *
 * Chrome will not render an <input type="date"> below about 159px: the mm/dd/yyyy text and the
 * picker button are its intrinsic minimum. So the pair needs 328px, and an equal .field-grid column
 * gives 283px at 1024px and 308px at 390px - which is why the second date input on the proof form
 * was drawn outside the card. Measured before the fix: 43px out at 1024, 75px at 600, 18px at 390.
 *
 * min-width holds each control at its readable minimum, which is what makes the line wrap instead
 * of shrinking into an unreadable box. The suffix on the certificate page is not a control and
 * opts out, or "Tonnes" would claim half the row. */
.input-pair { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.input-pair[hidden] { display: none; }
.input-pair > .input { flex: 1 1 10rem; min-width: 10rem; }

/* A checkbox and its wording, kept on one line so the words never wrap under the box. inline-flex
   and a margin rather than a flex row around them, because these flow as text: they wrap where
   they run out of room and the last one on a line must not carry a trailing gap. */
.check-inline {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    margin-right: var(--sp-5);
}
.check-inline[hidden] { display: none; }
.check-inline:last-child { margin-right: 0; }

/* The stacked twin of .check-inline, for options whose labels are phrases - "Waste Management
   Operator" wraps mid-phrase when two of them sit side by side at 390px. As a class it can carry
   the [hidden] companion that the inline display:block on the register radios never could. */
.choice-list {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    border: 0;
    padding: 0;
    margin: 0 0 var(--sp-4);
}
.choice-list[hidden] { display: none; }

/* A fieldset used purely to group radios. The browser draws a border and padding on every
   fieldset, which is why these carried an inline reset - and an inline rule can never have a
   [hidden] counterpart, which is the reason none of them are allowed to stay. */
.choice-set { border: 0; padding: 0; margin: 0 0 var(--sp-4); display: block; }
.choice-set[hidden] { display: none; }

.choice-list__option { display: flex; align-items: center; gap: var(--sp-2); }
.choice-list__option[hidden] { display: none; }

/* An auth form is one column of short fields; the 1120px container turns it into a ribbon. Two
   call sites carried this as an inline max-width. */
.container--narrow { max-width: 30rem; }
.container--tight { max-width: 26rem; }

/* The certificate is a document with an eight-column evidence table and a two-column body. At the
   1120px the rest of the product uses, both of them spent their width behind a scrollbar while the
   window had room to spare on either side. */
.container--wide { max-width: 1400px; }

/* The line under a form - "Already registered?". Was an inline margin on two pages. */
.form-footnote { margin-top: var(--sp-4); }

/* Cards in as many columns as fit, with no breakpoint to keep in step with the card count. */
.card-grid {
    display: grid;
    gap: var(--sp-3);
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
}
.card-grid[hidden] { display: none; }

/* A wider floor where the card carries a company name that must not hyphenate. */
.card-grid--wide { grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }

/* auto-FILL, not auto-fit: a lone photo should stay photo-sized rather than stretch across the
   whole row, which auto-fit would do by collapsing the empty tracks. */
.card-grid--photos {
    gap: var(--sp-4);
    grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
}

/* Who is signed in, beside the mark. Muted and a size down: it is orientation, not a heading, and
   it must never compete with the brand it sits next to. Hidden below the nav breakpoint - the
   header is already tight there and the greeting is the first thing that can go. */
.page-header__whoami {
    margin-left: var(--sp-2);
    color: var(--color-text-muted);
    /* A step up, as asked. It is still below the brand beside it - orientation, not a heading -
       but it is now legible rather than merely present. The cost is width, and the breakpoint
       below was re-measured because of it. */
    font-size: var(--fs-300);
    white-space: nowrap;
    /* It gives ground before the nav does, instead of disappearing whole. min-width:0 is what lets
       a flex item shrink below its content at all - without it the greeting keeps its full width
       and pushes the nav off the right edge, which is the overflow the old hide rule was avoiding.

       MEASURED at 1440: the lockup wants 251px, the operator nav - the longest of the five - wants
       769px, and the whole greeting wants 385px. That is about 1470px of header in 1440px of
       screen, so on the customer's own laptop something has to give. A flex row is what decides
       WHICH something: the name and the role hold their width, and the middle clause is the only
       one that shortens. Both of the parts that survive are parts the customer asked for by name
       (Corrections 34 and 144); the company and country in between degrade to an ellipsis. */
    display: flex;
    align-items: baseline;
    min-width: 0;
}
/* The word space is a real space, not a gap.
   A flex container drops the whitespace BETWEEN its items, which rendered "Akshayof Greenworms".
   The first fix was column-gap, and it looked right and was still wrong: a gap is drawn, not read,
   so a screen reader announced the run-together name. The space now lives inside each clause and
   white-space:pre is what stops the flex item trimming its own leading space - so the line reads
   correctly to a person AND to anything reading the text. */
.page-header__whoami > [data-role="whoami-org"],
.page-header__whoami > [data-role="whoami-role"] { white-space: pre; }
/* display:flex overrides the UA's [hidden] rule, so the twin is not optional - without it a signed
   out visitor gets an empty greeting box instead of nothing. */
.page-header__whoami[hidden] { display: none; }
.page-header__whoami > [data-role="whoami-name"],
.page-header__whoami > [data-role="whoami-role"] { flex: 0 0 auto; }
.page-header__whoami > [data-role="whoami-org"] {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}
.page-header__whoami-sep { margin-right: var(--sp-2); }
.page-header__whoami-org { color: var(--color-text-muted); }

/* The greeting shrinks rather than vanishes.
   It used to be hidden below 1520px, which is a measured number and was the right call while the
   line could not give ground: at 1380 the operator header overflowed by 110px. The cost was that
   the customer, on a 1440 laptop, never saw the greeting at all - and wrote it up three times
   (Corrections 15, 34, 52, 144), each time about a line that was rendering correctly and was
   display:none. Ellipsis is the better trade: the name stays, the country goes first.
   Below the nav breakpoint the header changes shape anyway - the links fold into a disclosure -
   and at that width the row is the mark plus a burger, so the greeting steps out entirely.
   Measured with scripts/browser/header-width.js; re-measure if the wording, the size or a nav link
   changes, because all three move this number. */
@media (max-width: 64rem) {
    .page-header__whoami { display: none; }
}
