/* ============================================================================
 * brand.css — the Drift design system. ONE file. Every site imports it.
 * ============================================================================
 *
 * THE DOCUMENTATION IS hq/brand/BRAND.html — open it in a browser, or reach it
 * in HQ at Company > Brand. Every rule below is rendered live there beside the
 * snippet that produces it. This file is the implementation; that file is the
 * argument for it. (It lived in its own repo until 2026-08-01; HQ owns it now.)
 *
 * WHAT LIVES HERE, AND WHAT DOES NOT
 *
 * Here: THE PRIMITIVES the system is built from — tokens, the reset, base type,
 * focus, the toy affordance, buttons, cards, panels, forms, tags, the spinner,
 * code blocks, and the shared header (announce bar + navbar + accent stripe).
 * Every surface loads this file whole, so everything in it is paid for by every
 * page.
 *
 * NOT here: a COMPONENT. Those live one to a folder under
 * `shared/components/<name>/`, with their own CSS, markup and README, and are
 * imported by the surfaces that actually use them — see that directory's README
 * for the contract. `.sidenav` was in this file and moved out: HQ wears it, the
 * status page does not, and there is no reason a status page should download a
 * navigation column to render one table.
 *
 * Also not here: one surface's own furniture. `website/html/styles/hero.css` and
 * `footer.css`, `website/html/docs/docs.css` and the bulk of
 * `hq/static/styles.css` are page and app layout.
 *
 * THERE WAS A brand.css BEFORE THIS ONE, AND IT DIED
 *
 * `sites/shared/styles/brand.css` existed until 2026-07-28 and its header called
 * it "the single source of truth for colors, typography, and common patterns
 * across all Drift sites". It was loaded by exactly ONE page. Its `.toy-raise`,
 * `.drift-logo` and `.drift-spinner` classes were used by nothing at all, and
 * `.drift-spinner` set a border and `display: inline-block` with no width or
 * height, so it rendered 0x0 and had never once been seen. It was deleted.
 *
 * The name is reused deliberately, and the difference is the whole point: this
 * file is the source of truth because every site LINKS it, not because its
 * comment says so. If you find yourself adding a rule here for a component no
 * page uses, you are rebuilding the file that died.
 *
 * A NOTE ON THE RESET
 *
 * `* { box-sizing: border-box }` below is load-bearing and was not free. HQ set
 * it; the marketing site did not. Same stylesheets, two box models, which is how
 * the shared header ended up 76px on one site and 74px on the other from
 * character-for-character identical rules. Adopting it was measured: fourteen of
 * the site's fifteen pages came back pixel-identical, and the fifteenth moved
 * because `.btn` declared `height: 1.5rem` written for content-box. That is
 * fixed below by stating the height as a TOTAL.
 *
 * If you add a rule with an explicit height or width next to a padding or a
 * border, state the total. That is the whole lesson, and it has now cost this
 * codebase the navbar CTA, the hero terminal, the docs content column and the
 * buttons.
 *
 * HOW EACH SITE GETS THIS FILE
 *
 *   website/  nginx serves sites/shared/ at /shared/ (see website/Dockerfile),
 *             so pages link /shared/styles/brand.css. One file, no copy.
 *   status/   same document root convention.
 *   hq/       embeds its frontend with `//go:embed all:static`, and go:embed
 *             refuses any path outside the package directory. The bytes must be
 *             inside sites/hq/static/ before the compiler runs, so a COPY is
 *             unavoidable. It is generated by scripts/sync-shared.py, carries a
 *             do-not-edit header, and `--check` fails the build if it drifts.
 * ========================================================================== */


/* ---- THE CASCADE, STATED ----------------------------------------------------
 * The order every Drift stylesheet resolves in. Declared here because brand.css
 * is the first sheet every surface loads, and a layer order is fixed by where it
 * is FIRST named — anywhere later and the sheets that already loaded would have
 * created their own order by arriving.
 *
 *   brand      this file. Tokens, reset, base type, and the primitives.
 *   site       a site's own layout: global.css.
 *   component  a folder under shared/components/: sidenav, topbar, searchbar,
 *              navbar, footer, status-badge.
 *   page       one page or region: docs.css, hero.css, hq/static/styles.css.
 *
 * WHY THIS EXISTS. The intended layering was previously the ORDER OF FIVE <link>
 * TAGS, so any two rules of equal specificity were decided by which file the
 * page happened to load first. docs.css needed `body > .site-footer` in six
 * places for no reason except to out-specify footer.css, and its own comment
 * said so. A layer makes the precedence a stated fact, and the workarounds that
 * simulated it can go.
 *
 * WHAT CHANGES, AND IT IS NOT SUBTLE: between layers, LAYER ORDER BEATS
 * SPECIFICITY. A one-class rule in `page` now beats a three-class rule in
 * `brand`. That is the point — precedence follows the architecture rather than
 * selector arms races — but it means a sheet must be assigned to the layer that
 * describes what it IS, not to whichever one makes today's rule win.
 *
 * UNLAYERED STYLES BEAT EVERY LAYER. So nothing may be left out of one by
 * accident: an unlayered sheet silently outranks the whole system. Every Drift
 * stylesheet is wrapped, including HQ's and the status page's. */
@layer brand, site, component, page;

