/* ==========================================================================
   Komunidad Platform — product chrome

   Sign-in, the single-pane assistant, the usage dashboard, and the workspace
   activation pages. The assembler at /build/ carries its own stylesheet; this
   one has to agree with it, because a person crosses between the two in a
   single session and a change of palette mid-flow reads as a change of
   product.

   So the palette here is the one from assembler.css — cool
   teal on white — and not the warm paper stock this file used to carry. There
   is deliberately no dark variant: /build/ has none, and a machine set to dark
   would otherwise show a dark sign-in page and a light app behind it.

   Pure CSS, no framework. All tokens are custom properties.
   ========================================================================== */

:root {
  /* Surfaces — the assembler's working surfaces, so the two agree */
  --paper:        #f4f7f8;
  --surface:      #ffffff;
  --surface-2:    #fafcfc;
  --surface-sunk: #eef2f4;

  /* Ink */
  --ink:          #17262b;
  --ink-2:        #41545c;
  --ink-3:        #6b7a84;
  --ink-faint:    #93a3ab;

  /* Rules and edges */
  --rule:         #e2eaec;
  --rule-strong:  #cfdade;

  /* Brand. #1d969e, not the #2dd4bf of the dark marketing pages: mint on
     white fails contrast for text and small controls. */
  --accent:       #1d969e;
  --accent-2:     #17787f;
  --accent-soft:  #eaf6f7;
  --accent-ink:   #135c62;
  --accent-line:  #a9d9dd;

  /* Semantic */
  --warn:         #8a5a06;
  --warn-soft:    #fdf5e6;
  --danger:       #b4322f;
  --danger-soft:  #fdefee;
  --ok:           #1c7a52;
  --ok-soft:      #eaf6f0;

  /* Type. Poppins throughout, self-hosted in css/fonts.css. --font-mono and
     --font-serif are kept as roles so existing rules need no rewriting; all
     three resolve to the one family, and the tabular-figure rules below do the
     digit alignment the monospace face used to. */
  --font-sans: Poppins, -apple-system, BlinkMacSystemFont, "Segoe UI",
               Roboto, "Helvetica Neue", sans-serif;
  --font-mono: Poppins, -apple-system, BlinkMacSystemFont, "Segoe UI",
               Roboto, "Helvetica Neue", sans-serif;
  --font-serif: Poppins, -apple-system, BlinkMacSystemFont, "Segoe UI",
                Roboto, "Helvetica Neue", sans-serif;

  /* Metrics. Rounded rather than the old 3px filing-card corners, to match
     the 26px composer pill in the assembler. */
  /* ONE RADIUS (2026-09-22, customer request: "uniform radius border for
     all"). The two larger tokens are ALIASES now, not values: every corner
     on every console screen is this one, and `--radius-lg` / `--radius-pill`
     survive only so an old rule keeps resolving. ui.css says what is exempt
     (a circle, a concentric ring, a miniature mock of the tenant app). */
  --radius:    10px;
  --radius-lg: var(--radius);
  --radius-pill: var(--radius);
  --gutter:    20px;
  --rhythm:    24px;
  --shadow:    0 1px 2px rgba(20, 60, 66, .04),
               0 4px 16px rgba(20, 60, 66, .06);
  --shadow-lg: 0 2px 8px rgba(20, 60, 66, .06),
               0 20px 48px rgba(20, 60, 66, .10);
  --ring:      0 0 0 3px rgba(29, 150, 158, .16);
  --maxw:      1320px;

  /* THE CONSOLE'S EIGHT GRADIENT PAIRS (moved here 2026-09-18 from
     operator-home.css, which declared them on `.oh`). A hue belongs to a TOOL
     or a GROUP (core/operator_home.py's `hue`), never to a position in a row,
     and the SCREEN a tool opens now wears its own hue too — the Knowledge
     Studio's head, the Builder Studio's — so a studio is recognisable as the
     tile that opened it. Three screens reading one copy, because two copies of
     one palette is two things to keep in step.

     Mixed from the brand's own stops (k_color.svg: #1F3556 to #2BA093) plus
     four neighbours, so the console reads as one family rather than a candy
     shelf. */
  --oh-g1a: #1F3556; --oh-g1b: #3B6A9C;   /* navy      */
  --oh-g2a: #1F7079; --oh-g2b: #2BA093;   /* teal      */
  --oh-g3a: #2BA093; --oh-g3b: #6FD1B0;   /* sea green */
  --oh-g4a: #4B3F9E; --oh-g4b: #8A7BDA;   /* indigo    */
  --oh-g5a: #A24A7A; --oh-g5b: #D98BB5;   /* plum      */
  --oh-g6a: #21495F; --oh-g6b: #4A8DA3;   /* slate     */
  --oh-g7a: #B8641F; --oh-g7b: #E7A55A;   /* amber     */
  --oh-g8a: #C4453E; --oh-g8b: #F08A7E;   /* coral     */
}

/* The pair an element wants, chosen by its `data-hue`. Declared here rather
   than in one screen's stylesheet so every console screen can read it. */
[data-hue="1"] { --ta: var(--oh-g1a); --tb: var(--oh-g1b); }
[data-hue="2"] { --ta: var(--oh-g2a); --tb: var(--oh-g2b); }
[data-hue="3"] { --ta: var(--oh-g3a); --tb: var(--oh-g3b); }
[data-hue="4"] { --ta: var(--oh-g4a); --tb: var(--oh-g4b); }
[data-hue="5"] { --ta: var(--oh-g5a); --tb: var(--oh-g5b); }
[data-hue="6"] { --ta: var(--oh-g6a); --tb: var(--oh-g6b); }
[data-hue="7"] { --ta: var(--oh-g7a); --tb: var(--oh-g7b); }
[data-hue="8"] { --ta: var(--oh-g8a); --tb: var(--oh-g8b); }

/* --------------------------------------------------------------------------
   Reset / base
   -------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

/* HOW MUCH OF THE LEFT EDGE THE RAIL HAS TAKEN, as a custom property.

   Zero unless the operator has moved their menu to the side. Everything that
   has to keep clear of the rail reads THIS rather than the rail's own width,
   for two reasons learned by shipping the other way first:

   - the rail is `position: fixed`, so it is out of flow and reserves nothing
     on its own. Pushing `main.shell` with a margin worked for ordinary pages
     and was silently undone by the three that lay themselves out: the Brand
     Studio and the Framework Studio both reset `main.shell`'s `margin` to 0
     (they need the full width), so the rail drew straight over their content.
     PADDING ON THE BODY cannot be undone by a rule about `.shell`.
   - a full-bleed measured in `vw` bleeds under the rail, because `vw` is the
     whole viewport however much of it something else has taken. `.tours` does
     exactly that, and it subtracts this inset now.  */
:root {
  --rail-w: 232px;
  --rail-icon-w: 62px;
  --nav-inset: 0px;
}

body {
  margin: 0;
  padding-left: var(--nav-inset);
  /* Reserved by a BOTTOM menu bar only; 0 in every other position. */
  padding-bottom: var(--nav-bottom, 0px);
  /* THE FOOTER SITS AT THE FOOT OF THE WINDOW (2026-09-28, customer report:
     on a short page it floated under the content with an empty band below).
     A column at least one window tall, with main taking the slack. It is the
     same shape the studios already give body (`body:has(.bs)`,
     `body:has(.ks)`), whose more specific rules still win on their pages.
     Border-box so the bottom bar's padding is inside the window height rather
     than a scrollbar's worth below it. */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
  box-sizing: border-box;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 { margin: 0; font-weight: 600; letter-spacing: -0.012em; }
h1 { font-size: 1.35rem; }
h2 { font-size: 1.05rem; }
h3 { font-size: .92rem; }

p { margin: 0 0 var(--rhythm); }
a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--accent-ink); }

code, kbd, .mono, .tabular {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

::selection { background: var(--accent-soft); color: var(--accent-ink); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius);
}

/* --------------------------------------------------------------------------
   Layout shell
   -------------------------------------------------------------------------- */

.masthead {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 0 var(--gutter);
  height: 58px;
  background: var(--surface);
  border-bottom: 1px solid var(--rule);
  backdrop-filter: saturate(180%) blur(8px);
}

/* The mark is a link home, and it is the real logo rather than a text
   wordmark plus a square — the same lockup the builder opens with, so crossing
   from /build/ to /login/ does not look like arriving somewhere else. */
.masthead__mark {
  display: flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
  color: inherit;
  white-space: nowrap;
}

.masthead__logo {
  height: 24px;
  width: auto;
  display: block;
  transition: opacity var(--dur) var(--ease);
}
.masthead__mark:hover .masthead__logo { opacity: .72; }

.masthead__rule {
  width: 1px;
  height: 18px;
  background: var(--rule);
}

.masthead__sub {
  font-size: .72rem;
  font-weight: 500;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-3);
}
/* The tagline in the sub slot: sentence case, not the spaced capitals a
   short name wears, or a long line turns into a row of letters. */
.masthead__sub--tag { text-transform: none; letter-spacing: 0; font-size: .8rem; }

/* THE NAV SCROLLS RATHER THAN WRAPPING, because the bar is a FIXED 58px and
   a wrapped link cannot fit in it. A superadmin's row is eleven links wide --
   it needs 1154px and a 1440px laptop leaves it 1006 -- so without `nowrap`
   the flex items shrank under their own text, every link grew to 78px inside
   a 58px bar, and the current-page pill's pill radius turned it into a large
   oval floating out of the masthead. `min-width: 0` is what lets the flex
   item shrink so `overflow-x` has something to scroll; the scrollbar itself
   is hidden because a 4px gutter under a 58px bar is chrome, not a control,
   and the row stays reachable by wheel, trackpad, touch and keyboard. */
.masthead__nav {
  display: flex; gap: 4px; margin-left: auto;
  min-width: 0; overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none; -ms-overflow-style: none;
}
.masthead__nav::-webkit-scrollbar { display: none; }

/* AN OPERATOR'S NAV IS DENSER THAN A VISITOR'S. Scrolling is the safety net
   (the scroller above); it is not a good first answer, because the item
   scrolled out of sight is usually the CURRENT page. The density is keyed on
   the operator's own header (`.masthead--op`) rather than on a child count:
   since the menu became GROUPS (2026-09-15) the nav's children are the five
   groups, not the links, and a count would say "five" of a row of fifteen.
   The visitor's short row is untouched and keeps its air.

   THE LOCKUP GIVES UP ITS SUBTITLE in an operator's ROW: "Komunidad Platform"
   beside the mark is ~160px of the widest thing on the row, and the mark
   alone still says whose product this is. `:root:not([data-nav="side"])` is
   the CONDITION, not a specificity trick: a rail has room for the subtitle,
   so the rule simply does not apply there. */
.masthead--op .masthead__nav { gap: 2px; }
.masthead--op .masthead__nav .masthead__link {
  padding: 7px 8px;
  font-size: .82rem;
}
:root:not([data-nav="side"]) .masthead--op .masthead__sub,
:root:not([data-nav="side"]) .masthead--op .masthead__rule {
  display: none;
}

/* --- The menu's GROUPS (customer arrangement, 2026-09-15) -------------------
   Home; Deliver; Manage; Grow; Account; Platform. In a ROW a group is a
   flex run of its links with a hairline before it, and its title is not
   drawn: a row that already barely fits has no room for five headings. In
   the RAIL (further down) a group is a column under a small uppercase
   title. The markup is one shape for both, drawn from core.operator_home. */
/* `flex: none`, NOT `min-width: 0` (2026-09-22): a group that may shrink
   shrinks below its own links, and on a phone the six groups of an
   operator's row were drawn on top of one another (measured at 400px: the
   first group 14px wide holding a 57px link). The nav is the scroller; the
   groups keep their width so it has something to scroll. */
