/* Shared design-system components — pick up `--ds-*` tokens from
 * design-tokens.css. Any page can use these classes directly; no
 * scope wrapper needed.
 *
 * Class naming uses the `.callout-` / `.code-` prefix so the
 * semantics are obvious at the markup site (no ambiguity with a
 * page-local `.rec` or `.hint` that might mean something else).
 *
 * Components included:
 *   .callout-rec       — amber recommendation box (lightbulb prefix)
 *   .callout-hint      — blue info box
 *   .code-output       — terminal-style "WHAT YOU SHOULD SEE" block
 *   .lightbox          — full-bleed image overlay (click backdrop / Esc to close)
 *   .setup-section-header — eyebrow + heading + lede floating above a wizard card
 *
 * JS contract for `.lightbox`: an anchor with class
 * `.lightbox-trigger` opens the matching `#<id>-lightbox` div. The
 * VS Code thumb on /home is the canonical consumer; the inline JS
 * there shows the pattern. A future shared lightbox-trigger.js can
 * generalize this when a second consumer arrives.
 */

/* ─── Recommendation callout ─────────────────────────────────────
   Amber/warn vocabulary. Used for opinionated "I do it this way"
   guidance that's softer than a warning. Lightbulb prefix via
   ::before. */
.callout-rec {
    background: var(--ds-warn-bg);
    border-left: 3px solid var(--ds-warn-line);
    color: var(--ds-warn-ink);
    padding: 12px 16px;
    border-radius: 8px;
    font-size: 14px;
    line-height: 1.55;
    margin: 12px 0;
}
.callout-rec::before { content: "\1F4A1\00a0"; }
.callout-rec strong { color: var(--ds-warn-ink); }
.callout-rec code {
    background: rgba(245, 200, 75, 0.18);
    color: var(--ds-warn-ink);
    padding: 1px 6px;
    border-radius: 4px;
}

/* ─── Hint callout ────────────────────────────────────────────────
   Blue info vocabulary. Used for short educational asides next to
   a command (e.g. "What does mkdir -p do?"). Always visible. For
   collapsible OS-aware variants the wizard uses `details` with the
   same colour vocabulary. */
.callout-hint {
    background: var(--ds-info-bg);
    border-left: 3px solid var(--ds-info-line);
    color: var(--ds-info-ink);
    padding: 12px 16px;
    border-radius: 8px;
    font-size: 14px;
    line-height: 1.55;
    margin: 12px 0;
}
.callout-hint strong { color: var(--ds-info-ink); }
.callout-hint code {
    background: rgba(79, 124, 242, 0.14);
    color: var(--ds-info-ink);
    padding: 1px 6px;
    border-radius: 4px;
}
.callout-hint ol {
    margin: 8px 0 0 0;
    padding-left: 20px;
}
.callout-hint li { margin-bottom: 4px; }

/* ─── Code output block ───────────────────────────────────────────
   Dim surface with a dashed border + a "WHAT YOU SHOULD SEE"
   eyebrow rendered via ::before. Reserves vertical space for a
   block of terminal output so the reader knows exactly what the
   command should print. Whitespace is preserved (pre-line). */
.code-output {
    background: var(--ds-surface-dim);
    border: 1px dashed var(--ds-border);
    border-radius: 8px;
    padding: 14px 16px;
    font-family: var(--ds-font-mono);
    font-size: 12.5px;
    color: var(--ds-text-secondary);
    margin: 10px 0;
    white-space: pre-line;
}
.code-output::before {
    content: "What you should see";
    display: block;
    font-family: var(--ds-font);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 1px;
    color: var(--ds-text-muted);
    text-transform: uppercase;
    margin-bottom: 8px;
}

/* ─── Image lightbox overlay ──────────────────────────────────────
   Page-level overlay. Click the backdrop or press Esc to close
   (consumer wires the keydown handler). Designed for click-to-
   enlarge image triggers; the VS Code thumb on /home is the first
   consumer. */
.lightbox {
    position: fixed;
    inset: 0;
    background: rgba(15, 27, 58, 0.85);
    display: none;
    align-items: center;
    justify-content: center;
    padding: 32px;
    z-index: 200;
    cursor: zoom-out;
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
}
.lightbox.open { display: flex; }
.lightbox img {
    max-width: 100%;
    max-height: 100%;
    border-radius: 10px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}

