/* Self-hosted webfonts. Google Fonts was the source here (inherited from the
   vendored design system), but a hardcoded fonts.googleapis.com is exactly
   what AGENTS.md forbids, and it made the canonical typography of an
   internal tool depend on a third-party request — one that leaks which
   internal pages load and fails whenever that host is blocked or slow.

   Latin subset only: this is an English-language internal tool, and the
   full unicode coverage was 39 files against 5 here. 220 KB total.

   Filenames carry an 8-char content hash, and that is load-bearing rather
   than tidy: `/portal/fonts/*` is served `immutable, max-age=1y`, so a
   stable filename would strand a corrected face in browsers for a YEAR —
   revalidating this stylesheet cannot dislodge it, because the URL it
   points at has not changed. New bytes must mean a new URL. mq.css is the
   mutable pointer (it revalidates) and the fonts are immutable content.
   Regenerate a font and you must regenerate its filename;
   `home/tests/test_font_fingerprints.py` fails if you forget.

   All five files are VARIABLE fonts with a wght axis of 100–900 (verified
   with fontTools), so each family+style is declared ONCE with a weight
   RANGE. The first version of this block instead transcribed Google's
   discrete faces — `font-weight: 400`, `500`, `700`, `900` all pointing at
   the same variable file — which silently threw away the axis: a weight
   with no declared face falls back to the nearest one that has it, so
   `font-weight: 600` (used five times below, and by all four modules)
   rendered identical to 700, and Roboto Condensed, which had no 900 face
   at all, rendered its 900 headings at 700. Measured, not guessed: the
   600 and 700 runs were the same width to the hundredth of a pixel.

   A range costs nothing — same five files, same bytes — and every weight
   in 100–900 now renders truly. If you ever add a face here, give it a
   range, not a number. */

@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/portal/fonts/roboto-normal.0a44e0bb.woff2') format('woff2');
}
@font-face {
  font-family: 'Roboto';
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url('/portal/fonts/roboto-italic.9f06741f.woff2') format('woff2');
}
@font-face {
  font-family: 'Roboto Condensed';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/portal/fonts/robotocondensed-normal.718ced55.woff2') format('woff2');
}
@font-face {
  font-family: 'Roboto Condensed';
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url('/portal/fonts/robotocondensed-italic.f0b2892a.woff2') format('woff2');
}
@font-face {
  font-family: 'Roboto Slab';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/portal/fonts/robotoslab-normal.317b2daf.woff2') format('woff2');
}


/* mq.css — the Mister Quik internal design system, served once from the
   portal at /portal/mq.css and loaded by every module.
   ============================================================================
   SOURCE OF TRUTH. Do not copy this into an app repo. Change it here, deploy
   internal-proxy, and every module updates — that is the entire point. Before
   this file the design system was vendored three times and ~320 lines of
   chrome were retyped per repo, so a topnav change meant three PRs, three
   reviews, three deploys, and one forgotten repo away from the modules not
   looking like one product.

   The chrome below is recruiting's, which Greg picked as the canonical look
   (2026-08-13): red eyebrow, red-underline active tabs, pill user chip with a
   red avatar. It was also the most token-disciplined of the four — almost
   nothing brand is hardcoded where a token exists. Keep it that way.

   TWO THINGS TO PRESERVE IF YOU EDIT THIS FILE:

   1. No @import at all, anywhere. The portal wrapper rewrites URLs in HTML
      but not inside CSS, so `@import url('/portal/...')` 404s behind a
      module's prefix; and an @import that follows any rule is ignored
      outright by CSS, which silently drops whatever it was loading. Tokens
      are concatenated and the fonts are self-hosted @font-face — one file,
      one request, no ordering trap.
   2. `url()` inside @font-face is fine where @import is not: it resolves
      against /portal/, which the wrapper never prefixes.

   App-specific styling stays in that app's own /static/app.css, loaded after
   this one. Put something here only if more than one module needs it.
   ============================================================================ */