.masthead__group { display: flex; align-items: center; gap: 2px; flex: none; }
.masthead__group + .masthead__group {
  margin-left: 4px;
  padding-left: 6px;
  border-left: 1px solid var(--rule);
}
.masthead__grouph { display: none; }

/* A SOON item: a tool the menu names that the platform does not hold yet.
   A span, never a link, faint, with a small tag; shown only in the rail,
   where there is room for a statement beside the links (a row hides it,
   and a row of glyphs has nothing to say it with). */
.masthead__link--soon {
  display: none;
  color: var(--ink-faint);
  cursor: default;
}
.masthead__soon {
  flex: none;
  margin-left: auto;
  padding: 1px 6px;
  border-radius: var(--radius);
  background: var(--surface-sunk);
  color: var(--ink-3);
  font-size: .58rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
}

/* --- The toggle, and the rail it opens ------------------------------------

   TOP OR SIDE (customer request, 2026-09-14). The button renders only for an
   operator — see core.context_processors.operator's `nav_toggle` — because it
   is their rows that are twelve and ten links long, and measured in a real
   browser the twelve do not fit a 1280 laptop across the top. */

.masthead__navpos {
  display: grid;
  place-items: center;
  flex: none;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
}
/* `.masthead__navpos` sets a `display`, which BEATS the hidden attribute's own
   `display: none`. The button ships hidden and navpos.js reveals it, so
   without this guard a page with no script would show a control that does
   nothing — the trap the tour's back-to-top arrow and the paywall's pay
   button each met before it. */
.masthead__navpos[hidden] { display: none; }
/* And not offered where it does nothing. The rail is a desktop layout — below
   901px a 232px column is most of the screen, so the CSS ignores the stored
   choice and the top bar comes back. A button that changes nothing visible is
   a button somebody presses twice and then distrusts. The VALUE is untouched,
   so widening the window restores the layout they picked. */
.masthead__navpos:hover { border-color: var(--ink-3); color: var(--ink); }
.masthead__navpos:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.masthead__navpos svg { width: 15px; height: 15px; fill: currentColor; }
/* The glyph IS the state: a bar over a pane while the menu is on top, rotated
   into a rail beside a pane once it has moved. Colour never carries it alone,
   and the button's own label says the same thing in words. */
.masthead__navpos .navpos__a { opacity: .95; }
.masthead__navpos .navpos__b { opacity: .35; }
[data-nav="side"] .masthead__navpos svg { transform: rotate(-90deg); }

/* The glyph beside each word. Hidden in the top ROW, where the word is the
   control and a row of twelve icons plus twelve words would be a row half
   again as long as the one that already does not fit. */
.masthead__ico { display: none; }
[data-nav="side"] .masthead__ico {
  display: block;
  flex: none;
  width: 19px;
  height: 19px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* The sprite is a definitions-only document: it must take no space. */
.navsprite { position: absolute; width: 0; height: 0; overflow: hidden; }

/* The glyph-only mark. Present on every operator page and drawn in exactly
   one state — see the collapsed rail below — so the default is simply off. */
.masthead__glyph { display: none; }

/* The size control wears the move control's dressing — they are a pair and
   sit together — and turns its chevron round to say which way it goes. */
.masthead__railsize {
  display: grid;
  place-items: center;
  flex: none;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
}
.masthead__railsize[hidden] { display: none; }
.masthead__railsize:hover { border-color: var(--ink-3); color: var(--ink); }
.masthead__railsize:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.masthead__railsize svg {
  width: 15px; height: 15px;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
[data-rail="icons"] .masthead__railsize svg { transform: rotate(180deg); }

/* THE RAIL.

   The masthead stops being a bar and becomes a fixed column down the left.
   Four things move with it and all four are here rather than in a second
   stylesheet, so the layout is one block somebody can read at once: the
   header, the nav inside it, the lockup above the nav, and the page content —
   which has to be pushed clear, because a fixed element is out of flow and
   would otherwise be drawn over.

   Only above 900px. On a phone a 232px rail is most of the screen, so the
   preference is ignored there and the top bar comes back; the stored value is
   untouched, so widening the window restores the choice. */
@media (min-width: 901px) {
  [data-nav="side"] { --nav-inset: var(--rail-w); }
  [data-nav="side"][data-rail="icons"] { --nav-inset: var(--rail-icon-w); }

  [data-nav="side"] .masthead {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: var(--rail-w);
    height: auto;
    flex-direction: column;
    align-items: stretch;
    gap: 14px;
    padding: 18px 14px;
    border-bottom: 0;
    border-right: 1px solid var(--rule);
    overflow-y: auto;
  }

  /* The lockup keeps its subtitle here: a column has the room the row did
     not, and the rule that hides it above is scoped to say exactly that.

     STACKED, though. `.masthead__mark` is a nowrap row, and measured in the
     rail "KOMUNIDAD PLATFORM" ran straight out of the 232px column and under
     the toggle. A column has room for the subtitle on a LINE OF ITS OWN, not
     beside the mark. The little vertical hairline goes with the change: it
     separated two things sitting side by side and there is nothing beside
     anything now. */
  [data-nav="side"] .masthead__mark {
    flex-direction: column;
    align-items: flex-start;
    gap: 7px;
    padding: 2px 34px 12px 6px;
    border-bottom: 1px solid var(--rule);
    white-space: normal;
  }
  [data-nav="side"] .masthead .masthead__rule { display: none; }

  /* A column, at full size: the whole point of moving is that the pills stop
     being squeezed, so every density rule above is undone here. */
  [data-nav="side"] .masthead .masthead__nav {
    flex-direction: column;
    align-items: stretch;
    margin-left: 0;
    gap: 3px;
    overflow-x: hidden;
    overflow-y: auto;
  }
  /* `.masthead__nav` is named again on purpose. The density rule above is
     `.masthead--op .masthead__nav .masthead__link`, which is three
     class-weight parts; `[data-nav="side"] .masthead__link` is only two and
     LOSES to it. Measured before this: the rail's links were still drawn at
     the squeezed 13.12px inside a column with room to spare. Matching the
     weight and coming later in the file is what undoes them. */
  /* A ROW: glyph then word, on one line.

     `.masthead__link` is an `<a>`, which is inline, and `align-items` on an
     inline box does nothing — the block-level `<svg>` inside it forced a line
     break and the word landed UNDER its glyph (reported from a screenshot;
     the probe had counted the words as visible, which they were, just not
     where they belonged). `display: flex` is what puts them side by side, and
     it is the declaration that was missing rather than an alignment tweak. */
  [data-nav="side"] .masthead__nav .masthead__link {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 9px 12px;
    font-size: .86rem;
    text-align: left;
    border-radius: var(--radius);
  }

  /* The session block sits at the foot of the rail. `margin-top: auto` on a
     column flex child is what puts it there whatever the nav's length.

     The left border, margin and padding are cleared explicitly: they are the
     divider that separates the session from the nav in a ROW, and in a column
     they met the border-top below and drew an L that read as a stray box
     around the username (seen in a screenshot before it was measured). */
  [data-nav="side"] .masthead__session {
    margin-top: auto;
    margin-left: 0;
    padding-left: 0;
    border-left: 0;
    padding-top: 12px;
    border-top: 1px solid var(--rule);
    flex-wrap: wrap;
    gap: 6px;
  }
  [data-nav="side"] .masthead__navpos {
    position: absolute;
    top: 16px;
    right: 12px;
  }

  /* The groups, as columns under their titles. The hairline a row draws
     BEFORE a group becomes air above it; the title is the small uppercase
     word the customer's arrangement names (Deliver, Manage, Grow, Account,
     Platform). Home has no title and sits alone at the top. */
  [data-nav="side"] .masthead__group {
    flex-direction: column;
    align-items: stretch;
    gap: 3px;
    margin: 0;
    padding: 0;
    border-left: 0;
  }
  [data-nav="side"] .masthead__group + .masthead__group { margin-top: 12px; }
  [data-nav="side"]:not([data-rail="icons"]) .masthead__grouph {
    display: block;
    padding: 0 12px 4px;
    font-size: .64rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--ink-3);
  }
  [data-nav="side"] .masthead__nav .masthead__link--soon { display: flex; }

  /* NOTHING pushes `main.shell` here. The body's own padding is what reserves
     the rail's width, so a page that rewrites `.shell` for its own layout —
     the Brand Studio and the Framework Studio both do, and must — stays clear
     of the rail without knowing the rail exists. `.shell` then centres itself
     in what is left, which is what it already does. */

  /* --- Collapsed to glyphs --------------------------------------------------

     The rail narrows to the width of one icon and the words go. Two things
     make that safe rather than a guessing game:

     - EVERY LINK KEEPS ITS WORD, as `data-label` in the markup and printed by
       the tooltip below on hover AND on keyboard focus. The word travels with
       the link rather than being written a second time in CSS, so it cannot
       come to disagree with the link it names.
     - the words are hidden with a CLIP, not `display: none`, so a screen
       reader still reads the link's name. A rail of unlabelled glyphs is a
       rail nobody can use without one.

     Hovering does NOT expand the rail. An overlay that grows under the
     pointer is the usual trick and it moves the thing you were aiming at; a
     tooltip says the same word and nothing shifts. */
  [data-nav="side"][data-rail="icons"] .masthead { width: var(--rail-icon-w); }

  /* The lockup keeps the MARK and gives up everything else. The full lockup
     is 949x265 and its wordmark ran clean out of a 62px column, so the glyph
     alone is shown instead — two elements in the markup, one of them drawn,
     rather than a script swapping a `src` after the first paint. */
  [data-nav="side"][data-rail="icons"] .masthead .masthead__sub { display: none; }
  [data-nav="side"][data-rail="icons"] .masthead__logo { display: none; }
  [data-nav="side"][data-rail="icons"] .masthead__glyph {
    display: block;
    height: 26px;
    width: auto;
  }
  [data-nav="side"][data-rail="icons"] .masthead__mark {
    align-items: center;
    padding: 2px 0 12px;
  }

  [data-nav="side"][data-rail="icons"] .masthead__nav .masthead__link {
    justify-content: center;
    padding: 10px 0;
  }
  /* Clipped, not removed: the accessible name has to survive. */
  [data-nav="side"][data-rail="icons"] .masthead__w {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* The word, on hover and on focus, drawn OUTSIDE the rail. `.masthead` is
     `overflow-y: auto`, which makes it a scrollport and would clip a tooltip
     inside it — the trap the map legend and the handbook carousel each met —
     so the tip is `position: fixed` and placed from the link's own row.
     `left: var(--rail-icon-w)` puts it just clear of the rail; `top` is not
     set, so it sits on the link's own line. */
  [data-nav="side"][data-rail="icons"] .masthead__link {
    position: relative;
  }
  [data-nav="side"][data-rail="icons"] .masthead__link::after {
    content: attr(data-label);
    position: absolute;
    left: calc(100% + 6px);
    top: 50%;
    transform: translateY(-50%);
    z-index: 60;
    padding: 5px 10px;
    border-radius: var(--radius);
    background: var(--ink);
    color: var(--surface);
    font-size: .76rem;
    font-weight: 500;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur) var(--ease);
  }
  [data-nav="side"][data-rail="icons"] .masthead__link:hover::after,
  [data-nav="side"][data-rail="icons"] .masthead__link:focus-visible::after {
    opacity: 1;
  }
  /* THE GLYPH RAIL SCROLLS (2026-09-28, customer report: collapsed, the rail
     ran past the bottom of the window and the avatar and the last links were
     cut off with no way to reach them). It used to be `overflow: visible`, so
     the word-on-hover could stick out beside it, and a list taller than the
     window simply fell off the screen. Now the LINK LIST scrolls, exactly as
     it does in the full rail, and the mark, the controls and the avatar stay
     where they are.

     THE WORD IS DRAWN BY navpos.js (`.railtip`, below), outside the rail: a
     scrollport clips anything positioned inside it, so the `::after` tip
     above could no longer leave the rail. It stays as the no-script fallback
     and stands down once the script says it is drawing the tip. */
  [data-nav="side"][data-rail="icons"] .masthead { overflow: hidden; }
  [data-nav="side"][data-rail="icons"] .masthead .masthead__nav {
    flex: 0 1 auto;
    min-height: 0;
    overflow-x: hidden;
    overflow-y: auto;
    scrollbar-width: thin;
  }
  :root[data-railtips][data-nav="side"][data-rail="icons"] .masthead__link::after { display: none; }


  [data-nav="side"][data-rail="icons"] .masthead__navpos,
  [data-nav="side"][data-rail="icons"] .masthead__railsize {
    position: static;
    margin: 0 auto;
  }
  /* A group of glyphs is a hairline above it; its title has no room. */
  [data-nav="side"][data-rail="icons"] .masthead__group + .masthead__group {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--rule);
  }
  [data-nav="side"][data-rail="icons"] .masthead__soon { display: none; }
}

