/*
 * KB chrome (ticket 03 / decision 0003) — a reader-first help-center skin in
 * the APU family. Adopts the app design system: every color, surface, and
 * radius derives from the shared design tokens (--cd-*, tokens.css, loaded by
 * layouts/kb.hbs), so the KB follows the app's light/dark theme and matches
 * the public landing page instead of committing to a bespoke skin. Scoped
 * under `.kb-site` / `.kb-*` so it never leaks into the app shell.
 */

.kb-site {
  /* Brand accents — the app's design tokens, aliased for local readability. */
  --kb-maroon: var(--cd-brand);
  --kb-maroon-dark: var(--cd-brand-hover);
  /* Was `var(--apu-gold-accent)`, which is defined NOWHERE in main.css or
     tokens.css — every rule that used it silently dropped (the category
     drop-into indicator has been invisible since ticket 07). Real token. */
  --kb-gold: var(--cd-warning);
  /* Neutrals — the shared surface tier so the KB tracks light/dark. */
  --kb-ink: var(--cd-text);
  --kb-muted: var(--cd-text-muted);
  --kb-bg: var(--cd-surface-hover);
  --kb-surface: var(--cd-surface-raised);
  --kb-border: var(--cd-line);

  background-color: var(--cd-surface);
  color: var(--kb-ink);
  /* The app shell pins `body` to `height:100vh; overflow:hidden` so only inner
     panels scroll (main.css). The KB is a standalone document that scrolls
     normally, so override both here — otherwise any page taller than the
     viewport is clipped and can't scroll. Sticky-footer flex is kept. */
  height: auto;
  min-height: 100vh;
  overflow: visible;
  display: flex;
  flex-direction: column;
}

/* ---- Header ---- */

/* Solid maroon bar, matching the app + public navbar (`.navbar-apu`). Its
   contents are all white-on-brand, so they use `--cd-text-on-brand` — pinned
   #FFFFFF in BOTH themes (--cd-brand-fill stays deep in dark), unlike
   --cd-text / --cd-text-inverse which flip. White *alphas* stay as
   rgba(255,255,255,x) literals: there is no token tier for translucency.

   The inverted white pills below (the focused header search field, the Done
   button's hover state) take `--cd-surface-on-brand`, NOT the ink token. Same
   value, pinned for the same
   reason — but the role differs, and this comment used to argue the opposite:
   "a separate surface token would carry the same value in both modes, so there
   is nothing for it to diverge on". Divergence is not the test. An ink token
   appearing in a `background-color` is unreadable as intent — the next person
   cannot tell a deliberate inversion from a copy-paste slip. Those pills take
   --cd-brand-fill as their ink, so the pair is an exact inversion. */
.kb-header {
  background-color: var(--cd-brand-fill);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
  position: sticky;
  top: 0;
  z-index: 1020;
}

/* Full-bleed bar: brand hugs the left edge, Sign In the right. The three
   groups below (start / search / actions) are what centre the search box. */
.kb-header-inner {
  padding: 0.4rem 1.5rem;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}

/* `flex:1 1 0` on BOTH end groups is the centring trick: identical flex
   settings means they always resolve to the same width, so the search
   between them lands on the bar's true centre no matter how wide either
   side's contents are — or how far the search itself has grown. */
.kb-header-start {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

/* An EXPLICIT max-content floor on both end groups. Without it the `1 1 0`
   basis lets a group's box shrink below its own contents and the nav links
   (white-space:nowrap) spill out and render on top of the centred search —
   measured 377px of box holding 439px of nav at 1200px wide. `min-width:auto`
   is documented to do this and does not, so don't "simplify" it back.
   The search gives up width first (it can shrink to 200px, then wraps to its
   own row); when both sides fit inside their equal share it stays centred. */
.kb-header-start,
.kb-actions {
  min-width: max-content;
}

/* Brand lockup: mark + divider + name, on one line, hard left. */
.kb-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  flex: 0 0 auto;
  margin-right: 0.5rem;
}

.kb-brand .brand-logo {
  height: 26px;
  width: 26px;
}

.kb-brand-divider {
  width: 1px;
  height: 22px;
  background-color: rgba(255, 255, 255, 0.35);
}

.kb-brand-name {
  font-size: 1rem;
  font-weight: 700;
  color: var(--cd-text-on-brand);
  letter-spacing: 0.01em;
}