/* ---------- Tokens ---------- */
/* Mister Quik — Webfonts
   Brand Guidelines 2024 (p9, Website Typography):
     Header     → Roboto Bold
     Subheader  → Roboto Slab Bold
     Accent     → Roboto Condensed
     Body       → Arial (system; Roboto used as the web fallback face)
   Social-only faces (Coolvetica, ITC Avant Garde Gothic Pro) are NOT shipped —
   they are reserved for social graphics, not product UI.

   Self-hosted from /portal/fonts (done 2026-08-13 — this note used to say
   "served from Google Fonts" and to suggest exactly the swap that has now
   been made). See the @font-face block at the top of this file. */

/* Mister Quik — Color tokens
   Source: Brand Guidelines 2024 (p4). Four brand colors:
   MQ Red #FE1507 · MQ Yellow #FFD300 · MQ Black #000000 · MQ Blue #0A5A9A */

:root {
  /* ---- Brand core ---- */
  --mq-red: #FE1507;          /* Main color — primary action, energy */
  --mq-yellow: #FFD300;       /* Main color — highlight, attention */
  --mq-black: #000000;        /* Bold color — outlines, text, contrast */
  --mq-blue: #0A5A9A;         /* Accent color — trust, links, secondary */

  /* ---- Red ramp (interaction states) ---- */
  --mq-red-hover: #E00D00;    /* hover — slightly darker */
  --mq-red-press: #BE0A00;    /* active/pressed — darker still; white text ≥4.5:1 at 12.5px (6.50:1) */
  --mq-red-tint: #FFE7E5;     /* soft red surface */

  /* ---- Yellow ramp ---- */
  --mq-yellow-hover: #F2C800;
  --mq-yellow-press: #D9B400;
  --mq-yellow-tint: #FFF6CC;

  /* ---- Blue ramp ---- */
  --mq-blue-hover: #084B82;
  --mq-blue-press: #063A66;
  --mq-blue-tint: #E4EEF6;

  /* ---- Neutrals ---- */
  --white: #FFFFFF;
  --gray-50: #F7F8FA;
  --gray-100: #EEF0F3;
  --gray-200: #E0E3E8;
  --gray-300: #C7CCD4;
  --gray-400: #9AA1AC;
  --gray-500: #6B7280;
  --gray-600: #4B5159;
  --gray-700: #33373D;
  --gray-800: #1E2125;
  --gray-900: #111315;

  /* ---- Semantic aliases ---- */
  --surface-page: var(--white);
  --surface-muted: var(--gray-50);
  --surface-card: var(--white);
  --surface-inverse: var(--mq-black);
  --surface-brand: var(--mq-red);
  --surface-brand-yellow: var(--mq-yellow);

  --text-heading: var(--mq-black);
  --text-body: var(--gray-800);
  --text-muted: var(--gray-500);
  --text-inverse: var(--white);
  --text-on-red: var(--white);
  --text-on-yellow: var(--mq-black);
  --text-link: var(--mq-blue);

  --border: var(--gray-200);
  --border-strong: var(--mq-black);
  --border-focus: var(--mq-blue);

  /* ---- Status ---- */
  --success: #1F8A3B;
  --warning: var(--mq-yellow);
  --danger: var(--mq-red);
  --info: var(--mq-blue);
}

/* Mister Quik — Typography tokens
   Header: Roboto Bold · Subheader: Roboto Slab Bold · Accent: Roboto Condensed · Body: Arial */