/* The glyph rail's word on hover, drawn by navpos.js on <body> so the rail's
   scroll cannot clip it. Its look is the `::after` tip's, above. */
.railtip {
  position: fixed;
  z-index: 95;
  padding: 5px 10px;
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--surface);
  font-size: .76rem;
  font-weight: 500;
  white-space: nowrap;
  pointer-events: none;
  transform: translateY(-50%);
}
.railtip[hidden] { display: none; }

/* THE RAIL STANDS DOWN ON A PHONE, and so does everything drawn for it.

   AFTER the rail's own query on purpose: these rules and the ones above are
   the same two class-weight parts, so source order is what decides, and
   placed earlier they simply lost (measured: twelve glyphs still drawn in the
   fallback row). The stored VALUE is untouched throughout, so widening the
   window restores the layout that was chosen. */
@media (max-width: 900px) {
  .masthead__navpos,
  .masthead__railsize { display: none; }
  /* No glyphs in the fallback row: the rail's layout lives in a min-width
     query, so without this a stored preference put an icon beside every word
     in the tightest row there is. */
  [data-nav="side"] .masthead__ico { display: none; }
  [data-nav="side"] .masthead__glyph { display: none; }
}

.masthead__link {
  padding: 7px 15px;
  flex: none;
  white-space: nowrap;
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-size: .84rem;
  font-weight: 500;
  color: var(--ink-2);
  text-decoration: none;
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease), background var(--dur) var(--ease);
}
/* HOVER AND CURRENT ARE A TINT, NEVER AN OUTLINE (2026-09-28, customer
   request: "fix the sidebar hover selection or selection"). They were a
   border in `--accent-line` and a fill in `--accent-soft`, which reads well
   for a mid colour and turns into a hard grey frame for a partner whose brand
   is black or near it. A tint MIXED from the accent itself works for any
   colour. The focus ring is drawn INSIDE the link, because the rail scrolls
   and clipped the browser's own outline at its edge into a lopsided frame;
   a mouse click (`:focus` without `-visible`) draws none. */
.masthead__link:hover {
  background: color-mix(in srgb, var(--accent) 5%, transparent);
  color: var(--accent-ink);
}
.masthead__link[aria-current="page"] {
  background: color-mix(in srgb, var(--accent) 13%, transparent);
  color: var(--accent-ink);
  font-weight: 600;
}
.masthead__link:focus { outline: none; }
.masthead__link:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent) 55%, transparent);
}

.shell {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: var(--rhythm) var(--gutter) 56px;
}
/* Main is the flex item that takes the slack, so the footer is pushed down.
   WIDTH IS STATED because auto margins on a flex item's cross axis turn off
   stretching: without it the centred shell would shrink to its content, the
   trap the Brand Studio met on 2026-09-01. */
body > main.shell { flex: 1 0 auto; width: 100%; box-sizing: border-box; }

/* --------------------------------------------------------------------------
   Panel — the core "record card"
   -------------------------------------------------------------------------- */

.panel {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.panel__head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 20px;
  border-bottom: 1px solid var(--rule);
  background: var(--surface-2);
}

.panel__title {
  font-size: .74rem;
  font-weight: 650;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.panel__meta { margin-left: auto; font-size: .78rem; color: var(--ink-3); }

.panel__body { padding: 18px; }

/* --------------------------------------------------------------------------
   Chat
   -------------------------------------------------------------------------- */

/* Four rows, because the panel has four children: header, turn meter, log,
   composer. It declared three, so the meter took the flexible row and floated
   in the middle of the page with the log collapsed underneath it. */
.chat {
  display: grid;
  grid-template-rows: auto auto minmax(0, 1fr) auto;
  height: calc(100dvh - 58px - var(--rhythm) * 2);
  min-height: 520px;
  overflow: hidden;
}

.chat__log {
  overflow-y: auto;
  padding: 8px 22px 18px;
  scroll-behavior: smooth;
}

/* The ruled-paper gradient that used to live here belonged to the warm filing
   aesthetic. Against white it reads as banding rather than texture, and it
   scrolled with `background-attachment: local` so the lines slid under the
   text. Entries carry their own separators instead. */

@media (prefers-reduced-motion: reduce) {
  .chat__log { scroll-behavior: auto; }
}

.entry {
  display: grid;
  grid-template-columns: 78px minmax(0, 1fr);
  gap: 18px;
  padding: 16px 14px;
  margin-bottom: 10px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  animation: entry-in .22s ease-out both;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.entry:last-child { margin-bottom: 0; }

/* The assistant's turns are the ones people re-read, so they get the surface
   and the user's stay plain — the asymmetry is what makes a thread skimmable
   without avatars or coloured bubbles. */
.entry--assistant {
  background: var(--accent-soft);
  border-color: var(--accent-line);
}
.entry--user:hover { background: var(--surface-2); border-color: var(--rule); }

@keyframes entry-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .entry { animation: none; }
}

.entry__gutter {
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-faint);
  padding-top: 2px;
}

.entry__role { display: block; font-weight: 600; color: var(--ink-3); }
.entry__seq  { display: block; margin-top: 2px; font-variant-numeric: tabular-nums; }

.entry__body { min-width: 0; }

.entry__body p { margin: 0 0 .7em; }
.entry__body p:last-child { margin-bottom: 0; }

.entry--assistant .entry__body {
  font-size: .97rem;
  line-height: 1.62;
  color: var(--ink);
}

.entry--system .entry__body {
  font-size: .86rem;
  color: var(--ink-3);
  font-style: italic;
}

.entry__footnote {
  margin-top: 8px;
  font-family: var(--font-mono);
  font-size: .68rem;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

.entry__footnote span + span::before {
  content: "·";
  margin: 0 7px;
  color: var(--rule-strong);
}

/* Typing indicator */
.typing { display: inline-flex; gap: 4px; align-items: center; height: 1.4em; }
.typing i {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--ink-faint);
  animation: pulse 1.1s ease-in-out infinite;
}
.typing i:nth-child(2) { animation-delay: .15s; }
.typing i:nth-child(3) { animation-delay: .3s; }
@keyframes pulse {
  0%, 60%, 100% { opacity: .25; transform: translateY(0); }
  30%           { opacity: 1;   transform: translateY(-2px); }
}
@media (prefers-reduced-motion: reduce) {
  .typing i { animation: none; opacity: .5; }
}

/* Empty state */
.chat__empty {
  max-width: 46ch;
  margin: auto;
  padding: 6vh 0;
  text-align: center;
  color: var(--ink-3);
}
/* `margin: auto` only centres inside a flex/grid parent. */
.chat__log:has(.chat__empty) { display: grid; place-items: center; }
.chat__empty h2 { margin-bottom: 8px; color: var(--ink); }
.chat__empty p  { font-size: .9rem; }

/* --------------------------------------------------------------------------
   Turn meter (rate-limit indicator)
   -------------------------------------------------------------------------- */

.meter {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 18px;
  border-bottom: 1px solid var(--rule);
  background: var(--surface);
  font-size: .78rem;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}

.meter__label {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
  color: var(--ink-2);
  white-space: nowrap;
}
.meter__label b { color: var(--ink); font-weight: 650; }

.meter__pips { display: flex; gap: 3px; }

.meter__pip {
  width: 16px; height: 5px;
  border-radius: var(--radius);
  background: var(--surface-sunk);
  border: 1px solid var(--rule);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.meter__pip[data-spent="true"] { background: var(--accent); border-color: var(--accent); }

.meter__note { margin-left: auto; color: var(--ink-3); }

/* Warning state — 8/10 and 9/10 */
.meter[data-state="warning"] {
  background: var(--warn-soft);
  border-bottom-color: var(--warn);
}
.meter[data-state="warning"] .meter__label b,
.meter[data-state="warning"] .meter__note { color: var(--warn); }
.meter[data-state="warning"] .meter__pip[data-spent="true"] {
  background: var(--warn); border-color: var(--warn);
}

/* Exhausted state — 10/10 */
.meter[data-state="exhausted"] {
  background: var(--danger-soft);
  border-bottom-color: var(--danger);
}
.meter[data-state="exhausted"] .meter__label b,
.meter[data-state="exhausted"] .meter__note { color: var(--danger); }
.meter[data-state="exhausted"] .meter__pip[data-spent="true"] {
  background: var(--danger); border-color: var(--danger);
}

/* --------------------------------------------------------------------------
   Composer
   -------------------------------------------------------------------------- */

.composer {
  border-top: 1px solid var(--rule);
  background: var(--surface-2);
  padding: 13px 18px;
}

.composer__row { display: flex; gap: 11px; align-items: flex-end; }

.composer__input {
  flex: 1;
  min-height: 44px;
  max-height: 200px;
  padding: 11px 13px;
  resize: none;
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.composer__input::placeholder { color: var(--ink-faint); }
.composer__input:hover:not(:disabled) { border-color: var(--accent-line); }
.composer__input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.composer__input:disabled {
  background: var(--surface-sunk);
  color: var(--ink-faint);
  cursor: not-allowed;
  border-color: var(--rule);
}

.composer__hint {
  margin-top: 7px;
  font-size: .72rem;
  color: var(--ink-faint);
}

/* --------------------------------------------------------------------------
   Buttons — `.btn` and every modifier live in ui.css (the console's
   component kit, loaded after each page's own styles by base.html). Nothing
   here, or the two would drift.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   Notices
   -------------------------------------------------------------------------- */

.notice {
  display: flex;
  gap: 13px;
  padding: 14px 16px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface-2);
  font-size: .88rem;
  animation: entry-in .2s ease-out both;
}
.notice__title { font-weight: 650; margin-bottom: 3px; }
.notice__body  { color: var(--ink-2); }
.notice__body p:last-child { margin-bottom: 0; }
.notice__actions { margin-top: 11px; display: flex; gap: 8px; }

.notice--warning { background: var(--warn-soft); }
.notice--danger  { background: var(--danger-soft); }
.notice--ok      { background: var(--ok-soft); }

.notice--warning .notice__title { color: var(--warn); }
.notice--danger  .notice__title { color: var(--danger); }
.notice--ok      .notice__title { color: var(--ok); }

/* The shared sign-in page's "your workspace has its own door" notice. Their
   own mark and name answer the reader's only question — is this about my
   workspace — faster than any sentence, so the copy under it is one line. */
.moved__who {
  display: flex;
  align-items: center;
  gap: 11px;
  margin: 10px 0 8px;
}
.moved__mark {
  width: 40px;
  height: 40px;
  flex: none;
  object-fit: contain;      /* a customer's mark is any aspect ratio */
  border-radius: var(--radius);
  border: 1px solid var(--rule);
  background: #fff;
  padding: 3px;
}
.moved__name { display: grid; min-width: 0; }
.moved__name b { color: var(--ink); font-weight: 650; }
.moved__name i {
  font-style: normal;
  font-size: .82rem;
  color: var(--ink-2);
}
/* The label sits back so the tier is what carries — it is the answer, the
   label only says what kind of answer it is. */
.moved__lbl { color: var(--ink-3); }
.moved__lede { margin: 0; font-size: .88rem; }
.moved__go { margin: 12px 0 0; }

/* --------------------------------------------------------------------------
   Analytics
   -------------------------------------------------------------------------- */

.toolbar {
  display: flex;
  align-items: center;
  gap: 11px;
  flex-wrap: wrap;
  margin-bottom: var(--rhythm);
}
.toolbar__spacer { margin-left: auto; }

.select {
  height: var(--ctl-h, 36px);
  padding: 0 30px 0 11px;
  font: inherit;
  font-size: var(--ctl-fs, .84rem);
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  appearance: none;
  cursor: pointer;
}

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px;
  margin-bottom: var(--rhythm);
}

