/* Symmetric header insets in compact/cloud mode: the trailing inset is the
 * sidebar's own (--sidebar-padding-right), the same measure the leading side
 * takes from --sidebar-padding-left — so the header's two ends range with the
 * columns below them instead of with a literal. (The base rule sets 1em/56px.)
 * Shipped inline — the assets submodule is volatile. */
body[data-global-nav="compact"] #global-header { padding-right: var(--sidebar-padding-right); }

/* --- Which instance is this? -------------------------------------------
 * The staging box carries body[data-instance-env="dev"], a developer's own
 * machine data-instance-env="local", and production says PROD in the chip
 * rather than in a body attribute. Superuser-only, in every environment: the
 * chip is the environment switcher's trigger (partials/kik_env_badge.html),
 * and a deployment name is operator's chrome.
 *
 * A CHIP IN THE CHROME, not a pattern across it (Daniel, 2026-08-16). Dev
 * used to wear a diagonal zebra over the header and the rail, local a field
 * of polka dots — both readable as "not production" at a glance, neither
 * readable as WHICH, so telling the two apart meant remembering which shape
 * belonged to which box. The word says it outright, and it costs the chrome
 * a chip rather than its whole surface.
 *
 * partials/kik_env_badge.html renders it: one letter — D, T or P — in a
 * square, the same shape in the header and in the vertical rail. It was a
 * word (DEV / THINK / PROD) in a chip until 2026-08-25; the colour is what
 * this is read by, and the initial is enough to confirm it.
 *
 * The ink is one colour at full strength on a 12% wash of itself — this is a
 * label meant to be READ, where the patterns were a texture meant to sit under
 * everything else. WHICH colour is the chip's whole job: dev keeps the brand
 * accent it has always worn, local takes purple, and production takes a plain
 * grey. Grey because it is the one environment where nothing is unusual, and a
 * chip that shouts on the box everyone is normally on teaches the eye to skip
 * every chip; next to the other two it reads as the absence of a warning
 * rather than as a state of its own.
 *
 * One token carries it. The chip's four surfaces (ink, wash, ring, hover) are
 * all mixes of --kik-env-colour, so an environment is one line and cannot end
 * up half-recoloured. Keyed on a CLASS rather than data-kik-env: for a
 * superuser the chip is a pat-context-menu trigger, and menu_class is the only
 * hook that partial can be handed.
 */
