/* VENDORED AT DEPLOY TIME from theme/src/kit/css/hj-ui.css. Do not edit here —
   change it in the theme kit so the whole estate gains it. */
/* hj-ui.css — the shared hellojade component layer.
 *
 * STANDING RULE: every product in the jadeworks VPC builds its UI from THIS
 * file plus brand/tokens.css. Product-specific styling belongs here too, not in
 * the product — so the next service inherits it instead of reinventing it, and
 * the whole estate moves together when the brand does.
 *
 * Served by jadethemed at https://theme.hellojade.ai/css/hj-ui.css and vendored
 * into each product at deploy time (same as tokens.css) so a page still renders
 * if the theme host is down.
 *
 * LAYERING — do not skip a step:
 *   brand/tokens.json   the source of truth, generated by tools/hjkit
 *   brand/tokens.css    :root custom properties, GENERATED — never hand-edit
 *   css/hj-ui.css       this file: components built ONLY from those tokens
 *   product css         layout unique to one app (a map pane, a canvas)
 *
 * ⚠️ NO RAW HEX IN THIS FILE. Every colour must be a var(--hj-*) or a
 * color-mix() of them. If a value you need does not exist, add it to
 * brand/tokens.json and regenerate — that is how the kit grows.
 *
 * First extracted 2026-07-27 from campaign.hellojade.ai, which had ~370 lines of
 * component CSS inline. Anything below that reads as app-specific is a bug in
 * this file, not a reason to fork it.
 */

/* ---- derived surface tokens -----------------------------------------------
 * tokens.css gives raw brand values. These are the two or three mixes every
 * dark surface needs, defined once so products stop re-deriving them slightly
 * differently. */
:root{
  --hj-line:       color-mix(in srgb, var(--hj-semantic-brand-primary) 34%, transparent);
  --hj-line-soft:  color-mix(in srgb, var(--hj-semantic-brand-primary) 18%, transparent);
  --hj-muted:      color-mix(in srgb, var(--hj-semantic-text-primary) 62%, transparent);
  --hj-overlay-bg: color-mix(in srgb, var(--hj-semantic-bg-surface) 92%, transparent);
  /* raised surface (a card ON a panel) and an off/disabled fill. Every canvas app
   * (crm, jadeops) re-derived these slightly differently — defined once here so a
   * kit change moves them together. */
  /* weights sum to 100% so the result is fully opaque — a raised surface must
   * not let the page bleed through (color-mix treats a <100% sum as alpha). */
  --hj-surface-2:  color-mix(in srgb, var(--hj-semantic-bg-surface) 93%, var(--hj-primitive-jade-bright) 7%);
  --hj-state-off:  color-mix(in srgb, var(--hj-semantic-text-primary) 15%, transparent);
}

/* ---- light theme (opt-in) ------------------------------------------------
 * The brand is dark-first; light mode is a FUNCTIONAL accommodation that
 * connect and cal each re-derived on their own. Rather than a `--role-*` rename
 * of every component rule, the kit re-POINTS the ~dozen semantic + derived
 * tokens the components read — because they are CSS custom properties, one
 * override block flips the whole component layer with no rule rewrites.
 *
 * It is OPT-IN: light applies ONLY under `:root[data-kind="light"]` (the
 * convention connect already stamps on <html>), so a dark-only app that sets
 * nothing is UNAFFECTED — dark stays the default. No `prefers-color-scheme`
 * auto-switch, which would silently flip apps that never opted in.
 *
 * Values are color-mix of the SAME brand tokens (jade-deep for text/lines,
 * jade for accents that must stay legible on a light ground) over a neutral
 * white anchor, so the light theme is on-brand: pale-jade paper, deep-jade ink.
 * `white` here is the one neutral anchor a light theme needs and the brand has
 * no token for — it is not a forked brand colour. */
:root[data-kind="light"]{
  --hj-semantic-bg-page:      color-mix(in srgb, white 92%, var(--hj-primitive-jade) 8%);
  --hj-semantic-bg-surface:   color-mix(in srgb, white 97%, var(--hj-primitive-jade) 3%);
  --hj-semantic-text-primary: var(--hj-primitive-ground-deepest);
  --hj-semantic-link:         var(--hj-primitive-jade-deep);
  --hj-semantic-brand-accent: var(--hj-primitive-jade);
  --hj-semantic-brand-bright: var(--hj-primitive-jade);
  /* the wordmark must stay legible on the pale ground — near-white "hello"
   * would vanish (≈1.06:1), so darken both halves like the other accents. */
  --hj-semantic-wordmark-hello: var(--hj-primitive-ground-deepest);
  --hj-semantic-wordmark-jade:  var(--hj-primitive-jade-deep);
  --hj-line:       color-mix(in srgb, var(--hj-primitive-jade-deep) 26%, transparent);
  --hj-line-soft:  color-mix(in srgb, var(--hj-primitive-jade-deep) 14%, transparent);
  --hj-muted:      color-mix(in srgb, var(--hj-primitive-ground-deepest) 66%, transparent);
  --hj-overlay-bg: color-mix(in srgb, white 90%, transparent);
  --hj-surface-2:  white;
  --hj-state-off:  color-mix(in srgb, var(--hj-primitive-ground-deepest) 12%, transparent);
}

/* ---- base ---------------------------------------------------------------- */
*{ box-sizing:border-box }
html,body{ height:100% }
html{ -webkit-text-size-adjust:100% }
body{
  margin:0;
  background:var(--hj-semantic-bg-page);
  color:var(--hj-semantic-text-primary);
  font-family:var(--hj-font-family-sans);
  font-size:var(--hj-font-size-small);
  line-height:var(--hj-font-leading-body);
}

/* ---- wordmark ------------------------------------------------------------ */
.hj-brand{ display:flex; align-items:baseline; gap:var(--hj-space-2); margin:0 0 var(--hj-space-1) }
.hj-wordmark{
  font-size:var(--hj-font-size-h3);
  font-weight:var(--hj-font-weight-heavy);
  letter-spacing:-.02em;
  line-height:var(--hj-font-leading-tight);
}
.hj-wordmark .hello{ color:var(--hj-semantic-wordmark-hello) }
.hj-wordmark .jade { color:var(--hj-semantic-wordmark-jade) }

/* ---- typography ---------------------------------------------------------- */
.hj-title{
  font-size:var(--hj-font-size-h3);
  font-weight:var(--hj-font-weight-medium);
  margin:0 0 var(--hj-space-1);
  letter-spacing:-.01em;
  line-height:var(--hj-font-leading-tight);
}
.hj-sub{ color:var(--hj-muted); font-size:var(--hj-font-size-caption); margin:0 0 var(--hj-space-6) }
.hj-hint{ color:var(--hj-muted); font-size:var(--hj-font-size-caption); margin-top:var(--hj-space-4) }
.hj-mono{ font-family:var(--hj-font-family-mono) }