.kb-brand:hover .kb-brand-name {
  color: rgba(255, 255, 255, 0.85);
}

/* Admin eyebrow (CD-2200 ticket 1.2.5) — the only difference between this
   header and the reader's. `rgba(255,255,255,x)`, not a `--cd-kb-*` token:
   those aliases are the module's cooler NEUTRAL surface (bone/white/grey,
   ticket 1.2.1) and would read as near-invisible grey-on-grey against this
   header, which stays on the brand-maroon fill regardless of `manageTab`.
   White-alpha is already how this header spells "muted", and the endorsement
   for it is at the top of this file: there is no token tier for translucency.

   The alpha is 0.85 — `.kb-nav-link`'s, this header's actual TEXT idiom, not
   the 0.65 its search PLACEHOLDER uses. Measured over --cd-brand-fill it is
   ~6.4:1 light (#9D2E34) and ~4.7:1 dark (#B23A40); 0.65 gave ~4.0 and ~3.4,
   under AA for text this size in both themes. CD-2119 was the same brand-on-
   brand bug (invariants/ui-and-design.md).

   Type comes from the role tokens rather than three magic numbers: the token
   named `eyebrow` is what this component is. The `font:` shorthand carries
   weight/size/line-height/family and deliberately NOT transform or tracking,
   so those stay separate declarations. */
.kb-brand-eyebrow {
  font: var(--cd-type-eyebrow);
  text-transform: uppercase;
  letter-spacing: var(--cd-tracking-wide);
  color: rgba(255, 255, 255, 0.85);
  white-space: nowrap;
}

/* ---- Nav ---- */

.kb-nav {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

.kb-nav-link {
  color: rgba(255, 255, 255, 0.85);
  text-decoration: none;
  font-weight: 500;
  font-size: 0.875rem;
  padding: 0.5rem 0.9rem;
  border-radius: var(--cd-radius-sm);
  white-space: nowrap;
}

.kb-nav-link:hover,
.kb-nav-link:focus {
  color: var(--cd-text-on-brand);
  background-color: rgba(255, 255, 255, 0.12);
}

.kb-nav-link.active {
  color: var(--cd-text-on-brand);
  background-color: rgba(255, 255, 255, 0.18);
  box-shadow: none;
}

/* ---- Search ---- */

/* Grows into spare bar width up to 420px, shrinks when the end groups need
   the room (e.g. the staff edit toolbar). Growing doesn't cost the centring:
   .kb-header-start and .kb-actions share one flex setting, so they stay
   equal to each other however the leftover space is split. */
.kb-search {
  flex: 1 1 320px;
  max-width: 420px;
  /* Floor it rather than letting it collapse to a sliver — once the bar is
     too tight for 200px the whole field wraps to its own row instead. */
  min-width: 200px;
}

/* Trailing magnifier button, translucent like the field it closes. Extra
   right padding keeps the glyph off the pill's curve. */
.kb-search .kb-search-btn {
  background-color: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.28);
  color: rgba(255, 255, 255, 0.8);
  border-radius: 0 var(--cd-radius-pill) var(--cd-radius-pill) 0;
  padding: 0.15rem 0.8rem 0.15rem 0.55rem;
}

.kb-search .kb-search-btn:hover,
.kb-search .kb-search-btn:focus {
  background-color: rgba(255, 255, 255, 0.28);
  color: var(--cd-text-on-brand);
}

.kb-search .form-control {
  background-color: rgba(255, 255, 255, 0.14);
  border-color: rgba(255, 255, 255, 0.28);
  color: var(--cd-text-on-brand);
  border-radius: var(--cd-radius-pill) 0 0 var(--cd-radius-pill);
  padding-left: 0.9rem;
}

.kb-search .form-control::placeholder {
  color: rgba(255, 255, 255, 0.65);
}

/* The focused field goes solid --cd-text-on-brand (white) in BOTH themes, so
   its ink comes from the PRIMITIVE tier (--cd-slate / --cd-warm-600, which
   never flip) rather than --cd-text / --cd-text-muted, which lighten in dark
   mode and would leave this near-invisible on the white fill. */
.kb-search .form-control:focus {
  background-color: var(--cd-surface-on-brand);
  border-color: var(--cd-surface-on-brand);
  color: var(--cd-slate);
  box-shadow: 0 0 0 0.15rem rgba(255, 255, 255, 0.25);
}

