/* Shared gallery components — the small, hand-authored layer the
 * security-posture UI epic (av-jafp: card badge av-isb3, posture popover
 * av-41se, edit-page management av-p0a1) builds on. Explicitly NOT a utility
 * framework: a handful of audited classes over tokens.css (av-xgik). Loaded
 * on every gallery page after tokens.css and before the page sheet, so a
 * page sheet can still override or extend a component.
 *
 * The .btn family, .card surface, and .spacer moved here from the three page
 * stylesheets, where they were triplicated verbatim; values are unchanged. */

/* --- buttons ---------------------------------------------------------- */
.btn{display:inline-flex;align-items:center;gap:var(--space-2);padding:var(--space-3) 18px;background:var(--brand-blue);color:var(--color-panel);border:none;border-radius:var(--radius-md);font-size:14px;cursor:pointer;font-weight:500}
.btn:hover{background:var(--brand-blue-hover)}
.btn-sm{padding:5px var(--space-5);font-size:13px}
.btn-sec{background:var(--color-panel);color:var(--color-ink-soft);border:1px solid var(--color-border)}
.btn-sec:hover{border-color:var(--brand-blue);color:var(--brand-blue);background:var(--color-panel)}
.btn-danger{background:var(--color-danger);color:var(--color-panel);border:none}
.btn-danger:hover{background:var(--color-danger-hover)}
/* Square, label-less .btn — the gallery header's "Add artifact" and profile
 * controls (av-qo05). A modifier rather than a page rule because it is the
 * .btn family's fourth member: it changes the box and nothing else, so it
 * composes with .btn-sec and .btn-danger the way the others do. The side is a
 * labelled .btn's own height, which is what makes an icon-only control a peer
 * of one beside it rather than a smaller afterthought, and a comfortable tap
 * target on a phone. The glyph runs a little larger than body text because it
 * is now carrying the whole meaning; the words live in aria-label/title. */
.icon-btn{width:36px;height:36px;padding:0;justify-content:center;flex:0 0 auto;font-size:17px}
.icon-btn i{line-height:1}
/* A control that is present but cannot act — /profile's delete button until
 * av-4wyq lands. It stays legible rather than ghosted, because the reason
 * beside it is the point and an unreadable control just sends the reader
 * looking for the enabled one that does not exist. The hover rule is what
 * keeps a disabled button from lighting up under the pointer as though it
 * would do something. */
.btn:disabled{opacity:.55;cursor:not-allowed}
.btn:disabled:hover{background:var(--brand-blue)}
.btn-sec:disabled:hover{background:var(--color-panel);border-color:var(--color-border);color:var(--color-ink-soft)}
.btn-danger:disabled:hover{background:var(--color-danger)}

/* --- surfaces --------------------------------------------------------- */
.card{background:var(--color-panel);border-radius:var(--radius-lg);padding:var(--space-6);box-shadow:var(--shadow-card)}

/* --- card widget (av-fafu) --------------------------------------------- */
/* The tile at the top of an artifact card: either a live widget frame from the
 * render origin, or the default monogram tile. Shared by the gallery card and
 * the edit page's widget preview, which is why it lives here — both must show
 * the same box, or "preview" would be a lie.
 *
 * The well bleeds to the card's edges (negative margins cancel .card's padding)
 * and clips to the card's top corners, so the widget reads as the card's face
 * rather than as content pasted inside it. Height is fixed: a tile is a
 * fixed-size surface an author designs for, and letting it grow with content
 * would make a row of cards ragged.
 *
 * pointer-events:none on the frame is the load-bearing rule. It makes the
 * widget non-interactive by construction — clicks, drags, and scrolls all pass
 * through to the card, whose handler opens the artifact — so "the widget is
 * informative, tap it to open the tool" needs no event plumbing to enforce. */
/* The well's own background is the card surface, not the page ground: the
 * frame renders transparent by default, so whatever is behind it IS the tile's
 * background — and a widget that paints nothing must still read as part of the
 * card rather than as a hole cut in it. */