/* ---- status dot ---------------------------------------------------------- */
.hj-dot{
  display:inline-block; width:7px; height:7px; border-radius:var(--hj-radius-pill);
  background:var(--hj-semantic-brand-accent); vertical-align:middle; margin-right:6px;
  animation:hj-pulse var(--hj-duration-glow-period) var(--hj-easing-ease-out-cubic) infinite;
}
.hj-dot.is-down{ background:var(--hj-motion-glitch-red); animation:none }
@keyframes hj-pulse{
  0%  { box-shadow:0 0 0 0 color-mix(in srgb, var(--hj-semantic-brand-accent) 65%, transparent) }
  70% { box-shadow:0 0 0 7px transparent }
  100%{ box-shadow:0 0 0 0 transparent }
}
@media (prefers-reduced-motion:reduce){ .hj-dot{ animation:none } }

/* ---- controls ------------------------------------------------------------ */
.hj-label{
  display:block; font-size:11px; text-transform:uppercase; letter-spacing:.08em;
  font-weight:var(--hj-font-weight-medium); color:var(--hj-muted);
  margin:var(--hj-space-4) 0 var(--hj-space-1);
}
.hj-label .opt{ text-transform:none; letter-spacing:0; opacity:.7; font-weight:var(--hj-font-weight-regular) }

.hj-field{
  width:100%; max-width:100%; padding:9px var(--hj-space-3);
  background:var(--hj-semantic-bg-page); color:var(--hj-semantic-text-primary);
  border:1px solid var(--hj-line); border-radius:var(--hj-radius-sm);
  font-family:inherit; font-size:var(--hj-font-size-small);
}
.hj-field:focus-visible, .hj-focusable:focus-visible{
  outline:2px solid var(--hj-semantic-brand-accent); outline-offset:2px;
}

.hj-btn{
  width:100%; max-width:100%; padding:9px var(--hj-space-3);
  margin-top:var(--hj-space-4);
  background:var(--hj-semantic-brand-primary); border:1px solid var(--hj-semantic-brand-primary);
  color:var(--hj-primitive-ink); border-radius:var(--hj-radius-sm);
  font-family:inherit; font-size:var(--hj-font-size-small);
  font-weight:var(--hj-font-weight-medium); cursor:pointer;
  transition:background var(--hj-duration-cut-in) var(--hj-easing-ease-out-cubic);
}
.hj-btn:hover:not(:disabled){
  background:var(--hj-semantic-brand-bright); border-color:var(--hj-semantic-brand-bright);
}
.hj-btn:disabled{ opacity:.45; cursor:default }
.hj-btn--ghost{
  width:auto; margin:0; padding:3px 9px;
  background:transparent; border-color:var(--hj-line);
  color:var(--hj-semantic-link); border-radius:var(--hj-radius-pill);
  font-size:var(--hj-font-size-caption); font-weight:var(--hj-font-weight-regular);
}
.hj-btn--ghost:hover{
  background:var(--hj-semantic-bg-page); border-color:var(--hj-semantic-brand-accent);
}

/* ---- surfaces ------------------------------------------------------------ */
.hj-rail{
  background:var(--hj-semantic-bg-surface);
  border-right:1px solid var(--hj-line-soft);
  padding:var(--hj-space-6); overflow-y:auto; min-width:0;
}
.hj-panel{
  background:var(--hj-semantic-bg-surface); border:1px solid var(--hj-line);
  border-radius:var(--hj-radius-lg); padding:var(--hj-space-4);
}
.hj-overlay{
  background:var(--hj-overlay-bg); border:1px solid var(--hj-line);
  border-radius:var(--hj-radius-sm);
  padding:var(--hj-space-2) var(--hj-space-3);
  font-size:var(--hj-font-size-caption);
}
.hj-code{
  background:var(--hj-semantic-bg-surface); border:1px solid var(--hj-line-soft);
  padding:1px 6px; border-radius:var(--hj-radius-sm);
  font-family:var(--hj-font-family-mono); font-size:12px; overflow-wrap:anywhere;
}
.hj-divider{ border:0; border-top:1px solid var(--hj-line-soft); margin:var(--hj-space-4) 0 }

/* ---- messages ------------------------------------------------------------ */
.hj-error{
  color:var(--hj-motion-glitch-red); font-size:var(--hj-font-size-caption);
  margin-top:var(--hj-space-3); border-left:2px solid var(--hj-motion-glitch-red);
  padding-left:var(--hj-space-2);
}

/* ---- key/value data rows -------------------------------------------------
 * The workhorse for every panel that shows measured values. dt is the label,
 * dd the number; tabular-nums so columns of figures line up. */
.hj-kv-group{ margin-bottom:var(--hj-space-4) }
.hj-kv-group > h3, .hj-kv-title{
  font-size:11px; text-transform:uppercase; letter-spacing:.08em;
  font-weight:var(--hj-font-weight-medium); color:var(--hj-semantic-brand-accent);
  margin:0 0 var(--hj-space-1);
}
.hj-kv-list{ margin:0 }
.hj-kv{
  display:flex; justify-content:space-between; align-items:baseline;
  gap:var(--hj-space-3); padding:6px 0; border-bottom:1px solid var(--hj-line-soft);
}
.hj-kv dt{ color:var(--hj-muted); min-width:0; overflow-wrap:anywhere }
.hj-kv dd{
  margin:0; font-variant-numeric:tabular-nums;
  font-weight:var(--hj-font-weight-medium); white-space:nowrap;
}
.hj-kv dd .hj-pct{
  color:var(--hj-muted); font-weight:var(--hj-font-weight-regular);
  font-size:var(--hj-font-size-caption); margin-left:6px;
}

/* ---- breadcrumbs --------------------------------------------------------- */
.hj-crumbs{
  display:flex; flex-wrap:wrap; align-items:center; gap:6px;
  margin-top:var(--hj-space-4); font-size:var(--hj-font-size-caption);
}
.hj-crumbs .here{ color:var(--hj-muted); padding:3px 0; overflow-wrap:anywhere }
.hj-crumbs .sep { color:var(--hj-muted) }

/* ---- selection header ---------------------------------------------------- */
.hj-selection{ margin-top:var(--hj-space-6); padding-top:var(--hj-space-3); border-top:1px solid var(--hj-line) }
.hj-selection h2{
  font-size:var(--hj-font-size-h3); font-weight:var(--hj-font-weight-medium);
  margin:0; letter-spacing:-.01em; line-height:var(--hj-font-leading-tight);
}
.hj-selection .id{ color:var(--hj-muted); font-family:var(--hj-font-family-mono); font-size:12px }

/* ---- data-viz legend -----------------------------------------------------
 * Not map-specific: any product showing a continuous scale needs a ramp, its
 * end labels, and an explicit no-data swatch. The no-data swatch matters —
 * without one, "absent" and "lowest value" look identical. */
.hj-legend .lt{ color:var(--hj-muted); margin-bottom:6px; overflow-wrap:anywhere; white-space:normal }
.hj-legend .and{ color:var(--hj-semantic-brand-accent); font-weight:var(--hj-font-weight-medium) }
.hj-ramp{
  height:8px; border-radius:var(--hj-radius-pill);
  background:linear-gradient(90deg,
    color-mix(in srgb, var(--hj-semantic-bg-surface) 30%, var(--hj-primitive-jade-deep)),
    var(--hj-primitive-jade-deep), var(--hj-primitive-jade), var(--hj-primitive-jade-bright),
    color-mix(in srgb, var(--hj-primitive-mint) 58%, var(--hj-semantic-text-primary)));
}
.hj-ramp-ends{
  display:flex; justify-content:space-between;
  color:var(--hj-muted); margin-top:4px; font-size:11px;
}
.hj-nodata{
  display:flex; align-items:center; gap:6px;
  color:var(--hj-muted); margin-top:6px; font-size:11px;
}
.hj-nodata .sw{
  width:11px; height:11px; flex:0 0 auto; border-radius:3px;
  background:color-mix(in srgb, var(--hj-semantic-bg-surface) 84%, var(--hj-semantic-text-primary));
}