.kb-search .form-control:focus::placeholder {
  color: var(--cd-warm-600);
}

/* ---- Actions (role-specific) ---- */

.kb-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.6rem;
  flex: 1 1 0;
}

/* Two classes, one treatment: .kb-return-link is staff's way back to
   /dashboard, .kb-home-link is a signed-in end user's way back to /tickets/my.
   Same affordance, so they must look identical — but they stay separate class
   names because impersonation.spec.js asserts .kb-return-link is ABSENT for an
   impersonated end user, to prove the header is not silently the admin's.
   Sharing the rule keeps them visually one thing without collapsing that
   discriminator. */
.kb-return-link,
.kb-home-link {
  color: rgba(255, 255, 255, 0.8);
  text-decoration: none;
  font-size: 0.9rem;
  white-space: nowrap;
}

.kb-return-link:hover,
.kb-return-link:focus,
.kb-home-link:hover,
.kb-home-link:focus {
  color: var(--cd-text-on-brand);
}

/* Done (CD-2312): same white-on-maroon treatment as the other header
   controls now that the header is a solid brand bar. */
.kb-header .btn-outline-secondary {
  border-color: rgba(255, 255, 255, 0.55);
  color: var(--cd-text-on-brand);
}

.kb-header .btn-outline-secondary:hover,
.kb-header .btn-outline-secondary:focus {
  background-color: var(--cd-surface-on-brand);
  border-color: var(--cd-surface-on-brand);
  color: var(--cd-brand-fill);
}

/* Site switcher (hidden until the viewer can read ≥2 Sites). `flex: 0 0 auto`
   is load-bearing: the trigger is a fixed label, so the control is the same
   width at any Site count. An inline list per Site would grow the header's
   start group without bound, which is the horizontal scroll the 640px block
   below exists to prevent. */
.kb-site-switcher {
  flex: 0 0 auto;
}

/* White pill on the maroon bar — the same treatment as .kb-submit-btn and the
   other header controls, not Bootstrap's default btn chrome. The hover rule is
   NOT redundant with the base one: bare `.btn` never sets `--bs-btn-hover-bg`,
   and `.btn:hover` outranks a single class, so without an override the pill
   goes transparent on hover. Values match the siblings so it does not become
   the one control that gives no hover feedback. */
.kb-site-switcher-btn {
  background-color: var(--cd-surface-on-brand);
  border-color: var(--cd-surface-on-brand);
  color: var(--cd-brand-fill);
  font-weight: 600;
  white-space: nowrap;
}

.kb-site-switcher-btn:hover,
.kb-site-switcher-btn:focus {
  background-color: rgba(255, 255, 255, 0.88);
  border-color: rgba(255, 255, 255, 0.88);
  color: var(--cd-brand-fill-hover);
}

/* Keeps non-current entries' labels aligned with the checked one's, without
   giving every row an icon. Matches the check glyph's width + its me-1. */
.kb-site-switcher-gutter {
  display: inline-block;
  width: 1.25em;
}

/* ---- Admin shell (CD-2200 ticket 1.2.2) ---- */

/* The module's own two-column region, rendered by layouts/kb.hbs only when
   `manageTab` is set — reader pages take the plain body arm and never see any
   of this. Its NEUTRALS come from the `--cd-kb-*` alias layer (ticket 1.2.1)
   rather than the `--kb-*` reader aliases above: the two are scoped to
   different parts of this same page and are not meant to track each other.
   The one exception is the current-entry accent, which is the shared brand
   pair — see the nav-link rules below for why. */
.kb-manage-shell {
  display: flex;
  align-items: flex-start;
  gap: 1.5rem;
}

.kb-manage-sidebar {
  flex: 0 0 200px;
  background-color: var(--cd-kb-surface-raised);
  border: 1px solid var(--cd-kb-line);
  /* A panel, so `md` — the radius scale is assigned by ROLE, and `sm` is
     inputs/chips/small controls (invariants/ui-and-design.md). The nav links
     inside it are small controls and do take `sm`. */
  border-radius: var(--cd-radius-md);
  padding: 1rem 0.75rem;
}

.kb-manage-content {
  flex: 1 1 auto;
  min-width: 0;
}

.kb-manage-nav-group + .kb-manage-nav-group {
  margin-top: 1.25rem;
}