:root {
  /* ---- Families ---- */
  --font-heading: 'Roboto', 'Helvetica Neue', Arial, sans-serif;        /* headers */
  --font-subhead: 'Roboto Slab', Georgia, 'Times New Roman', serif;     /* subheaders */
  --font-accent: 'Roboto Condensed', 'Arial Narrow', Arial, sans-serif; /* eyebrows, labels, prices */
  --font-body: Arial, 'Roboto', Helvetica, sans-serif;                  /* body copy */

  /* ---- Weights ---- */
  --fw-regular: 400; /* @kind font */
  --fw-medium: 500; /* @kind font */
  --fw-bold: 700; /* @kind font */
  --fw-black: 900; /* @kind font */

  /* ---- Type scale (1.25 major-third-ish, tuned for a loud consumer brand) ---- */
  --text-display: 64px;   /* hero headlines */
  --text-h1: 48px;
  --text-h2: 36px;
  --text-h3: 28px;
  --text-h4: 22px;
  --text-lg: 18px;
  --text-base: 16px;
  --text-sm: 14px;
  --text-xs: 12px;
  --text-eyebrow: 13px;   /* condensed uppercase kicker */

  /* ---- Line heights ---- */
  --lh-tight: 1.05; /* @kind font */       /* big display headlines */
  --lh-snug: 1.2; /* @kind font */
  --lh-normal: 1.5; /* @kind font */       /* body */
  --lh-relaxed: 1.65; /* @kind font */

  /* ---- Letter spacing ---- */
  --ls-tight: -0.02em; /* @kind font */
  --ls-normal: 0; /* @kind font */
  --ls-wide: 0.04em; /* @kind font */
  --ls-eyebrow: 0.12em; /* @kind font */   /* uppercase condensed kickers */
}

/* Mister Quik — Spacing & layout tokens (4px base grid) */

:root {
  --space-0: 0;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;
  --space-20: 80px;
  --space-24: 96px;

  /* ---- Container widths ---- */
  --container-sm: 640px;
  --container-md: 960px;
  --container-lg: 1200px;
  --container-xl: 1320px;

  /* ---- Section rhythm ---- */
  --section-y: var(--space-20);
  --gutter: var(--space-6);
}

/* Mister Quik — Radius, border, shadow & motion tokens
   Brand Guidelines 2024 (p8): "Photos and borders on the website should be
   rounded (20pts)" — emulating phone-home-screen app icons. 20px is the
   signature radius for cards, images and media. */

:root {
  /* ---- Radius ---- */
  --radius-xs: 4px;
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-brand: 20px;     /* signature — cards, photos, media */
  --radius-lg: 28px;
  --radius-pill: 999px;     /* buttons, chips, deal badges */
  /* .card, and the inner radius of its first/last child derives from this.
     14px, not `--radius-md`'s 12px, because recruiting's card has always been
     14px and recruiting is the canonical design (Greg, 2026-08-13). AGENTS.md
     said cards used `--radius-md` — that was written before this file existed,
     describing the vendored design system, and it never matched the rendered
     product. Naming the value here made the mismatch visible (Codex P2); the
     resolution is that AGENTS.md is corrected to match the design, not that
     every card in the platform silently moves 2px during the migration. */
  --radius-card: 14px;

  /* ---- Stacking ----
     One scale, because the alternative is every module inventing a number
     and discovering the collision in production. A popover must sit ABOVE
     the sticky header: HR's typeahead panel used z-index 10 against the
     header's 20, so even once it stopped being clipped it would have gone
     behind the header near the top of a page. A popover's z-index belongs
     on the open state, not the container — a per-row container that always
     raises itself defeats the scale because every row wins equally. */
  --z-base: 1;
  --z-header: 20;    /* .shell-sticky */
  --z-popover: 60;   /* typeaheads, menus, tooltips — above the header */
  --z-modal: 100;

  /* ---- Borders ---- */
  --border-width: 1px;
  --border-width-bold: 3px; /* heavy comic-style outline (logo lockups, callouts) */

  /* ---- Shadows (soft, friendly, neutral — never colored) ---- */
  --shadow-sm: 0 1px 2px rgba(17, 19, 21, 0.08);
  --shadow-md: 0 4px 12px rgba(17, 19, 21, 0.10);
  --shadow-lg: 0 12px 32px rgba(17, 19, 21, 0.14);
  --shadow-card: 0 6px 20px rgba(17, 19, 21, 0.10);
  --shadow-focus: 0 0 0 3px var(--mq-blue-tint);

  /* ---- Motion ---- */
  --ease-standard: cubic-bezier(0.2, 0, 0.2, 1); /* @kind other */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1); /* @kind other */
  --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1); /* @kind other */ /* playful pop on hover/CTA */
  --dur-fast: 120ms; /* @kind other */
  --dur-base: 200ms; /* @kind other */
  --dur-slow: 320ms; /* @kind other */
}