.stat {
  padding: var(--card-pad, 14px 16px);
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.stat:hover {
  border-color: var(--accent-line);
  transform: translateY(-1px);
  box-shadow: var(--shadow-lg);
}

.stat__label {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 7px;
}

.stat__value {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 1.6rem;
  font-weight: 550;
  letter-spacing: -0.02em;
  line-height: 1.1;
  color: var(--ink);
}

.stat__foot { margin-top: 5px; font-size: .74rem; color: var(--ink-3); }

.stat--alert .stat__value { color: var(--danger); }
.stat--good  .stat__value { color: var(--ok); }

/* Bars */
.bars { display: grid; gap: 11px; }

.bar__head {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: .82rem;
  margin-bottom: 5px;
}
.bar__name  { font-weight: 550; }
.bar__value { font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--ink-2); }

.bar__track {
  height: 8px;
  background: var(--surface-sunk);
  border-radius: var(--radius);
  overflow: hidden;
}
.bar__fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent) 0%, var(--accent-2) 100%);
  border-radius: var(--radius);
  transition: width .4s cubic-bezier(.2, .7, .3, 1);
}
@media (prefers-reduced-motion: reduce) {
  .bar__fill { transition: none; }
}

/* Daily-spend column chart.

   `flex: 1` alone made one day of data a single slab the width of the card,
   which reads as a filled progress bar rather than a chart. Columns now have a
   sane maximum and the row starts from the left, so a sparse window looks
   sparse — which is the honest picture. */
.spark {
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
  gap: 4px;
  height: 120px;
  padding-top: 8px;
}
.spark__col {
  flex: 1 1 auto;
  min-width: 3px;
  max-width: 46px;
  background: linear-gradient(180deg, var(--accent) 0%, var(--accent-2) 100%);
  border-radius: var(--radius) var(--radius) 0 0;
  opacity: .86;
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
  transform-origin: bottom;
}
.spark__col:hover { opacity: 1; transform: scaleY(1.02); }
.spark__col[data-blocked="true"] {
  background: linear-gradient(180deg, var(--danger) 0%, #8f2724 100%);
}

@media (prefers-reduced-motion: reduce) {
  .spark__col { transition: none; }
  .spark__col:hover { transform: none; }
}

.spark-axis {
  display: flex;
  justify-content: space-between;
  margin-top: 7px;
  font-size: .68rem;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

/* Table */
.grid-2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: var(--rhythm);
  margin-bottom: var(--rhythm);
}

.table { width: 100%; border-collapse: collapse; font-size: .85rem; }

.table th {
  text-align: left;
  padding: 8px 12px;
  font-size: .68rem;
  font-weight: 650;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-3);
  border-bottom: 1px solid var(--rule-strong);
  white-space: nowrap;
}

.table td {
  padding: 9px 12px;
  border-bottom: 1px solid var(--rule);
  color: var(--ink-2);
}
.table tr:last-child td { border-bottom: none; }
.table tbody tr:hover td { background: var(--surface-2); }

.table .num {
  text-align: right;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.table__wrap { overflow-x: auto; }
.empty-row { padding: 28px; text-align: center; color: var(--ink-faint); font-size: .86rem; }

/* The kit chip's metrics (ui.css `.chip`), under the analytics page's own
   name because analytics.js builds these. */
.tag {
  display: inline-flex;
  align-items: center;
  padding: 2px 9px;
  font-size: var(--chip-fs, .7rem);
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
  border-radius: var(--radius);
  background: var(--surface-sunk);
  color: var(--ink-2);
}
.tag--alert { background: var(--danger-soft); color: var(--danger); }
.tag--ok    { background: var(--ok-soft);     color: var(--ok); }

.skeleton {
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-sunk) 50%, var(--surface-2) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.3s linear infinite;
  border-radius: var(--radius);
  color: transparent !important;
}
@keyframes shimmer { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .skeleton { animation: none; } }

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

/* ==========================================================================
   Phone and tablet — assistant, analytics and sign-in

   Same rules of thumb as the assembler: dvh instead of vh so the composer is
   not hidden behind a mobile browser toolbar, 16px inputs so iOS does not zoom
   the page on focus, and nothing interactive smaller than a fingertip.
   ========================================================================== */

@media (max-width: 900px) {
  :root { --gutter: 14px; --rhythm: 18px; }

  .masthead {
    height: auto;
    min-height: 54px;
    padding: 8px var(--gutter);
    gap: 10px 12px;
    flex-wrap: wrap;
  }
  .masthead__sub { display: none; }
  .masthead__nav { margin-left: auto; gap: 2px; }
  .masthead__link { padding: 8px 10px; }
  .masthead__session {
    margin-left: 0;
    padding-left: 0;
    border-left: 0;
  }

  .shell { padding: var(--rhythm) var(--gutter) calc(28px + env(safe-area-inset-bottom, 0px)); }

  /* The chat fills the screen below the masthead rather than guessing at a
     fixed height; 100dvh tracks the visible viewport as the toolbar hides. */
  .chat {
    height: calc(100dvh - 54px - var(--rhythm) * 2);
    min-height: 380px;
  }
  .chat__log { padding: 14px 12px; }

  .panel__head { flex-wrap: wrap; gap: 8px; padding: 10px 12px; }
  .panel__meta { order: 3; width: 100%; }

  .composer { padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0px)); }
  .composer__row { gap: 8px; }
  .composer__input { font-size: 16px; min-height: 46px; }
  .composer__hint { display: none; }

  .select { height: 42px; font-size: 16px; }

  .toolbar { gap: 8px; }
  .toolbar h1 { width: 100%; }
  .toolbar__spacer { display: none; }

  .stat-grid { grid-template-columns: 1fr 1fr; }

  .entry { grid-template-columns: 1fr; gap: 6px; }
  .entry__gutter { display: flex; gap: 10px; }
  .meter__note { display: none; }

  /* Wide tables scroll in their own box; the page itself must never scroll
     sideways. */
  .table__wrap { -webkit-overflow-scrolling: touch; }
  .table { font-size: .8rem; }
  .table th, .table td { padding-left: 8px; padding-right: 8px; }

  .auth { margin-top: 4vh; }
  /* Sign-in fields inherit 15px from the body, which is under iOS Safari's
     16px zoom threshold — focusing one would zoom the whole page. */
  .field__input { font-size: 16px; height: 46px; }
  .auth__submit { height: 48px; }
}

@media (max-width: 480px) {
  .stat-grid { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   Auth
   -------------------------------------------------------------------------- */

.auth {
  position: relative;
  z-index: 1;
  max-width: 420px;
  margin: 7vh auto 0;
}

/* THE SIGN-UP FACE IS WIDER (2026-09-16, customer request: "it's too narrow").
   Sign-in is two fields and 420px suits it; sign-up is four plus a Google
   button, and at the same width the names stacked and the card ran off a
   laptop screen. The wrapper widens only while that face is the one showing,
   so the sign-in card is untouched.

   `:has()` on the wrapper rather than a class toggled by script: the width
   then follows whichever face is visible with nothing to keep in step, and
   the standalone /partner-signup/ page — which has the sign-up card and no
   sign-in one — gets it for free. */
.auth:has(.auth__card--signup:not([hidden])) { max-width: 940px; margin-top: 4vh; }

/* THE SIGN-UP CARD, TWO COLUMNS (2026-09-28, customer request: one page, one
   wider card, two columns). The offer and Google on the left, the email form
   on the right, a hairline between; stacked below 760px of card. */
.suc { display: grid; grid-template-columns: minmax(0, .95fr) minmax(0, 1fr); gap: 0 36px; }
.suc__intro { display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
              padding-right: 36px; border-right: 1px solid var(--rule); }
.suc__logo { margin: 0 0 2px; }
.auth__logo.suc__logo { max-height: 34px; width: auto; }
.suc__tag { margin: 0; font-size: .84rem; color: var(--ink-3); line-height: 1.45; }
.suc__chip { display: inline-block; margin-top: 8px; padding: 3px 10px; border-radius: 999px;
             font-size: .68rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
             color: var(--accent-ink); background: var(--accent-soft); }
.suc__h { margin: 2px 0 0; font-size: 1.3rem; line-height: 1.25; letter-spacing: -.01em; }
.suc__list { margin: 4px 0 8px; padding: 0; list-style: none; display: grid; gap: 7px;
             font-size: .88rem; color: var(--ink-2); }
.suc__list li { position: relative; padding-left: 22px; line-height: 1.45; }
.suc__list li::before { content: ""; position: absolute; left: 2px; top: .38em; width: 11px; height: 6px;
                        border-left: 2px solid var(--accent); border-bottom: 2px solid var(--accent);
                        transform: rotate(-45deg); }
.suc__intro .auth__oauth { margin-top: auto; width: 100%; }
.suc__intro .auth__oauthnote { margin: 0; text-align: left; font-size: .76rem; }
.suc__formh { margin: 0 0 12px; font-size: .78rem; font-weight: 600; letter-spacing: .06em;
              text-transform: uppercase; color: var(--ink-3); }
.suc__form .field { margin-bottom: 12px; }
.suc__back { margin-top: 14px; text-align: center; font-size: .86rem; color: var(--ink-3); }
.suc__back p { margin: 0; }
@media (max-width: 800px) {
  .suc { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .suc__intro { padding-right: 0; border-right: 0; padding-bottom: 20px; border-bottom: 1px solid var(--rule); }
}

/* Self-contained card rather than .panel: the sign-in page has no chrome to
   share with the rest of the app, and a titled header bar above a form that
   already says "Sign in" in three other places is one label too many. */
.auth__card {
  padding: 34px 32px 30px;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  animation: auth-in .42s cubic-bezier(.2, .7, .3, 1) both;
}

@keyframes auth-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

.auth__brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  margin-bottom: 26px;
}

.auth__logo { width: 210px; max-width: 78%; height: auto; }
/* A workspace's own mark (white label): bounded on both axes because it is
   their upload, not our artwork — a square icon must not fill the card. */
.auth__logo--brand { width: auto; max-width: 210px; max-height: 64px; object-fit: contain; }

.auth__lede {
  margin: 16px 0 0;
  font-size: .9rem;
  color: var(--ink-3);
}

.auth__form { display: grid; gap: 16px; }

/* The notice is a sibling of the form, so the form's own gap does not apply
   to it and it would otherwise sit flush against the first label. */
.auth__card .notice { margin-bottom: 20px; }

.auth__submit {
  width: 100%;
  height: 44px;
  margin-top: 6px;
  font-size: .92rem;
}

/* The ways ON, inside the card and under a rule.
   They are the card's own business — this is where somebody goes who cannot
   sign in — and under it as separate paragraphs they were three more lines of
   loose grey text competing with the one control on the page. One hairline,
   tight rows, and the support address stays OUTSIDE as the only thing there,
   because it is the answer when the card itself has failed you. */
/* "Powered by" and the Komunidad mark, small and centred at the foot of the
   plain sign-in card (2026-09-28). */
.auth__powered { display: flex; align-items: center; justify-content: center; gap: 6px;
                 margin: 18px 0 0; font-size: .7rem; color: var(--ink-3); }
.auth__powered img { height: 16px; width: auto; display: block; }
.auth__alt {
  margin-top: 24px;
  padding-top: 18px;
  border-top: 1px solid var(--rule);
  display: grid;
  gap: 8px;
  text-align: center;
  font-size: .8rem;
  line-height: 1.5;
  color: var(--ink-3);
}

/* The lead may wrap, the LINK may not: "Become a / partner" across two lines
   reads as a broken control rather than one destination. Every line here is
   also written short enough to need neither, which is the real fix; this is
   the insurance for a narrow screen or a longer translation. */
.auth__alt a { font-weight: 600; white-space: nowrap; }

/* SIGN UP AS A PARTNER: a real button, the size and shape of Sign in
   (customer request, 2026-09-16) — it was a text link at the foot of the page
   and read as fine print rather than as the other thing you can do here.
   OUTLINED, not filled: two filled teal buttons one above the other is two
   primary actions on a page that has one, and a visitor signing in must not
   have to pick their button out of a pair. The base `.btn` is already that
   outline, and `.auth__submit` is what sizes Sign in, so reusing both is what
   makes the two identical rather than merely similar. */
.auth__alt .btn {
  margin-top: 0;
  margin-bottom: 4px;
  /* The lead line under it is .8rem; the button carries the form's own size. */
  font-size: .88rem;
}

/* ---------------------------------------------------------------------------
   THE CARD'S OTHER FACE: partner sign-up (2026-09-16, customer request: "when
   click the sign up it will change the login card"), and the Google button on
   it.

   `[hidden]` is declared HERE as well as on the element, and it is load-
   bearing: `.auth__card` has rules that set a display of its own, and the
   attribute's `display: none` loses to a class. This product has now met that
   trap four times (`.rpicks`, `.tut-top`, the weather chips, this) — an
   element that ships `hidden` and is styled by a class needs the guard.
   --------------------------------------------------------------------------- */
.auth__card[hidden] { display: none; }

/* The Google button. Our own markup and our own mark: `accounts.google.com`'s
   script would be the second third-party script this product loads, and
   Mapbox GL is the only one. Outlined like "Sign up as a partner" beside it,
   for the same reason — the filled teal is the one primary action. */
.auth__oauth {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-bottom: 6px;
  font-size: .88rem;
}
.auth__oauthico { width: 18px; height: 18px; flex: none; }
.auth__oauthnote {
  margin: 0 0 18px;
  font-size: .76rem;
  line-height: 1.5;
  color: var(--ink-3);
  text-align: center;
}

/* "or with your email" — a rule with a word sitting in it. The word carries
   the card's own background so the line appears to pass behind it, which is
   one element rather than two half-rules that have to stay the same length. */
.auth__or {
  position: relative;
  margin: 0 0 18px;
  text-align: center;
  font-size: .74rem;
  color: var(--ink-faint);
}
.auth__or::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  border-top: 1px solid var(--rule);
}
.auth__or span {
  position: relative;
  padding: 0 10px;
  background: var(--surface);
}

/* Two fields on one row — the first and last name, which are one fact read
   left to right. `minmax(0, 1fr)` or a long placeholder pushes its column
   past the card; one column again when the card is narrow, which is a phone
   and the 420px sign-in width both. */
.field__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 0 14px;
}
/* A media query and NOT a container query: nothing here declares
   `container-type`, so a container query would never match — and giving
   `.auth__card` one would make it the containing block for any fixed
   descendant, which is the Brand Studio's own measured lesson. */