.kb-manage-nav-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.kb-manage-nav-heading {
  display: block;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--cd-kb-text-muted);
  padding: 0 0.5rem 0.375rem;
}

/* Muted default, full ink on hover, soft-brand tint when current — the app's
   own side-nav idiom (`#sidebar .nav-link` in tokens.css), so the module's
   navigation behaves like the navigation staff already know. The accent comes
   from the shared brand tokens rather than a `--cd-kb-*` alias: the alias
   layer scopes this surface's NEUTRALS (the design's cooler greys over the
   app's warm ramp), and 1.1 established that the design's brick IS the app's
   brand ramp, so there is nothing here for an alias to diverge on. */
.kb-manage-nav-link {
  display: block;
  color: var(--cd-kb-text-muted);
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 500;
  padding: 0.5rem;
  border-radius: var(--cd-radius-sm);
}

.kb-manage-nav-link:hover,
.kb-manage-nav-link:focus {
  background-color: var(--cd-kb-surface);
  color: var(--cd-kb-text);
}

.kb-manage-nav-link.active {
  background-color: var(--cd-brand-soft);
  color: var(--cd-brand);
}

/* Homepage (CD-2312) is a <button> in a <form>, not an <a> — flipping edit
   mode needs a POST — so it needs the browser chrome stripped off before
   `.kb-manage-nav-link` above can make it look like its siblings. */
.kb-manage-nav-form {
  margin: 0;
}

.kb-manage-nav-button {
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  font: inherit;
  cursor: pointer;
}

/* The section count (ticket 1.2.4) — muted so the entry's name stays the
   thing a screen-scan lands on, present only when the current page actually
   loaded that count (kb-manage-sidebar.hbs, `isNum`). */
.kb-manage-nav-count {
  color: var(--cd-kb-text-muted);
  font-weight: 400;
}

/* The managing-Site card (ticket 1.2.3) — below the nav groups, in the same
   `--cd-kb-*` neutral tier as the rest of this rail. A real panel, as the
   spec and the canvas both call it: this is the one place a maintainer checks
   before filing content, and a bordered-off run of small text at the foot of
   the rail reads as a caption rather than as the thing it is. It grounds on
   `--cd-kb-surface` against the rail's own `-raised`, so it reads as inset
   rather than as a second card stacked on the first. */
.kb-manage-site-card {
  margin-top: 1.25rem;
  padding: 0.75rem;
  background-color: var(--cd-kb-surface);
  border: 1px solid var(--cd-kb-line);
  border-radius: var(--cd-radius-md);
}

/* The Site's own name is the card's headline — story 4 asks for it
   PROMINENTLY, and it replaced a line that used to sit at the top of the main
   column, so it carries more weight than the nav entries beside it rather
   than less. */
.kb-manage-site-name {
  margin: 0 0 0.25rem;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--cd-kb-text);
}

.kb-manage-site-dept,
.kb-manage-site-admin-note {
  margin: 0;
  font-size: 0.8rem;
  color: var(--cd-kb-text-muted);
}

.kb-manage-site-admin-note {
  margin-top: 0.25rem;
}

/* The create entrance (CD-2264 ticket 11). Sits under the admin note in the
   managing-Site card, which is the only surface that renders for an admin no
   matter how many Sites exist. */
.kb-manage-site-new {
  display: inline-block;
  margin-top: 0.5rem;
  font-size: 0.85rem;
}

/* ---- Main + footer ---- */

.kb-main {
  flex: 1 0 auto;
  /* The hero breaks out of the container with `calc(-50vw + 50%)` margins;
     100vw counts the scrollbar, so clip the overshoot here rather than on
     `.kb-site` — an overflow on the body's scroll container would break the
     sticky header. */
  overflow-x: hidden;
}

.kb-main .container {
  max-width: 1000px;
}

/* Manage + the full-page editor (CD-2313) — both set `manageTab`, which is
   what `.kb-manage-container` gates on in layouts/kb.hbs. Reading width
   (1000px above) is right for prose; it starves the articles table and the
   editor's body field, which want the room a management screen can spare.
   Two classes beats the plain `.kb-main .container` above on specificity, so
   order here does not matter. */
.kb-main .container.kb-manage-container {
  max-width: 1600px;
}

/* ---- Hero block ---- */