.kik-env-badge {
    --kik-env-colour: var(--colour-accent, #ea6c1a);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    align-self: center;
    flex: none;
    box-sizing: border-box;
    /* A SQUARE. Width and height are the same number, and the box holds one
       letter — so there is nothing for a min-width to negotiate with and no
       flanks to tune: the letter is centred by the flex above. */
    width: 1.9em;
    height: 1.9em;
    padding: 0;
    border-radius: var(--border-radii-medium, 8px);
    /* MIXED INTO THE GROUND IT STANDS ON, not into white (Daniel, 2026-08-31:
       "make the env hopper dark mode compliant"). The chip's wash is a 12%
       tint of its environment colour, and the other 88% has to be whatever is
       behind it or the tile stops being a tint and becomes a light patch: on
       the dark theme a literal #fff left a near-white square glowing in a
       charcoal header. --colour-header is the bar's own ground and flips with
       the theme (#ffffff / #1d1a16), so the same 12% reads as a tint at both
       exposures. The hook is there for a surface that is neither — the rail
       paints its own ground — and the #fff fallback keeps a theme that
       declares no header colour exactly where it was. */
    background: color-mix(in srgb, var(--kik-env-colour) 12%,
                          var(--kik-env-ground, var(--colour-header, #fff)));
    color: var(--kik-env-colour);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--kik-env-colour) 35%, transparent);
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: 0;
    line-height: 1;
    text-transform: uppercase;
    /* Chrome furniture, not content: it must never be the thing a click or a
       text selection lands on. */
    pointer-events: none;
    user-select: none;
}

/* Dev keeps the accent (the default above). Local is purple — far enough from
   the brand orange that a glance at the tab tells you which of the two
   non-production boxes you are on, which is the whole reason the patterns were
   replaced by words. Production is grey. */
.kik-env-badge.kik-env-local { --kik-env-colour: #7c4dff; }
.kik-env-badge.kik-env-prod  { --kik-env-colour: #8a8f98; }

/* …unless it IS the control. For a superuser the same chip is the environment
   switcher's pat-context-menu trigger (partials/kik_env_badge.html) — one
   element wearing both classes, so it keeps every seating and painting rule
   above and only has to take its clicks back. An anchor, so the link
   decoration and the accent-on-hover an anchor picks up from base.css have to
   be refused too: the chip's colour is a state read-out, not a link colour. */
.kik-env-badge.kik-env-switch {
    pointer-events: auto;
    text-decoration: none;
    color: var(--kik-env-colour);

    @media (hover: hover) {
        &:hover {
            text-decoration: none;
            color: var(--kik-env-colour);
            background: color-mix(in srgb, var(--kik-env-colour) 20%,
                                  var(--kik-env-ground, var(--colour-header, #fff)));
        }
    }
}

/* In the top header the chip joins the float:right control row, which is how
   every other control there is placed (avatar, fullscreen toggle, favourite
   icons) — a bare inline span would otherwise fall into the normal flow at
   the header's leading edge, nowhere near them. Rendered after the
   fullscreen toggle, and float:right lays that row out right-to-left, so it
   seats immediately to that button's left.

   Centred in the band by margin rather than by alignment: a float has no
   line box to be centred in, so the top margin carries the difference
   between the header's height and the chip's. Same shape as the avatar's own
   seating rule, and it tracks --global-header-height rather than a literal
   54.

   It stands as TALL as everything else riding this row — the avatar, the
   fullscreen toggle, the app tab, the media-player chip are all
   --kik-global-nav-icon-size (see "ONE SEAT" below) — rather than the 22px
   it used to be. A chip two thirds the height of its neighbours read as a
   sticker dropped on the row instead of a control seated in it.

   And now as WIDE as it is tall (Daniel, 2026-08-25). This rule used to spend
   15px flanks specifically to stop a 36px box around three letters from
   becoming a square; the badge is one letter now, so the square is the point
   and the flanks are what would break it.

   The letter is set larger here than the base .7rem. That size was chosen for
   a word riding a busy row, where a small dense chip is what keeps it from
   shouting; a single glyph in a 36px box at the same size reads as a speck
   with a lot of ring around it. The rail keeps the base size, where the box
   is 1.9em and the proportion already works.

   The 8px side margin STAYS: the app tab beside it leaves 2px and expects
   this 8 to make up the row's 10 (base.css, "TRAILING SIDE ONLY"). */
#global-header .kik-env-badge {
    float: right;
    width: var(--kik-global-nav-icon-size, 36px);
    height: var(--kik-global-nav-icon-size, 36px);
    padding: 0;
    font-size: .9rem;
    margin: calc((var(--global-header-height, 54px)
                  - var(--kik-global-nav-icon-size, 36px)) / 2) 8px 0;
}

/* ONE RHYTHM FOR THE WHOLE BAR — 6px, which is what the pinned app tiles have
 * had between them all along (app-label.css lays them out in a flex row with
 * that gap). The float-right group at the trailing end had never been measured
 * against them: the env chip carried 8px each side, the two loose controls
 * 10px, and the avatar 16 — so the same header ran at four different spacings
 * and the right-hand end read as scattered next to the tab row's even beat
 * (measured 18 / 10 / 16 / 16; Daniel, 2026-08-25).
 *
 * Stated in ONE place rather than by correcting each source, because the
 * figures came from four (the shared header CSS, base.css, the env chip's own
 * file and the avatar's seat rule) and the point is that they are now the same
 * number. Leading margin only: these are floats laid out right to left, so
 * each item's own leading margin IS the gap between it and its neighbour, and
 * a trailing one would double up.
 *
 * The orb takes it from here too — its whole reason for a leading margin was
 * to match the avatar's, and the row now says what that is. */
#global-header .kik-env-badge,
#global-header .kik-header-switch-env,
#global-header .kik-header-fullscreen,
#global-header .kik-media-player-chip.in-header,
#global-header .kik-orb,
#global-header a#user-avatar.user-info-avatar,
#global-header .hub-user-menu {
    --kik-header-row-gap: 6px;
    margin-inline-start: var(--kik-header-row-gap);
    margin-inline-end: 0;
}

/* Mobile: keep the personal-menu trigger (avatar) in the same float-right
 * control row as the candy box / favourites so the two triggers don't overlap.
 * On small screens (--screen-small, <=769px) the shared header CSS pulls the
 * avatar out of flow (position:absolute, right-pinned), stacking it on top of
 * the floated candy box — re-assert the float-row layout here. */
@container screen style(--screen-small: true) {
    body[data-global-nav="compact"] #global-header .user-info-avatar,
    body[data-global-nav="compact"] #global-header .hub-user-menu {
        position: static;
        float: right;
        right: auto;
        margin-left: var(--application-label-white-space);
    }
    body[dir="rtl"][data-global-nav="compact"] #global-header .user-info-avatar,
    body[dir="rtl"][data-global-nav="compact"] #global-header .hub-user-menu {
        float: left;
        left: auto;
        margin-left: 0;
        margin-right: var(--application-label-white-space);
    }
}

/* Cloud mode: the app-label menu's favourite toggle reads "Pin" and wears a
 * PIN glyph instead of the star — in cloud the favourites are the pinned apps
 * of the navigation (the side rail lists pinned apps first; the compact
 * header's quick icons are that same set), so "Pin" is what the action means
 * here. The label is swapped in the template (app_label_favourite.html); this
 * only repaints the glyph.
 *
 * Overriding the ::before CONTENT rather than swapping the button's classes
 * keeps every other rule that keys off .icon-bookmark / .app-fav-on working
 * untouched — size, colour, and the app-colour tint on the pinned state.
 * Specificity beats .nomenclature-favourites .icon-bookmark::before (which
 * puts the star there), so it holds under either nomenclature.
 *
 * Fontello has ONE pin glyph — no outline/filled pair like the star — so both
 * states share it and "pinned" is carried by the app-colour tint alone. */
body[data-global-nav="compact"] .app-label-favourite > button.icon-bookmark::before,
body[data-global-nav="compact"] .app-label-favourite > button.icon-bookmark-empty::before {
    content: var(--glyph-pin);
    /* …and the ONE thing the swap does not get for free: optical size. The
     * pin is drawn to fill its em box top to bottom (16.5px of ink at the
     * menu's 18px), while the glyphs it stands beside in the app-label menu
     * are cap-height marks — the help ? is 12.8px, the close ✕ 11.8px. Same
     * 16px icon cell, same centring, and the pin still read a size larger
     * than its neighbours and hung below their line. Corrected the way the
     * Music transport glyphs are (toolbar.css, "per-glyph optical
     * corrections"): shrink the glyph, not the cell, so nothing about the
     * row's geometry moves. */
    font-size: 0.8em;
}

/* Cloud mode: the EVENTS app calendar (FullCalendar 7) goes edge-to-edge in
 * the document body. Its inset comes from padding on the .document-content
 * that holds the pane — drop left/right/bottom so the calendar reaches those
 * edges (top stays, below the app toolbar). The FC view's rounded corners and
 * inset 1px hairline (its card chrome) flatten to square, no shadow, no
 * border. */
body[data-global-nav="compact"] .application-body.application-events .document-content:has(.events-calendar-pane) {
    padding-left: 0;
    padding-right: 0;
    padding-bottom: 0;
}
/* The grid is flush to the screen edges here, so its rounded frame is
 * squared and FC's own border dropped — but it keeps a hairline (Daniel,
 * 2026-08-29). Without one the grid has no edge at all: the top row runs
 * straight into the bar above it and the last hour into the strip below,
 * and a calendar reads as a ruled surface, so the outermost rule has to be
 * there like all the others. The theme's own inset ring, restated through
 * the house border token rather than the theme's literal rgba, so a brand
 * that re-tones its lines re-tones this too. */
body[data-global-nav="compact"] .application-body.application-events .kik-events-calendar .kik-fc-view {
    border-radius: 0;
    box-shadow: inset 0 0 0 1px var(--default-border-colour);
    border: none;
}
/* The bar's two gutters, as vars so the app CSS can read them back: the
 * narrow bar pulls its wrapped title row out over them again (a row that
 * carries no toggles, so the date centres on the calendar — see
 * apps/events/styling/all.css). The right one reserves the window's
 * controls' room — --kik-win-trailing-slot, one slot outside windowed mode
 * (the close outlives the mode) and two inside, from libraries/kikaron/
 * windowed-mode; the left is the plain 16px while the sidebar is open, and
 * the sidebar handle's own slot once it collapses onto the bar. */
body[data-global-nav="compact"] .application-body.application-events {
    --kik-fc-bar-gutter-start: 16px;
    --kik-fc-bar-gutter-end: calc(var(--kik-win-inset) + var(--kik-win-trailing-slot));
}
body[data-global-nav="compact"] .application-body.application-events.sidebar-left-closed {
    --kik-fc-bar-gutter-start: calc(var(--kik-win-inset) + var(--kik-win-slot));
}
/* A phone keeps none at all: there the close is hidden too (the carousel
 * shell closes an app), and the slot would reserve room for nothing — which
 * on a phone is exactly the room the clock and + need to stay on the control
 * row. */
@media (max-width: 680px) {
    html:not(.kik-windowed) body[data-global-nav="compact"] .application-body.application-events {
        --kik-fc-bar-gutter-end: 16px;
    }
}
/* …but NOT the sidebar handle's slot at the start: a phone-sized window used
 * to drop that one too, on the grounds that the handle sat under the bar's
 * landing back there. That button is gone (partials/app_body_frame.html —
 * the pane's own handle is the one control that opens the column, on every
 * width), and on a phone the handle is painted over a landing bar's leading
 * end with nothing beneath it to hold its room. The 16px start then put the
 * month title's first letters under the hamburger disc (Daniel, 2026-09-06:
 * "the month name disappears behind the hamburger disc"). The inset-plus-slot
 * the wider bar reserves is exactly right here as well: the handle sits at
 * the inset at every width, and its slot is the handle's own size.
 *
 * In the drawer band the key is focus-document rather than sidebar-left-closed:
 * below 768 the sidebar-left-* pair is inert (the drawer is out in
 * focus-sidebar and parked in focus-document — libraries/kikaron/sidebar), so
 * a pane parked with `sidebar-left-open` still on it has the handle over this
 * bar all the same. With the drawer out the handle rides the drawer, and the
 * plain 16px is right again. */
@container main (width <= 768px) {
    body[data-global-nav="compact"] .application-body.application-events.focus-document {
        --kik-fc-bar-gutter-start: calc(var(--kik-win-inset) + var(--kik-win-slot));
    }
    body[data-global-nav="compact"] .application-body.application-events.focus-sidebar {
        --kik-fc-bar-gutter-start: 16px;
    }
}
/* The FC header toolbar (only fc-classic-* hashed classes — FullCalendar's
 * classic-theme build names, no stable hook, so this rule needs revisiting
 * whenever the FC bundle is rebuilt): reinstate a left/right gutter now
 * that the calendar itself is flush to the edges. This hashed rule outguns
 * the app-css copy of these values, so the padding has to live HERE. */
body[data-global-nav="compact"] .application-body.application-events .kik-events-calendar
    .fc-classic-dl1.fc-classic-1sP.fc-classic-dNl.fc-classic-XpK.fc-classic-N2M.fc-classic-wwb {
    padding: 0 var(--kik-fc-bar-gutter-end) 0 var(--kik-fc-bar-gutter-start);
}
/* The last chunk (timezone + create) clusters at the row's end with the
 * toolbar's own gap — FC spreads a chunk's children apart otherwise. */
body[data-global-nav="compact"] .application-body.application-events .kik-events-calendar
    .fc-classic-yi0.fc-classic-dl1.fc-classic-1sP.fc-classic-XpK.fc-classic-wwb:last-child {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--pat-toolbar-element-separation, 12px);
}
/* FC view body wrapper (fc-classic-Jk3, likewise a hashed classic-theme
 * name): square its corners and drop its left/right/bottom borders so the
 * grid meets the flush edges cleanly. */
body[data-global-nav="compact"] .application-body.application-events .kik-events-calendar .fc-classic-Jk3 {
    border-radius: 0;
    border-left: none;
    border-right: none;
    border-bottom: none;
}
/* THE TWO SEGMENTED GROUPS ARE NOT DRAWN HERE. (Daniel, 2026-08-30.)
 *
 * What stood in this place was a third hand-drawn cluster: a 1px ring and a
 * 20px radius on the group wrapper, the per-button rings cleared, and an
 * inset 1px seam between abutting buttons — written when FullCalendar's
 * classic theme outlined every button and the seams doubled up.
 *
 * Both groups are pat-button-clusters now, and the component draws exactly
 * that frame itself, from the same tokens as every other strip in the house.
 * Two of these three did nothing but repeat it. The third actively broke it:
 * `overflow: hidden` on the wrapper clips the current item's accent pill,
 * which button-cluster.css paints one toggle-margin OUTSIDE the item's box on
 * all four sides — so the lit segment came back cropped flush to its label.
 *
 * The FC per-button ring that made the seams necessary is gone with the
 * dress in events-fullcalendar-theme (keyed `:not(.kik-fc-grouped)` there),
 * and the cluster clears its children's borders and grounds on its own. */
/* Match the FC toolbar controls (buttons + timezone select) to the regular
 * .pat-toolbar .icon: its frost background + backdrop-blur, and its hover.
 * FC's classic theme gives them a flat opaque button background with no
 * backdrop-filter; align to the exact vars the effective .pat-toolbar .icon
 * uses (frost-background / icon-backdrop-filter, verified against a real
 * events-app icon — NOT the dark --pat-toolbar-icon-background-colour). The
 * today button is a default-background button with an orange DOT glyph, so it
 * is INCLUDED — it gets the frost bg + hover, dot untouched. Only the active
 * view / today[aria-pressed] toggles are excluded, keeping their app-colour
 * accent (this scoped selector would otherwise out-specify their own rules
 * and grey out the selection). */
/* …AND NOT INSIDE A CLUSTER (Daniel, 2026-08-29). The two grouped strips —
 * month/week/day and ‹ • › — are pat-button-clusters now
 * (events-calendar.js), and a cluster carries ONE frosted surface for the
 * whole strip. Frosting each segment inside it as well drew a strip of pills
 * within a strip, which is the thing the conversion was for. Excluded here
 * rather than reset in the app CSS because this is the rule that paints it:
 * it carries an attribute and four classes, so nothing downstream can undo it
 * — measured, twice, before this was found with CSS.getMatchedStylesForNode.
 * The standalone controls (the clock, the +, the bell) keep the frost, which
 * is what it was written for. */
body[data-global-nav="compact"] .application-body.application-events .kik-events-calendar
    :is(.kik-fc-toolbar-button, .kik-events-tz-select):not([aria-pressed="true"]):not(.kik-fc-view-active):not(.kik-fc-cluster *) {
    background-color: var(--pat-toolbar-icon-frost-background);
    -webkit-backdrop-filter: var(--pat-toolbar-icon-backdrop-filter);
    backdrop-filter: var(--pat-toolbar-icon-backdrop-filter);
}
@media (hover: hover) {
  body[data-global-nav="compact"] .application-body.application-events .kik-events-calendar
    :is(.kik-fc-toolbar-button, .kik-events-tz-select):not([aria-pressed="true"]):not(.kik-fc-view-active):not(.kik-fc-cluster *):hover {
      background-color: var(--pat-toolbar-icon-background-colour-hover);
}
}

/* Candy box menu open (compact/top header waffle launcher): the whole tile
 * fills with the accent and the waffle goes white, exactly like an open pinned
 * app — the tokens are set in kik_app_label.html, beside the launcher-active
 * rule that does the same for the other way in. The dots need filling here
 * because the apps SVG carries fill:none/stroke:currentColor as presentation
 * attributes: currentColor already follows the tile's colour, but fill:none
 * would leave them hollow. `svg *`, not `svg circle` — the header's waffle is
 * four rounded RECTS (the rail's mark is circles), so the circle selector
 * matched nothing and the icon stayed an outline. */
/* The waffle's shapes rest at TRANSPARENT, not `fill: none`. Both look empty,
   but `none` is not a colour and cannot interpolate — so when the menu opened
   the dots' interiors snapped to accent while their outlines eased across
   (kik-app-label .kal-icon svg * carries transition: all 0.2s), which read as
   a flash. From transparent the fill animates with everything else. */
#global-header kik-app-label.kal-candy .kal-icon svg * {
    /* !important because the shared tab-icon rules paint app SVGs with their
       own !important fills; this mark is not an app icon and wants none of
       that. The wash is the app icons' own (--app-icon-fill-opacity, 0% on a
       theme without the knob), mixed from the mark's colour, so the waffle
       wears the same duotone as the tiles it opens (Daniel, 2026-09-09). */
    fill: color-mix(in srgb, currentColor var(--app-icon-fill-opacity, 0%),
        transparent) !important;
}
#global-header kik-app-label.kal-candy .kal-icon.tooltip-active-click svg *,
body[data-global-nav="compact"]:has(#app-space.state-on.active-app-apps):has(#application-body-apps.state-on) #global-header kik-app-label.kal-candy .kal-icon svg * {
    /* !important to answer the resting fill above, which needs its own to beat
       the shared app-icon rules. */
    fill: currentColor !important;
    stroke: currentColor !important;
}

/* The two loose controls in the header's float-right row — the personal-menu
 * avatar and the fullscreen toggle — answer the pointer like the tab row does:
 * the same grey wash, in the same 36px square with the row's 8px corner, so a
 * hand moving along the bar meets one shape rather than three. The avatar also
 * takes it while its menu is UP (.tooltip-active-click), which is the state a
 * tab gets for free from its label's :hover; the fullscreen toggle opens
 * nothing, so hover is all it has.
 *
 * Painted by an ::after rather than on the controls themselves, because
 * neither box is the right shape: the avatar is a 34px CIRCLE with its own
 * background disc, and the toggle is a 34x32 glyph box. The pseudo is
 * absolutely positioned and centred, so it lands on the tabs' geometry without
 * touching either control's layout — and it is the plate, not the highlight of
 * a bigger control, so it stays put when the header zooms on landscape phones.
 *
 * The content has to be lifted over it (z-index: 1): the plate is a POSITIONED
 * descendant and would otherwise paint above the in-flow img/glyph. */
#global-header a.user-info-avatar,
#global-header .kik-header-fullscreen {
    position: relative;
}
/* The toggle's plate is on ::before, the avatar's on ::after, and they cannot
   swap (Daniel, 2026-08-16: the tooltip was icon-width, too tall, and bled out
   of the viewport).
   Each control has exactly one pseudo-element free. The toggle carries a
   data-kal-tip, and the header draws those tooltips on ::after — so a plate
   there meant one box serving two features: the tooltip overrode position and
   padding but never width/height, inherited the plate's 36x36, and laid its
   label out in a box the size of the glyph. The avatar cannot take the same
   move: .pat-avatar draws the INITIALS DISC on its ::before.

   The avatar has since been given a tooltip of its own, so it has no pseudo
   left at all — its plate is painted on the ELEMENT instead, below. */