@layer brand {

/* ---- Tokens ----------------------------------------------------------------
 * The eight core values, plus two state colours and the layout grid. Declared
 * with fallbacks at every use site further down as well, so a page that somehow
 * loads a component without this block still renders correctly rather than
 * invisibly.
 *
 * The triad is ABC and the mapping is load-bearing — it appears in the wordmark
 * underlines, the accent stripe, the favicon and the docs pillars. Never
 * reassign it. */
:root {
  --brand-1: #f1a006;    /* orange — Atomic:  functions, deploys, compute */
  --brand-2: #8269eb;    /* purple — Backbone: data, storage, state       */
  --brand-3: #10b981;    /* green  — Canvas:   sites, hosting, output     */

  --ink: #1b2844;        /* all text, all borders, every drop shadow */
  --ink-subtle: #1b284476; /* ink at ~46%. Hairlines and de-emphasised rules.
                              An opacity trick, and a deliberate one: one
                              softened ink beats five inline rgba() values. */
  /* The reading face, on every surface. "Inter Fallback" is the metric-matched
     stand-in declared below; the system names behind it are what renders if the
     page never fetched Inter, which is a bug rather than a mode. */
  --body: "Inter", "Inter Fallback", system-ui, -apple-system,
    BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell,
    "Open Sans", "Helvetica Neue", sans-serif;
  /* One monospace stack for everything that shows machine text — inline code,
     code blocks, filenames in a tree. Named because it had begun to be retyped
     per component, which is how two of them end up disagreeing. System, and
     that is a brand choice rather than a font nobody got round to picking. */
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --bg: #e2e2e2;         /* the "desk" cards sit on */
  --panel: #ffffff;      /* card and panel fill. always white */
  --muted: #5f6b85;      /* secondary text, hints, units, resting nav links */
  /* ---- The status three ------------------------------------------------------
   * Red, yellow and blue for what a thing IS — broken, risky, worth knowing —
   * as opposed to the triad, which says which PRIMITIVE something belongs to.
   * Two questions, two sets, and a surface answering both never has to make one
   * colour mean two things.
   *
   * Built to sit in the triad's family rather than beside it. Measured in OKLCH,
   * the triad runs L 0.61–0.77 at C 0.15–0.19, and these are cut from the same
   * band. Their hues are held at least 20° off the nearest pillar so a status
   * never reads as a primitive: warning is 22° from Atomic's amber, info is 40°
   * from Backbone's purple.
   *
   * YELLOW IS THE ONE THAT CANNOT MATCH, and that is the colour space rather
   * than a compromise: a yellow at the triad's lightness is olive and stops
   * reading as yellow at all. It sits at L 0.85, lighter than any pillar, which
   * is also why it is the one that takes ink text instead of white. */
  --error: #d23838;      /* error, failure, refusal. never decorative red */
  --warning: #efcc36;    /* risk, a footgun, a thing that costs money */
  --info: #3797e9;       /* worth knowing, changes nothing on its own */
  --in-progress: #5f5f5f; /* neutral grey for an unfinished/pending state */

  /* ---- On ink ----------------------------------------------------------------
   * Text and fills for surfaces drawn ON --ink: the sidebar, an inverted card,
   * a selected row. The light side has three ranks — --ink, --muted, --bg — and
   * the dark side needs the same three or every author writes a hex.
   *
   * --muted is a DARK-ON-LIGHT value: on ink it measures 1.4:1 and is not
   * text, it is a shade of the background. That is why it must never be
   * reached for on a dark fill, and why these exist. --panel (white) is the
   * primary rank; the two below are the secondary and the field a row lifts to
   * when it is hovered or current. */
  --on-ink: #d6dcea;       /* body text on ink — a row's resting label */
  --on-ink-muted: #8ea0c4; /* one rank down: group headings, captions */
  --ink-raised: #26344f;   /* ink lifted a step: hover, and the current row */

  /* Content column. Every container uses these so edges align down the page and
   * ACROSS sites. Two surfaces with different values is how the navbar and the
   * content beneath it stopped lining up. */
  --max-width: 1500px;
  --padding: clamp(24px, 6vw, 150px);

  /* The sidebar's width, declared HERE rather than on .sidenav because the host
   * has to read it too: the column is pinned out of flow, so whatever sits
   * beside it offsets itself by exactly this. A custom property inherits down
   * the tree and not across it, so one declared on the component is a number
   * the content next to it cannot see. */
  --sidenav-w: 284px;

  /* Header bands. All three are declared together because anything offsetting
   * itself below the header needs every one of them, and hunting a height
   * across files is how an offset ends up short.
   *
   * --announce-h keeps its ORIGINAL unprefixed name. It was briefly renamed to
   * --drift-announce-h, which broke seven calc() call sites in hero.css and
   * docs.css. An undefined variable inside calc() does not fall back — it
   * invalidates the whole declaration — so the hero silently lost its top
   * padding and nothing reported an error. Namespacing a token other
   * stylesheets already consume is a rename, and a rename needs a grep. */
  --announce-h: 40px;
  --nav-h: 76px;         /* TOTAL, including the 2px bottom rule */
  --header-h: calc(var(--announce-h) + var(--nav-h));
  --subnav-h: 74px;      /* the docs statcard row, when a host pins it */
}


/* ---- Reset -----------------------------------------------------------------
 * See "A NOTE ON THE RESET" at the top. Every site now shares one box model. */
* { box-sizing: border-box; margin: 0; padding: 0; }


/* ---- Base ------------------------------------------------------------------
 * One family for the UI, loading nothing. Tinos, for the wordmark, is the single
 * web font on the platform and the single exception to that.
 *
 * Body at 300 is what makes 600 read as bold without real boldface. The
 * impression should be airy. There is no 400 and no 500 in this system; if you
 * find one it is a bug. */
html {
  background: var(--bg);
}

/* ---- The reading face, and the wordmark's -----------------------------------
 * Inter and Tinos, SELF-HOSTED from Drift's own origin. Declared here, in the
 * file all four surfaces load, so no page needs a font tag of its own — the
 * faces arrive with the stylesheet that names them, and there is no second
 * thing to keep in step.
 *
 * SELF-HOSTED, and both reasons are in shared/fonts/README.md: a render-blocking
 * third-party request blocks the first paint on a round trip nobody controls,
 * and it hands every visitor's IP to that third party before the page will
 * render — which a site selling EU sovereignty cannot do.
 *
 * `--display` (Mozilla Text) is deliberately NOT here. It is the marketing
 * site's and the docs' headline face and nothing else loads it, so it is
 * declared in website/html/styles/global.css beside the pages that use it. Mono
 * stays the system stack on purpose — a brand choice, not a fallback.
 *
 * TWO SUBSETS EACH, and the unicode-range on each one belongs to that exact
 * file. A range claiming more than the file contains makes the browser skip the
 * fallback for characters it cannot draw, which renders as tofu rather than as a
 * substitution. Re-fetching a face means re-copying its ranges in the same pass.
 *
 * Tinos is italic 700 alone. Every rule naming it across all five stylesheets
 * sets exactly that; it draws the wordmark and nothing else. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/shared/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/shared/fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Tinos';
  font-style: italic;
  font-weight: 700;
  /* `block` rather than `swap`: this face draws the WORDMARK, and a wordmark
     that renders in a serif fallback and then snaps into Tinos is a logo
     changing shape on screen. A short block is the lesser fault. */
  font-display: block;
  src: url('/shared/fonts/tinos-italic-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Tinos';
  font-style: italic;
  font-weight: 700;
  font-display: block;
  src: url('/shared/fonts/tinos-italic-700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* The metric-matched stand-in for Inter: it pins ONE local face rather than
   leaving it to system-ui, which resolves differently on every OS and so cannot
   be corrected for, and size-adjust scales it until its advance width matches.
   Measured, not guessed — the arithmetic is in global.css beside its Mozilla
   Text twin. Without it the swap re-wraps text and moves everything below it. */
@font-face {
  font-family: "Inter Fallback";
  src: local("Arial"), local("Helvetica"), local("Liberation Sans");
  size-adjust: 105.00%;
}

body {
  font-family: var(--body);
  font-weight: 300;
  line-height: 1.625;
  color: var(--ink);
  background: var(--bg);
  text-align: left;
}

strong, b { font-weight: 600; }

/* NO heading rules here, and that is deliberate rather than an omission.
 *
 * BRAND.html says headings are 600. The marketing site sets h2 and h3 to 300
 * and has since before this file existed. Putting the documented value here
 * would have been a redesign wearing a refactor's clothes, so the divergence is
 * recorded in BRAND.html under "Known divergences" and left for a decision.
 *
 * The near-miss is worth keeping: a first version of this file also set
 * `line-height: 1.2` on h1-h6. Nothing had ever set a heading line-height, so
 * it applied everywhere at once and every one of the fifteen pages came back
 * shorter — the docs index by 55px, the CLI reference by 319px. It was caught
 * only because the refactor was diffed page by page against the baseline. A
 * "sensible default" added to a file every site loads is not a small change. */

/* Radius is 0 everywhere, and a rounded corner is a bug. Stated on the form
 * elements explicitly because user-agent stylesheets round them by default. */
button, input, select, textarea { border-radius: 0; font-family: inherit; }

/* Small uppercase structural signpost — not a heading. */
.section-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}


/* ---- Focus -----------------------------------------------------------------
 * :focus-visible, not :focus. A mouse click drawing a ring is what makes people
 * reach for `outline: none`, and that breaks keyboard navigation for everyone
 * who depends on it. This way the ring appears for the keyboard and nobody is
 * tempted to remove it. */
:focus { outline: none; }
:focus-visible { outline: 2px solid var(--brand-2); outline-offset: 2px; }


/* ---- The toy affordance ----------------------------------------------------
 * The signature interaction, and the single most recognisable thing about a
 * Drift interface. Flat on the desk, rises under the cursor, slams flush when
 * pressed.
 *
 * The shadow is solid, hard-edged, directly below, and var(--ink) — never
 * blurred, never coloured, never offset horizontally. `#000` is a bug; five of
 * them were found in HQ and the docs on 2026-07-28. */
.toy-raise {
  transition: transform 0.1s ease, box-shadow 0.1s ease;
}
.toy-raise:hover {
  transform: translateY(-4px);
  box-shadow: 0 4px 0 var(--ink);
}
.toy-raise:active {
  transform: translateY(0);
  box-shadow: 0 0 0 var(--ink);
}


/* ---- Buttons ---------------------------------------------------------------
 * TWO forms, and they are not drift — they are two decisions.
 *
 * `.btn` is the compact control: flat at rest, 3px lift, 100ms. It is what a
 * dense UI full of controls wants, and it is what HQ uses everywhere.
 *
 * `.btn-raised` is the marketing CTA: sitting UP at rest with a 6px shadow, and
 * slamming flat when pressed — the inverse gesture. It reads as a physical
 * pushbutton waiting to be hit, which is right for one hero call to action and
 * wrong for the twelfth button on a board. The configurator's steppers use it
 * for the same reason.
 *
 * Both are here so the choice is visible. Reach for `.btn` unless the element is
 * genuinely the thing the page is asking you to do. */
.btn {
  font-weight: 600;
  font-size: 14px;
  color: #fff;
  background: var(--brand-1);
  border: 2px solid var(--ink);
  padding: 0.6rem 1rem;
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
  transition: transform 0.1s ease, box-shadow 0.1s ease;
}
.btn:hover  { transform: translateY(-3px); box-shadow: 0 3px 0 var(--ink); }
.btn:active { transform: translateY(0);    box-shadow: 0 0 0 var(--ink); }

.btn-primary   { background: var(--brand-1); }  /* main CTA        */
.btn-secondary { background: var(--brand-2); }  /* alternatives    */
.btn-tertiary  { background: var(--brand-3); }  /* completion      */
.btn-dark      { background: var(--ink); }      /* neutral, cancel */

/* A control that lifts under the cursor is promising something it will not do. */
.btn:disabled,
.btn[disabled],
.btn.is-disabled {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.btn-raised {
  display: inline-block;
  padding: 0.75rem 1.25rem;
  /* 52px TOTAL, border included. This was `height: 1.5rem` — 24px of CONTENT
   * plus 24px of padding plus a 4px border, which came to the same 52 only
   * because the marketing site had no box-sizing reset. The moment every site
   * shared one box model, the same declaration meant a 28px button. Heights
   * next to a padding and a border are stated as totals here for exactly this
   * reason; see the note at the top of the file. */
  height: 52px;
  font-weight: 600;
  color: #fff;
  background: var(--brand-1);
  border: 2px solid var(--ink);
  text-decoration: none;
  cursor: pointer;
  /* Raised AT REST — already up, waiting to be pushed. */
  transform: translateY(-4px);
  box-shadow: 0 6px 0 var(--ink);
  /* Governs the RELEASE. A springy overshoot so the button visibly bounces back
   * past rest before settling; a plain ease reads as sluggish at this size. */
  transition: transform .10s cubic-bezier(.34, 1.56, .64, 1),
              box-shadow .10s cubic-bezier(.34, 1.56, .64, 1),
              background .2s ease, color .2s ease;
}
.btn-raised:active { transform: translateY(0); box-shadow: 0 0 0 var(--ink); }

/* `.pressed` rather than only `:active`, because the marketing site's buttons
 * navigate. js/press-buttons.js intercepts the click, adds this class, and holds
 * the navigation until the animation has visibly finished — otherwise the page
 * changes mid-stomp and the gesture never reads. :active alone cannot do that:
 * it ends the instant the mouse comes up, which on a link is the same instant
 * the browser leaves.
 *
 * Fast and sharp on the way DOWN, distinct from the bouncy return above. The
 * two durations are mirrored in press-buttons.js as PRESS_MS and RELEASE_MS; if
 * you change one, change both. */
.btn-raised.pressed {
  transform: translateY(0);
  box-shadow: 0 0 0 var(--ink);
  transition: transform .09s ease-in, box-shadow .09s ease-in;
}

/* On an ink ground the shadow inverts. An ink shadow on an ink background is
 * invisible, and the affordance would silently disappear. */
.btn-inverse {
  border-color: #fff;
  box-shadow: 0 6px 0 #fff;
  color: var(--ink);
}
.btn-inverse:active { box-shadow: 0 0 0 #fff; }


/* ---- Button groups ---------------------------------------------------------
 * Two or more buttons side by side. The GROUP owns the spacing; the buttons own
 * nothing but themselves.
 *
 * This exists because the alternative had been tried and kept failing. The
 * marketing site's buttons carried `margin-right: 1rem` and `margin-top: 2rem`,
 * which works until the button is put in a container that also spaces things —
 * and then the margin is added to the container's gap on one side only. Inside
 * the docs' card grid it pushed the document to 470px wide in a 390px viewport
 * and /docs/ was the last page on the site still scrolling sideways. The fix at
 * the time was a media query zeroing the margin back out again.
 *
 * A margin on a component is a claim about what is next to it, and a component
 * cannot know that. Spacing belongs to the parent. */
.btns {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  /* Matches the navbar's own cluster gap, so a pair of buttons in a hero and
   * the links-plus-CTA in the header read at the same rhythm. */
  gap: 1.25rem;
}


/* ---- Cards and panels ------------------------------------------------------
 * The paper-cutout primitive everything else sits inside. */
.card {
  background: var(--panel);
  border: 2px solid var(--ink);
  padding: 14px 18px;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
/* A card that is a link — a navigation tile. Without this it arrives underlined
 * and browser-blue, which is why such tiles kept being built out of button
 * classes and inline `style="text-decoration:none"` instead. */
a.card {
  display: block;
  text-decoration: none;
  color: inherit;
}
/* Only cards that DO something get the affordance. A static card that lifts is
 * inviting a click that goes nowhere. */
.card-selectable { cursor: pointer; }
.card-selectable:hover  { transform: translateY(-4px); box-shadow: 0 4px 0 var(--ink); }
.card-selectable:active { transform: translateY(0);    box-shadow: 0 0 0 var(--ink); }
.card.selected { background: var(--brand-2); color: #fff; }

/* A panel that floats ABOVE the page rather than one you press — a search
 * dropdown, the hero terminal. Static, diagonal, never animated.
 *
 * This is the one place a horizontal shadow offset is correct, and the reason
 * it is a separate class rather than a variant: the toy-raise says "press me",
 * this says "I am on top of the page". Using the diagonal on something clickable
 * blurs two vocabularies that are doing different jobs. */
.panel-floating {
  background: var(--panel);
  border: 2px solid var(--ink);
  box-shadow: 4px 4px 0 var(--ink);
}


/* ---- Forms -----------------------------------------------------------------
 * Inputs are cards you can type in. */
input, select, textarea {
  font-size: 13px;
  /* NOT 400. Browsers default form controls to 400, and 400 is a weight this
   * system does not have — eight of them were sitting in HQ's stylesheet
   * unnoticed because the audit's own grep never read that file. */
  font-weight: 300;
  color: var(--ink);
  background: var(--panel);
  border: 2px solid var(--ink);
  padding: 8px 10px;
}
/* Inset, so focusing a field does not nudge its neighbours. */
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--brand-2);
  outline-offset: -2px;
}
label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  margin-bottom: 4px;
}


/* ---- Tags: see `.alpha-tag` in the header section below --------------------
 * ONE badge doing several jobs — CLOSED ALPHA beside the marketing wordmark,
 * DOCS in the docs navbar, HQ in HQ. It is defined with the header rather than
 * here because that is where it was already written and where its inverted
 * variant lives. Deliberately not restated: this file was assembled from two
 * stylesheets and a second `.alpha-tag` was the one selector that collided.
 * Two definitions do not stay identical. */


/* ---- The spinner -----------------------------------------------------------
 * A static square whose four edges light in sequence, then snap to one colour on
 * completion. No rotation — nothing else in this system rotates, and progress is
 * carried by colour.
 *
 * The completion snap is the point. A success that simply disappears leaves the
 * operator inferring a pass from an absence, and "nothing shown" is
 * indistinguishable from "nothing checked". This one turns green first, then
 * leaves. */
.drift-spinner {
  --unlit: rgba(27, 40, 68, 0.15);
  display: inline-block;
  flex: none;
  /* BOTH required. The previous brand.css set a border and inline-block with
   * neither, so it rendered 0x0 for months and nobody saw it — which is the
   * clearest evidence that stylesheet was dead. */
  width: 14px;
  height: 14px;
  border: 3px solid var(--unlit);
  animation: drift-edge-fill 2.4s steps(1, end) infinite;
}
/* Every frame names all four edges. An animation REPLACES border-color outright
 * rather than layering over it, so an unnamed edge is not "left unlit" —
 * `transparent` there punches a hole and the mark reads as a broken bracket
 * instead of a box. */
@keyframes drift-edge-fill {
  0%   { border-color: var(--brand-1) var(--unlit)   var(--unlit)   var(--unlit); }
  25%  { border-color: var(--unlit)   var(--brand-2) var(--unlit)   var(--unlit); }
  50%  { border-color: var(--unlit)   var(--unlit)   var(--brand-3) var(--unlit); }
  75%  { border-color: var(--unlit)   var(--unlit)   var(--unlit)   var(--ink); }
  100% { border-color: var(--brand-1) var(--unlit)   var(--unlit)   var(--unlit); }
}
@media (prefers-reduced-motion: reduce) {
  .drift-spinner { animation: none; border-color: var(--ink); }
}
/* Set the moment the answer arrives, so the square is never left mid-sequence. */
.drift-spinner.is-ok    { animation: none; border-color: var(--brand-3); }
.drift-spinner.is-error { animation: none; border-color: var(--error); }


/* ---- Reference table -------------------------------------------------------
 * Key on the left, meaning on the right. Modes, flags, tokens, status codes,
 * fields — the shape most of the documentation is made of.
 *
 * The left column sizes to its content: `width: 1%` with `white-space: nowrap`
 * makes a table column shrink to its widest cell rather than take an equal
 * share, so the prose gets the remaining space instead of the key being
 * squeezed into a two-line stack.
 *
 * Inline <code> never wraps anywhere in the table. A token broken across lines
 * ("auth=non" / "e") is not a smaller token, it is a wrong one — the reader has
 * to reassemble it before they can use it. */
.reference-table {
  width: 100%;
  border-collapse: collapse;
  border: 2px solid var(--ink);
  /* White on the desk, like every other panel. The row separators are --bg,
   * which needs a fill behind it to read as a line rather than as nothing. */
  background: var(--panel);
  margin: 1rem 0;
  font-size: 0.9em;
}
.reference-table th {
  background: var(--ink);
  color: #fff;
  font-weight: 600;
  text-align: left;
  padding: 8px 12px;
}
.reference-table td {
  padding: 8px 12px;
  border-bottom: 2px solid var(--bg);
  vertical-align: top;
}
.reference-table tr:last-child td { border-bottom: none; }
.reference-table th:first-child,
.reference-table td:first-child {
  width: 1%;
  white-space: nowrap;
}
.reference-table code {
  white-space: nowrap;
  overflow-wrap: normal;
}

/* A table cannot be held to `width: 100%` when a cell's min-content is wider
 * than the viewport: the declaration is satisfied and the table overflows
 * anyway, taking the page with it. Scroll the table inside its own box so the
 * reader moves one table sideways instead of the whole document. */
@media (max-width: 768px) {
  .reference-table {
    display: block;
    width: 100%;
    overflow-x: auto;
  }
}


/* ---- Copy button -----------------------------------------------------------
 * The control that lifts a snippet out of a code block. It sits INSIDE the
 * block, so its host is the one dark surface on the platform and it is styled
 * for that ground rather than for the page.
 *
 * Ink fill with a --muted edge, because an ink border on a #1e1e1e block is
 * invisible and a white one shouts louder than the code. Purple on hover and
 * green on success are the palette's own "acting" and "done" colours.
 *
 * The block needs `position: relative` for this to anchor. */
.copy-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--ink);
  color: #fff;
  border: 2px solid var(--muted);
  padding: 4px 9px;
  cursor: pointer;
}
.copy-btn:hover { background: var(--brand-2); border-color: var(--brand-2); }
.copy-btn:focus-visible { outline: 2px solid var(--brand-2); outline-offset: 2px; }
/* Set on success and cleared on a timer, so the confirmation is something the
 * reader sees rather than infers from the click having happened. */
.copy-btn.done { background: var(--brand-3); border-color: var(--brand-3); }


/* ---- Code ------------------------------------------------------------------
 * The block is VS Code Dark+ on #1e1e1e — the ONLY dark surface on the platform,
 * a deliberate frame-break saying "this is a terminal, not the product". The
 * colours match the CLI's own palette (cli/common/style.go), so documentation
 * looks like the terminal it describes.
 *
 * Inline <code> is the opposite: white fill, ink border. An object on the page
 * rather than a window into a terminal. */
/* A desk-coloured chip: --bg fill, ink text, a soft --ink-subtle ring. The
   token recedes because the fill is the surface the cards already sit on and
   the edge is a hairline rather than a rule — not because the text is dimmed.
   Ink on --bg is 11.3:1, so a paragraph carrying six tokens is still readable
   on a bad screen.
   The border is the ONE place --ink-subtle belongs here: it is ink at 46%
   alpha, so it needs something lighter behind it to read as grey. */
code {
  font-family: var(--mono);
  font-size: 14px;
  background: var(--bg);
  color: var(--ink);
  border: 2px solid var(--ink-subtle);
  padding: 0 4px;
}
pre.code-block,
pre.code-block code {
  background: #1e1e1e;
  color: #dadada;
  border: none;
  padding: 0;
}
pre.code-block {
  border: 2px solid var(--ink);
  padding: 14px 16px;
  overflow-x: auto;
  font-size: 13px;
  line-height: 1.7;
}
.tok-comment  { color: #6A9955; }
.tok-keyword  { color: #569CD6; }
.tok-control  { color: #C586C0; }
.tok-string   { color: #CE9178; }
.tok-function { color: #DCDCAA; }
.tok-number   { color: #B5CEA8; }
.tok-variable { color: #9CDCFE; }


/* ============================================================================
 * THE SHARED HEADER — announce strip + navbar, as one component
 * ============================================================================
 *
 * The navbar has no stylesheet of its own: its appearance is here, because the
 * wordmark's geometry is brand law rather than a component's preference, and
 * because every surface loads this file first anyway. --announce-h, --nav-h,
 * --header-h and --subnav-h are declared once at the top of this file.
 * shared/components/navbar/ carries the markup and the scroll script.
 *
 * WHY IT IS WRITTEN THE WAY IT IS
 *
 * HQ's header was once hand-ported from the marketing site's by copying the
 * rules across verbatim. It still came out wrong in six ways, and the two that
 * took longest to find were invisible on inspection, because the rules involved
 * were character-for-character IDENTICAL:
 *
 *   - the marketing site did not load a `* { box-sizing: border-box }` rule and
 *     HQ did, so `height: 74px` plus a 2px border meant 76px on one site and
 *     74px on the other, and the CTA's `height: 1.5rem` meant 44px on one and
 *     34.4px on the other. Same declarations, different totals, because the box
 *     model came from whichever stylesheet happened to be hosting them.
 *   - the two sites used different --max-width and --padding, so the wordmark
 *     and the nav links sat at different x-positions.
 *
 * Both causes are gone now: one file declares the tokens and one reset applies
 * everywhere. The defensive habits below stay anyway — explicit box-sizing,
 * heights stated as totals, fallbacks on every var() — because they cost
 * nothing and they are what made the bugs findable.
 *
 * WHAT THIS SECTION DOES NOT OWN: positioning. ondrift.eu pins the header with
 * position:fixed and pads its hero to clear it; HQ makes it position:sticky
 * inside a flex column. Both are legitimate, neither is a property of the header
 * itself, so each host adds one rule. Everything that actually broke was
 * geometry, and geometry lives here.
 *
 * The markup skeleton is shared/components/navbar/navbar.html, composed by nginx with
 * SSI. The wordmark inside it is LIVE TEXT and must never become an SVG — see
 * BRAND.html, "The wordmark".
 * ========================================================================== */

/* ---- Announcement strip ----------------------------------------------------
 * A fixed height, deliberately: a strip sized by its content changes height
 * when the content does, and shared chrome that moves is worse than no shared
 * chrome. Hosts vary the ALIGNMENT of what sits inside it — the marketing site
 * centres a broadcast, HQ right-aligns a greeting — which is a modifier, not a
 * reason to fork. */
.announce-bar {
  box-sizing: border-box;
  height: var(--announce-h);
  background: var(--ink, #1b2844);
  color: #fff;
}
.announce-bar .container {
  box-sizing: border-box;
  height: 100%;
  width: 100%;
  max-width: var(--max-width, 1500px);
  margin: 0 auto;
  padding: 0 var(--padding, clamp(24px, 6vw, 150px));
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  font-size: 0.85rem;
  font-weight: 300;
  text-align: center;
}
.announce-bar .container.align-end {
  justify-content: flex-end;
  text-align: right;
}

/* ---- Navbar ---------------------------------------------------------------- */
.navbar {
  box-sizing: border-box;
  height: var(--nav-h);
  background: var(--bg, #e2e2e2);
  border-bottom: 2px solid var(--ink, #1b2844);
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

/* The ABC signature stripe — the brand triad as a permanent graphic mark at the
 * top of every page, not merely tucked into the logo underlines. */
.navbar-accent {
  display: flex;
  width: 100%;
  height: 4px;
  flex-shrink: 0;
}
.navbar-accent span { flex: 1; }
.navbar-accent span:nth-child(1) { background: var(--brand-1, #f1a006); }
.navbar-accent span:nth-child(2) { background: var(--brand-2, #8269eb); }
.navbar-accent span:nth-child(3) { background: var(--brand-3, #10b981); }

/* Links inside the navbar take the surrounding colour — EXCEPT the call to
 * action, which sets its own.
 *
 * The :not() is load-bearing. `.navbar a` is (0,1,1) and `.navbar-cta` is
 * (0,1,0), so this reset quietly won and the CTA inherited ink instead of the
 * white it declares. Both buttons have been rendering dark text on their fill
 * since the day the component was written — the declaration was right and never
 * applied. */
.navbar a:not(.navbar-cta),
.navbar a:not(.navbar-cta):visited,
.navbar a:not(.navbar-cta):hover,
.navbar a:not(.navbar-cta):active {
  text-decoration: none;
  color: inherit;
}
.navbar a.navbar-cta { text-decoration: none; }

.navbar .container {
  box-sizing: border-box;
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  max-width: var(--max-width, 1500px);
  margin: 0 auto;
  padding: 14px var(--padding, clamp(24px, 6vw, 150px));
}

/* Wordmark plus whatever sits with it. The gap is larger than the gap BETWEEN
 * nav items, so those read as a group beside the logo rather than as one more
 * item in it. .brand keeps its own optical lift and the list does not inherit
 * it — that lift corrects for the italic serif's box, which nothing else on the
 * row has. */
.navbar .nav-left {
  display: flex;
  align-items: center;
  gap: 2.25rem;
}

/* ---- Wordmark -------------------------------------------------------------- */
/* The right-hand cluster always reserves a button's height, even when it holds
   nothing. Without this the navbar's inner height is decided by whatever happens
   to be in it: HQ has a 44px Log out, the docs have had an empty .right since
   their CTA was deleted, so their containers came out 72px and 68px — and
   because the row is centred, the wordmark sat 2px higher on the docs than on
   HQ. Same component, same font, same margins, two different logo positions.
   A chrome bar's height should be a property of the bar, not of its contents. */
.navbar .right { min-height: 44px; }

.navbar .brand {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  /* Pulls the italic serif wordmark up so its optical centre, rather than its
     box, lines up with the rest of the row. */
  margin-top: -8px;
}
/* The wordmark is LIVE TEXT — five <span>s in Tinos Bold Italic, each carrying
   its own `text-decoration-color`. Every site renders it this way.

   IT MUST NOT BECOME AN SVG, for good-sounding reasons that do not survive
   contact: no webfont dependency, and something a print shop can use. Outlining
   costs the thing that makes the mark the mark.
   `text-decoration-skip-ink` is what breaks the ink rule around the italic
   `f`'s descender — green rule stops, clean gap, ink rule resumes under the
   `t` — and that break is browser behaviour, not geometry. The SVG has to
   reproduce it with a mask, and a mask cuts exactly at the outline while
   Chrome dilates by a fixed amount around it. At navbar size the masked
   version's gap closes to nothing and the rule runs straight through the `f`.
   Side by side against HQ, which never stopped using text, it is obvious.

   So: no SVG wordmark, anywhere. Print artwork is screenshotted from a real
   browser at rasterisation density instead, which cannot get skip-ink wrong
   because it is the browser doing the skipping. */
.navbar .title {
  font-family: 'Tinos', serif;
  font-weight: 700;
  font-style: italic;
  font-size: 3rem;
  line-height: 1;
}

/* Per-letter underline, each letter keeping its triad colour (BRAND.html "The
   logo"). Always on. */
.navbar .title .lg {
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 3px;
}
.navbar .title .lg-1 { text-decoration-color: var(--brand-1, #f1a006); }
.navbar .title .lg-2 { text-decoration-color: var(--brand-2, #8269eb); }
.navbar .title .lg-3 { text-decoration-color: var(--brand-3, #10b981); }
.navbar .title .lg-4,
.navbar .title .lg-5 { text-decoration-color: var(--ink, #1b2844); }

/* ---- Badge -----------------------------------------------------------------
 * ONE object with several jobs: "CLOSED ALPHA" beside the marketing wordmark,
 * "HQ" beside HQ's, and the signed-in username inside HQ's greeting. It had
 * been written out three times under three names before this. Three copies do
 * not stay identical — the first person to nudge the letter-spacing does it in
 * whichever file they happen to have open. */
.alpha-tag {
  box-sizing: border-box;
  font-size: 11px;
  font-weight: 600;
  /* Stated for the same reason as .sidenav-group: the badge sits on four
     surfaces with three different body leadings, and an inherited line-height
     made it a different height on each. */
  line-height: 1.5;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  border: 2px solid var(--ink, #1b2844);
  background: var(--ink, #1b2844);
  color: #fff;
  padding: 3px 8px;
  align-content: center;
}
/* For use ON the ink announcement strip, where a filled-ink badge would be an
   invisible rectangle. */
.alpha-tag.inverse {
  background: #fff;
  color: var(--ink, #1b2844);
}
.navbar .alpha-tag { margin-top: 4px; }

/* ---- Right-hand cluster: links + CTA ---------------------------------------- */
.navbar .right {
  display: flex;
  align-items: center;
  gap: 1.25rem;
}
.navbar ul {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 1.25rem;
  padding: 0;
  margin: 0;
}
/* Nav links are secondary text that darkens to full ink on hover, so they are
   --muted and --ink. They used to be #374151 / #111827: two hand-picked slate
   greys that belong to no palette, close enough to the tokens to look right and
   far enough to keep the header from matching anything else on the page. */
.navbar ul li {
  position: relative;
  cursor: pointer;
  color: var(--muted, #5f6b85);
  font-weight: 300;
  font-size: 1rem;
  padding-bottom: 2px;
  transition: color 0.25s ease;
}
/* Underline grows from the left on hover. Selected-state variants live in the
   host: "which section am I in" is not a question every site has. */
.navbar ul li::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  height: 2px;
  width: 0;
  background: var(--ink, #1b2844);
  transition: width 0.25s ease;
}
.navbar ul li:hover { color: var(--ink, #1b2844); }
.navbar ul li:hover::after { width: 100%; }

/* The navbar's call to action. 44px TOTAL — stated as a total rather than as
 * `height: 1.5rem` plus whatever the host's box model makes of the padding and
 * the border, which is exactly the bug this component exists to prevent.
 *
 * Raised at REST and slamming flat on click, per BRAND.html's toy affordance:
 * the opposite of a button that lifts on hover. */
.navbar-cta {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  padding: 0 1rem;
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1;
  border-radius: 0;
  border: 2px solid var(--ink, #1b2844);
  background: var(--brand-1, #f1a006);
  color: #fff;
  text-decoration: none;
  cursor: pointer;
  transform: translateY(-4px);
  box-shadow: 0 6px 0 var(--ink, #1b2844);
  /* Springy overshoot on RELEASE, so it visibly bounces back past rest. */
  transition: transform .10s cubic-bezier(.34, 1.56, .64, 1),
              box-shadow .10s cubic-bezier(.34, 1.56, .64, 1),
              background .2s ease,
              color .2s ease;
}
.navbar-cta:active,
.navbar-cta.pressed {
  transform: translateY(0);
  box-shadow: 0 0 0 var(--ink, #1b2844);
  /* Fast and sharp on the way DOWN. The press should feel like a stomp and the
     release like a bounce, which one shared timing cannot express. */
  transition: transform .06s ease-out, box-shadow .06s ease-out;
}
/* Leaving, not arriving. Same object as the primary CTA it stands in place of,
   so it cannot drift out of alignment with it. */
.navbar-cta-danger { background: var(--error, #d23838); }

/* .navbar-cta-tertiary is gone with its only consumer. It painted the docs'
   "Deploy in 5 minutes" button Canvas green; that button was deleted from
   header.html on 2026-07-27 because it crowded the four group tabs on a phone
   and a reader already inside the docs has arrived. A modifier with nothing
   left to modify is dead weight that reads as a live option. */


/* ---- Scroll-linked collapse -------------------------------------------------
 * --header-shift is written by navbar.js: how far the header is
 * currently retracted, in px, moving 1:1 with the scroll. Zero when the page is
 * near the top or the script never ran, so a page without it renders a normal
 * fixed header and nothing here needs a fallback beyond the default.
 *
 * NO TRANSITION on these. The motion IS the scroll — adding a duration would
 * make the header finish travelling after the finger stops and ignore a
 * reversal until it had played out. transform (not `top`) so the compositor
 * moves it without relayout on every frame.
 *
 * A host pins these itself (the component does not position); this only shifts
 * whatever position the host chose. */
.announce-bar,
.navbar {
  transform: translateY(calc(-1 * var(--header-shift, 0px)));
  will-change: transform;
}

/* ---- Narrow screens --------------------------------------------------------
 * ONE set of breakpoints for every site. HQ previously used 900px where the
 * marketing site used 768px and 640px, so the two headers agreed at desktop
 * width and nowhere else. */
/* APP CHROME goes compact below 900px; the marketing site does not.
 *
 * HQ and the docs are working surfaces — their navbars carry section tabs, a
 * badge, an account cluster — and a 3rem wordmark on a phone is a masthead
 * competing with the controls beside it. The marketing site's navbar carries two
 * links, and there the wordmark IS the point, so it holds 3rem at every width
 * (see the exception in the site's own global.css, which outranks this on
 * specificity rather than order).
 *
 * The .brand correction is deliberately NOT rescaled. At 1.6rem the -8px lifts
 * the mark slightly more than optical centring alone would; that is the look HQ
 * has had, and matching it exactly is the point of moving the rule here rather
 * than writing a second one.
 */
@media (max-width: 900px) {
  .navbar .title { font-size: 1.6rem; }
  /* Tighter than the desktop 14px, so a 52px bar has room for a 26px row. The
     HEIGHT itself is a per-surface token (--nav-h), declared by the app surfaces
     in their own sheets — the marketing site keeps 76px and derives its hero
     offsets from it, so this must not be set globally. */
  .navbar .container { padding-top: 12px; padding-bottom: 12px; }
  /* The 44px floor exists to keep the desktop bar's height independent of
     whether .right holds a button (it is what aligned the HQ and docs
     wordmarks). On a phone there is nothing in it to align against — HQ moves
     its account controls to the footer, the docs have none — and the floor was
     the entire reason the docs bar stood 20px taller than HQ's. */
  .navbar .right { min-height: 0; }
}

@media (max-width: 768px) {
  /* The wordmark's SIZE is settled above. What used to live here — a drop to
     2rem plus `margin-top: 0` on .brand — was wrong in both halves: it changed
     the logotype's size at an arbitrary width, and zeroing the margin deleted
     the optical correction rather than scaling it, so the mark appeared to fall
     as well as shrink. */
  .navbar ul { gap: 0.75rem; }
  .navbar ul li { font-size: 0.85rem; }
  .navbar .right { gap: 0.85rem; }
  .alpha-tag { font-size: 9px; padding: 2px 6px; }
}

/* The strip's text wraps to two lines below this width, so the strip grows —
   and because the navbar's offset and the hero's top padding are both driven by
   --announce-h, they follow it instead of overlapping. */
@media (max-width: 640px) {
  /* Back to the one-line height, because the strip now says one line's worth.
     It was 58px here for a real reason — the full sentence wrapped to two lines
     and the band had to grow with it — but the tail is dropped below this width
     (see .announce-tail), so the strip fits again and 58px would leave a gap
     under it. --announce-h feeds --header-h, which positions the fixed navbar
     and every offset beneath it, so this number and the content have to agree. */
  :root { --announce-h: 40px; }
  .announce-bar .container { font-size: 0.75rem; }
  /* "— we will update you when it's ready!" goes. The badge already carries the
     whole message on a phone: Drift is currently in CLOSED ALPHA. Keeping the
     promise as well cost a second line of a band that is now permanently on
     screen, and it wrapped mid-phrase around the badge. */
  .announce-tail { display: none; }
}

/* ── Footer status badge ──────────────────────────────────────────────────────
   Injected by shared/components/status-badge/status-badge.js, directly above the footer's
   rule. It is a live reading of status.ondrift.eu, so everything here is built
   to be honest at a glance and quiet the rest of the time.

   THE DOT IS A SQUARE. The obvious build for this pattern is a circular dot in
   a rounded pill — it is what every other status badge on the web looks like.
   Drift's radius is 0 everywhere and BRAND.html states it plainly: "a rounded
   corner is a bug". A 6px square in the triad's green reads exactly as well and
   belongs to this brand rather than to a screenshot of someone else's. */
.footer-status {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1.25rem;
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--muted, #5f6b85);
  text-decoration: none;
  /* Sits on the footer's own surface rather than in a filled chip: the footer
     is already a distinct band, and a second fill inside it is noise. */
  background: none;
  border: none;
  padding: 0;
}
.footer-status:hover { color: var(--ink, #1b2844); }
.footer-status:focus-visible {
  outline: 2px solid var(--brand-2, #8269eb);
  outline-offset: 3px;
}

.footer-status-dot {
  width: 6px;
  height: 6px;
  flex: 0 0 auto;
  /* No border-radius. See above — this is the whole point. */
  background: var(--brand-3, #10b981);
}

/* Green is Canvas in the triad, and it is the right colour here for the same
   reason it is there: it means "serving". Degraded borrows Atomic's orange.
   Down is the one state that does NOT take a triad colour — the triad names
   parts of the product, and an outage is not a product. */
.footer-status--ok .footer-status-dot       { background: var(--brand-3, #10b981); }
.footer-status--degraded .footer-status-dot { background: var(--brand-1, #f1a006); }
.footer-status--down .footer-status-dot     { background: #d64545; }

/* A degraded or down footer should be readable as such without hovering, so
   those two states darken the label instead of leaving it muted. */
.footer-status--degraded,
.footer-status--down { color: var(--ink, #1b2844); font-weight: 600; }

} /* @layer brand */