/* ---------- Chrome: shell, page, cards, tables, pills, forms ---------- */
* { box-sizing: border-box; }

/* `hidden` has to actually hide. The UA sheet's [hidden]{display:none} is a
   plain element rule, so ANY class below that sets `display` outranks it —
   `.pill` is `inline-block`, and `el.hidden = true` on a pill therefore did
   nothing at all. That is not a styling nit: a status pill that cannot be
   lowered (or, unrendered, cannot be raised) freezes at whatever the page
   load happened to show, and the roles editor spent a day telling admins
   nothing had changed when it had (2026-08-18).
   `!important` is right here rather than lazy: this must beat every
   component rule in the file, including ones not written yet. An element
   that wants to be visible should not be carrying `hidden`. */
[hidden] { display: none !important; }
html, body { margin: 0; padding: 0; }
body {
  background: #F6F4F1;
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--text-body);
}
a { color: var(--mq-blue); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ---------- Shell ---------- */
.shell-sticky { position: sticky; top: 0; z-index: var(--z-header); }
.accent-rule { height: 4px; background: var(--mq-red); }
header.site {
  height: 68px; background: #fff; border-bottom: 1px solid var(--border);
  padding: 0 32px; display: flex; align-items: center; gap: 16px;
}
header.site .q-mark { height: 36px; }
/* The mark is the way home from every page of every app (Greg, 2026-08-18).
   `display: flex` so the link is exactly the image and not a taller line box
   with dead space above and below it. */
header.site .q-home { display: flex; align-items: center; border-radius: 6px; }
header.site .q-home:hover { opacity: .82; }
header.site .q-home:focus-visible { outline: 2px solid var(--mq-blue);
                                    outline-offset: 3px; }
.brand-block { border-left: 1px solid var(--border); padding-left: 16px; }
/* `display: block` on both, and it is load-bearing rather than tidy-up.
   Neither rule set a display, so the eyebrow and the module name stacked
   only when the app happened to use <div>. portal-home does; accounting and
   recruiting use <span>, so their headers rendered on ONE line —
   "MISTER QUIK HOME SERVICES Accounting" — on every page (Greg, 2026-08-14).
   A shared component's layout must not depend on which element an app
   picked; that is not a choice we ever asked them to make. */
.brand-block .eyebrow {
  display: block;
  font-family: var(--font-accent); font-weight: 700; font-size: 11px;
  letter-spacing: var(--ls-eyebrow); text-transform: uppercase; color: var(--mq-red);
}
.brand-block .title {
  display: block;
  font-family: var(--font-heading); font-weight: 900; font-size: 18px;
  color: var(--text-heading); letter-spacing: -0.01em;
}
nav.tabs {
  display: flex; gap: 20px; margin-left: 32px; height: 68px; flex: none;
}
nav.tabs a {
  font-family: var(--font-accent); font-weight: 700; font-size: 13px;
  text-transform: uppercase; letter-spacing: var(--ls-wide);
  color: var(--text-muted); display: flex; align-items: center;
  border-bottom: 3px solid transparent; padding-top: 3px;
}
nav.tabs a:hover { text-decoration: none; color: var(--text-heading); }
nav.tabs a.active { color: var(--text-heading); border-bottom-color: var(--mq-red); }
.header-right { margin-left: auto; display: flex; align-items: center; gap: 16px; }
.util-link { font-size: 13px; color: var(--text-muted); white-space: nowrap; }
.util-link:hover { color: var(--text-heading); text-decoration: none; }
.util-link.active { color: var(--text-heading); font-weight: 600; }
.search-box input {
  font-size: 13px; padding: 7px 12px; border: 1px solid var(--gray-300);
  border-radius: var(--radius-pill); width: 210px; background: #FBFAF8;
}
.user-chip {
  background: #FBFAF8; border: 1px solid var(--border); border-radius: var(--radius-pill);
  padding: 5px 12px 5px 6px; display: flex; align-items: center; gap: 8px; flex: none;
}
.user-chip .avatar {
  position: relative;
  width: 26px; height: 26px; border-radius: 50%; background: var(--mq-red);
  color: #fff; font-family: var(--font-heading); font-weight: 900; font-size: 12px;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden; flex: none;
}
.user-chip .avatar img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; border-radius: 50%;
}
.user-chip .who { font-size: 12.5px; color: var(--text-body); white-space: nowrap; }
@media (max-width: 1280px) { .search-box input { width: 140px; } }