/* ─── Setup-section header ────────────────────────────────────────
   Wizard-style "First time here / <heading> / <lede>" header that
   floats above its setup card. Stays on the page background so the
   card below is the visible rectangle. Used by the /home install
   hero. */
.setup-section-header {
    margin-bottom: 18px;
}
.setup-section-header .eyebrow {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1.2px;
    color: var(--ds-primary);
    margin-bottom: 8px;
}
.setup-section-header .setup-heading {
    font-size: 28px;
    font-weight: 700;
    color: var(--ds-text-primary);
    margin: 0 0 12px;
    line-height: 1.2;
}
.setup-section-header .lead {
    font-size: 15px;
    color: var(--ds-text-secondary);
    line-height: 1.6;
    margin: 0 0 10px;
    max-width: 760px;
}
.setup-section-header .lead code {
    background: var(--ds-primary-light);
    color: var(--ds-primary-dark);
    padding: 1px 6px;
    border-radius: 4px;
    font-family: var(--ds-font-mono);
    font-size: 12.5px;
}

/* ── Fast tooltip for `[data-tip]` ──────────────────────────────────────────
   Shared (v113). Replaces the native `title` tooltip, whose show delay is
   OS-controlled at 600ms+ — far too slow for an affordance that is the ONLY
   explanation of an icon-only marker.

   Fixed-position and appended to <body> by js/components/tooltip.js rather than
   drawn as a CSS ::after, because a ::after is clipped by the ancestors these
   markers actually live in: `.lib-table td` is `overflow: hidden`, `.lib-tablewrap`
   is `overflow-x: auto` (which computes `overflow-y: auto` too), and a grid
   `.fbar-card` is `overflow: hidden` — so a bubble on a card would be sliced off
   at the card edge.

   Lived in library.html as `.lib-tip` until the trust markers had to carry the
   same behaviour onto the catalog + detail pages; one implementation now, since
   two would eventually disagree about the delay or the geometry. */
.ds-tip {
    position: fixed;
    z-index: 500;
    max-width: 260px;
    padding: 6px 10px;
    border-radius: 6px;
    font-size: 12px;
    line-height: 1.4;
    font-weight: 500;
    letter-spacing: normal;
    text-transform: none;
    background: var(--ds-text-primary);
    color: var(--ds-text-inverse);
    box-shadow: var(--ds-shadow-md);
    pointer-events: none;
    opacity: 0;
    transform: translateY(2px);
    transition: opacity .08s ease, transform .08s ease;
}
.ds-tip.is-visible { opacity: 1; transform: translateY(0); }

/* Status badge modifiers — the .badge--* family design-tokens.css documents
   as consuming the one status accent vocabulary (--ds-accent-{info,warn,
   success,danger}-*). A plain .badge stays neutral; these tint it so an
   `invalid` model or an `error`-severity constraint reads red, a warning
   amber, an informational chip blue. Retinting any status is a one-token edit
   (system.md: "One status vocabulary, five surfaces"). */
.badge--info    { background: var(--ds-accent-info-bg);    color: var(--ds-accent-info-ink); }
.badge--warn    { background: var(--ds-accent-warn-bg);    color: var(--ds-accent-warn-ink); }
.badge--success { background: var(--ds-accent-success-bg); color: var(--ds-accent-success-ink); }
.badge--danger  { background: var(--ds-accent-danger-bg);  color: var(--ds-accent-danger-ink); }

/* Sprite icons — the design system's one icon seam (#1503). An icon is
   `<svg class="ds-icon"><use href=".../vendor/lucide-sprite.svg#<name>"/></svg>`,
   built by the `ds.icon(name)` macro (_components.html) server-side or
   `iconEl(name)` (static/js/chat_icons.js) client-side. Lucide bodies draw
   with `stroke="currentColor"`, so an icon takes the surrounding text color;
   1em sizing + the -0.125em shift make it sit on the text baseline like a
   glyph would. */
.ds-icon {
  width: 1em;
  height: 1em;
  display: inline-block;
  flex: none;
  vertical-align: -0.125em;
}