@media (max-width: 560px) { .field__row { grid-template-columns: minmax(0, 1fr); } }

/* The line under a field saying what it is for. Quiet: it is an answer to a
   question somebody may not have, so it must not compete with the label. */
.field__hint {
  margin: 5px 0 0;
  font-size: .74rem;
  line-height: 1.45;
  color: var(--ink-3);
}
.field__hint code {
  font-size: .95em;
  padding: 0 3px;
  border-radius: var(--radius);
  background: var(--surface-sunk);
}

.auth__foot {
  margin-top: 16px;
  text-align: center;
  font-size: .78rem;
  color: var(--ink-3);
}
.auth__foot + .auth__foot { margin-top: 6px; }

.field { display: grid; gap: 7px; }

.field__label {
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-2);
}

/* A field's name with a small link beside it, right-aligned on the same line.
   "Forgot your password?" belongs HERE and not under the card, which is where
   it sat for one afternoon: a reader looks for it while they are standing in
   the password box, not after they have scrolled past the button, and four
   loose paragraphs under a card read as page furniture rather than as part of
   signing in. Baseline alignment, because the label is uppercase at .72rem
   and the link is sentence case at .74 — centring two different cap heights
   leaves both looking a pixel out. */
.field__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

/* Resets the label's own typography rather than living outside .field__head,
   because uppercase letter-spaced link text reads as a heading somebody has
   made clickable. */
.field__aside {
  font-size: .74rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
}

.field__wrap { position: relative; display: grid; }

.field__input {
  height: 46px;
  padding: 0 15px;
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.field__input::placeholder { color: var(--ink-faint); }

.field__input:hover { border-color: var(--accent-line); }

.field__input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}

/* Room for the reveal button so a long password never runs under it. */
.field__input--reveal { padding-right: 68px; }

.field__reveal {
  position: absolute;
  top: 50%;
  right: 7px;
  transform: translateY(-50%);
  height: 32px;
  padding: 0 12px;
  font: inherit;
  font-size: .76rem;
  font-weight: 500;
  color: var(--ink-3);
  background: var(--surface-sunk);
  border: 1px solid transparent;
  border-radius: var(--radius);
  cursor: pointer;
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.field__reveal:hover {
  color: var(--accent-ink);
  background: var(--accent-soft);
  border-color: var(--accent-line);
}
.field__reveal:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}

/* In flight. Not :disabled — a disabled submit is dropped from the POST body
   by some browsers and the form would arrive without it. */