#global-header .kik-header-fullscreen::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    translate: -50% -50%;
    width: var(--kik-global-nav-icon-size);
    height: var(--kik-global-nav-icon-size);
    border-radius: var(--kal-corner-radius, 8px);
    background-color: transparent;
    /* Both painted properties, so the plate arrives and leaves as one thing —
       the wash and, on the avatar, the slot's shadow. */
    transition: background-color 0.2s, box-shadow 0.2s;
    pointer-events: none;
}
#global-header a.user-info-avatar > img,
#global-header .kik-header-fullscreen > span {
    position: relative;
    z-index: 1;
}
/* While the personal menu is open, the avatar's plate deepens into a recessed
   SLOT — an inset shadow all round, so the face sits IN the bar rather than on
   it. The avatar only — it is the one control in the row holding a picture, and
   the socket is what seats it; around a glyph, or standing at rest, it is a box
   drawn around nothing. Open-menu only: there is no hover twin (below).
   .tooltip-active-click lands on the anchor itself here: the avatar IS the
   pat-context-menu trigger, unlike the launcher, where it sits on a child of
   the label that paints. */
/* Painted ON THE ELEMENT, not on a pseudo: the avatar has none to spare.
   ::before is .pat-avatar's initials disc and ::after is now its tooltip, this
   control having joined the ones that name themselves on hover. It does not
   need a pseudo anyway — the anchor IS the 36px box the plate was drawing, so
   it can carry the wash and the slot itself. The transparent/none pair below
   is what it rests at. */