/* ─────────────────────────────────────────────────────────────────────────
   Kind tag — "what kind of thing is this row".

   One component, two densities, because the two surfaces that name a kind
   have opposite problems:

     .ds-kindtag           glyph + word. For a list whose rows are of MIXED
                           kind (/admin/access: a package, a plugin and an
                           agent in one group's holdings), where the word is
                           the only thing that says which is which.
     .ds-kindtag--glyph    glyph alone. For a list GROUPED by kind (the
                           Library), where the band overhead already said the
                           word and repeating it on every row is noise.

   Same glyph (js/kind_glyph.js / the kind_glyph() macro), same colour
   (--ds-kind-*), same corner. The label is the variable, not the identity —
   which is what makes a row recognisable as the same kind of thing whichever
   page it is read on.

   Colour arrives through `data-kind`, so a caller sets ONE attribute and gets
   both halves. An unmapped kind falls back to the neutral border and the
   neutral glyph rather than borrowing a colour that means something else. */
.ds-kindtag {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    flex: none;
    padding: 2px 8px 2px 6px;
    border: 1px solid color-mix(in srgb, var(--ds-kindtag, var(--ds-border)) 30%, transparent);
    border-radius: var(--ds-radius-btn);
    background: color-mix(in srgb, var(--ds-kindtag, var(--ds-text-muted)) 8%, var(--ds-surface));
    color: var(--ds-kindtag, var(--ds-text-secondary));
    font-size: 11.5px;
    font-weight: 600;
    line-height: 1.5;
    white-space: nowrap;
}
.ds-kindtag svg { width: 13px; height: 13px; flex: none; }
/* Glyph-only: square, so a row of them reads as a column of icons rather
   than as a column of empty pills. */
.ds-kindtag--glyph {
    gap: 0;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
}
.ds-kindtag--glyph svg { width: 15px; height: 15px; }

.ds-kindtag[data-kind="data"]    { --ds-kindtag: var(--ds-kind-data); }
.ds-kindtag[data-kind="memory"]  { --ds-kindtag: var(--ds-kind-memory); }
.ds-kindtag[data-kind="recipe"]  { --ds-kindtag: var(--ds-kind-recipe); }
.ds-kindtag[data-kind="library"] { --ds-kindtag: var(--ds-kind-library); }
.ds-kindtag[data-kind="file"]    { --ds-kindtag: var(--ds-kind-file); }
.ds-kindtag[data-kind="app"]     { --ds-kindtag: var(--ds-kind-app); }
.ds-kindtag[data-kind="plugin"]  { --ds-kindtag: var(--ds-kind-plugin); }
.ds-kindtag[data-kind="skill"]   { --ds-kindtag: var(--ds-kind-skill); }
.ds-kindtag[data-kind="agent"]   { --ds-kindtag: var(--ds-kind-agent); }

/* A GROUP is the one mark in this set that is deliberately COLOURLESS.
   `--ds-kind-*` is a palette of content types, and a group is not content —
   it is who the content reaches. Left unmapped, `--ds-kindtag` resolves to
   the neutral fallbacks declared above, which is exactly right: in a mixed
   row ("this package, reaching these groups") the coloured half is the thing
   and the neutral half is the audience. Written out rather than left to the
   fallback so the absence reads as a decision, and so nobody closes the
   apparent gap by inventing a --ds-kind-group. */
.ds-kindtag[data-kind="group"] {
    --ds-kindtag: var(--ds-text-secondary);
    background: var(--ds-surface-sunken);
    border-color: var(--ds-border);
}

/* The group mark's second density: the bare shape, for inside something that
   already has a shell — an origin chip, a "via <b>Delivery</b>", a link. The
   26px tile above is for the leading marker of a ROW; a tile inside a pill is
   a box in a box. Sized and nudged to sit on the text's own line. */
.ds-groupglyph {
    display: inline-flex;
    flex: none;
    align-items: center;
    width: 12.5px;
    height: 12.5px;
    vertical-align: -1.5px;
    opacity: .75;
}
.ds-groupglyph svg { width: 100%; height: 100%; }

/* ── Tabs — ONE definition for every secondary tab row ────────────────────
   Four copies of this look had drifted apart: `.tab-strip` in the legacy
   sheet on legacy tokens (People, Access), `.tab-flow__item` here on --ds-
   tokens (Data), and a page-local rewrite in library.html re-underlining a
   pill segmented control (Library). The Data row was the one that looked
   right, so it is the one that stayed — and it now lives here, in the global
   component sheet, because Library is not an admin page and cannot reach
   admin_page.css.

   The FLOW variant differs only in its connectors: arrows between the tabs of
   a pipeline, a rule where the pipeline ends. Those stay in admin_page.css
   with the one section that asks for them (Data). The items themselves are
   the same object everywhere — which is what the flow variant's own comment
   already claimed, before the two definitions diverged.

   `.fbar-seg__btn` appears in the selector list ONLY inside `.tab-strip`:
   the Library's tabs are wired to filter_toolbar.js through that class, so
   the hook stays and the look comes from the strip around it. */