/* The paint (gradient, white type, pill search field + button) is SHARED with
   the public landing hero — `.landing-hero, .kb-hero` in main.css — so /kb and
   / can't drift. Only the KB's own layout lives here: the container breakout
   and its padding. */
.kb-hero {
  padding: 4rem 1rem 5rem;
  margin-left: calc(-50vw + 50%);
  margin-right: calc(-50vw + 50%);
}

/* Flush against the header when the hero leads the page (the container's
   own py-4 would otherwise leave a band of page background above it).
   Reader mode puts the hero directly under #kbHomepageBlocks; edit mode
   wraps every block in a .kb-block-edit-row, hence the second selector. */
#kbHomepageBlocks > .kb-hero:first-child,
#kbHomepageBlocks > .kb-block-edit-row:first-child > .kb-hero {
  margin-top: -1.5rem;
}

.kb-hero-inner {
  max-width: 1000px;
  margin: 0 auto;
}

/* "Popular" quick-search chips under the hero search box (CD-922). White-alpha
   treatment to match the maroon-gradient hero paint (main.css .kb-hero), same
   pattern as .kb-nav-link / .kb-search above. */
.kb-hero-popular {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
}

.kb-hero-popular-label {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.7);
}

.kb-chip {
  display: inline-block;
  padding: 0.4rem 1rem;
  border-radius: var(--cd-radius-pill);
  background-color: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.28);
  color: var(--cd-text-on-brand);
  font-size: 0.88rem;
  font-weight: 600;
  text-decoration: none;
  transition: background-color 0.12s ease, border-color 0.12s ease;
}

.kb-chip:hover,
.kb-chip:focus {
  background-color: rgba(255, 255, 255, 0.24);
  border-color: rgba(255, 255, 255, 0.4);
  color: var(--cd-text-on-brand);
}

/* ---- Input groups on KB pages ---- */

/* Bootstrap rounds an input-group's outer corners with its own 6px radius,
   but the app's single pill idiom (tokens.css `.btn`) makes a trailing button
   999px — so the search block rendered square-left / pill-right. Round both
   ends of the group so they match whatever sits at each edge (addon, input,
   or button). Scoped to `.kb-main`: the header's own search group is small
   and already symmetric. */
.kb-main .input-group > :first-child {
  border-top-left-radius: var(--cd-radius-pill);
  border-bottom-left-radius: var(--cd-radius-pill);
}

.kb-main .input-group > :last-child {
  border-top-right-radius: var(--cd-radius-pill);
  border-bottom-right-radius: var(--cd-radius-pill);
}

/* Keep a leading icon off the curve. */
.kb-main .input-group > .input-group-text:first-child {
  padding-left: 0.9rem;
}

/* The header is sticky, so the Browse/Recent anchor jumps have to clear it —
   otherwise the heading they target lands underneath the bar. */
#kb-browse,
#kb-recent {
  scroll-margin-top: 5rem;
}

/* ---- Category / quick-link cards ---- */

/* `.kb-action-card` itself is styled in main.css alongside
   `.landing-action-card` (one white-card definition for both surfaces); the
   hover lift's reduced-motion guard lives there too. */

/* Category-grid section meta (count summary, CD-922) — plain muted text, no
   bespoke class needed beyond layout. */
.kb-section-meta {
  color: var(--kb-muted);
  font-size: 0.9rem;
  white-space: nowrap;
}

/* The dark bar the rest of the app ends on. Its colours are the grouped
   `.app-footer, .kb-footer` rule in main.css — one definition for both — so
   only the KB's own spacing lives here. */
.kb-footer {
  padding: 1.1rem 1.25rem;
  font-size: 0.85rem;
}