#global-header a.user-info-avatar {
    border-radius: var(--kal-corner-radius, 8px);
    transition: background-color 0.2s, box-shadow 0.2s;
}
#global-header a.user-info-avatar.tooltip-active-click,
#global-header a.user-info-avatar:has(.tooltip-active-click) {
    background-color: var(--kal-hover-bg, rgba(0, 0, 0, 0.06));
    box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.15);
}
/* The avatar takes the pointer wash like the rest of the row (Daniel,
   2026-08-20). It once did, then didn't — a plate sliding in and out under a
   full-bleed face read as the header twitching. What makes it read now is that
   the face no longer fills its seat: pulled in and round, it leaves a square of
   clear space for the wash to arrive in, so the plate lands AROUND the picture
   instead of behind it. The wash only; the inset slot stays the open-menu
   state's alone, so the two still say different things. */
@media (hover: hover) {
    #global-header a.user-info-avatar:hover {
        background-color: var(--kal-hover-bg, rgba(0, 0, 0, 0.06));
    }
    #global-header .kik-header-fullscreen:hover::before,
    #global-header .kik-header-switch-env:hover::before {
        background-color: var(--kal-hover-bg, rgba(0, 0, 0, 0.06));
    }
}
/* The hopper needs the plate DRAWN as well as coloured: unlike the fullscreen
   toggle it never had a ::before of its own, so there was no box for the wash
   to land in — the two controls sit side by side and only one answered the
   pointer. Same 36x36 centred plate, same corner. */