.auth__submit[data-busy="true"] {
  opacity: .75;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   Water behind the sign-in card

   A four-layer parallax, fixed, behind the content and inert to the pointer.
   It was shared with the landing page that used to sit at /; this is now the
   only copy.
   -------------------------------------------------------------------------- */

.authwaves {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: 30vh;
  min-height: 170px;
  z-index: 0;
  pointer-events: none;
}
.authwaves svg { width: 100%; height: 100%; display: block; }

.authwaves__set > use { animation: auth-wave-drift 26s cubic-bezier(.55, .5, .45, .5) infinite; }
.authwaves__l1 { animation-delay: -2s; animation-duration:  9s; fill: rgba(29, 150, 158, .16); }
.authwaves__l2 { animation-delay: -3s; animation-duration: 13s; fill: rgba(45, 180, 190, .11); }
.authwaves__l3 { animation-delay: -4s; animation-duration: 17s; fill: rgba(29, 150, 158, .08); }
.authwaves__l4 { animation-delay: -5s; animation-duration: 24s; fill: rgba(29, 150, 158, .22); }

@keyframes auth-wave-drift {
  from { transform: translate3d(-90px, 0, 0); }
  to   { transform: translate3d( 85px, 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .authwaves__set > use { animation: none; }
  .auth__card { animation: none; }
}

/* --------------------------------------------------------------------------
   THE FLAT SIGN-IN (2026-10-01, customer request: "flat style lang, match our
   interface", after the Komunidad card artwork). The plain Komplee door only;
   a branded door keeps its waves. A warm off-white ground, a faint grid and
   one soft teal glow, fixed behind the card; the card itself a hairline and
   no shadow, because a shadow is the depth this style leaves out.
   -------------------------------------------------------------------------- */
.authbg {
  position: fixed;
  inset: 0;
  /* Below every block in the page, not just the positioned ones: at 0 it
     painted over the unpositioned footer text. */
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(42vw 42vw at 88% 72%, rgba(29, 150, 158, .10), transparent 70%),
    linear-gradient(rgba(13, 27, 33, .045) 1px, transparent 1px) 0 0 / 28px 28px,
    linear-gradient(90deg, rgba(13, 27, 33, .045) 1px, transparent 1px) 0 0 / 28px 28px,
    #f5f6f3;
}
/* CENTRED IN THE WINDOW (2026-10-01, customer request: "a little lower, in
   the middle vertically"). `main` already takes the page's spare height (the
   body is a flex column), so the card's block is centred inside it rather
   than placed by a margin that is right at one window height only. The
   bottom padding is made equal to the top, or the centre sits 16px high. */
main.shell:has(> .auth--flat) {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-bottom: var(--rhythm);
}
.auth.auth--flat,
.auth.auth--flat:has(.auth__card--signup:not([hidden])) { margin: 0 auto; width: 100%; }
.auth.auth--flat .auth__legal { margin-bottom: 0; }
.auth--flat .auth__card {
  background: #fbfbf9;
  border-color: rgba(13, 27, 33, .10);
  box-shadow: none;
}
.auth--flat .auth__logo { width: 190px; }
/* Balanced, so the tagline breaks as two even lines rather than leaving
   "compliance" alone on the second. */
.auth--flat .auth__lede { margin-top: 12px; font-size: .84rem; line-height: 1.45; text-wrap: balance; }
.auth--flat .field__input { background: #fff; box-shadow: none; }
.auth--flat .auth__alt { border-top-color: rgba(13, 27, 33, .08); }
.auth__legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 4px 0;
  margin: 10px 0 24px;
  font-size: .72rem;
}
.auth__legal a { color: var(--ink-3); text-decoration: none; padding: 0 10px; }
.auth__legal a + a { border-left: 1px solid rgba(13, 27, 33, .14); }
.auth__legal a:hover { color: var(--accent-ink); text-decoration: underline; }

@media (max-width: 520px) {
  .auth { margin-top: 4vh; }
  .auth__card { padding: 26px 20px 24px; }
  .auth__logo { width: 180px; }
}

/* Masthead session control */
.masthead__session {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-left: 14px;
  padding-left: 14px;
  border-left: 1px solid var(--rule);
}

/* WHO IS SIGNED IN: an avatar of initials, and a <details> panel with the
   person (customer request, 2026-09-14). The avatar wears the brand's own
   gradient stops (k_color.svg), so it reads as the product's mark for a
   person rather than a random colour. A PARTNER'S OWN COLOUR (2026-09-28,
   customer request): the stops read `--brand-accent-*`, which exist only
   while a partner has chosen a colour (core.operator_brand), so everybody
   else keeps the product's gradient. */
.masthead__me { position: relative; }
.masthead__meav {
  list-style: none;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  cursor: pointer;
  outline-offset: 3px;
}
.masthead__meav::-webkit-details-marker { display: none; }
.masthead__initials {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--brand-accent-ink, #1F3556) 0%, var(--brand-accent-2, #1F7079) 60%, var(--brand-accent-bright, #2BA093) 100%);
  color: #fff;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .04em;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .28), 0 1px 2px color-mix(in srgb, var(--brand-accent-ink, #143c42) 25%, transparent);
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.masthead__meav:hover .masthead__initials,
.masthead__me[open] .masthead__initials {
  transform: scale(1.06);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .28), 0 0 0 3px var(--accent-soft);
}
.masthead__initials--big { width: 48px; height: 48px; font-size: 1rem; }

/* The panel. In a TOP row it hangs below the avatar, right-aligned to it;
   the other positions re-place it further down the file. */
.masthead__mepanel {
  position: absolute;
  right: 0;
  top: calc(100% + 10px);
  z-index: 70;
  width: 300px;
  padding: 14px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-lg), 0 24px 60px -30px rgba(20, 60, 66, .4);
  text-align: left;
  color: var(--ink);
}
.masthead__meid { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.masthead__mewho { display: grid; gap: 4px; min-width: 0; }
.masthead__mewho b { font-size: .95rem; font-weight: 600; overflow-wrap: anywhere; }
.masthead__merole {
  justify-self: start;
  padding: 2px 8px;
  border-radius: var(--radius);
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-size: .68rem;
  font-weight: 500;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.masthead__mefacts {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 12px 0;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  font-size: .8rem;
}
/* `minmax(0, 1fr)`, never a bare `1fr`: an email is one long word, and a
   `1fr` track's automatic minimum is its min-content width, so the value
   column refuses to narrow and the label column is squeezed instead. */
.masthead__mefacts > div { display: grid; grid-template-columns: 88px minmax(0, 1fr); gap: 10px; }
.masthead__mefacts dt { margin: 0; color: var(--ink-3); }
.masthead__mefacts dd { margin: 0; color: var(--ink); overflow-wrap: anywhere; }
.masthead__meout { margin: 12px 0 0; }
.masthead__logout {
  width: 100%;
  height: 34px;
  padding: 0 12px;
  font: inherit;
  font-size: .8rem;
  font-weight: 500;
  color: var(--ink-2);
  background: var(--surface-2);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  cursor: pointer;
}
.masthead__logout:hover { color: var(--danger); border-color: var(--danger); }

@media (min-width: 901px) {
  /* A BOTTOM bar: the panel opens upwards. */
  [data-nav="bottom"] .masthead__mepanel { top: auto; bottom: calc(100% + 10px); }
  /* A full RAIL is a scrollport (`overflow-y: auto`), which would clip an
     absolute panel, so WITH NO SCRIPT the panel opens IN THE FLOW above the
     avatar: the session block is a column with the avatar last, and a long
     rail simply scrolls. The avatar sits at the left, where the words were.
     navpos.js floats it beside the rail instead (`[data-float]`, below), so
     this is the fallback rather than the ordinary rendering. */
  [data-nav="side"]:not([data-rail="icons"]) .masthead__me {
    display: flex; flex-direction: column-reverse; align-items: flex-start; gap: 10px; width: 100%;
  }
  [data-nav="side"]:not([data-rail="icons"]) .masthead__mepanel {
    position: static; width: 100%; box-shadow: none; padding: 12px;
  }
  /* In the rail the panel is as wide as the rail, which is far narrower than
     the 300px it gets anywhere else, so the two-column facts leave the value
     a strip too narrow for a username and break every one of them mid-word
     (measured: ~60px for a 33-character email). Stacked, each value gets the
     whole width. Label over value, which is what a definition list is. */
  [data-nav="side"]:not([data-rail="icons"]) .masthead__mefacts > div {
    grid-template-columns: 1fr; gap: 1px;
  }
  [data-nav="side"]:not([data-rail="icons"]) .masthead__mefacts dt { font-size: .72rem; }
  /* A collapsed rail is `overflow: visible` for its tooltips, so the panel
     can open BESIDE it, bottom-aligned to the avatar. */
  [data-nav="side"][data-rail="icons"] .masthead__session { justify-content: center; }
  [data-nav="side"][data-rail="icons"] .masthead__mepanel {
    top: auto; right: auto; bottom: 0; left: calc(100% + 12px);
  }
  /* ...and beside a RIGHT rail it opens to the left (measured: it opened
     off the right edge of the window before this rule). */
  [data-side="right"][data-rail="icons"] .masthead__mepanel {
    left: auto; right: calc(100% + 12px);
  }
}

/* A CARD ON THE AVATAR (customer request, 2026-09-23: "a popup card that on
   the avatar", not a block inside the sidebar).

   navpos.js sets this attribute and places the panel from the avatar's own
   rect, in the two cases the stylesheet cannot reach on its own: beside a
   RAIL, whose masthead is `overflow-y: auto` and clips every positioned
   descendant, and on a PHONE, where the panel is right-aligned to an avatar
   near the left edge and hung 223px off the side of the window (measured at
   400px). It also MOVES THE NODE TO <body> while it floats, because
   `.masthead` carries a `backdrop-filter`, which makes it the containing
   block for a fixed descendant and pulls it straight back inside the rail.

   So these selectors have to reach the panel from the root, and they sit
   after the rail rules above (equal specificity, later wins) because those
   still match a panel parked on <body>. `left`/`top`/`right`/`bottom` all
   arrive inline. Floating gives the panel its full width back, so the facts
   return to their two columns.

   No script and nothing is set: the panel stays where the rules above put
   it, which is narrower in a rail but complete. */
:root .masthead__mepanel[data-float] {
  position: fixed;
  /* Wider than the 300px it gets in a row (customer request, 2026-09-23,
     twice), and 420 rather than 360 because that is what puts a
     33-character email on ONE line: it leaves the value column 294px
     against a measured 254px of text, where 360 left 234 and broke it. */
  width: min(420px, calc(100vw - 16px));
  padding: 14px;
  max-height: calc(100vh - 16px);
  overflow-y: auto;
  box-shadow: var(--shadow-lg), 0 24px 60px -30px rgba(20, 60, 66, .4);
}
:root .masthead__mepanel[data-float] .masthead__mefacts > div {
  grid-template-columns: 88px minmax(0, 1fr); gap: 10px;
}
:root .masthead__mepanel[data-float] .masthead__mefacts dt { font-size: inherit; }


/* --------------------------------------------------------------------------
   Checkout

   An invoice, and it stays one: the order is a real table with quantity and
   rate beside every amount, because a page that shows only a total asks to be
   trusted rather than checked, and the moment somebody is about to pay is the
   moment they are most entitled to check.

   What changed is the dressing. It is wider, it is quieter, and it tints itself
   with `--co-accent` — the accent of the *workspace's own* app template, passed
   in by the view. Paying for something should look like the thing being paid
   for, and a payment page in a palette of its own reads as a third party.

   Every tint below is `color-mix` off that one value, so there is one colour on
   the page and eight shades of it. No second hue, and nothing hard-coded: the
   amber hatching the test band used to wear was a warning sticker slapped over
   the design, and it is gone.
   -------------------------------------------------------------------------- */

.co {
  /* Falls back to the product accent for any render that has no workspace. */
  --co-accent: var(--accent);
  --co-wash: color-mix(in srgb, var(--co-accent) 7%, transparent);
  --co-line: color-mix(in srgb, var(--co-accent) 22%, var(--rule));
  --co-deep: color-mix(in srgb, var(--co-accent) 78%, #06202a);

  max-width: 1080px;
  margin: 0 auto;
  padding: clamp(14px, 3vw, 40px) 0 64px;
}

.co__card {
  border: 1px solid var(--rule);
  border-radius: calc(var(--radius-lg) + 4px);
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(20, 60, 66, .05), 0 24px 60px -34px rgba(20, 60, 66, .38);
  overflow: hidden;
}

/* --- Test mode ------------------------------------------------------------
   Ink, not amber. It has to be unmissable without pretending to be a hazard —
   nothing here is dangerous, it just is not real money. */

.co__test {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding: 13px clamp(18px, 3vw, 34px);
  background: linear-gradient(100deg, #10242c 0%, var(--co-deep) 140%);
  color: rgba(255, 255, 255, .82);
  font-size: .84rem;
}
.co__testtag {
  flex: none;
  padding: 3px 10px;
  border-radius: var(--radius);
  background: rgba(255, 255, 255, .16);
  color: #fff;
  font-size: .62rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
}
.co__testtxt b { color: #fff; font-weight: 600; }

/* --- Head ----------------------------------------------------------------- */

.co__head {
  position: relative;
  padding: clamp(24px, 3vw, 34px) clamp(18px, 3vw, 34px) clamp(20px, 2.5vw, 26px);
  /* The one flourish on the page: the accent fading out of the top-left corner.
     Enough to say whose app this is, not enough to compete with the total. */
  background:
    radial-gradient(120% 150% at 0% 0%, var(--co-wash) 0%, transparent 62%);
  border-bottom: 1px solid var(--rule);
}

.co__eyebrow {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 8px;
  font-size: .66rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--co-accent);
}
/* The workspace's template, named quietly beside the eyebrow. */
.co__tmpl {
  padding: 2px 9px;
  border: 1px solid var(--co-line);
  border-radius: var(--radius);
  color: var(--ink-3);
  letter-spacing: .08em;
}

.co__h1 {
  margin: 0 0 8px;
  font-size: clamp(1.5rem, 3vw, 2rem);
  letter-spacing: -.025em;
  line-height: 1.15;
}
.co__sub { margin: 0; font-size: .92rem; color: var(--ink-2); max-width: 70ch; }
.co__sub b { color: var(--ink); font-weight: 600; }

/* --- The order table ------------------------------------------------------ */

.co__scroll { overflow-x: auto; }

.co__tbl {
  width: 100%;
  min-width: 560px;
  border-collapse: collapse;
  font-size: .89rem;
}

.co__tbl thead th {
  padding: 10px clamp(18px, 3vw, 34px);
  border-bottom: 1px solid var(--rule);
  font-size: .62rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  text-align: left;
  white-space: nowrap;
}

.co__tbl tbody th,
.co__tbl tbody td,
.co__tbl tfoot th,
.co__tbl tfoot td {
  padding: 16px clamp(18px, 3vw, 34px);
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
  text-align: left;
  font-weight: 400;
}
.co__tbl tbody tr:hover { background: var(--co-wash); }

.co__item { display: block; font-weight: 600; color: var(--ink); }
.co__note {
  display: block;
  margin-top: 4px;
  font-size: .78rem;
  font-weight: 400;
  color: var(--ink-3);
  max-width: 52ch;
}

/* Right-aligned tabular figures, so the money lines up on the decimal point. */
.co__num {
  text-align: right !important;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}
.co__num i { font-style: normal; font-size: .74rem; color: var(--ink-faint); }
.co__amt { color: var(--ink); font-weight: 600; }

.co__tbl tfoot th { color: var(--ink-2); }
.co__save td { color: var(--ok); }

.co__total th, .co__total td {
  border-bottom: 0;
  background: linear-gradient(90deg, transparent 0%, var(--co-wash) 100%);
}
.co__total th { color: var(--ink); font-weight: 600; }
.co__total td {
  font-size: 1.6rem;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -.03em;
}
.co__total .co__note { font-weight: 400; }

/* --- Detail blocks -------------------------------------------------------- */

.co__cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(20px, 3vw, 44px);
  padding: clamp(22px, 3vw, 30px) clamp(18px, 3vw, 34px);
  border-top: 1px solid var(--rule);
}

.co__h2 {
  margin: 0 0 12px;
  font-size: .66rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* The second heading inside a block — the resource ceilings under the feature
   list. Same eyebrow treatment as .co__h2 with the rule above it that says a
   new group has started. */
.co__h3 {
  margin: 22px 0 10px;
  padding-top: 16px;
  border-top: 1px solid var(--rule);
  font-size: .66rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.co__feats { list-style: none; margin: 0; padding: 0; }
.co__feats li {
  position: relative;
  padding: 5px 0 5px 22px;
  font-size: .86rem;
  color: var(--ink-2);
}
.co__feats li::before {
  content: "";
  position: absolute;
  left: 1px;
  top: 12px;
  width: 9px;
  height: 5px;
  border-left: 2px solid var(--co-accent);
  border-bottom: 2px solid var(--co-accent);
  transform: rotate(-45deg);
}

.co__defs { width: 100%; border-collapse: collapse; font-size: .86rem; }
.co__defs th {
  padding: 6px 14px 6px 0;
  text-align: left;
  font-weight: 400;
  color: var(--ink-3);
  white-space: nowrap;
  vertical-align: top;
}
.co__defs td { padding: 6px 0; color: var(--ink); overflow-wrap: anywhere; }
.co__defs code {
  font-size: .8rem;
  padding: 1px 6px;
  border-radius: var(--radius);
  background: var(--surface-sunk);
}

/* --- Actions -------------------------------------------------------------- */

.co__acts, .co__done {
  padding: clamp(20px, 3vw, 28px) clamp(18px, 3vw, 34px);
  border-top: 1px solid var(--rule);
  background: linear-gradient(180deg, var(--surface) 0%, var(--co-wash) 100%);
}
.co__acts { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.co__acts form { margin: 0; }

.co__go {
  display: inline-block;
  padding: 13px 30px;
  border: 0;
  border-radius: var(--radius);
  /* The gradient is the accent against a deepened version of itself, so the
     button belongs to the same colour as everything else on the page. */
  background: linear-gradient(135deg, var(--co-accent) 0%, var(--co-deep) 100%);
  color: #fff;
  font: inherit;
  font-size: .95rem;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), filter var(--dur) var(--ease);
  box-shadow: 0 6px 18px -10px color-mix(in srgb, var(--co-accent) 80%, transparent);
}
.co__go:hover:not(:disabled) {
  color: #fff;
  filter: brightness(1.06);
  transform: translateY(-1px);
  box-shadow: 0 12px 26px -12px color-mix(in srgb, var(--co-accent) 85%, transparent);
}
.co__go:active:not(:disabled) { transform: translateY(0); }
.co__go:disabled { opacity: .6; cursor: progress; transform: none; }

.co__cancel {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: .84rem;
  color: var(--ink-3);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.co__cancel:hover { color: var(--danger); }

.co__done p { margin: 0 0 8px; font-size: .9rem; color: var(--ink-2); }
.co__done p:last-of-type { margin-bottom: 16px; }
.co__done b { color: var(--ink); }

.co__fine {
  margin: 0;
  padding: 16px clamp(18px, 3vw, 34px) 20px;
  border-top: 1px solid var(--rule);
  font-size: .78rem;
  color: var(--ink-3);
}
.co__fine code { font-size: .74rem; }

@media (max-width: 720px) {
  .co__cols { grid-template-columns: 1fr; }
  .co__test { flex-direction: column; gap: 8px; }
}

/* The lift and the hover shift are decoration; the colour change is not. */
@media (prefers-reduced-motion: reduce) {
  .co__go { transition: none; }
  .co__go:hover:not(:disabled) { transform: none; }
}

/* --- Card entry ------------------------------------------------------------
   The number input is the only field on this product that a person will check
   character by character against an object in their hand, so it is set in a
   monospace face at a size that survives being read off a card in bad light.
   ------------------------------------------------------------------------- */

.co__pay {
  margin: 0;
  padding: clamp(20px, 3vw, 28px) clamp(18px, 3vw, 34px);
  border-top: 1px solid var(--rule);
}

.co__payhead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}
.co__payhead .co__h2 { margin: 0; }

/* The detected brand, named as you type. Reassurance that the field is being
   read, and a check that the right card came out of the wallet. */
.co__brand {
  font-size: .64rem;
  font-weight: 600;
  letter-spacing: .14em;
  color: var(--co-accent);
}

.co__cardmsg {
  margin: 0 0 16px;
  padding: 11px 14px;
  border-radius: var(--radius);
  background: var(--surface-sunk);
  font-size: .84rem;
  color: var(--ink-2);
}
.co__cardmsg b { color: var(--ink); }
.co__cardmsg[data-tone="bad"] { background: var(--danger-soft); }
.co__cardmsg[data-tone="bad"] b { color: var(--danger); }

/* The test numbers. Deliberately plain and deliberately present: a stand-in
   gateway that rejects every card is indistinguishable from a broken one, and
   somebody trying to make it work will eventually reach for a real card. */
.co__testcards {
  margin: 0 0 18px;
  padding: 14px 16px;
  border: 1px dashed var(--rule-strong);
  border-radius: var(--radius);
  background: var(--surface-2);
  font-size: .8rem;
  color: var(--ink-2);
}
.co__testcards p { margin: 0 0 8px; }
.co__testcards b { color: var(--ink); }
.co__testcards ul { margin: 0; padding-left: 18px; }
.co__testcards li { padding: 2px 0; }
.co__testcards code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .82rem;
  color: var(--ink);
  margin-right: 6px;
}
.co__testcards-note { margin: 8px 0 0 !important; color: var(--ink-3); }

.co__fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px 18px;
}
.co__field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.co__field--wide { grid-column: 1 / -1; }

.co__field > span {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.co__field input {
  padding: 12px 14px;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  background: var(--surface);
  font: inherit;
  font-size: 1rem;
  color: var(--ink);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
/* Monospace and a touch of tracking on the three that hold digits: grouped
   numerals in a proportional face do not line up with the card. */
#card-number, #card-exp, #card-cvc {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: .04em;
}
.co__field input:focus {
  outline: none;
  border-color: var(--co-accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--co-accent) 18%, transparent);
}
.co__field input[aria-invalid="true"] { border-color: var(--danger); }
.co__field input[aria-invalid="true"]:focus {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 18%, transparent);
}

.co__err {
  min-height: 1em;
  font-style: normal;
  font-size: .76rem;
  color: var(--danger);
}

.co__paynote { margin: 0; font-size: .8rem; color: var(--ink-3); }
.co__paynote[data-state="bad"] { color: var(--danger); }

.co__afterpay {
  padding: 0 clamp(18px, 3vw, 34px) 4px;
}
.co__afterpay form { margin: 0; }

/* The `.co__acts` inside the pay form carries no background of its own — it is
   part of the form, not a footer under it. */
.co__pay .co__acts {
  padding: 18px 0 0;
  border-top: 0;
  background: none;
}

@media (max-width: 560px) {
  .co__fields { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  .co__field input { transition: none; }
}

/* --- The payment dialog -----------------------------------------------------
   Native <dialog>, so the browser owns Escape, the backdrop and focus. Two
   panels share it: the card form, and the completion state checkout.js swaps in
   once the server confirms. Tinted from --co-accent like the rest of the
   checkout, so the dialog visibly belongs to the page that opened it.
   -------------------------------------------------------------------------- */

.paydlg {
  /* The Komunidad logo's own gradient stops, from k_logo_color.svg. The page
     behind the dialog wears the workspace's accent; the dialog is the moment
     money changes hands, and it wears the brand of the company taking it, the
     same way a hosted Stripe page wears Stripe's. */
  --kbrand-1: #1F3556;
  --kbrand-2: #21495F;
  --kbrand-3: #1F7079;
  --kbrand-4: #2BA093;
  --kbrand: linear-gradient(135deg, var(--kbrand-1) 0%, var(--kbrand-2) 42%,
                            var(--kbrand-3) 70%, var(--kbrand-4) 100%);
  width: min(460px, calc(100vw - 32px));
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: calc(var(--radius-lg) + 2px);
  background: var(--surface);
  box-shadow: 0 24px 70px -28px rgba(20, 60, 66, .45);
}
.paydlg::backdrop {
  background: rgba(13, 27, 33, .45);
  backdrop-filter: blur(2px);
}

.paydlg[open] { animation: paydlg-in .18s ease-out; }
@keyframes paydlg-in {
  from { opacity: 0; transform: translateY(8px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

.paydlg__form, .paydlg__done { padding: 22px 24px 24px; }

.paydlg__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}
.paydlg__eyebrow {
  margin: 0 0 4px;
  font-size: .64rem;
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--kbrand-4);
}
.paydlg__title {
  margin: 0;
  font-size: 1.45rem;
  font-weight: 600;
  letter-spacing: -.02em;
}
.paydlg__title small {
  display: block;
  margin-top: 2px;
  font-size: .8rem;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--ink-3);
}

.paydlg__close {
  flex: none;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink-3);
  cursor: pointer;
}
.paydlg__close svg { width: 16px; height: 16px; fill: currentColor; }
.paydlg__close:hover { color: var(--ink); border-color: var(--rule-strong); }

/* The test numbers, compact inside the dialog. Dashed border on purpose: it
   reads as scaffolding, which is what it is. */
.paydlg__test {
  margin: 0 0 16px;
  padding: 11px 13px;
  border: 1px dashed var(--rule-strong);
  border-radius: var(--radius);
  background: var(--surface-2);
  font-size: .76rem;
  color: var(--ink-2);
}
.paydlg__test p { margin: 0 0 6px; }
.paydlg__test b { color: var(--ink); }
.paydlg__test ul { margin: 0; padding: 0; list-style: none; }
.paydlg__test li {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 2px 0;
}
.paydlg__test code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color: var(--ink);
}
.paydlg__test span { color: var(--ink-3); white-space: nowrap; }
.paydlg__testnote { margin: 6px 0 0 !important; color: var(--ink-3); }

.paydlg__msg { margin-bottom: 14px; }

.paydlg .co__field input:focus {
  border-color: var(--kbrand-3);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--kbrand-4) 20%, transparent);
}
.paydlg .co__brand { color: var(--kbrand-3); }

/* Inside the dialog the fields stack in one narrow column; expiry and the
   security code still share a row. */
.paydlg .co__fields { grid-template-columns: 1fr 1fr; }
.paydlg .co__field--wide { grid-column: 1 / -1; }

/* The detected brand sits inside the number field's corner rather than in a
   header row the dialog does not have. */
.paydlg .co__field--wide { position: relative; }
.paydlg .co__brand {
  position: absolute;
  right: 12px;
  bottom: 34px;
  pointer-events: none;
}

.paydlg__pay {
  width: 100%;
  margin-top: 18px;
  text-align: center;
  background: var(--kbrand);
  box-shadow: 0 6px 18px -10px color-mix(in srgb, var(--kbrand-3) 80%, transparent);
}
.paydlg__pay:hover:not(:disabled) {
  box-shadow: 0 12px 26px -12px color-mix(in srgb, var(--kbrand-3) 85%, transparent);
}

.paydlg__note {
  margin: 10px 0 0;
  text-align: center;
  font-size: .76rem;
  color: var(--ink-3);
}

/* --- Completion ------------------------------------------------------------
   What a customer screenshots: the amount, the reference, where the receipt
   went. The check is drawn, and drawn in the page's own accent. */

.paydlg__done { text-align: center; }

.paydlg__check {
  width: 52px;
  height: 52px;
  margin: 6px auto 14px;
  display: block;
}
.paydlg__check path {
  stroke-dasharray: 30;
  stroke-dashoffset: 30;
  animation: paydlg-tick .4s ease-out .15s forwards;
}
@keyframes paydlg-tick { to { stroke-dashoffset: 0; } }

.paydlg__sub {
  margin: 8px 0 18px;
  font-size: .88rem;
  color: var(--ink-2);
}

.paydlg__ref {
  display: grid;
  gap: 1px;
  margin: 0 0 18px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--rule);
  text-align: left;
}
.paydlg__ref > div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 14px;
  background: var(--surface-2);
}
.paydlg__ref dt {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.paydlg__ref dd {
  margin: 0;
  font-size: .88rem;
  color: var(--ink);
  overflow-wrap: anywhere;
  text-align: right;
}
.paydlg__ref code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .86rem;
  letter-spacing: .03em;
}