.card-widget{position:relative;height:132px;margin:calc(var(--space-6) * -1) calc(var(--space-6) * -1) 0;border-radius:var(--radius-lg) var(--radius-lg) 0 0;overflow:hidden;background:var(--color-panel);border-bottom:1px solid var(--color-hairline)}
.card-widget-frame{position:absolute;inset:0;z-index:1;display:block;width:100%;height:100%;border:0;background:transparent;pointer-events:none}
/* Default tile: a monogram on a tint derived from the artifact id (--tile-hue
 * comes from the server, so the same artifact always wears the same face). */
.card-widget-default{position:absolute;inset:0;z-index:0;display:flex;align-items:center;justify-content:center;background:linear-gradient(140deg,hsl(var(--tile-hue) 58% 96%),hsl(calc(var(--tile-hue) + 28) 52% 89%))}
/* With a live frame the monogram is a fallback, not a backdrop: widgets render
 * on a transparent background by contract, so leaving it painted underneath
 * would show through the widget. It comes back — and the frame goes — only
 * when the widget fails to report itself healthy (components.js). */
.card-widget.has-frame .card-widget-default{display:none}
.card-widget.has-frame.widget-failed .card-widget-default{display:flex}
.card-widget.has-frame.widget-failed .card-widget-frame{display:none}
.card-widget-monogram{display:flex;align-items:center;justify-content:center;width:56px;height:56px;border-radius:16px;background:hsl(var(--tile-hue) 60% 100% / .72);box-shadow:0 1px 4px hsl(var(--tile-hue) 40% 30% / .16);color:hsl(var(--tile-hue) 42% 34%);font-size:22px;font-weight:600;letter-spacing:.5px}

/* Collapsible section (<details>/<summary>) with a muted summary line — the
 * edit page's security section (av-p0a1) was the first user; the artifact
 * source and gallery widget sections (av-fafu) are the rest, which is why the
 * caret rules below live here keyed on the component rather than on one
 * panel's id.
 *
 * The caret is a real icon (not a UTF-8 triangle) so it stays legible at any
 * size/zoom, and it sits outside the summary's text span so JS that refreshes
 * that text (edit.js renderSecurityPanel) never wipes it out. Two glyphs
 * (caret-right / caret-down) are swapped by [open] rather than rotating one in
 * place: Phosphor's caret-right glyph isn't centered in its em-box, so a
 * transform:rotate(90deg) pivots around the box's geometric center instead of
 * the visible mark's, swinging it off to a corner at an angle. */
.details-panel{background:var(--color-panel);border:1px solid var(--color-hairline);border-radius:var(--radius-md);padding:var(--space-3) var(--space-5)}
.details-panel>summary{cursor:pointer;font-size:13px;color:var(--color-muted);list-style:none;display:flex;align-items:center;gap:var(--space-2)}
.details-panel>summary::-webkit-details-marker{display:none}
.details-caret{flex-shrink:0}
.details-caret-open{display:none}
.details-panel[open]>summary .details-caret-closed{display:none}
.details-panel[open]>summary .details-caret-open{display:inline}
/* The body of an open panel, separated from its summary by a hairline. Shared
 * by all three panels so they open the same way. */
.details-panel>.panel-body{margin-top:var(--space-5);padding-top:var(--space-5);border-top:1px solid var(--color-hairline)}

/* --- controls --------------------------------------------------------- */
/* Floor for controls no rule below names: an unstyled input inherits the UA's
 * ~13.33px, under the zoom threshold just as surely as a chosen 14px. */
input,select,textarea{font-size:var(--field-font-size)}

.field{width:100%;padding:var(--space-3) var(--space-4);border:1px solid var(--color-border);border-radius:var(--radius-md);font-size:var(--field-font-size);outline:none;background:var(--color-panel);color:var(--color-ink)}
.field:focus{border-color:var(--brand-blue)}
.select{padding:7px var(--space-4);border:1px solid var(--color-border);border-radius:var(--radius-md);font-size:var(--field-font-size);outline:none;background:var(--color-panel);color:var(--color-ink)}
.select:focus{border-color:var(--brand-blue)}