#global-header .kik-header-switch-env {
    position: relative;
}
#global-header .kik-header-switch-env::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    translate: -50% -50%;
    width: var(--kik-global-nav-icon-size);
    height: var(--kik-global-nav-icon-size);
    border-radius: var(--kal-corner-radius, 8px);
    background-color: transparent;
    transition: background-color 0.2s;
    pointer-events: none;
}

/* The PICTURE is a disc; its SEAT is not. .pat-avatar's own 50% is kept on the
 * photo and on the initials disc — a face reads as a face at a circle, and it
 * is the one control in the row holding one. The anchor around it keeps
 * --kal-corner-radius, the corner the tabs, the pinned app icons and the plate
 * behind it all round by, so the wash that arrives on hover is the same square
 * with the same corner the rest of the row answers with. Two shapes, one inside
 * the other, which is what the pulled-in scale below makes room for.
 *
 * That means the disc cannot stay on the ANCHOR, where .pat-avatar puts it: an
 * element cannot shrink away from its own background. It moves to ::before,
 * which carries the initials — one layer, transformed as a unit — and the
 * anchor keeps nothing but the hit box. Its inset shadow goes for the same
 * reason: it paints under the element's content, so anything pulling off it
 * leaves the dark circular edge behind. Neither was ever visible on its own —
 * a full-bleed photo, or a disc of exactly the same colour, sat on top — but
 * the plate is a 6% wash rather than paint, so both would show through it as a
 * ring the moment the avatar pulled in.
 *
 * ::before is taken out of the grid and stretched over the whole box to BE
 * that disc. As a grid item it shrink-wraps the initials — a text-sized blob,
 * and not even a square one — and stretching it inside the grid doesn't help:
 * .pat-avatar centres its tracks (justify-content/align-items), so the track
 * it would stretch to is that same content box. Absolute + inset:0 measures
 * the anchor instead, which is the 34px square we want a circle of. grid-area
 * has to go with it: a definite grid placement would make the AREA the
 * containing block again, straight back to the content box. Stretched, it
 * re-centres the initials itself (place-content), the line-height that used to
 * do it no longer matching the box. A photo avatar never reaches any of this —
 * .pat-avatar:has(img) takes ::before out entirely. */