.paydlg__done .co__go {
  width: 100%;
  text-align: center;
  background: var(--kbrand);
}
.paydlg__ref code { color: var(--kbrand-3); }

.paydlg__sites {
  margin: 0 0 16px;
  padding: 11px 14px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface-2);
  font-size: .82rem;
  line-height: 1.55;
  color: var(--ink-2);
  text-align: left;
}
.paydlg__sites b { color: var(--ink); }
.paydlg__sites a { color: var(--kbrand-3); font-weight: 600; }

.co__cancelform { margin: 0; }

@media (prefers-reduced-motion: reduce) {
  .paydlg[open] { animation: none; }
  .paydlg__check path { animation: none; stroke-dashoffset: 0; }
}

/* --------------------------------------------------------------------------
   FIVE MENU POSITIONS (customer request, 2026-09-14, the same day the
   top-or-side toggle shipped): top, left, right, bottom, hidden, and
   glyphs-only in any of them.

   HOW THE FIVE MAP ONTO ATTRIBUTES. The head script in base.html stamps
   them before the first paint:
     top     nothing
     left    data-nav="side"                 every rail rule above
     right   data-nav="side" data-side="right"  the same rules, plus the
                                             handful below that flip an edge
     bottom  data-nav="bottom"
     hidden  data-nav="hidden"
   and data-rail="icons" for glyphs, whatever the position. `right` reuses
   the left rail's rules by construction rather than by a second copy of
   them: two rails that are the same rail written twice is how one edge
   comes to lag the other.

   Everything here is desktop-only, like the rail above: on a phone every
   position stands down and the top row comes back (the max-width block
   further down), the stored value untouched.
   -------------------------------------------------------------------------- */