@media (max-width: 640px) {
  .kb-header-inner {
    gap: 0.5rem;
    padding-left: 0.85rem;
    padding-right: 0.85rem;
  }
  /* Brand + nav can't hold one line at phone widths — let the group take the
     full row and wrap inside it, or the nav pushes the bar into a horizontal
     scroll. */
  .kb-header-start {
    flex: 1 1 100%;
    flex-wrap: wrap;
    gap: 0.4rem;
  }
  /* The max-content floor above would pin each group to one line and defeat
     the wrapping this narrow layout depends on. */
  .kb-header-start,
  .kb-actions {
    min-width: 0;
  }
  .kb-nav {
    flex-wrap: wrap;
  }
  .kb-nav-link {
    padding: 0.35rem 0.6rem;
  }
  /* The search field wraps onto its own row, but stays ABOVE Submit a Ticket
     / Sign In so the requested left-to-right order (search → submit → sign
     in) still reads top-to-bottom. `.kb-nav` keeps the default order:0 and
     `.kb-actions` is pushed last. */
  .kb-search {
    order: 1;
    flex: 1 1 100%;
    max-width: none;
  }
  .kb-actions {
    order: 2;
    flex: 1 1 100%;
    justify-content: flex-end;
  }
  .kb-hero {
    padding: 2.5rem 1rem 3rem;
  }
  /* The admin shell stacks rather than keeping a 200px rail beside the
     content. The tab strip it replaced wrapped for free; a fixed-basis flex
     child does not, and the column it squeezes holds the article table and
     the category tree. Sidebar first, so the module's navigation stays the
     thing you reach before the screen it navigates. */
  .kb-manage-shell {
    flex-wrap: wrap;
    gap: 1rem;
  }
  .kb-manage-sidebar,
  .kb-manage-content {
    flex: 1 1 100%;
  }
}

/* ---- Category drag-drop tree (ticket 07) ---- */

.kb-cat-tree,
.kb-cat-children {
  list-style: none;
  margin: 0;
  padding: 0;
}

.kb-cat-children {
  padding-left: 1.5rem;
  border-left: 1px dashed var(--kb-border);
  margin-left: 0.6rem;
}

.kb-cat-node {
  margin: 0.15rem 0;
}

.kb-cat-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.5rem;
  border-radius: var(--radius);
  transition: background-color 0.1s ease, box-shadow 0.1s ease;
}

.kb-cat-row:hover {
  background-color: var(--kb-bg);
}

.kb-cat-handle {
  cursor: grab;
  color: var(--kb-muted);
  opacity: 0.5;
  line-height: 1;
}

.kb-cat-row:hover .kb-cat-handle {
  opacity: 1;
}

.kb-cat-name {
  cursor: text;
}

.kb-cat-name-input {
  max-width: 260px;
}

.kb-cat-hidden-badge {
  font-weight: 400;
}

.kb-cat-actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.1rem;
  white-space: nowrap;
}

.kb-cat-empty {
  list-style: none;
}

/* Drag state + drop-zone indicators (kbCategoryTree.js). Class-based, like
   CdDragReorder — no marker elements are inserted into the flow. */
.kb-cat-row.kb-cat-dragging {
  opacity: 0.4;
}

.kb-cat-row.kb-cat-drop-before {
  box-shadow: inset 0 2px 0 0 var(--kb-maroon);
}

.kb-cat-row.kb-cat-drop-after {
  box-shadow: inset 0 -2px 0 0 var(--kb-maroon);
}

.kb-cat-row.kb-cat-drop-into {
  background-color: var(--kb-bg);
  box-shadow: inset 0 0 0 2px var(--kb-gold);
}

/* ---- Homepage block editing (ticket 08) ---- */

/* Each block on /kb gets a hover-revealed outline + toolbar in edit mode.
   .cd-reorder-row (main.css) supplies the drag-handle + drop-indicator
   styles; this file only adds the card look and the toolbar's position. */
.kb-block-edit-row {
  border: 1px dashed transparent;
  border-radius: var(--radius);
  padding: 0.5rem 0.5rem 0.5rem 2.25rem;
  transition: border-color 0.12s ease, background-color 0.12s ease;
}

.kb-block-edit-row:hover,
.kb-block-edit-row:focus-within {
  border-color: var(--kb-border);
  background-color: var(--kb-surface);
}

.kb-block-edit-row .cd-drag-handle {
  position: absolute;
  top: 0.6rem;
  left: 0.5rem;
  z-index: 2;
}

.kb-block-edit-toolbar {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  z-index: 2;
  display: flex;
  gap: 0.25rem;
  opacity: 0;
  transition: opacity 0.12s ease;
}

.kb-block-edit-row:hover .kb-block-edit-toolbar,
.kb-block-edit-row:focus-within .kb-block-edit-toolbar {
  opacity: 1;
}

.kb-block-article-picker {
  background-color: var(--kb-surface);
}