#global-header a.user-info-avatar > img {
    border-radius: 50%;
}
/* ONE SEAT for everything riding this row. The app tab and the media-player
 * chip are both 36px squares centred in the header's 54 (kik_app_label.html;
 * base.css's .kik-media-player-chip.in-header, which centres itself with
 * `margin: calc((var(--global-header-height) - 36px) / 2)`) — the avatar was
 * 34 at a 10px offset, from a height derived off --application-label-white-space
 * rather than off the row. Two pixels shorter and one pixel lower than its
 * neighbours: not obviously wrong on its own, but the three squares no longer
 * sat on a line, and the odd one out was the one holding a face.
 *
 * Same arithmetic as the chip, so the two stay together if the header height
 * ever moves. Two ids to out-rank global-header.css's `.pat-avatar#user-avatar`
 * height rule; this sheet also loads after all.built.css, which settles the
 * tie the specificity does not. */
#global-header a#user-avatar.user-info-avatar {
    width: var(--kik-global-nav-icon-size);
    height: var(--kik-global-nav-icon-size);
    margin-top: calc((var(--global-header-height, 54px) - var(--kik-global-nav-icon-size)) / 2);
    margin-bottom: 0;
}

/* Phones: close the gap between the album art and the avatar.
 *
 * It was 14px — the avatar's own 10px lead-in plus the chip's 4px trailing
 * margin, two spacings set independently and never against each other. At
 * desktop widths they sit in a row with the favourites and the fullscreen
 * toggle between them and it reads as even; on a phone those are all hidden, so
 * the two survivors sat further apart than anything else in the header.
 *
 * Expressed as ONE number: the chip gives up its trailing margin and the
 * avatar's lead-in is the whole of the gap. Both are floated right, so this is
 * the only space between them. */