/* The trigger opens a small menu. `position: fixed`, placed by navpos.js from
   the trigger's own rect, because inside the rail the masthead is a
   scrollport and would clip anything positioned within it. */
.masthead__navmenu {
  position: fixed;
  z-index: 70;
  width: 268px;
  padding: 12px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-lg), 0 24px 60px -30px rgba(20, 60, 66, .4);
}
.masthead__navmenu[hidden] { display: none; }
.masthead__navmenu-h {
  margin: 0 0 8px 2px;
  font-size: .7rem;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.masthead__navgrid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 4px;
}
/* Each option is its own glyph: the bar drawn on the edge it names, the
   pane faint beside it; the hidden one a crossed pane. Colour never carries
   the choice alone: the chosen one is bordered and its word is inked. */
.masthead__navopt {
  display: grid;
  justify-items: center;
  gap: 5px;
  padding: 8px 2px 7px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: transparent;
  color: var(--ink-3);
  font: inherit;
  font-size: .68rem;
  cursor: pointer;
}
.masthead__navopt svg { width: 22px; height: 22px; fill: currentColor; }
.masthead__navopt .navopt__pane { opacity: .3; }
.masthead__navopt:hover { background: var(--surface-2); color: var(--ink); }
.masthead__navopt[aria-checked="true"] {
  border-color: var(--accent-line);
  background: var(--accent-soft);
  color: var(--accent-ink);
}
.masthead__navopt:focus-visible { outline: 2px solid var(--ink); outline-offset: 1px; }

/* The glyphs switch, at the foot of the menu: a row with a word and a
   toggle knob. It REPLACES the chevron button the rail used, so the class
   is kept and its old dressing is overridden here. */
#nav-menu .masthead__railsize {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  height: auto;
  margin-top: 10px;
  padding: 9px 10px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  color: var(--ink-2);
  font: inherit;
  font-size: .78rem;
  text-align: left;
}
#nav-menu .masthead__railsize[hidden] { display: none; }
#nav-menu .masthead__railsize:hover { border-color: var(--ink-3); color: var(--ink); }
.masthead__railsize-k {
  flex: none;
  position: relative;
  width: 30px;
  height: 18px;
  border-radius: var(--radius);
  background: var(--rule-strong);
  transition: background var(--dur) var(--ease);
}
.masthead__railsize-k::after {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .25);
  transition: transform var(--dur) var(--ease);
}
.masthead__railsize[aria-checked="true"] .masthead__railsize-k { background: var(--accent); }
.masthead__railsize[aria-checked="true"] .masthead__railsize-k::after { transform: translateX(12px); }
/* The rail's old chevron rotation must not turn the switch's row round. */
[data-rail="icons"] #nav-menu .masthead__railsize svg { transform: none; }

/* The way back from hidden. Top-RIGHT, where the avatar sits when the bar is
   shown, so the menu comes back from the corner a reader already looks to
   for the account controls (customer request, 2026-09-15: "put the burger
   on the other side, beside the avatar"). It floats over the page while
   the bar is hidden; the bar's own controls take over the corner when it
   returns. Sized like the avatar disc. */
.masthead__navshow {
  position: fixed;
  top: 12px;
  right: var(--gutter, 20px);
  z-index: 60;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink-2);
  box-shadow: var(--shadow-lg);
  cursor: pointer;
}
.masthead__navshow[hidden] { display: none; }
.masthead__navshow:hover { color: var(--ink); border-color: var(--ink-3); }
.masthead__navshow svg { width: 18px; height: 18px; }

@media (min-width: 901px) {
  /* --- Right: the left rail, mirrored ------------------------------------
     The body reserves the width on the OTHER edge, the rail sits at
     `right: 0` with its border on the left, and the glyph tooltips open
     leftwards, or they would leave the window. */
  [data-side="right"] body { padding-left: 0; padding-right: var(--nav-inset); }
  [data-side="right"] .masthead {
    left: auto;
    right: 0;
    border-right: 0;
    border-left: 1px solid var(--rule);
  }
  [data-side="right"][data-rail="icons"] .masthead__link::after {
    left: auto;
    right: calc(100% + 6px);
  }

  /* --- Bottom: the row, along the foot -----------------------------------
     The same row the top has, fixed to the bottom edge, and the body pads
     below by the bar's height so the page's last line is never under it.
     `--nav-bottom` is 0 everywhere else, so the padding is inert by default
     and the Brand Studio's one-screen body (height: 100%, border-box) keeps
     its measure. */
  [data-nav="bottom"] { --nav-bottom: calc(58px + env(safe-area-inset-bottom, 0px)); }
  [data-nav="bottom"] .masthead {
    position: fixed;
    top: auto;
    bottom: 0;
    left: 0;
    right: 0;
    border-bottom: 0;
    border-top: 1px solid var(--rule);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }

  /* --- Hidden: no bar at all, and the show button --------------------------- */
  [data-nav="hidden"] .masthead { display: none; }
  /* The operator's centred-links rule below (`:root:not([data-nav="side"])
     .masthead--op { display: grid }`) is one class more specific than the
     line above and comes later, so it WON: "hidden" left the whole bar on
     screen with the show button sitting on the wordmark (customer
     screenshot, 2026-09-15). Restated with the class doubled so it outranks
     the grid whatever the source order. */
  :root[data-nav="hidden"] .masthead.masthead--op { display: none; }

  /* --- Glyphs in a ROW (top or bottom) -------------------------------------
     The rail's own glyph rules are keyed on [data-nav="side"]; a row wants
     the same three things: the glyph shown, the word clipped (never removed,
     the accessible name survives), and the word back as a tooltip on hover
     and focus. Twelve glyphs are ~500px, so the row no longer needs to
     scroll and stops clipping, or the tooltips would be cut at its edge. */
  :root:not([data-nav="side"])[data-rail="icons"] .masthead__ico {
    display: block;
    flex: none;
    width: 19px;
    height: 19px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.7;
    stroke-linecap: round;
    stroke-linejoin: round;
  }
  :root:not([data-nav="side"])[data-rail="icons"] .masthead__w {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  :root:not([data-nav="side"])[data-rail="icons"] .masthead__nav { overflow: visible; gap: 2px; }
  :root:not([data-nav="side"])[data-rail="icons"] .masthead__nav .masthead__link {
    position: relative;
    display: grid;
    place-items: center;
    width: 38px;
    height: 34px;
    padding: 0;
    border-radius: var(--radius);
  }
  :root:not([data-nav="side"])[data-rail="icons"] .masthead__link::after {
    content: attr(data-label);
    position: absolute;
    left: 50%;
    top: calc(100% + 8px);
    transform: translateX(-50%);
    z-index: 60;
    padding: 5px 10px;
    border-radius: var(--radius);
    background: var(--ink);
    color: var(--surface);
    font-size: .76rem;
    font-weight: 500;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur) var(--ease);
  }
  :root:not([data-nav="side"])[data-rail="icons"] .masthead__link:hover::after,
  :root:not([data-nav="side"])[data-rail="icons"] .masthead__link:focus-visible::after {
    opacity: 1;
  }
  /* Tooltips over a BOTTOM row open UPWARDS (customer report, 2026-09-14:
     they opened downwards, off the bottom of the window). `:root` is added
     for WEIGHT: the row rule above is `:root:not(...)[...] .x::after`, and
     `[data-nav][data-rail] .x::after` ties with it and loses on source
     order, which is what shipped for one pass. */
  :root[data-nav="bottom"][data-rail="icons"] .masthead__link::after {
    top: auto;
    bottom: calc(100% + 8px);
  }
  /* A row of glyphs has the room for the lockup's subtitle again. */
  :root:not([data-nav="side"])[data-rail="icons"] .masthead .masthead__sub,
  :root:not([data-nav="side"])[data-rail="icons"] .masthead .masthead__rule { display: revert; }
}

/* --- The links CENTRED in a top or bottom bar (customer request, 2026-09-14).

   An operator's row is a three-column grid: the mark, the links, the trailing
   controls (the position trigger and the session, wrapped in `.masthead__end`
   in the markup). The outer two tracks share the free space equally, which
   is what puts the middle track's centre on the window's centre whatever the
   mark and the controls measure. Their FLOOR is their own content: measured
   at 1280 with `minmax(0, 1fr)` the mark's track collapsed to 63px under an
   86px logo and the username was cut to 63px, because a `0` floor lets a
   track shrink under what is in it. With the floor, a row of words longer
   than the room shrinks and scrolls as before (the middle track is
   `minmax(0, max-content)` and the nav keeps `min-width: 0`), and only in
   THAT squeezed case is the row off exact centre, by half the difference
   between the mark and the controls. Measured: a superadmin's twelve WORDS
   are exact at 1600, scroll by 18px at 1440 and by 178px at 1280; the same
   twelve as GLYPHS are exact at 1280. The glyphs and the rail are what a row
   that long is for.

   In the RAIL the wrapper is `display: contents`, so the rail's own rules
   (the trigger absolute at the top-right, the session at the foot) still see
   the trigger and the session as children of the masthead, exactly as they
   were. A visitor's header carries neither the class nor the wrapper. */
@media (min-width: 901px) {
  :root:not([data-nav="side"]) .masthead--op {
    display: grid;
    grid-template-columns: minmax(max-content, 1fr) minmax(0, max-content) minmax(max-content, 1fr);
    align-items: center;
  }
  :root:not([data-nav="side"]) .masthead--op .masthead__nav {
    margin-left: 0;
    max-width: 100%;
    justify-self: center;
  }
  :root:not([data-nav="side"]) .masthead--op .masthead__end {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 18px;
    min-width: 0;
  }
  [data-nav="side"] .masthead__end { display: contents; }
}
@media (max-width: 900px) {
  .masthead__end { display: contents; }
}

/* Every position stands down on a phone, as the rail does above. */
@media (max-width: 900px) {
  .masthead__navmenu, .masthead__navshow { display: none; }
  [data-nav="bottom"] .masthead { position: sticky; top: 0; bottom: auto; border-top: 0; border-bottom: 1px solid var(--rule); }
  [data-nav="hidden"] .masthead { display: flex; }
  [data-rail="icons"] .masthead__ico { display: none; }
}