/* ---------- Page ---------- */
/* 1500px was chosen when the widest screen in the building was a laptop. On a
   27" monitor it strands 500px of empty gutter, and every table in every
   module gets squeezed into two thirds of the glass while the header runs the
   full width — which reads as the content being shoved to one side rather
   than as a deliberate measure (Luke, 19 Aug 2026).

   1900px uses the screen without letting a data table sprawl unreadably, and
   prose is already protected: modules give paragraphs their own max-width
   (marketing's `.reading`, the policy bodies) precisely so widening this does
   not produce 200-character lines. */
main.wrap {
  max-width: 1900px; margin: 0 auto; padding: 26px 32px 56px;
  display: flex; flex-direction: column; gap: 16px;
}
.title-row { display: flex; align-items: flex-end; gap: 16px; }
.title-row .eyebrow {
  font-family: var(--font-accent); font-weight: 700; font-size: 11px;
  letter-spacing: var(--ls-eyebrow); text-transform: uppercase; color: var(--text-muted);
}
.title-row h1 {
  font-family: var(--font-heading); font-weight: 900; font-size: 28px;
  letter-spacing: -0.015em; color: var(--text-heading); margin: 2px 0 0;
}
.title-row .actions { margin-left: auto; display: flex; gap: 10px; align-items: center; }

/* Bare headings. Recruiting only styles `.title-row h1`, so an unclassed
   <h1> fell through to the body face — every migrating module has those.
   Same reasoning as the unclassed button/input defaults below: make the
   plain element right, keep the classed variants for layout. */
h1, h2, h3 {
  font-family: var(--font-heading); font-weight: 900;
  color: var(--text-heading); letter-spacing: -0.015em;
}
h1 { font-size: 28px; margin: 2px 0 0; }
h2 { font-size: 20px; }
h3 { font-size: 16px; }

/* ---------- Cards ---------- */
/* `.card` does NOT clip its children, and that is load-bearing.
   It used to carry `overflow: hidden`, purely so a child painting to the edge
   would not square off the rounded corner. The cost was invisible until HR
   adopted this sheet: an absolutely-positioned child ESCAPING the card — a
   typeahead panel, a menu, a tooltip — was clipped out of existence. HR's
   offboarding search rendered its results 85px below the card's bottom edge
   and you simply could not see them (Greg, 2026-08-14). It would have done the
   same to every picker in every module.

   `overflow: hidden` cannot be narrowed to one axis — setting either axis to
   hidden forces the other to `auto` — so there is no version of it that clips
   a wide table without also clipping a dropdown. The corners are handled
   instead by rounding the first and last children, and horizontal overflow is
   `.table-scroll`'s job, which is why wrapping wide tables is still required.
   That requirement is now stronger, not weaker: an unwrapped wide table used
   to be clipped, and now pushes the whole page sideways. */
.card {
  background: #fff; border: 1px solid var(--border);
  border-radius: var(--radius-card);
  box-shadow: 0 1px 3px rgba(20,16,12,.07);
}
/* Inner radius is one border-width smaller, so a child's background follows
   the inside of the border rather than crossing it. */