.tab-strip {
    display: flex;
    align-items: stretch;
    flex-wrap: wrap;
    gap: 2px;
    margin: 0 0 18px;
    padding: 0;
    background: none;
    border: 0;
    border-bottom: 1px solid var(--ds-border);
}
.tab-strip__item,
.tab-strip .fbar-seg__btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: auto;
    padding: 9px 14px 10px;
    margin-bottom: -1px;
    font: inherit;
    font-size: 13.5px;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    color: var(--ds-text-secondary);
    background: transparent;
    border: 0;
    border-bottom: 2px solid transparent;
    border-radius: var(--ds-radius-btn) var(--ds-radius-btn) 0 0;
    cursor: pointer;
}
.tab-strip__item:hover,
.tab-strip .fbar-seg__btn:hover {
    background: var(--ds-surface-dim);
    color: var(--ds-text-primary);
}
/* `[aria-selected]` and `[aria-checked]` as well as the class: the three
   strips are variously tablists and a radiogroup, and a tab that looks
   inactive while announcing itself selected is the worse half of that
   mismatch. */
.tab-strip__item.is-active,
.tab-strip__item[aria-selected="true"],
.tab-strip .fbar-seg__btn.is-active,
.tab-strip .fbar-seg__btn[aria-checked="true"] {
    color: var(--ds-primary-dark);
    background: transparent;
    box-shadow: none;
    border-bottom-color: var(--ds-primary);
}
/* The count beside a tab's name. Quieter than the label at rest, and it
   takes the tab's own colour when active rather than a second accent. */
.tab-strip__n,
.tab-strip .fbar-seg__n {
    font-size: 11.5px;
    font-weight: 700;
    color: var(--ds-text-muted);
}
.tab-strip__item.is-active .tab-strip__n,
.tab-strip__item[aria-selected="true"] .tab-strip__n,
.tab-strip .fbar-seg__btn.is-active .fbar-seg__n,
.tab-strip .fbar-seg__btn[aria-checked="true"] .fbar-seg__n {
    color: var(--ds-primary-dark);
}
@media (max-width: 640px) {
    .tab-strip { flex-wrap: nowrap; overflow-x: auto; }
    .tab-strip__item, .tab-strip .fbar-seg__btn { flex: 0 0 auto; }
}

/* ── Page toolbar ────────────────────────────────────────────────────────
   The row of controls under a page's head — a time-range selector, a pair of
   sibling-page links, a primary verb. `base_page.html` wraps `{% block
   toolbar %}` in it, so a page declares WHAT its controls are and never where
   they sit or how far the content below them starts.

   It exists because that block emitted its children bare into the flow, which
   made the gap under it a property of whatever the page happened to put
   there. Three pages wrapped their controls in a private div carrying
   `margin: 0 0 var(--space-5)` (`.aov-bar`, `.slb-meta`, `.adopt-bar`); the
   ones that emitted a control directly — Adoption's window selector, the
   Audit-log links — got no gap at all and their first stat card sat flush
   against the buttons (#1956 item 9).

   It owns the GAP and nothing else — deliberately a plain block, not a flex
   row. A flex row is the tempting version and it is wrong: a toolbar block
   may hold more than one block-level child (semantic_layer_detail.html emits
   its badges AND its tab strip), and making them flex items lays them out
   side by side, which puts a six-item tab strip on the far right of the row
   with its rule spanning only the tabs. As a block wrapper every child keeps
   the layout it had before this existed; each page's own bar keeps its own
   `display: flex` internally.

   `:not(:has(*))` rather than `:empty`: the block renders a newline even when
   a page leaves it undefined, so the box is never truly empty and `:empty`
   would leave 20px of dead air on every page without a toolbar. Zeroing the
   MARGIN rather than setting `display: none` is deliberate too — a toolbar
   that one day emits bare text with no element would still render, where
   `display: none` would silently swallow it. */
.page-toolbar { margin: 0 0 var(--space-5); }
.page-toolbar:not(:has(*)) { margin-block-end: 0; }