@container screen style(--screen-small: true) {
    /* …and both grow to the phone row's 42px, the height the app tab takes
       there (kik_app_label.html). Re-centred on the way: the 36px seat above
       and the chip's own margin both centre by subtracting 36 from the header
       height, so the number has to move with the box or the row drops 3px low.
       One expression, so a change to --global-header-height still lands. */
    #global-header .kik-media-player-chip.in-header,
    #global-header a#user-avatar.user-info-avatar {
        width: 42px;
        height: 42px;
        margin-top: calc((var(--global-header-height, 54px) - 42px) / 2);
    }
    #global-header .kik-media-player-chip.in-header {
        margin-right: 0;
    }
    /* A 42px SQUARE is not a tab, so it carries no × — the same rule the
       chip's other two square docks follow (base.css: the rail and the phone
       bar). At this width the tab has given up its title and become the tile
       again, and a 15px close disc over a 42px cover hides the artwork that
       says what is playing. The player is one press away, and it closes from
       there. */
    #global-header .kik-media-player-chip.in-header .kmp-chip-close {
        display: none;
    }
    #global-header a#user-avatar.user-info-avatar {
        margin-left: 6px;
    }
}
#global-header a.user-info-avatar {
    background-color: transparent;
    box-shadow: none;
}
#global-header a.user-info-avatar::before {
    /* Over the plate, like the photo — see the z-index note above. */
    position: absolute;
    inset: 0;
    grid-area: auto;
    /* .pat-avatar centres ::before with justify-self/align-self. Those keep
       acting on an ABSOLUTE box — auto width against inset:0 resolves to
       fit-content and gets centred in the box rather than filling it, so the
       disc came out the size of the two initials. Stretch is what inset:0 is
       asking for. */
    justify-self: stretch;
    align-self: stretch;
    z-index: 1;
    display: grid;
    place-content: center;
    background-color: var(--pat-avatar-background-colour);
    border-radius: 50%;
}
/* The face sits INSIDE its seat at all times. The pulled-in size used to be the
   open-menu state only, the avatar filling its 36px square at rest and shrinking
   into the plate while its panel was up; Daniel (2026-08-20) wanted the smaller
   face to be the resting one. So the scale is unconditional, and what the open
   menu changes is the plate alone — the wash and the inset slot, which now have
   the ring of clear space around the face to show themselves in.

   Still a scale rather than a smaller box: the anchor is the 36px seat the row
   is measured on (and the hit target, and the plate), so only its CONTENTS pull
   in. No transition left — nothing moves between states. */
#global-header a.user-info-avatar > img,
#global-header a.user-info-avatar::before {
    transform: scale(0.7);
}

/* IMMEDIATE TOOLTIPS on the header's icon-only controls — the pinned app
 * tiles, the launcher waffle, the home brandmark and the fullscreen toggle.
 * The vertical rail has had these since it learned to collapse
 * (global-nav-side.css, from data-gns-label): once a control is a bare glyph,
 * its name has to be available without a wait, because the glyph IS the only
 * thing identifying it.
 *
 * Same recipe here, keyed on data-kal-tip. That attribute exists rather than
 * reading `title` because a title would ALSO raise the browser's own tooltip a
 * second later — two labels for one control, in two styles, at two positions.
 * The controls carry aria-label for the accessible name, so nothing is lost by
 * dropping title; a screen reader reads the same words either way.
 *
 * NOT ON A FULL TAB. An open app's tab already shows its name in the row, and
 * a tooltip repeating it is noise that also covers the tab underneath. Only
 * the controls that have no room for a name get one, which is why this is
 * keyed on the attribute rather than on the row: a tab never carries it.
 *
 * Below the control rather than beside it, since the row is at the top of the
 * screen. position: fixed takes it out of the header's overflow (the tab row
 * clips) and off the z-index of whatever it hangs from. */
@media (hover: hover) {
    /* Positioned against the CONTROL, not the viewport (Daniel, 2026-08-16:
       it did not look centred underneath its trigger). A fixed box with only
       `top` set takes its horizontal place from the static position, which is
       wherever the pseudo-element would have sat inside its control — for a
       flex control with centred content that is not the control's middle, and
       no amount of translating guesses it reliably. Anchoring to the control
       and centring on it is exact and needs no measurement. */
    body[data-global-nav="compact"] #global-header [data-kal-tip] {
        position: relative;
    }
    body[data-global-nav="compact"] #global-header [data-kal-tip]:hover::after {
        content: attr(data-kal-tip);
        position: absolute;
        /* 5px CLEAR OF THE BAR (Daniel, 2026-08-16). The old line was
           `header - 4px`, which put the box 4px INSIDE the bar it hangs from;
           the target is 5px below the bar's bottom edge.
           Restated from the control, since that is what the box hangs off: a
           control is centred in the bar, so its top is (header - h) / 2, and
           landing at (header + 5) from the viewport therefore means
           header/2 + 5 + h/2 below it. `50%` in `top` resolves against the
           containing block's height, which is exactly that h/2 — so a 36px
           tile and a 22px glyph put their labels on the same line. */
        top: calc(var(--global-header-height, 54px) / 2 + var(--kik-tip-gap) + 50%);
        left: 50%;
        translate: -50% 0;
        /* The card itself is the house tooltip's, from the shared --kik-tip-*
           tokens (quaive/settings/artefacts/variables.css) — the dark pair,
           since this one paints over the header rather than over the page.
           Only WHERE it sits is the header's own business. */
        background: var(--kik-tip-background-dark);
        color: var(--kik-tip-text-colour-dark);
        font-size: var(--kik-tip-font-size);
        font-weight: var(--kik-tip-font-weight);
        line-height: var(--kik-tip-line-height);
        padding: var(--kik-tip-padding);
        border-radius: var(--kik-tip-border-radius);
        box-shadow: var(--kik-tip-box-shadow);
        white-space: nowrap;
        z-index: 1000;
        pointer-events: none;
    }
    /* …but NOT inside the tab row, which clips: #kik-app-labels and its row
       both carry overflow: hidden (kik_app_label.html), so an absolutely
       positioned tooltip on a tab, the candy box or a favourite would be cut
       off at the row's edge. That is what the fixed positioning was for in the
       first place. Those keep it — uncentred, but visible, which is the trade
       the row has always made. */
    body[data-global-nav="compact"] #global-header #kik-app-labels [data-kal-tip]:hover::after {
        position: fixed;
        /* Straight from the viewport here, but the same line as the rest. */
        top: calc(var(--global-header-height, 54px) + var(--kik-tip-gap));
        /* Centred on the tile the hard way, since the row clips and this box
           therefore cannot be anchored to its control (Daniel's recipe,
           2026-08-16): leave it at its static position — `left`/`right` auto —
           nudge right by half a tile with a margin, which is what shifts a
           positioned box away from that static position, and then pull back by
           half of ITS OWN width. What lands is the tile's middle.
           --kal-tip-nudge is that half-tile, so a row whose icons change size
           is one number away from correct. */
        --kal-tip-nudge: calc(0.5 * var(--kal-icon-w, 33px));
        left: auto;
        right: auto;
        margin-left: var(--kal-tip-nudge);
        translate: -50% 0;
    }

    /* The LAST control in the bar gives up the centring: half a tooltip past
       the avatar's middle is past the screen. It runs to 5px off the viewport
       edge instead — as far right as it can go, which is the nearest it can
       get to centred.
       Expressed from the control, because that is what the box is anchored
       to: the header's trailing padding IS the gap between the avatar's right
       edge and the viewport's, so pulling the box out by that padding less
       5px lands it exactly 5px clear. A negative `right` is the box reaching
       past its control, which is the point. */
    body[data-global-nav="compact"] #global-header a.user-info-avatar:hover::after,
    body[data-global-nav="compact"] #global-header .hub-user-menu:hover::after {
        left: auto;
        right: calc(var(--kik-tip-gap) - var(--sidebar-padding-right, 25px));
        translate: none;
    }

    /* …and the FIRST control gives it up for the same reason at the other end
       (Daniel, 2026-08-16). The candy tile opens the row, so centring on it
       sends half the label — and "Dashboard" is a wide one — past the left
       edge of the screen, where it is simply cut off. It stops 5px clear
       instead, the mirror of the avatar above.
       Straight from the viewport rather than from the control: this box is
       already position: fixed (the row clips, which is what that is for), so
       a plain `left` is measured off the viewport edge and needs no knowledge
       of what sits to the tile's left. */
    body[data-global-nav="compact"] #global-header #kik-app-labels kik-app-label.kal-candy:hover::after {
        left: var(--kik-tip-gap);
        right: auto;
        margin-left: 0;
        translate: none;
    }
}