/* ---- app shell -----------------------------------------------------------
 * The rail + workspace split most tools in the estate use. minmax(0,1fr) is
 * load-bearing: a bare 1fr lets a wide child force the grid wider than the
 * viewport, which is the horizontal-spill failure the breakpoint battery gates
 * on. */
.hj-shell{
  display:grid;
  grid-template-columns:var(--hj-rail-w, 340px) minmax(0,1fr);
  overflow-x:hidden;
}
/* display:grid + place-items:center is part of the contract, not decoration —
   it is what centres a workspace's fallback/empty state, and dropping it shifts
   any canvas that sizes itself to this box. */
.hj-shell > main{
  position:relative; min-width:0; overflow:hidden;
  display:grid; place-items:center;
  background:var(--hj-semantic-bg-page);
}

@media (max-width:820px){
  .hj-shell{ grid-template-columns:minmax(0,1fr); grid-template-rows:auto minmax(460px,60vh) }
  .hj-rail{ border-right:0; border-bottom:1px solid var(--hj-line-soft); overflow-y:visible }
}

/* ── chips, tabs, and the screen-reader mirror ─────────────────────────────
 * Added 2026-07-29 for internal.hellojade.ai (the marketing agent console),
 * put HERE rather than in that product because all three are generic:
 * a chip row is any "what can this do" affordance, a tab strip is any
 * multi-session surface, and .hj-sr-only is needed by every product that
 * paints to a canvas.
 *
 * ⚠️ .hj-sr-only must NOT use display:none or visibility:hidden — both remove
 * the element from the accessibility tree, which is the one thing it exists to
 * stay in. The clip-path form keeps it announced and unpainted.
 */
.hj-chip{
  flex:0 0 auto; padding:4px 11px; cursor:pointer;
  background:var(--hj-semantic-bg-surface);
  border:1px solid var(--hj-line); border-radius:var(--hj-radius-pill);
  color:var(--hj-semantic-link);
  font-family:inherit; font-size:var(--hj-font-size-caption);
  font-weight:var(--hj-font-weight-regular); white-space:nowrap;
  transition:border-color var(--hj-duration-cut-in) var(--hj-easing-ease-out-cubic);
}
.hj-chip:hover:not(:disabled){ border-color:var(--hj-semantic-brand-accent) }
.hj-chip:disabled{ opacity:.4; cursor:not-allowed }

.hj-tab{
  flex:0 0 auto; padding:4px 12px; cursor:pointer;
  background:transparent; border:1px solid transparent;
  border-bottom-color:var(--hj-line);
  color:var(--hj-semantic-text-primary);
  font-family:inherit; font-size:var(--hj-font-size-caption);
  border-radius:var(--hj-radius-sm) var(--hj-radius-sm) 0 0; white-space:nowrap;
}
.hj-tab[aria-pressed="true"]{
  border-color:var(--hj-line); border-bottom-color:transparent;
  color:var(--hj-semantic-brand-accent);
}

.hj-sr-only{
  position:absolute; width:1px; height:1px;
  overflow:hidden; clip-path:inset(50%); white-space:nowrap;
}

/* ---- toolbar layer ------------------------------------------------------
 * The kit had a FORM layer and no TOOLBAR layer, and that absence is a bug
 * that propagates: a product needing a horizontal bar reaches for .hj-btn,
 * which is `width:100%` because it is a stacked-form submit button. cloudmap
 * did exactly that and its 899px of controls rendered 117px tall across EIGHT
 * rows inside a 1920px bar. Every element it used carried 16px of vertical
 * margin for the same reason: .hj-brand is a panel heading, .hj-divider is an
 * <hr>, .hj-label and .hj-hint are field furniture.
 *
 * ⚠️ .hj-btn's width:100% is CORRECT for forms and other products depend on
 * it. The fix is this missing variant, never a change to that rule.
 */
.hj-toolbar{
  display:flex;
  /* EXPLICIT. nowrap is already the initial value, but stating it means a
   * utility class or a later kit change cannot silently re-enable wrapping —
   * which is precisely how the 8-row bar happened. */
  flex-wrap:nowrap;
  align-items:center;
  gap:var(--hj-space-2);
  block-size:48px; min-block-size:48px; max-block-size:48px;
  flex:0 0 48px;                 /* content cannot grow it as a grid/flex child */
  padding-inline:var(--hj-space-3); padding-block:0;
  /* Converts the failure mode. A regression now clips one control — visible and
   * obviously wrong — instead of silently reflowing the bar and mis-sizing
   * every panel measured against it. */
  overflow:hidden;
  container-type:inline-size;
}
.hj-toolbar > *{ flex:0 0 auto; }
/* Neutralise the form layer's vertical rhythm for anything placed in a bar. */
.hj-toolbar :is(.hj-brand,.hj-divider,.hj-label,.hj-hint,.hj-btn,.hj-field){ margin:0 }

/* A bar's separator is a vertical rule, NOT .hj-divider (which is an <hr>
 * with border-top and 16px block margins). */
.hj-toolbar__rule{
  flex:0 0 1px; inline-size:1px; block-size:20px;
  margin-inline:var(--hj-space-2);
  background:var(--hj-line); border:0;
}

/* Exactly ONE per bar: the item that absorbs slack and truncates.
 * min-inline-size:0 is the whole trick — flex items default to min-width:auto
 * (= max-content), so they refuse to shrink below their text and
 * text-overflow never engages. */
.hj-toolbar__elastic{
  flex:1 1 auto; min-inline-size:0;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}

.hj-btn--toolbar{
  inline-size:auto; max-inline-size:none; margin:0;
  block-size:32px; padding:0 10px;
  display:inline-flex; align-items:center; gap:6px;
  white-space:nowrap; flex:0 0 auto;
  border-radius:var(--hj-radius-sm);
}
.hj-btn--icon{ inline-size:32px; padding:0; justify-content:center; }

/* ---- select ------------------------------------------------------------
 * The kit had no select at all, so products invented their own — cloudmap's
 * was a native <select>, whose intrinsic width is its WIDEST OPTION. Two of
 * them at ~340px each is what pushed its toolbar over.
 *
 * appearance:base-select (Chrome 135+) keeps a real <select>, so keyboard,
 * type-ahead, ARIA and form semantics stay native and correct, while the
 * button's width becomes independent of the option text. */