/* --- security-posture primitives -------------------------------------- */
/* Inline origin/chip badge — the allowlist badges are the first user. */
.badge{display:inline-block;background:var(--color-ground);padding:1px var(--space-2);border-radius:var(--radius-sm);margin-right:var(--space-1)}

/* One allowlist entry: origin chip plus its remove/allow affordance. */
.allowlist-row{display:flex;align-items:center;gap:var(--space-3);padding:var(--space-2) 0;font-size:13px}
.allowlist-row code{background:var(--color-ground);padding:1px var(--space-2);border-radius:var(--radius-sm)}

/* Small inline posture indicator (icon + optional label) — the gallery card
 * badge (av-isb3) and the popover header (av-41se) build on this. Neutral
 * throughout, no green/amber: the allowlist is transparency, not a verdict
 * (spec 6.2). Sandboxed (no .has-grants) stays fully muted; once a grant
 * exists the cluster reads slightly darker (mid-slate) so the glyphs read as
 * present information rather than a warning. */
.capability-cluster{display:inline-flex;align-items:center;gap:var(--space-3);font-size:12px;color:var(--color-muted);cursor:pointer;border-radius:var(--radius-sm);padding:2px var(--space-2);margin:-2px calc(var(--space-2) * -1);transition:background-color .1s ease,color .1s ease}
.capability-cluster.has-grants{color:var(--color-ink-soft)}
.capability-cluster:hover,.capability-cluster:focus-visible{background-color:var(--color-ground);color:var(--color-ink-soft)}
.capability-cluster .capability-glyph{display:inline-flex;align-items:center;font-size:14px;line-height:1}
.capability-cluster .capability-count{color:var(--color-ink);font-weight:600}

/* capability-wrap positions the popover (av-41se) relative to its trigger.
 * The popover opens only on explicit activation — click/tap, or Enter/Space
 * while the trigger has focus — handled by components.js; it does NOT open
 * on hover or on mere keyboard focus (:focus-within intentionally left out
 * of the visibility rule below). Hovering/focusing the trigger instead shows
 * a plain affordance highlight (background/color change above) signalling
 * it's clickable, without popping content open unasked. The popover stays a
 * plain div (not display:none) so it's always in the a11y/tab tree —
 * visibility is purely visual, gated on .is-open. */
.capability-wrap{position:relative;display:inline-flex}
.capability-popover{position:absolute;top:100%;right:0;margin-top:var(--space-3);z-index:30;width:260px;max-width:80vw;background:var(--color-panel);border:1px solid var(--color-hairline);border-radius:var(--radius-lg);box-shadow:var(--shadow-modal);padding:var(--space-5);font-size:12px;color:var(--color-ink-soft);text-align:left;visibility:hidden;opacity:0;pointer-events:none;transition:opacity .12s ease}
.capability-wrap.is-open .capability-popover{visibility:visible;opacity:1;pointer-events:auto}
.capability-popover-header{font-weight:600;color:var(--color-ink);margin-bottom:var(--space-4)}
.capability-popover-row{display:flex;align-items:flex-start;gap:var(--space-3);margin-bottom:var(--space-4)}
.capability-popover-row:last-child{margin-bottom:0}
.capability-popover-label{color:var(--color-ink);font-weight:600;margin-bottom:var(--space-1)}
.capability-popover-origins code{display:block;background:var(--color-ground);padding:1px var(--space-2);border-radius:var(--radius-sm);margin-top:var(--space-1);font-family:monospace;word-break:break-all}
.capability-popover-manage{display:block;margin-top:var(--space-4);padding-top:var(--space-4);border-top:1px solid var(--color-hairline);color:var(--brand-blue);text-decoration:none}
.capability-popover-manage:hover{text-decoration:underline}

/* --- utilities -------------------------------------------------------- */
.row{display:flex;align-items:center;gap:var(--space-3)}
.spacer{flex:1}
.muted{color:var(--color-muted)}
.faint{color:var(--color-faint)}
.text-sm{font-size:12px}