/* --- Room for the Mac app's window controls -----------------------------
 * Kikaron for Mac has no title bar of its own. Its window content runs to the
 * top edge, which puts the three traffic lights ON this header rather than
 * above it, and without a gap they land on the first app icon.
 *
 * The app sets data-mac-window-controls on <html> while the buttons are
 * actually there, and removes it in full screen — macOS takes the buttons away
 * then, and a header still holding the gap is holding it for nothing. An
 * attribute rather than a user-agent test because it has to change during a
 * session, not just at page load.
 *
 * 97px, measured against where the app actually puts the buttons rather than
 * against the sizes Apple documents: they are 14px on 23px centres, and the
 * app seats them at a 20px inset — (54px header − 14px button) / 2, the
 * measure that leaves the same gap above, below and to the left of the group.
 * So the group runs 20px→80px, and 97px leaves 17px of air before the first
 * app icon.
 *
 * `html … body` only to outrank the base rule's own leading inset; there is
 * nothing clever about the selector beyond that.
 */
html[data-mac-window-controls="1"] body #global-header {
    padding-left: 97px;
}

/* --- Kikaron for Mac: no hub hopper in the header -----------------------
 * The Mac app sets data-mac-app on <html> for its whole life — distinct from
 * data-mac-window-controls, which comes off in full screen. A rule that hid
 * the hopper on the window-controls attribute would put it back the moment the
 * window filled the screen, which is not what "not in the Mac app" means.
 *
 * The hopper stays exactly where it is in a browser tab on the same instance.
 */
html[data-mac-app="1"] #global-header .kik-header-switch-env {
    display: none;
}

/* --- THE CANDY BOX LIGHTS UP WHILE THE DESK IS THE ACTIVE APP (moved here
   from windowed-mode.css on 2026-09-04; keyed on html.kik-one, which only
   the One/Pro faces render).

   The box is the apps launcher, and since the apps grid lives in the desk
   (the bento's Apps portlet, the phone home's grid) tapping it brings the
   desk forward. It takes the swirl's treatment exactly — accent plate, white
   glyph (the waffle is an inline SVG stroked in currentColor). This out-ranks
   the apps-page-in-view tint in cloud-dashboard.css (a plain id/class chain)
   through the :has() prefix, which is what should happen: "the desk IS the
   page you are on" is the stronger statement of the two.

   NOT the phone bar's trigger. That one is a 50x64 hit area with a 32px chip
   inside it (--kik-dock-icon-size), so plating the trigger gave a tall
   rectangle instead of a square, and the bar paints its own iconography black
   with !important, which left the waffle dark on orange. The bar's chip
   already had the whole treatment — accent plate, white glyph, square, at the
   right strength — in phone_app_carousel.html; it is keyed there. The rail's
   trigger is cloud-nav-rail.css's. */
html.kik-one body:has(#app-space.state-on.active-app-dashboard) #compact-candy-box {
    background-color: var(--app-colour-apps, #F37021);
    color: #fff;
}