/* ── Manage table badges (ticket 1.3) ──────────────────────────────────
   The audience ladder is ONE colour system, not Bootstrap's semantic classes
   for the two widest rungs and tokens for the two narrowest. Public and
   Internal keep the hues they already shipped with — --cd-success and
   --cd-warning are within a shade of Bootstrap's `bg-success`/`bg-warning`,
   and neither flips in dark mode, so this is a token swap and not a
   recolouring. Story 35 wants every colour here to resolve to a token so a
   brand change reaches the module; a Bootstrap utility never would.

   Published (CD-2310) shares this rule rather than repeating the pair: it is
   the Status column's own "this is live" state, same meaning as Public on
   the Audience column, so one selector list keeps both in lockstep instead
   of three copies of --cd-success/--cd-success-on across the file. */
.kb-audience-badge--public,
.kb-status-badge--published {
  background-color: var(--cd-success);
  color: var(--cd-success-on);
}

.kb-audience-badge--internal {
  background-color: var(--cd-warning);
  color: var(--cd-warning-on);
}

/* Staff internal and Site internal: differentiated by their own text, not by
   a fourth and fifth badge colour — a neutral outline reads as "narrower",
   which is what both of them are, without inventing two more hues nothing
   else on the ladder uses. */
.kb-audience-badge--narrow {
  background-color: transparent;
  color: var(--cd-kb-text-muted);
  border: 1px solid var(--cd-kb-line);
  font-weight: 500;
}

/* First consumer of --cd-kb-badge/-badge-ink (ticket 1.2.1 reserved the pair;
   nothing drew from it until this ticket). Draft is the one state on this
   table that is not a reach question at all — "unfinished", not "who sees
   it" — so it gets a colour neither audience badge uses. */
.kb-status-badge--draft {
  background-color: var(--cd-kb-badge);
  color: var(--cd-kb-badge-ink);
}

/* ---- Category structure screen (ticket 1.4) ---- */

/* Two columns: the tree card on the left, the detail pane on the right —
   stacks at the same width the admin shell itself already stacks at, so
   nothing here fights that rule for space. */
.kb-cat-screen {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
}

.kb-cat-screen-tree {
  flex: 1 1 60%;
  min-width: 0;
}

.kb-cat-screen-detail {
  flex: 1 1 320px;
  max-width: 380px;
}

@media (max-width: 900px) {
  .kb-cat-screen {
    flex-wrap: wrap;
  }

  .kb-cat-screen-tree,
  .kb-cat-screen-detail {
    flex: 1 1 100%;
    max-width: none;
  }
}

/* The row currently open in the detail pane. Deliberately NOT `--kb-bg`: that
   is exactly `.kb-cat-row:hover` above, so a selected row was indistinguishable
   from whichever row the pointer happened to be over, and the 1px neutral
   hairline it carried was not enough to tell them apart. A brand-tinted ground
   plus a brand bar down the leading edge is a state the row cannot enter by
   being hovered — and it stays clear of the drop-zone gold, which means
   something else entirely. `aria-pressed` on the row's own control is what
   announces it (partials/kb-category-node.hbs); this is only the paint. */
.kb-cat-row.kb-cat-selected {
  background-color: var(--cd-brand-soft);
  box-shadow: inset 3px 0 0 0 var(--cd-brand);
}

/* ---- Access screen: the inherited-admins banner (CD-2199 4.2.2) ---- */

/* The inverse-surface pair is dark in BOTH themes (tokens.css), so this band
   needs no dark-mode branch of its own — the same reason the footer and the
   navbar ground on it. `md` radius: this is a panel, per the spec's "radius
   by role" rule, not a chip or a control. Sits ABOVE the member card so an
   admin reads the rule before an empty table. */
.kb-inherited-admins-banner {
  margin-bottom: 1rem;
  padding: 0.9rem 1rem;
  background-color: var(--cd-surface-inverse);
  color: var(--cd-text-on-inverse);
  border-radius: var(--cd-radius-md);
}

/* Gold INK on the inverse ground — the opposite composition from
   `.kb-status-badge--draft`, which is gold FILL with slate ink. That
   difference is what keeps this from reading as a second Draft badge, and
   it is the only gold on this screen (spec, "Implementation Decisions"). */
.kb-inherited-admins-eyebrow {
  display: block;
  margin-bottom: 0.25rem;
  font: var(--cd-type-eyebrow);
  text-transform: uppercase;
  letter-spacing: var(--cd-tracking-wide);
  color: var(--cd-gold);
}