.hj-select{
  appearance:base-select;
  block-size:32px; padding:0 8px;
  inline-size:auto; min-inline-size:9rem; max-inline-size:15rem;
  background:var(--hj-semantic-bg-page); color:var(--hj-semantic-text-primary);
  border:1px solid var(--hj-line); border-radius:var(--hj-radius-sm);
  font-family:inherit; font-size:var(--hj-font-size-small);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.hj-select::picker(select){
  appearance:base-select;
  min-inline-size:anchor-size(inline); inline-size:max-content;
  max-inline-size:min(420px,90vw); max-block-size:360px;
  overflow-y:auto; overscroll-behavior:contain;
  background:var(--hj-semantic-bg-surface);
  border:1px solid var(--hj-line); border-radius:var(--hj-radius-sm);
  box-shadow:0 12px 32px rgb(0 0 0 / .45); padding:4px;
}
.hj-select option{ padding:6px 10px; border-radius:var(--hj-radius-sm) }
.hj-select option:checked{ color:var(--hj-semantic-brand-accent) }

/* .hj-btn is width:100% because it was built for forms, where a full-width submit
 * is right. A button sitting BESIDE something — a composer, a toolbar, a row of
 * actions — needs to size to its label instead. That is generic enough to belong
 * here rather than being overridden in each product's own CSS, which is exactly
 * the drift the product-rule-count guard exists to catch. */
.hj-btn--inline{ width:auto; margin:0; padding:9px var(--hj-space-4) }

/* ---- canvas scroll affordances -------------------------------------------
 * A browser draws a scrollbar for a scrollable BOX. A <canvas> that paints its
 * own scrolled content is not one, so a product that renders its own document
 * — a transcript, a log, a timeline, a map legend — shows a 900-line document
 * and a 9-line document identically: no thumb, no shadow, no hint. The only
 * way to discover there is more is to try the wheel and watch for movement.
 * internal.hellojade.ai shipped like that.
 *
 * These two components put the affordance back in DOM, where it can be styled,
 * hit-tested and hidden from the accessibility tree independently of whatever
 * the canvas is painting. They are here rather than in one product's CSS
 * because every self-rendering surface in the estate needs the same two things.
 *
 * ⚠️ Geometry arrives from JS as --hj-thumb-size / --hj-thumb-pos, because it
 * depends on the document height and no stylesheet can know that. Everything
 * else — color, hit area, motion, the 24px floor — is declared HERE, so a
 * product never grows its own scrollbar. Both need a positioned ancestor.
 */
.hj-scrollbar{
  position:absolute; inset-block:0; inset-inline-end:2px; inline-size:10px;
  /* The track must not eat pointer events aimed at the surface behind it; only
   * the thumb takes them back. */
  pointer-events:none;
}
.hj-scrollbar__thumb{
  position:absolute; inset-inline:2px;
  inset-block-start:var(--hj-thumb-pos,0px);
  /* The floor is why a consumer cannot assume a 1:1 drag ratio: below ~5% of
   * the document the thumb stops shrinking, so thumb travel and scroll travel
   * diverge. Compute the ratio from the rendered height. */
  block-size:var(--hj-thumb-size,24px); min-block-size:24px;
  background:var(--hj-line); border-radius:var(--hj-radius-pill);
  pointer-events:auto; cursor:grab; touch-action:none;
  transition:background var(--hj-duration-cut-in) var(--hj-easing-ease-out-cubic);
}
.hj-scrollbar__thumb:hover{ background:var(--hj-semantic-brand-accent) }
.hj-scrollbar__thumb.is-dragging{ background:var(--hj-semantic-brand-accent); cursor:grabbing }

/* "Jump to latest" — shown only while the view is scrolled off the live end of
 * a streaming document. It floats over the surface rather than sitting in the
 * chrome so it is where the eye already is. */
.hj-jump{
  position:absolute; inset-block-end:12px; inset-inline:0;
  margin-inline:auto; inline-size:max-content; max-inline-size:calc(100% - 24px);
  display:inline-flex; align-items:center; gap:6px;
  padding:6px 14px; cursor:pointer;
  background:var(--hj-semantic-bg-surface); color:var(--hj-semantic-link);
  border:1px solid var(--hj-line); border-radius:var(--hj-radius-pill);
  font-family:inherit; font-size:var(--hj-font-size-caption); white-space:nowrap;
  box-shadow:0 6px 18px rgb(0 0 0 / .38);
}
.hj-jump:hover{ border-color:var(--hj-semantic-brand-accent) }
/* 🔴 REQUIRED, not defensive. `hidden` is a UA `display:none`, and the author
 * `display:inline-flex` above beats it — without this line the control is
 * permanently visible and toggling .hidden from JS does nothing at all. Any
 * kit component that declares `display` and is toggled with `hidden` needs it. */
.hj-jump[hidden]{ display:none }

/* A full-bleed focusable surface (a canvas filling its pane) cannot show the
 * standard outline-offset:2px ring — it would be drawn outside the element,
 * over whatever is next to it, or clipped away entirely. Inset it. */
.hj-focusable--inset:focus-visible{ outline-offset:-2px }

/* ---- inline control hints ----------------------------------------------
 * A caption-level row under a control, carrying three different KINDS of
 * message that are easy to conflate and must not be: a permanent affordance
 * ("Enter sends"), a transient reason the control is unavailable, and a live
 * counter.
 *
 * They are separate elements rather than one status line because their
 * accessibility semantics differ. The blocker is announced (role="status"); the
 * counter must NOT be, or a screen reader reads a ticking clock over everything
 * else. Wire the hint and the blocker to the control with aria-describedby and
 * leave the counter out of it.
 *
 * :empty collapses the unused ones so an idle row shows only the affordance,
 * with no stray gaps from the flex gap between empty spans. */
.hj-hints{
  display:flex; flex-wrap:wrap; align-items:baseline;
  gap:var(--hj-space-1) var(--hj-space-3);
  font-size:var(--hj-font-size-caption); color:var(--hj-muted);
}
.hj-hints__blocker{ color:var(--hj-primitive-amber) }
.hj-hints__timer{ font-family:var(--hj-font-family-mono); color:var(--hj-semantic-brand-accent) }
.hj-hints__blocker:empty, .hj-hints__timer:empty{ display:none }

/* ---- anchored results menu -----------------------------------------------
 * A typeahead's results list: a floating panel of selectable rows anchored
 * under its input. The wrapper holding input + menu provides
 * position:relative — the menu anchors to it, not to the page.
 *
 * Rows are BUTTONS, not divs: focus semantics, :hover and screen-reader
 * activation come free. Keyboard navigation highlights with .is-active
 * instead of moving DOM focus, so the input keeps receiving keystrokes. */
.hj-menu{
  position:absolute; inset-inline:0; z-index:5;
  margin-top:4px; padding:var(--hj-space-1);
  background:var(--hj-semantic-bg-surface); border:1px solid var(--hj-line);
  border-radius:var(--hj-radius-sm);
  box-shadow:0 6px 18px rgb(0 0 0 / .38);
  max-height:280px; overflow-y:auto;
  display:block;
}
/* see .hj-jump — an author display beats the UA's [hidden] display:none */
.hj-menu[hidden]{ display:none }
.hj-menu__item{
  display:flex; width:100%; align-items:baseline; justify-content:space-between;
  gap:var(--hj-space-3); padding:7px var(--hj-space-3);
  cursor:pointer; text-align:start;
  background:none; border:0; border-radius:var(--hj-radius-sm);
  color:var(--hj-semantic-text-primary);
  font-family:inherit; font-size:var(--hj-font-size-small);
}
.hj-menu__item:hover, .hj-menu__item.is-active{ background:var(--hj-semantic-bg-page) }
.hj-menu__item .meta{ color:var(--hj-muted); font-size:var(--hj-font-size-caption); white-space:nowrap }

/* ── modal ────────────────────────────────────────────────────────────────────
   A centered dialog over a dimming backdrop. Added 2026-07-31 for the marketing
   console's client picker (jadeinternal #48), and put HERE rather than in that
   product because a modal is the most obviously reusable thing an estate app
   needs — the standing rule is that new styling grows the kit so every product
   inherits it.

   Tokens only, no raw hex. The scrolling list is bounded so a long list (27
   client offices today) cannot push the actions off-screen — an actions row
   that scrolls away turns Cancel into a trap. */
.hj-modal{
  position:fixed; inset:0; z-index:50;
  display:flex; align-items:center; justify-content:center;
  padding:16px; background:rgba(0,0,0,.62);
}
.hj-modal__card{
  width:min(520px,100%); max-height:min(80vh,640px);
  display:flex; flex-direction:column; gap:10px;
  padding:16px;
  /* was var(--hj-semantic-bg-panel) — a token that never existed, so the card
   * rendered transparent over the backdrop. The raised-surface token is the
   * correct fill for a dialog floating above the page. */
  background:var(--hj-surface-2);
  border:1px solid var(--hj-line);
  border-radius:var(--hj-radius-md);
}
.hj-modal__title{
  margin:0; color:var(--hj-semantic-text-primary);
  font-family:inherit; font-size:var(--hj-font-size-body); font-weight:600;
}
.hj-modal__sub{
  margin:0; color:var(--hj-muted); font-size:var(--hj-font-size-caption);
}
.hj-modal__list{
  display:flex; flex-direction:column; gap:4px;
  overflow-y:auto; min-height:0; padding-right:4px;
}
.hj-modal__item{ justify-content:flex-start; text-align:left; width:100% }
.hj-modal__foot{ display:flex; justify-content:flex-end; gap:8px }

/* A tab that is pinned to one client. The marker is a leading glyph rather than
   colour alone, so it survives a colour-blind reader and a greyscale screenshot. */
.hj-tab--scoped::before{ content:"◆ "; color:var(--hj-semantic-brand-accent) }

/* ══════════════════════════════════════════════════════════════════════════
 * S05 UI-audit-v2 promotions (2026-08-02)
 * Components every product was re-inventing, surfaced by the fleet-wide UI
 * audit. Promoted here so the estate stops forking them; each names the apps
 * that asked for it. Tokens only — theme-aware via the light block above.
 * ══════════════════════════════════════════════════════════════════════════ */

/* ---- segmented control ---------------------------------------------------
 * The single highest-reuse gap: cal (day/week/month), office (edit/suggest/
 * view mode switch), jadeops, internal and catalog all hand-rolled one. A row
 * of connected buttons where exactly one is pressed. Drive it with
 * aria-pressed / aria-selected on the active item. */
.hj-segmented{
  display:inline-flex; align-items:stretch; max-inline-size:100%;
  border:1px solid var(--hj-line); border-radius:var(--hj-radius-sm);
  overflow:hidden; background:var(--hj-semantic-bg-page);
}
.hj-segmented__item{
  appearance:none; cursor:pointer; margin:0;
  padding:0 var(--hj-space-3); block-size:32px;
  display:inline-flex; align-items:center; justify-content:center; gap:6px;
  background:transparent; border:0;
  border-inline-start:1px solid var(--hj-line-soft);
  color:var(--hj-muted); font-family:inherit; font-size:var(--hj-font-size-small);
  white-space:nowrap;
}
.hj-segmented__item:first-child{ border-inline-start:0 }
.hj-segmented__item:hover:not(:disabled){ color:var(--hj-semantic-text-primary) }
.hj-segmented__item[aria-pressed="true"], .hj-segmented__item[aria-selected="true"]{
  background:var(--hj-semantic-brand-primary); color:var(--hj-primitive-ink);
}
.hj-segmented__item:disabled{ opacity:.45; cursor:not-allowed }

/* ---- vertical rail nav ---------------------------------------------------
 * jadeops/internal/campaign each built a column of view-switch buttons. The
 * kit's .hj-tab is HORIZONTAL (border-bottom) — wrong for a left-rail list.
 * Active state is aria-current="true". */
.hj-nav{ display:flex; flex-direction:column; gap:var(--hj-space-1) }
.hj-nav-item{
  appearance:none; text-align:left; cursor:pointer; width:100%;
  background:transparent; color:var(--hj-semantic-text-primary);
  border:1px solid transparent; border-radius:var(--hj-radius-md);
  padding:var(--hj-space-2) var(--hj-space-3);
  font:inherit; font-size:var(--hj-font-size-small);
}
.hj-nav-item:hover{ border-color:var(--hj-line) }
.hj-nav-item[aria-current="true"]{
  border-color:var(--hj-semantic-brand-bright); color:var(--hj-semantic-brand-bright);
}
.hj-nav-item:focus-visible{ outline:2px solid var(--hj-semantic-brand-accent); outline-offset:2px }

/* ---- definition grid -----------------------------------------------------
 * A dense two-column "click a thing, read its fields" panel (jadeops node
 * detail, crm record detail, campaign feature props). Distinct from .hj-kv,
 * which is a single-row metric list; this packs many short dt/dd pairs. */
.hj-deflist{ margin:0; display:grid; grid-template-columns:auto 1fr; gap:var(--hj-space-1) var(--hj-space-3) }
.hj-deflist dt{ color:var(--hj-muted); font-size:11px }
.hj-deflist dd{ margin:0; font-size:var(--hj-font-size-caption); word-break:break-word }

/* ---- toast stack ---------------------------------------------------------
 * Every app eventually needs a transient non-modal notice; connect learned the
 * hard way that a badge is not a notification. The container never eats clicks;
 * each toast does. Needs a positioned ancestor. */
.hj-toasts{
  position:absolute; inset-inline-start:var(--hj-space-4); inset-block-end:var(--hj-space-4);
  z-index:8; display:flex; flex-direction:column-reverse; gap:var(--hj-space-2);
  max-inline-size:min(90%,26rem); pointer-events:none;
}
.hj-toast{
  pointer-events:auto; cursor:pointer; display:flex; align-items:baseline; gap:var(--hj-space-2);
  padding:var(--hj-space-2) var(--hj-space-3); border-radius:var(--hj-radius-md);
  background:var(--hj-surface-2); border:1px solid var(--hj-line);
  box-shadow:0 8px 28px rgb(0 0 0 / .38); font-size:var(--hj-font-size-caption);
  animation:hj-toastin var(--hj-duration-cut-in) var(--hj-easing-ease-out-cubic);
}
.hj-toast--danger{ border-color:var(--hj-semantic-danger) }
.hj-toast__who{ font-weight:var(--hj-font-weight-medium); flex:0 0 auto }
.hj-toast__text{ min-inline-size:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
@keyframes hj-toastin{ from{opacity:0; transform:translateY(6px)} to{opacity:1; transform:none} }
@media (prefers-reduced-motion:reduce){ .hj-toast{ animation:none } }

/* ---- level / progress meter ---------------------------------------------
 * A bounded fill bar (connect's mic level, any progress/VU indicator). Set the
 * fill's inline-size from JS. */
.hj-meter{
  block-size:var(--hj-space-2); border-radius:var(--hj-radius-pill);
  background:color-mix(in srgb, var(--hj-semantic-text-primary) 12%, transparent); overflow:hidden;
}
.hj-meter__fill{
  block-size:100%; inline-size:0; border-radius:var(--hj-radius-pill);
  background:var(--hj-semantic-brand-primary);
  transition:inline-size var(--hj-duration-cut-in) linear;
}

/* ---- labelled switch row -------------------------------------------------
 * A settings toggle with an optional reason line; office/internal/catalog
 * settings panes all reinvent it. The coarse-pointer floor lives in the block
 * at the end of this file so the switch reaches 44×40 on touch. */
.hj-switchrow{ display:flex; align-items:center; justify-content:space-between; gap:var(--hj-space-3); padding:var(--hj-space-2) 0 }
.hj-switchrow__text{ display:flex; flex-direction:column; min-inline-size:0 }
.hj-switchrow__reason{ color:var(--hj-muted); font-size:var(--hj-font-size-caption) }
.hj-switchrow input[type="checkbox"]{ inline-size:2.1rem; block-size:1.2rem; flex:0 0 auto; accent-color:var(--hj-semantic-brand-primary); cursor:pointer }
.hj-switchrow input[type="checkbox"]:disabled{ cursor:not-allowed; opacity:.55 }

/* ---- card grid -----------------------------------------------------------
 * A responsive auto-fill grid of media cards — catalog's whole vocabulary, and
 * a natural fit for any gallery/library view. Set --hj-card-min to tune the
 * column width. An <a class="hj-card"> gets the hover affordance for free. */
.hj-cards{
  display:grid; gap:var(--hj-space-4);
  grid-template-columns:repeat(auto-fill, minmax(var(--hj-card-min, 240px), 1fr));
}
.hj-card{
  display:flex; flex-direction:column; overflow:hidden;
  background:var(--hj-semantic-bg-surface); border:1px solid var(--hj-line);
  border-radius:var(--hj-radius-lg);
  transition:border-color var(--hj-duration-cut-in) var(--hj-easing-ease-out-cubic);
}
a.hj-card, .hj-card--link{ cursor:pointer; text-decoration:none; color:inherit }
a.hj-card:hover, .hj-card--link:hover{ border-color:var(--hj-semantic-brand-accent) }
.hj-card__media{ aspect-ratio:16/10; background:var(--hj-surface-2); overflow:hidden }
.hj-card__media img{ width:100%; height:100%; object-fit:cover; display:block }
.hj-card__body{ padding:var(--hj-space-3); display:flex; flex-direction:column; gap:var(--hj-space-1) }
.hj-card__title{ margin:0; font-size:var(--hj-font-size-small); font-weight:var(--hj-font-weight-medium) }
.hj-card__meta{ color:var(--hj-muted); font-size:var(--hj-font-size-caption) }

/* A read-only chip (a label, not an action) — catalog's status/attribute tags.
 * Same shape as .hj-chip minus the interactive affordances. */
.hj-chip--static{ cursor:default; color:var(--hj-muted) }
.hj-chip--static:hover{ border-color:var(--hj-line) }

/* ---- map-first shell (mobile) --------------------------------------------
 * .hj-shell stacks the rail ABOVE main on narrow screens — right for a form
 * console, wrong for a map tool (campaign), where landing on a screen of
 * dropdowns defeats the point. Opt in with .hj-shell--map on the shell. */
@media (max-width:820px){
  .hj-shell--map{ display:flex; flex-direction:column; height:100dvh; min-height:0 }
  .hj-shell--map > main{ order:1; flex:0 0 58vh; min-height:0 }
  .hj-shell--map > .hj-rail{
    order:2; flex:1 1 auto; min-height:0; overflow-y:auto;
    border-bottom:0; border-top:1px solid var(--hj-line-soft);
  }
}

/* ---- coarse-pointer tap-target floor -------------------------------------
 * Measured across the fleet (internal, cal, connect): interactive controls
 * render 24–37px tall — WCAG 2.5.8 AA (24px) but tight for one-handed use on a
 * phone. Grow HEIGHT ONLY (min-block-size) on coarse pointers so nothing widens
 * — width-growth is what would re-introduce spill in overflow-x:auto tab/chip
 * rows on a 360px screen. Desktop (pointer:fine) is untouched, so visual-diff
 * baselines captured on desktop stay at zero. */
@media (pointer:coarse){
  .hj-btn, .hj-btn--ghost, .hj-btn--toolbar, .hj-btn--icon,
  .hj-chip, .hj-tab, .hj-menu__item, .hj-modal__item,
  .hj-nav-item, .hj-segmented__item{ min-block-size:40px }
  .hj-btn--toolbar, .hj-btn--icon, .hj-segmented__item{ display:inline-flex; align-items:center }
  .hj-switchrow input[type="checkbox"]{ min-inline-size:44px; min-block-size:40px }
}

/* ═══════════════════════════════════════════════════════════════════════════
 * ═ office-contributed components (S05 convergence) ═
 * ═══════════════════════════════════════════════════════════════════════════
 * The four richest components office (compose/compute/convey) had that the kit
 * lacked, re-expressed in the kit's --hj-semantic-* and --hj-primitive-* namespaces,
 * theme-aware (they flip under :root[data-kind="light"]), tokens only, no raw
 * hex. Responsive geometry arrives as consumer-set --hj-* custom props with
 * fallbacks — the kit owns LOOK, the consumer owns SIZING, same split the kit
 * already uses for --hj-rail-w / --hj-card-min / --hj-thumb-*. Source notes:
 * office/src/KIT-CANDIDATES.md §6. The three overlay cards (dialog, cmdk panel,
 * bottom-sheet) use --hj-radius-xl (16px, present in tokens.css) for the fuller
 * corner office's blocks called for.
 * ═══════════════════════════════════════════════════════════════════════════ */

/* ---- dense, scroll-reachable toolbar --------------------------------------
 * The kit's .hj-toolbar is a FIXED-height bar that clips overflow. This is its
 * sibling for CONTROL-DENSE bars (editor ribbons) that over-provision: it scrolls
 * horizontally so a control pushed past the viewport stays REACHABLE instead of
 * being silently clipped (the bug: a row wider than the viewport with
 * overflow:hidden leaves page scrollWidth 0, so an overflow gate reports clean
 * while the trailing controls are lost). Button size arrives as --hj-tb-btn. */
.hj-toolbar-dense{
  flex:none; position:relative;
  background:var(--hj-semantic-bg-surface);
  border-block-end:1px solid var(--hj-line);
}
.hj-toolbar-dense__row{
  display:flex; align-items:center; flex-wrap:nowrap;
  overflow-x:auto; overflow-y:hidden;               /* reachable, never clipped */
  scrollbar-width:thin;
  scrollbar-color:color-mix(in srgb, var(--hj-primitive-jade) 45%, transparent) transparent;
}
.hj-toolbar-dense__row::-webkit-scrollbar{ block-size:6px }
.hj-toolbar-dense__row::-webkit-scrollbar-thumb{
  background:color-mix(in srgb, var(--hj-primitive-jade) 40%, transparent); border-radius:3px;
}
.hj-toolbar-dense [hidden]{ display:none !important }   /* an explicit display must not resurrect [hidden] */
.hj-toolbar-dense__group{ display:flex; align-items:center; flex:none }
.hj-toolbar-dense__group:empty{ display:none }
/* a hairline rule between two non-empty groups (no extra element needed) */
.hj-toolbar-dense__group:not(:empty) + .hj-toolbar-dense__group:not(:empty)::before{
  content:''; inline-size:1px; block-size:18px; margin-inline:4px; background:var(--hj-line);
}
.hj-toolbar-dense__spacer{ flex:1; min-inline-size:8px }
.hj-toolbar-dense__btn{
  display:inline-flex; align-items:center; justify-content:center; gap:2px;
  inline-size:var(--hj-tb-btn, 34px); block-size:var(--hj-tb-btn, 34px); padding:0;
  border:1px solid transparent; border-radius:var(--hj-radius-sm);
  background:transparent; color:color-mix(in srgb, var(--hj-primitive-ink) 85%, transparent);
  font-family:var(--hj-font-family-sans); font-size:inherit; cursor:pointer;
}
.hj-toolbar-dense__btn:hover:not(:disabled){
  background:color-mix(in srgb, var(--hj-primitive-jade) 22%, transparent); color:var(--hj-primitive-ink);
}
.hj-toolbar-dense__btn:focus-visible{ outline:2px solid var(--hj-primitive-jade-bright); outline-offset:-2px }
.hj-toolbar-dense__btn:disabled{ opacity:.35; cursor:default }
.hj-toolbar-dense__btn.is-active{
  background:color-mix(in srgb, var(--hj-primitive-jade) 38%, transparent);
  color:var(--hj-primitive-jade-bright);
  border-color:color-mix(in srgb, var(--hj-primitive-jade-bright) 40%, transparent);
}
.hj-toolbar-dense__btn svg{ display:block }
/* a native <select> living in the bar (style/font/zoom pickers) */
.hj-toolbar-dense__select{
  block-size:var(--hj-tb-btn, 34px); padding:0 6px;
  border:1px solid var(--hj-line); border-radius:var(--hj-radius-sm);
  background:color-mix(in srgb, var(--hj-primitive-ground-deepest) 55%, transparent);
  color:var(--hj-primitive-ink); font-family:var(--hj-font-family-sans); font-size:inherit; cursor:pointer;
}
.hj-toolbar-dense__select:focus-visible{ outline:2px solid var(--hj-primitive-jade-bright); outline-offset:-1px }

/* ---- overlay dialog (invite + role + access list) --------------------------
 * The kit's .hj-modal is a centered card; this is the richer share/invite
 * pattern — a scrolling overlay panel with header+close, an invite row (email
 * field + role select + action), a bounded people access list, and a
 * general-access section. Geometry vars: --hj-dialog-maxw/-pad/-gap/-title/-body. */
.hj-dialog__overlay{
  position:fixed; inset:0; z-index:1000; display:grid; place-items:center;
  padding:var(--hj-space-4);
  background:color-mix(in srgb, var(--hj-primitive-ground-deepest) 78%, transparent);
  backdrop-filter:blur(3px);
}
.hj-dialog{
  inline-size:100%; max-inline-size:var(--hj-dialog-maxw, 480px); max-block-size:90vh; overflow-y:auto;
  display:flex; flex-direction:column; gap:var(--hj-dialog-gap, 16px);
  padding:var(--hj-dialog-pad, 24px);
  background:var(--hj-semantic-bg-surface); color:var(--hj-semantic-text-primary);
  border:1px solid var(--hj-line); border-radius:var(--hj-radius-xl);
  box-shadow:0 30px 80px rgb(0 0 0 / .5); font-size:var(--hj-dialog-body, var(--hj-font-size-small));
}
.hj-dialog__head{ display:flex; align-items:center; justify-content:space-between; gap:var(--hj-space-3) }
.hj-dialog__title{
  margin:0; font-size:var(--hj-dialog-title, var(--hj-font-size-h3)); font-weight:var(--hj-font-weight-medium);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.hj-dialog__close{
  flex:none; inline-size:32px; block-size:32px; border:0; border-radius:var(--hj-radius-pill);
  background:transparent; color:var(--hj-muted); font-size:24px; line-height:1; cursor:pointer;
}
.hj-dialog__close:hover, .hj-dialog__close:focus-visible{
  outline:none; background:color-mix(in srgb, var(--hj-primitive-ink) 10%, transparent);
  color:var(--hj-primitive-ink);
}
/* invite row: email field grows, role select + action are fixed */
.hj-dialog__invite{ display:flex; gap:var(--hj-space-2); align-items:stretch }
.hj-dialog__invite .hj-field{ flex:1; min-inline-size:0; margin:0 }
.hj-dialog__action{                                   /* the primary invite/copy button */
  flex:none; border:1px solid var(--hj-semantic-brand-accent); border-radius:var(--hj-radius-sm);
  background:linear-gradient(135deg, var(--hj-primitive-jade-deep), var(--hj-primitive-jade));
  color:var(--hj-primitive-ink); font-weight:var(--hj-font-weight-medium); padding:8px 14px; cursor:pointer;
}
.hj-dialog__action:hover{ background:linear-gradient(135deg, var(--hj-primitive-jade), var(--hj-primitive-jade-bright)) }
.hj-dialog__action:disabled{ opacity:.5; cursor:not-allowed }
/* filled danger notice (distinct from the kit's left-border .hj-error) */
.hj-dialog__error{
  padding:8px 12px; border-radius:var(--hj-radius-sm);
  background:color-mix(in srgb, var(--hj-semantic-danger) 18%, transparent);
  border:1px solid color-mix(in srgb, var(--hj-semantic-danger) 45%, transparent);
  color:var(--hj-primitive-ink); font-size:var(--hj-font-size-small);
}
/* the people access list */
.hj-dialog__people{ display:flex; flex-direction:column; gap:var(--hj-space-2); max-block-size:40vh; overflow-y:auto }
.hj-dialog__person{ display:flex; align-items:center; gap:var(--hj-space-2) }
.hj-dialog__who{ flex:1; min-inline-size:0; display:flex; flex-direction:column }
.hj-dialog__who .name{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.hj-dialog__who .sub{ font-size:var(--hj-font-size-caption); color:var(--hj-muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.hj-dialog__tag{ flex:none; font-size:var(--hj-font-size-small); color:var(--hj-muted) }
.hj-dialog__remove{
  flex:none; border:1px solid var(--hj-line); border-radius:var(--hj-radius-sm);
  background:transparent; color:color-mix(in srgb, var(--hj-primitive-ink) 80%, transparent);
  padding:6px 10px; cursor:pointer;
}
.hj-dialog__remove:hover{ border-color:var(--hj-semantic-danger); color:var(--hj-primitive-ink) }
/* general-access section, divided from the people list */
.hj-dialog__access{
  display:flex; flex-direction:column; gap:var(--hj-space-2);
  padding-block-start:var(--hj-space-3); border-block-start:1px solid var(--hj-line-soft);
}

/* ---- command palette (⌘K) --------------------------------------------------
 * A top-anchored fuzzy command overlay: search input, grouped rows with a
 * right-aligned shortcut hint, active-row highlight, empty state. Geometry vars:
 * --hj-cmdk-top/-maxw/-maxh/-font/-pad/-row/-detail. */
.hj-cmdk{
  position:fixed; inset:0; z-index:1100;             /* above side panels + the dialog overlay */
  display:grid; grid-template-rows:var(--hj-cmdk-top, 88px) auto 1fr; justify-items:center;
  padding-inline:var(--hj-space-4);
  background:color-mix(in srgb, var(--hj-primitive-ground-deepest) 72%, transparent); backdrop-filter:blur(3px);
}
.hj-cmdk[hidden]{ display:none }
.hj-cmdk__panel{
  grid-row:2; inline-size:100%; max-inline-size:var(--hj-cmdk-maxw, 620px);
  max-block-size:var(--hj-cmdk-maxh, 60vh); display:flex; flex-direction:column; overflow:hidden;
  background:var(--hj-semantic-bg-surface); color:var(--hj-semantic-text-primary);
  border:1px solid var(--hj-line); border-radius:var(--hj-radius-xl);
  box-shadow:0 30px 80px rgb(0 0 0 / .55); font-family:var(--hj-font-family-sans);
}
.hj-cmdk__input{
  flex:none; border:0; outline:none; background:transparent; color:var(--hj-semantic-text-primary);
  font-family:inherit; font-size:calc(var(--hj-cmdk-font, 16px) + 1px);
  padding:calc(var(--hj-cmdk-pad, 10px) + 6px) calc(var(--hj-cmdk-pad, 10px) + 8px);
  border-block-end:1px solid var(--hj-line-soft);
}
.hj-cmdk__input::placeholder{ color:var(--hj-muted) }
.hj-cmdk__list{ flex:1 1 auto; overflow-y:auto; padding:var(--hj-cmdk-pad, 10px); scrollbar-width:thin }
.hj-cmdk__group{
  padding:8px 10px 4px; font-size:var(--hj-cmdk-detail, 13px); font-weight:var(--hj-font-weight-medium);
  letter-spacing:.04em; text-transform:uppercase; color:var(--hj-muted);
}
.hj-cmdk__row{
  display:flex; align-items:center; gap:var(--hj-space-3); min-block-size:var(--hj-cmdk-row, 40px);
  padding:6px 10px; border-radius:var(--hj-radius-md); cursor:pointer; user-select:none;
}
.hj-cmdk__row.is-active{ background:color-mix(in srgb, var(--hj-primitive-jade) 22%, transparent) }
.hj-cmdk__rowmain{ display:flex; flex-direction:column; gap:1px; min-inline-size:0; flex:1 1 auto }
.hj-cmdk__label{ font-size:var(--hj-cmdk-font, 16px); overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.hj-cmdk__detail{ font-size:var(--hj-cmdk-detail, 13px); color:var(--hj-muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
.hj-cmdk__kbd{
  flex:none; font-family:var(--hj-font-family-mono); font-size:var(--hj-cmdk-detail, 13px); color:var(--hj-muted);
  background:color-mix(in srgb, var(--hj-primitive-ink) 8%, transparent);
  border:1px solid color-mix(in srgb, var(--hj-primitive-ink) 12%, transparent);
  border-radius:var(--hj-radius-sm); padding:2px 7px; white-space:nowrap;
}
.hj-cmdk__empty{ padding:24px 12px; text-align:center; color:var(--hj-muted); font-size:var(--hj-cmdk-font, 16px) }

/* ---- side drawer ↔ bottom sheet -------------------------------------------
 * A panel that is a right-rail drawer on wide screens and a full-width bottom
 * sheet under narrow — the mode is a consumer-set data-mode attribute, never a
 * media query. Docks below the topbar (--hj-topbar-h) so its controls stay
 * clickable. Geometry vars: --hj-panel-pad/-row-pad/-font. */
.hj-side-panel{
  --hj-panel-pad:16px; --hj-panel-row-pad:12px; --hj-panel-font:var(--hj-font-size-small);
  position:fixed; z-index:40; display:flex; flex-direction:column;
  background:var(--hj-semantic-bg-surface); color:var(--hj-semantic-text-primary);
  font-family:var(--hj-font-family-sans); box-shadow:0 8px 40px rgb(0 0 0 / .45);
  overflow:hidden; will-change:transform;
  transition:transform var(--hj-duration-cut-in) var(--hj-easing-ease-out-cubic);
}
.hj-side-panel[hidden]{ display:none }
/* drawer (wide): right rail, docked below the topbar; slides in from the right */
.hj-side-panel[data-mode="drawer"]{
  inset-block:var(--hj-topbar-h, 0) 0; inset-inline-end:0;
  border-inline-start:1px solid var(--hj-line-soft); transform:translateX(100%);
}
.hj-side-panel[data-mode="drawer"].is-open{ transform:translateX(0) }
/* sheet (narrow): full-width bottom sheet; slides up */
.hj-side-panel[data-mode="sheet"]{
  inset-inline:0; inset-block-end:0; inline-size:100%; max-block-size:74vh;
  border-block-start:1px solid var(--hj-line-soft);
  border-radius:var(--hj-radius-xl) var(--hj-radius-xl) 0 0; transform:translateY(100%);
}
.hj-side-panel[data-mode="sheet"].is-open{ transform:translateY(0) }
.hj-side-panel__head{
  display:flex; align-items:center; justify-content:space-between;
  padding:var(--hj-panel-pad); border-block-end:1px solid var(--hj-line-soft);
}
.hj-side-panel__title{ margin:0; font-size:calc(var(--hj-panel-font) + 2px); font-weight:var(--hj-font-weight-heavy); letter-spacing:.01em }
.hj-side-panel__close{
  border:0; background:transparent; color:inherit; font-size:22px; line-height:1; cursor:pointer;
  padding:2px 8px; border-radius:var(--hj-radius-sm);
}
.hj-side-panel__close:hover{ background:color-mix(in srgb, var(--hj-primitive-ink) 10%, transparent) }
.hj-side-panel__body{ flex:1 1 auto; overflow-y:auto; overflow-x:hidden; padding-block:4px var(--hj-panel-pad); outline:none }
/* a vertical timeline row with a spine + node dot — the reusable "list of moments" shape */
.hj-side-panel__row{
  display:flex; align-items:flex-start; gap:10px; inline-size:100%; text-align:start;
  border:0; background:transparent; color:inherit; cursor:pointer; font-family:inherit; position:relative;
  padding:var(--hj-panel-row-pad) var(--hj-panel-pad);
}
.hj-side-panel__row::before{                          /* the spine */
  content:''; position:absolute; inset-block:0; inset-inline-start:calc(var(--hj-panel-pad) + 5px);
  inline-size:1px; background:var(--hj-line-soft);
}
.hj-side-panel__row:hover{ background:color-mix(in srgb, var(--hj-primitive-ink) 7%, transparent) }
.hj-side-panel__row[aria-selected="true"]{ background:color-mix(in srgb, var(--hj-primitive-jade) 16%, transparent) }
.hj-side-panel__dot{
  position:relative; z-index:1; flex:0 0 auto; inline-size:11px; block-size:11px; margin-block-start:3px;
  border-radius:var(--hj-radius-pill); background:var(--hj-semantic-bg-surface);
  border:2px solid color-mix(in srgb, var(--hj-primitive-ink) 30%, transparent);
}
.hj-side-panel__row[data-kind="marked"] .hj-side-panel__dot{
  border-color:var(--hj-primitive-jade-bright); background:var(--hj-primitive-jade-bright);
}