.card > :first-child {
  border-top-left-radius: calc(var(--radius-card) - var(--border-width));
  border-top-right-radius: calc(var(--radius-card) - var(--border-width));
}
.card > :last-child {
  border-bottom-left-radius: calc(var(--radius-card) - var(--border-width));
  border-bottom-right-radius: calc(var(--radius-card) - var(--border-width));
}
.card-head {
  padding: 14px 18px; background: #FBFAF8; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 10px;
}
.card-head .card-title {
  font-family: var(--font-subhead); font-weight: 700; font-size: 15px;
  color: var(--text-heading);
}
.card-head .card-sub { font-size: 12px; color: var(--text-muted); }
.card-head .card-actions { margin-left: auto; display: flex; gap: 10px; align-items: center; }
.card-body { padding: 16px 18px; }
.card-grid { display: grid; gap: 16px; }
.card-grid.half { grid-template-columns: 1fr 1fr; }
@media (max-width: 1100px) { .card-grid.half { grid-template-columns: 1fr; } }

/* ---------- KPI tiles ---------- */
.kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.kpi { background: #fff; border: 1px solid var(--border); border-radius: 14px;
  box-shadow: 0 1px 3px rgba(20,16,12,.07); padding: 16px 18px; }
.kpi .label {
  font-family: var(--font-accent); font-weight: 700; font-size: 11px;
  text-transform: uppercase; letter-spacing: var(--ls-wide); color: var(--text-muted);
}
.kpi .value {
  font-family: var(--font-heading); font-weight: 900; font-size: 27px;
  letter-spacing: -0.02em; color: var(--text-heading);
  font-variant-numeric: tabular-nums; margin-top: 4px;
}
.kpi .value .denom { color: var(--gray-400); font-size: 15px; font-weight: 900; }
.kpi .sub { font-size: 11px; color: var(--text-muted); margin-top: 3px; }
.kpi .value.bad { color: #C41208; }
.kpi .value.warn { color: #7A6400; }
a.kpi { display: block; color: inherit; }
a.kpi:hover { text-decoration: none; border-color: var(--gray-400); box-shadow: 0 2px 6px rgba(20,16,12,.10); }

/* ---------- Tables ---------- */
table.data { border-collapse: collapse; width: 100%; font-variant-numeric: tabular-nums; font-size: 13px; }
table.data th {
  font-family: var(--font-accent); font-weight: 700; font-size: 10.5px;
  text-transform: uppercase; letter-spacing: var(--ls-wide); color: var(--gray-500);
  border-bottom: 1px solid var(--gray-200); text-align: left; padding: 9px 12px;
}
table.data td { border-bottom: 1px solid var(--gray-100); padding: 10px 12px; vertical-align: top; }
table.data tr:last-child td { border-bottom: none; }
table.data td.num, table.data th.num { text-align: right; }
table.data a.rowlink { font-weight: 600; }
.table-scroll { overflow-x: auto; }

/* ---------- Pills ---------- */
/* A bare `.pill` gets the neutral treatment rather than nothing: without a
   background it reads as stray uppercase text with mysterious padding, which
   is how `<span class="pill">directory admin</span>` rendered on the portal's
   own admin pages after they adopted this sheet. Same principle as the
   unclassed button/input/heading defaults below — a variant is a choice, not
   a requirement. `.neutral` stays as the explicit spelling. */
.pill {
  display: inline-block; padding: 3px 12px; border-radius: var(--radius-pill);
  font-family: var(--font-accent); font-weight: 700; font-size: 11px;
  text-transform: uppercase; letter-spacing: var(--ls-wide); white-space: nowrap;
  background: var(--gray-100); color: var(--gray-600);
}
.pill.ok { background: #E2F3E8; color: #1E7A44; }
.pill.warn { background: var(--mq-yellow-tint); color: #7A6400; }
.pill.bad { background: #FCE6E4; color: #C41208; }
.pill.neutral { background: var(--gray-100); color: var(--gray-600); }
.pill.info { background: #EEF3FB; color: var(--mq-blue); }

/* Directory/permission vocabulary. These lived in the portal-admin template's
   inline <style> until 2026-08-17, which is the gap AGENTS.md names: the
   stylesheet guard reads app.css only, so a shared selector inside a template
   sails past it. The line to hold is structural rather than a judgement call —
   **a selector that starts with `.pill` defines the component and belongs
   here; one where an ancestor qualifies it (`.permgrid .pill.danger`) is
   contextual placement and stays with that context.**

   `.perm` is a permission key, not a status word, so it opts out of the
   uppercase every other pill wants: twenty of `HR:CHANNEL_MAP.REFRESH` in a
   row is one block of texture, and the lowercase key shape is what a reader
   actually scans by. */
.pill.perm {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  text-transform: none; letter-spacing: 0; font-weight: 400; font-size: 11.5px;
  margin: 0 4px 4px 0;
}
.pill.perm.orphan { background: #FFF4E5; color: #8A5A00; }
.pill.danger { background: #FDECEA; color: #B3261E; }
.pill.lev-none { background: var(--gray-100); color: var(--gray-600); }
.pill.lev-view { background: #EEF3FB; color: var(--mq-blue); }
.pill.lev-edit { background: var(--mq-blue); color: #fff; }
/* The inline remove control a dismissible pill carries. */
.pill .x {
  background: none; border: 0; color: var(--text-muted); cursor: pointer;
  font-size: 13px; padding: 0 0 0 4px; line-height: 1;
}
.pill .x:hover { color: var(--mq-red); background: none; }

.chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px;
  border-radius: var(--radius-pill); font-size: 12px; font-weight: 600;
  border: 1px solid rgba(0,0,0,.06);
}

/* ---------- Buttons & forms ---------- */
.btn {
  display: inline-block; border-radius: var(--radius-md); padding: 8px 16px;
  font-size: 13px; font-weight: 600; border: 1px solid transparent;
  cursor: pointer; font-family: var(--font-body); line-height: 1.2;
  /* Stated, not inherited. The unclassed `button` default below paints blue
     on white text; `.btn` is (0,1,0) and beats it, but only for properties
     it actually declares — so without these two a variant-less
     `<button class="btn small">` would come out white-on-blue instead of
     the plain control it has always been. The variants override both. */
  background: transparent; color: var(--text-body);
}
.btn.primary { background: var(--mq-blue); color: #fff; }
.btn.primary:hover { background: var(--mq-blue-hover); text-decoration: none; }
.btn.outline { background: #fff; border-color: var(--gray-300); color: var(--text-body); }
.btn.outline:hover { border-color: var(--gray-400); text-decoration: none; }
.btn.small { padding: 5px 12px; font-size: 12px; }
.btn.danger { background: #fff; border-color: #F0B9B4; color: #C41208; }
/* ---------- Section nav: the screens inside a hub tab ----------

   The hub header holds TABS (Compliance, Win the Zip, …). The screens inside
   one tab are SECTION navigation, and they render as a row of pills: outline
   for the screens you could go to, filled red for the one you are on.

   This lives here because every module was copying it. Marketing had six tabs
   emitting `.sub-nav` markup whose CSS one of them had already deleted, so
   five of them rendered as bare underlined text until somebody noticed. A
   component two modules copy is a component the shared sheet should own.

   Usage — one include per app, not one per section:

     <div class="section-btns">
       <a class="btn" href="…">Top Metrics</a>
       <a class="btn btn-primary" href="…">Custom Reporting</a>   <-- current
     </div>

   `.btn-primary` here is deliberately NOT the same as `.btn.primary` above:
   that one is the blue primary action, this one is the red "you are here"
   marker, and conflating them would make every section nav look like a row
   of submit buttons. Modules carrying a local copy of these rules should
   delete it once this ships, rather than letting two versions drift. */
.section-btns { display: flex; gap: 8px; flex-wrap: wrap; margin: .25rem 0 1.75rem; }
.section-btns .btn {
  background: #fff; border: 1px solid var(--gray-300); border-radius: var(--radius-md);
  padding: 7px 13px; font: inherit; font-weight: 700; font-size: 12.5px;
  color: var(--text-body); text-decoration: none; cursor: pointer;
}
.section-btns .btn:hover { border-color: var(--mq-red); color: var(--mq-red);
                           background: #fff; text-decoration: none; }
.section-btns .btn-primary,
.section-btns .btn.btn-primary { background: var(--mq-red-press); border-color: var(--mq-red-press);
                                 color: #fff; }
.section-btns .btn-primary:hover { background: var(--mq-red-hover);
                                   border-color: var(--mq-red-hover); color: #fff; }

select, input[type=text], input[type=number], textarea {
  font-family: var(--font-body); font-size: 13px; padding: 7px 10px;
  border: 1px solid var(--gray-300); border-radius: var(--radius-md); background: #fff;
}

/* Sane defaults for UNCLASSED controls. The other modules have hundreds of
   bare <button> and untyped <input> elements, and requiring a class on each
   is the kind of migration cost that stops a shared stylesheet ever being
   adopted. These make a plain control look right; .btn.* stays available
   for variants.

   The selector is the bare element on purpose — specificity (0,0,1), so
   ANY class an app puts on a button beats it. The first version was
   `button:not(.btn):not(.x)`, which is (0,3,0): that is *more* specific
   than a one-class app rule, so it stopped being a default and started
   overriding the apps. Recruiting's `<button class="step-pill todo">`
   rendered as a blue primary button instead of a gray step pill (Codex
   P2), and the fix would have been to keep bolting `:not()`s on for every
   app class in the platform — a list that only grows and that every module
   has to know about. A default should lose every argument. This one now
   does, and `.x` needed no special case once it did. */
button {
  border-radius: var(--radius-md); padding: 8px 16px; font-size: 13px;
  font-weight: 600; border: 1px solid transparent; cursor: pointer;
  font-family: var(--font-body); line-height: 1.2;
  background: var(--mq-blue); color: #fff;
}
button:hover { background: var(--mq-blue-hover); }
button.ghost {
  background: #fff; border-color: var(--gray-300); color: var(--text-body);
}
button.ghost:hover { border-color: var(--mq-red); color: var(--mq-red); }
input:not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=button]) {
  font-family: var(--font-body); font-size: 13px; padding: 7px 10px;
  border: 1px solid var(--gray-300); border-radius: var(--radius-md); background: #fff;
}
textarea { width: 100%; min-height: 90px; }


/* ---------- Brand link + search preview ---------- */
a.brand-link { display: flex; align-items: center; gap: 16px; color: inherit; }
a.brand-link:hover { text-decoration: none; }
.search-box { position: relative; }


/* Narrow viewports. Not cosmetics — without this the header is a functional
   dead end on a phone: it is a fixed-height flex row whose children all set
   `flex: none`, so everything past the tabs is pushed outside the viewport,
   and because the page itself does not scroll horizontally there is no way
   to reach it. On the portal that means the user chip and Sign out are
   simply gone. Measured at 375px before this block: header content 160px
   tall inside a 68px box, `.header-right` starting past the right edge.

   Deliberately minimal — this is not a mobile redesign, and nothing above
   860px changes. Let the bar grow, give the tabs their own scrollable row,
   and drop the decorative eyebrow (the title carries the meaning).

   KEEP THIS BLOCK LAST. A media query carries no extra specificity, so
   `main.wrap { padding }` in here ties with the base `main.wrap` rule and
   is decided purely by source order. Sitting where it was first written —
   next to the header rules, above the Page section — the mobile gutters
   silently lost to the base padding at every width (Codex P2). Anything
   added below this block that restates a selector used here will break it
   the same way, with no error. */
@media (max-width: 860px) {
  header.site {
    height: auto; min-height: 60px; padding: 10px 16px; flex-wrap: wrap;
    row-gap: 8px;
  }
  header.site .q-mark { height: 30px; }
  .brand-block { padding-left: 12px; }
  .brand-block .eyebrow { display: none; }
  .brand-block .title { font-size: 16px; }
  nav.tabs {
    order: 3; width: 100%; margin-left: 0; height: auto; gap: 16px;
    overflow-x: auto; scrollbar-width: none;
  }
  nav.tabs::-webkit-scrollbar { display: none; }
  nav.tabs a { border-bottom-width: 2px; padding: 4px 0; }
  .header-right { gap: 10px; }
  main.wrap { padding: 18px 16px 40px; }
}
@media (max-width: 560px) {
  /* The initials still say who is signed in; the name is what overflows. */
  .user-chip .who { display: none; }
  .user-chip { padding: 4px; }
}