.kb-inherited-admins-banner p {
  margin: 0;
  font-size: var(--cd-text-base);
  color: var(--cd-text-on-inverse);
}

/* ---- Full-page article editor: metadata beside the body (CD-2201 3.2) ---- */

/* The shared field partial (`kb-article-editor-fields.hbs`) renders one flat,
   undecorated field order; this class is the ONLY thing that reassigns where
   each one sits, via named grid areas — the panel (`kb/edit-panel.hbs`) never
   carries it, so the identical include just stacks in document order inside
   the modal there. Neither consumer needs a second copy of the markup to get
   its own layout. Narrow first: a single column in source order reads better
   than a cramped two-up on a phone-width management sidebar. */
.kb-editor-grid {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-areas:
    "title"
    "excerpt"
    "category"
    "audience"
    "status"
    "placements"
    "body"
    "tags"
    "actions";
  gap: 1.25rem;
}

@media (min-width: 900px) {
  .kb-editor-grid {
    grid-template-columns: minmax(0, 1fr) 320px;
    grid-template-areas:
      "title      title"
      "body       excerpt"
      "body       category"
      "body       audience"
      "body       status"
      "body       placements"
      "tags       tags"
      "actions    actions";
  }
}

/* The fields carry Bootstrap's `mb-3` so they space themselves in the PANEL,
   which stacks them in plain document flow. Inside the grid that margin is a
   second spacing system fighting `gap`, and on a grid item it also pushes the
   row below — so the grid takes it back and owns the rhythm alone. */
/* `[data-kb-placements]` is named alongside the fields because the placement
   picker is a shared partial that carries its own `mb-3` and no
   `.kb-editor-field` class — without it, that one row keeps a margin while
   every sibling has had it taken back. */
.kb-editor-grid .kb-editor-field,
.kb-editor-grid [data-kb-placements] { margin-bottom: 0; }

.kb-editor-grid .kb-editor-field--title { grid-area: title; }
.kb-editor-grid .kb-editor-field--excerpt { grid-area: excerpt; }
.kb-editor-grid .kb-editor-field--category { grid-area: category; }
.kb-editor-grid .kb-editor-field--audience { grid-area: audience; }
.kb-editor-grid .kb-editor-field--status { grid-area: status; }
/* The placement picker partial owns its own root element (`kb-placement-
   picker.hbs`), so this targets its presence marker rather than a class this
   stylesheet would have to add to a partial the focused panel renders too —
   where there is no grid to assign an area in. */
.kb-editor-grid [data-kb-placements] { grid-area: placements; }
.kb-editor-grid .kb-editor-field--body { grid-area: body; }
.kb-editor-grid .kb-editor-field--tags { grid-area: tags; }
.kb-editor-grid .kb-editor-actions { grid-area: actions; }

.kb-editor-back {
  display: inline-flex;
  align-items: center;
  font-size: var(--cd-text-sm);
  color: var(--kb-muted);
}

/* ---- Autosave status and the conflict banner (CD-2201 3.3) ---- */

/* Sits above the editor grid rather than inside it: the grid's areas are the
   article's own fields, and a status line is not one of them. Keeping it out
   also means the two-up layout at 900px needs no new area. */
.kb-draft-bar {
  display: flex;
  align-items: center;
  gap: .75rem;
  min-height: 1.75rem;
  margin-bottom: .75rem;
}

.kb-draft-status {
  font-size: var(--cd-text-sm);
  color: var(--kb-muted);
}

/* `Not saved` is the one state that must not read as ambient chrome — it is
   the author's cue to copy their text somewhere, and it does not fade. */
.kb-draft-status--failed {
  color: var(--cd-danger-fg);
  font-weight: 600;
}

.kb-draft-status--saved { color: var(--cd-success-fg); }

.kb-draft-discard {
  padding: 0;
  font-size: var(--cd-text-sm);
  color: var(--kb-muted);
}

.kb-draft-conflict__list {
  margin: 0 0 .75rem;
  padding-left: 1.25rem;
}

/* Both values, side by side at width and stacked when narrow — story 19 asks
   to be told WHAT changed, which one value cannot answer. */
.kb-draft-conflict__pair {
  display: flex;
  flex-wrap: wrap;
  gap: .25rem 1rem;
  font-size: var(--cd-text-sm);
}
