/* ============================================================================
   Hub-ONLY components, layered over the SHARED tokens.css.
   ----------------------------------------------------------------------------
   The shared design system (palette, type, topbar, buttons, cards, forms,
   responsive rules) lives in cockpit/apps/shared/tokens.css and is served to
   this app straight from there (config.assets.paths) — ONE file for Hub and
   Cockpit, which is what keeps the two headers identical. This file may only
   hold what exists nowhere in the Cockpit: the nameplate fleet, the Brain
   detail ledger, onboarding, API docs, toasts. A selector that exists in the
   shared file must not reappear here — later-loaded rules would win and the
   drift this file replaced (552 forked lines, two different headers, no phone
   spacing) would quietly return. Guarded by spec/config/shared_tokens_spec.rb.
   ============================================================================ */

/* ---- Hub shell (the one layout thing the Cockpit does not have) ----
   `body.pf { margin: 0 }` moved to the shared tokens.css — the Cockpit needed
   it too (its topbar was floating on an 8px cream margin). */
body.pf-hub { display: flex; flex-direction: column; min-height: 100dvh; }
body.pf-hub .pf-content { flex: 1 0 auto; width: 100%; }

/* ---- shared-header parity: the Sign-out door is a button_to here ---- */
.pf-baract-form { margin: 0; display: contents; }

/* ============================================================================
   SIGNATURE: brushed-metal "nameplate" VM tile (.plate/.rivet/.engr/.lamp/.etch)
   Ported verbatim from F2-reference.html. Only ever used inside tokens.css pages
   (no Tailwind), so the terse class names cannot collide.
   ============================================================================ */
/* auto-fit (not auto-fill) so a lone Brain fills the content column and lines up
   with the full-width hosting card above it — no tiny card marooned on the left.
   min(100%, …) lets the track shrink on mobile instead of overflowing. */
.pf-vm-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 440px), 1fr)); gap: 22px; align-items: start; }

.plate { position: relative; border-radius: 13px; padding: 22px 22px 20px;
  background: linear-gradient(158deg,#E4E6E9,#F4F5F7 34%,#D5D8DD 63%,#EAECEF);
  border: 1px solid #C6CAD0;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.95), inset 0 -2px 3px rgba(0,0,0,.05), 0 14px 30px -20px rgba(28,30,33,.4); }
.plate::after { content: ""; position: absolute; inset: 0; border-radius: 13px; pointer-events: none;
  background: repeating-linear-gradient(94deg,rgba(255,255,255,0) 0 2px,rgba(0,0,0,.02) 2px 3px); }
.rivet { position: absolute; width: 7px; height: 7px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%,#fff,#aeb4bc 55%,#7f858e); box-shadow: 0 1px 1px rgba(0,0,0,.3); }
.rivet.tl { top: 9px; left: 9px; } .rivet.tr { top: 9px; right: 9px; }
.rivet.bl { bottom: 9px; left: 9px; } .rivet.br { bottom: 9px; right: 9px; }
.pl-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; position: relative; z-index: 1; padding: 0 6px; }
.engr { font-family: var(--pf-disp); font-weight: 700; font-size: 20px; letter-spacing: .01em; color: #232830;
  text-shadow: 0 1px 0 rgba(255,255,255,.9), 0 -1px 0 rgba(0,0,0,.1); }
.engr-link { text-decoration: none; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.engr-link:hover, .engr-link:focus-visible { color: var(--pf-navy); text-decoration: underline; text-underline-offset: 3px; }

/* The serial stamped under the nameplate: our id + Hetzner's, always visible. */
.pl-ids { position: relative; z-index: 1; display: flex; flex-wrap: wrap; gap: 6px 12px; margin-top: 8px; padding: 0 6px; }
.pl-id { font-family: var(--pf-mono); font-size: 10.5px; letter-spacing: -.01em; color: #6b717a;
  text-transform: uppercase; white-space: nowrap; }
.pl-id b { color: #3c424b; font-weight: 600; text-transform: none; user-select: all; }

.lamp { display: inline-flex; align-items: center; gap: 7px; font-family: var(--pf-sans); font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .05em; color: #4a5058; white-space: nowrap; }
.lamp .b { width: 10px; height: 10px; border-radius: 50%; flex: none; }
.lamp.live .b { background: var(--pf-green); box-shadow: 0 0 0 3px var(--pf-mint), 0 0 6px rgba(39,79,66,.5); }
.lamp.cast .b { background: var(--pf-warn); box-shadow: 0 0 0 2px rgba(180,115,42,.22), 0 0 7px var(--pf-warn); }
.lamp.dead .b { background: var(--pf-bad); box-shadow: 0 0 0 2px rgba(178,58,58,.2); }
.etch { position: relative; z-index: 1; margin-top: 14px; padding: 12px 14px; border-radius: 8px;
  background: rgba(18,47,77,.06); box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
  display: grid; grid-template-columns: 1fr 1fr; gap: 6px 14px; }
.etch div { font-family: var(--pf-mono); font-size: 11.5px; color: #3c424b; overflow: hidden; text-overflow: ellipsis; }
.etch b { color: var(--pf-navy); font-weight: 600; }

/* CEO health verdict — the plain-language green/orange reading that leads the
   active plate. Technical signals + controls hide under .pl-tech below it. */
.pl-health { position: relative; z-index: 1; margin-top: 16px; display: flex; align-items: flex-start; gap: 11px;
  padding: 14px 16px; border-radius: 9px; border: 1px solid transparent;
  background: rgba(18,47,77,.05); box-shadow: inset 0 1px 2px rgba(0,0,0,.06); }
.pl-health-dot { flex: none; width: 11px; height: 11px; margin-top: 3px; border-radius: 50%;
  background: var(--pf-faint); }
.pl-health-copy { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pl-health-copy strong { font-family: var(--pf-sans); font-size: 13.5px; font-weight: 650; color: var(--pf-navy); }
.pl-health-detail { font-family: var(--pf-sans); font-size: 12px; color: #5a616b; line-height: 1.4; }
.pl-health.is-green  { background: color-mix(in srgb, var(--pf-ok) 9%, #fff); border-color: color-mix(in srgb, var(--pf-ok) 26%, transparent); }
.pl-health.is-green  .pl-health-dot { background: var(--pf-ok); box-shadow: 0 0 0 3px color-mix(in srgb, var(--pf-ok) 20%, transparent); }
.pl-health.is-orange { background: color-mix(in srgb, var(--pf-warn) 11%, #fff); border-color: color-mix(in srgb, var(--pf-warn) 32%, transparent); }
.pl-health.is-orange .pl-health-dot { background: var(--pf-warn); box-shadow: 0 0 0 3px color-mix(in srgb, var(--pf-warn) 22%, transparent); }
.pl-health.is-orange .pl-health-copy strong { color: var(--pf-warn); }
.pl-health.is-red    { background: color-mix(in srgb, var(--pf-bad) 10%, #fff); border-color: color-mix(in srgb, var(--pf-bad) 30%, transparent); }
.pl-health.is-red    .pl-health-dot { background: var(--pf-bad); box-shadow: 0 0 0 3px color-mix(in srgb, var(--pf-bad) 20%, transparent); }
.pl-health.is-red    .pl-health-copy strong { color: var(--pf-bad); }
.pl-health.is-setup  .pl-health-dot { background: var(--pf-faint); }

/* The web server's IP — the one thing a CEO needs, to forward a domain at. */
.ws-addr { position: relative; z-index: 1; margin-top: 12px; padding: 12px 14px; border-radius: 10px;
  background: linear-gradient(180deg, #fff, #f4f6f8); border: 1px solid var(--pf-line);
  display: flex; flex-direction: column; gap: 2px; }
.ws-addr-label { font-family: var(--pf-sans); font-size: 11px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--pf-faint); }
.ws-addr-ip { font-family: var(--pf-mono); font-size: 20px; font-weight: 600; color: var(--pf-navy);
  letter-spacing: .01em; user-select: all; }
.ws-addr-hint { font-family: var(--pf-sans); font-size: 11.5px; color: var(--pf-faint); }

/* Cockpit "your custom URL" banner — the customer's live hosting address. */
.pf-url-card { padding: 18px 20px; border-radius: var(--pf-radius); border: 1px solid var(--pf-line);
  background: linear-gradient(180deg, #fff, #f4f6f8); }
.pf-url-label { margin: 4px 0 2px; font-size: 15px; color: var(--pf-ink); }
.pf-url-value { display: inline-block; font-family: var(--pf-mono); font-size: 24px; font-weight: 700;
  color: var(--pf-navy); letter-spacing: .01em; text-decoration: none; word-break: break-all; }
.pf-url-value:hover { text-decoration: underline; }

.pl-tech { position: relative; z-index: 1; margin-top: 16px; }
.pl-tech > summary { list-style: none; cursor: pointer; user-select: none;
  font-family: var(--pf-sans); font-size: 11.5px; font-weight: 500; color: #6b7079;
  display: inline-flex; align-items: center; gap: 6px; padding: 3px 2px; }
.pl-tech > summary::-webkit-details-marker { display: none; }
.pl-tech > summary::before { content: "▸"; font-size: 10px; transition: transform .15s ease; }
.pl-tech[open] > summary::before { transform: rotate(90deg); }
.pl-tech > summary:hover { color: var(--pf-navy); }
.pl-more { position: relative; z-index: 1; margin-top: 16px; padding-top: 14px; border-top: 1px solid rgba(18,47,77,.10); }
.pl-more-link { font-family: var(--pf-sans); font-size: 12px; font-weight: 600; color: var(--pf-navy);
  text-decoration: none; display: inline-flex; align-items: center; gap: 5px; }
.pl-more-link:hover { text-decoration: underline; text-underline-offset: 3px; }

.pl-acts { position: relative; z-index: 1; display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.plate .pf-btn, .plate form { margin: 0; }
/* On a tile plate the component runs small — same recipe, tile-scale.
   SIZE only: this rule outranks every variant (two classes beat one), so a
   `color` here repaints them all — it turned the navy-filled primary into
   navy-on-navy, an unreadable blank pill (owner report, 2026-08-03). Each
   variant keeps its own text color from tokens.css. */
.plate .pf-btn { min-height: 0; font-size: 12px; font-weight: 500;
  border-radius: 8px; padding: 7px 12px; }

/* ---- per-Brain detail page: the plate, unfolded ---------------------------
   A key/value ledger in the plate's own etched vocabulary. `auto-fit` collapses
   to one column on a phone with no media query. Hairlines come from each cell's
   1px shadow, not the container's background — a part-filled last row must end
   in a clean edge, not a grey block. */
.pf-kv { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1px;
  background: var(--pf-surface); border: 1px solid var(--pf-line); border-radius: var(--pf-radius); overflow: hidden; }
.pf-kv > div { background: var(--pf-surface); padding: 13px 15px; min-width: 0;
  box-shadow: 0 0 0 1px var(--pf-line); }
.pf-kv dt { font-family: var(--pf-sans); font-size: 11px; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--pf-faint); margin: 0 0 5px; }
.pf-kv dd { margin: 0; font-size: 14px; color: var(--pf-ink); overflow-wrap: anywhere; }
.pf-kv dd.pf-mono { font-size: 12.5px; user-select: all; }
.pf-kv dd.is-empty { color: var(--pf-faint); }

/* The detail page's traffic light — the same verdict the plate leads with,
   sized up. Colours come from .pl-health.is-* above; only the scale changes. */
.pf-verdict { display: flex; align-items: flex-start; gap: 13px; padding: 16px 18px;
  border-radius: var(--pf-radius); border: 1px solid transparent; }
.pf-verdict .pl-health-copy strong { font-size: 16px; }
.pf-verdict .pl-health-detail { font-size: 13px; }
.pf-verdict .pl-health-dot { width: 13px; height: 13px; margin-top: 4px; }

/* ---- "forge" primary action (navy pill w/ anvil glyph) ---- */

/* ---- secret reveal (SSH private key) ---- */
.pf-secret { filter: blur(5px); transition: filter .15s ease; user-select: none; }
.pf-secret.is-revealed { filter: none; user-select: text; }
.pf-key-actions { display: flex; align-items: center; gap: 8px; margin-top: 6px; }

/* ---- onboarding gate steps ---- */
.pf-steps { display: flex; flex-direction: column; gap: 10px; }
.pf-step { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border: 1px solid var(--pf-line); border-radius: var(--pf-radius-sm); background: var(--pf-paper); }
.pf-step .pf-step-num { width: 24px; height: 24px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; background: var(--pf-line); color: var(--pf-muted); flex: none; }
.pf-step.is-done .pf-step-num { background: var(--pf-mint); color: var(--pf-green); }
.pf-step .pf-step-body { flex: 1; min-width: 0; }
.pf-empty { color: var(--pf-muted); border: 1px dashed var(--pf-line-2); border-radius: var(--pf-radius); padding: 22px; text-align: center; }

/* ---- base-image build progress rail ---- */
.pf-phases { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.pf-phase { position: relative; display: inline-flex; align-items: center; gap: 7px; padding: 4px 11px 4px 10px; border-radius: 999px; font-size: 11.5px; font-weight: 600; font-family: var(--pf-mono); border: 1px solid var(--pf-line); color: var(--pf-muted); background: var(--pf-paper); }
.pf-phase::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }
.pf-phase.is-done   { color: var(--pf-ok);   background: color-mix(in srgb, var(--pf-ok) 10%, transparent); border-color: color-mix(in srgb, var(--pf-ok) 30%, transparent); }
.pf-phase.is-active { color: var(--pf-warn); background: color-mix(in srgb, var(--pf-warn) 12%, transparent); border-color: color-mix(in srgb, var(--pf-warn) 35%, transparent); }
.pf-phase.is-active::before { animation: pf-phase-pulse 1.1s ease-in-out infinite; }
@keyframes pf-phase-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
@media (prefers-reduced-motion: reduce) { .pf-phase.is-active::before { animation: none; } }

/* ============================================================================
   Craftsman layer — tactile refinements for the nameplate fleet.
   Casting lifecycle (molten plate → cooled), breathing lamps, glint sweeps,
   in-flight button states, plaque onboarding, token-styled toasts.
   ============================================================================ */

/* -- lamps: breathing when live, pulsing while casting ---------------------- */
.lamp.live .b { animation: pf-lamp-breathe 3.2s ease-in-out infinite; }
@keyframes pf-lamp-breathe {
  0%, 100% { box-shadow: 0 0 0 3px var(--pf-mint), 0 0 6px rgba(39,79,66,.5); }
  50%      { box-shadow: 0 0 0 4px var(--pf-mint), 0 0 12px rgba(39,79,66,.75); }
}
.lamp.cast .b { animation: pf-lamp-cast 1.4s ease-in-out infinite; }
@keyframes pf-lamp-cast {
  0%, 100% { box-shadow: 0 0 0 2px rgba(180,115,42,.22), 0 0 7px var(--pf-warn); }
  50%      { box-shadow: 0 0 0 3px rgba(180,115,42,.34), 0 0 12px var(--pf-warn); }
}

/* -- online plate: slow glint sweep across the brushed metal ---------------- */
.glint { position: absolute; inset: 0; border-radius: 13px; overflow: hidden; pointer-events: none; z-index: 1; }
.glint::after { content: ""; position: absolute; top: -40%; bottom: -40%; left: 0; width: 34%;
  background: linear-gradient(100deg, rgba(255,255,255,0) 0%, rgba(255,255,255,.5) 48%, rgba(255,255,255,0) 100%);
  transform: translateX(-140%) skewX(-14deg); animation: pf-glint 9s ease-in-out infinite; }
@keyframes pf-glint {
  0%   { transform: translateX(-140%) skewX(-14deg); }
  16%  { transform: translateX(440%) skewX(-14deg); }
  100% { transform: translateX(440%) skewX(-14deg); }
}

/* -- casting plate: molten placeholder, engraving still cooling ------------- */
.plate.casting { animation: pf-molten 2.6s ease-in-out infinite;
  border-color: color-mix(in srgb, var(--pf-warn) 42%, #C6CAD0); }
@keyframes pf-molten {
  0%, 100% { box-shadow: inset 0 1px 0 rgba(255,255,255,.95), inset 0 -2px 3px rgba(0,0,0,.05),
             0 14px 30px -20px rgba(28,30,33,.4), 0 0 0 1px rgba(180,115,42,.18), 0 0 18px -2px rgba(180,115,42,.28); }
  50%      { box-shadow: inset 0 1px 0 rgba(255,255,255,.95), inset 0 -2px 3px rgba(0,0,0,.05),
             0 14px 30px -20px rgba(28,30,33,.4), 0 0 0 1px rgba(180,115,42,.32), 0 0 30px 0 rgba(180,115,42,.42); }
}
.plate.casting .engr { filter: blur(.7px); opacity: .62; }
.cast-copy { position: relative; z-index: 1; margin-top: 14px; padding: 12px; border-radius: 8px;
  background: rgba(180,115,42,.07); box-shadow: inset 0 1px 2px rgba(0,0,0,.08);
  font-family: var(--pf-mono); font-size: 11.5px; color: #7a5a30; }
.cast-copy .dots::after { content: ""; display: inline-block; width: 1.2em; text-align: left;
  animation: pf-dots 1.6s steps(4, end) infinite; }
@keyframes pf-dots { 0% { content: ""; } 25% { content: "."; } 50% { content: ".."; } 75% { content: "..."; } }

/* mini casting rail: Pour ▸ Cool ▸ Stamp ▸ Ready */
.cast-rail { list-style: none; display: flex; align-items: center; gap: 6px; margin: 10px 0 0; padding: 0; }
.cast-rail li { display: inline-flex; align-items: center; gap: 5px; font-family: var(--pf-mono); font-size: 10.5px;
  font-weight: 600; letter-spacing: .02em; color: var(--pf-faint); }
.cast-rail li::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
.cast-rail .sep { color: #b9bec5; font-size: 9px; }
.cast-rail .sep::before { display: none; }
.cast-rail li.done { color: var(--pf-ok); }
.cast-rail li.active { color: var(--pf-warn); }
.cast-rail li.active::before { animation: pf-phase-pulse 1.1s ease-in-out infinite; box-shadow: 0 0 6px var(--pf-warn); }

/* -- button lifecycle: rest → pressed/in-flight → success -------------------- */

/* -- attention plate: highlighted etch row + friendly inline hint ------------ */
.etch div.etch-alert { color: var(--pf-bad); background: color-mix(in srgb, var(--pf-bad) 9%, transparent);
  margin: -2px -6px; padding: 2px 6px; border-radius: 5px;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pf-bad) 22%, transparent); }
.etch div.etch-alert b { color: var(--pf-bad); }
.plate-hint { position: relative; z-index: 1; display: flex; align-items: center; gap: 8px; margin-top: 10px;
  padding: 8px 11px; border-radius: 8px; font-size: 12px; color: #8a3030;
  background: color-mix(in srgb, var(--pf-bad) 7%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pf-bad) 20%, transparent); }
.plate-hint svg { width: 13px; height: 13px; flex: none; }
.plate-hint b { font-weight: 600; }
/* A recommendation, not a fault: amber, and it sits on the face of the plate
   rather than inside "Technical details", because the owner is the one who
   decides when to act on it. Nothing is broken, so nothing is red. */
.plate-hint.is-advice { align-items: flex-start; color: #7a4d17; line-height: 1.45;
  background: color-mix(in srgb, var(--pf-warn) 8%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pf-warn) 24%, transparent); }
.plate-hint.is-advice svg { margin-top: 2px; }
.plate-hint.is-advice strong { display: block; font-weight: 600; margin-bottom: 1px; }
/* On the detail page it sits under the full-width verdict, where a 12px line run
   across the whole viewport is unreadable. Match the verdict's weight and hold
   the measure to something the eye can track. */
.pf-verdict + .plate-hint.is-advice { font-size: 13px; padding: 11px 14px; }
.pf-verdict + .plate-hint.is-advice span { max-width: 78ch; }

/* -- commissioning plaque: engraved onboarding ------------------------------- */
.plaque { position: relative; background: var(--pf-surface); border: 1px solid var(--pf-line); border-radius: var(--pf-radius);
  padding: 24px 26px 22px; box-shadow: 0 14px 30px -24px rgba(28,30,33,.35), inset 0 0 0 1px rgba(255,255,255,.7); }
.plaque::before { content: ""; position: absolute; inset: 7px; border-radius: 8px; pointer-events: none;
  border: 1px solid var(--pf-line); opacity: .8; }
.plaque-head { display: flex; align-items: baseline; gap: 12px; margin-bottom: 16px; position: relative; }
.plaque-head .pf-h2 { margin: 0; }
.plaque-head .rule { flex: 1; height: 1px; background: linear-gradient(90deg, var(--pf-line-2), rgba(213,216,221,0)); margin-bottom: 4px; }
.pf-step.is-done { background: linear-gradient(180deg, #FDFCF9, var(--pf-paper)); }
.pf-step.is-done .pf-step-body strong { color: var(--pf-muted); text-shadow: 0 1px 0 rgba(255,255,255,.85); }
.pf-step.is-done .pf-step-num { box-shadow: inset 0 1px 2px rgba(39,79,66,.28), 0 1px 0 rgba(255,255,255,.9); }
.pf-step.is-active { border-color: color-mix(in srgb, var(--pf-warn) 32%, var(--pf-line)); background: var(--pf-surface); }
.pf-step.is-active .pf-step-num { background: color-mix(in srgb, var(--pf-warn) 15%, #fff); color: var(--pf-warn);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pf-warn) 35%, transparent); }

/* active build phase: soft shimmer travelling through the pill */
.pf-phase.is-active { overflow: hidden; }
.pf-phase.is-active::after { content: ""; position: absolute; inset: 0; border-radius: 999px;
  background: linear-gradient(100deg, rgba(180,115,42,0) 20%, rgba(180,115,42,.14) 50%, rgba(180,115,42,0) 80%);
  transform: translateX(-100%); animation: pf-phase-shimmer 2.2s ease-in-out infinite; }
@keyframes pf-phase-shimmer { 0% { transform: translateX(-100%); } 60%, 100% { transform: translateX(100%); } }

/* indeterminate hairline progress under the build rail */
.pf-progress { position: relative; height: 3px; margin-top: 12px; border-radius: 999px; overflow: hidden;
  background: color-mix(in srgb, var(--pf-warn) 12%, transparent); max-width: 430px; }
.pf-progress::after { content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 36%; border-radius: 999px;
  background: linear-gradient(90deg, rgba(180,115,42,.15), var(--pf-warn), rgba(180,115,42,.15));
  animation: pf-rail-run 1.8s cubic-bezier(.45,.1,.55,.9) infinite; }
@keyframes pf-rail-run { 0% { transform: translateX(-110%); } 100% { transform: translateX(390%); } }

/* -- toasts: the one flash system -------------------------------------------- */
/* Below the bar, never on it: at top:18px the toast parked exactly over the
   brand and the My Foundry door for its whole lifetime — the owner sent the
   screenshot back with "komplett overlapped" (2026-07-29). The bar is 72px
   (56px on phones); the toast clears it on both. */
.pf-toast { position: fixed; top: 84px; left: 50%; transform: translateX(-50%); z-index: 60;
  display: flex; align-items: center; gap: 9px; max-width: min(92vw, 560px);
  background: var(--pf-surface); border: 1px solid var(--pf-line-2); border-radius: 10px;
  padding: 10px 16px; font: 500 13.5px/1.4 var(--pf-sans); color: var(--pf-ink);
  box-shadow: 0 18px 40px -18px rgba(28,30,33,.5);
  animation: pf-toast-in .25s ease-out both;
  transition: opacity .3s ease, transform .3s ease; }
.pf-toast::before { content: ""; width: 8px; height: 8px; border-radius: 50%; flex: none; }
.pf-toast-ok::before  { background: var(--pf-ok);  box-shadow: 0 0 0 3px color-mix(in srgb, var(--pf-ok) 18%, transparent); }
.pf-toast-bad::before { background: var(--pf-bad); box-shadow: 0 0 0 3px color-mix(in srgb, var(--pf-bad) 16%, transparent); }
.pf-toast-bad { border-color: color-mix(in srgb, var(--pf-bad) 35%, var(--pf-line-2)); }
.pf-toast.is-dismissed { opacity: 0; transform: translateX(-50%) translateY(-10px); }
@keyframes pf-toast-in { from { opacity: 0; transform: translateX(-50%) translateY(-8px); } }
.pf-toast + .pf-toast { top: 132px; }

/* Phone: the toast goes to the BOTTOM.
   Floating it at the top could only ever cover something — first it sat ON the
   bar (brand and My Foundry door unreadable, owner screenshot 2026-07-29), and
   moved below the bar it covered the first card's heading instead. A 390px
   column has no free top strip. Bottom is also where a phone user expects a
   transient confirmation (iOS toast, Android snackbar) and where the thumb
   already is. It clears the safe area and never touches the header. */
@media (max-width: 760px) {
  .pf-toast {
    top: auto;
    bottom: calc(16px + env(safe-area-inset-bottom));
    left: 12px;
    right: 12px;
    transform: none;
    max-width: none;
  }
  .pf-toast + .pf-toast { top: auto; bottom: calc(74px + env(safe-area-inset-bottom)); }
  /* The shared entry/exit keyframes carry translateX(-50%) for the centred
     desktop toast; on the phone the box is left/right-anchored, so it rises
     instead of sliding down out of a centre it no longer has. */
  .pf-toast { animation-name: pf-toast-in-bottom; }
  .pf-toast.is-dismissed { transform: translateY(10px); }
}

@media (prefers-reduced-motion: reduce) {
  .lamp.live .b, .lamp.cast .b, .glint::after, .plate.casting, .cast-rail li.active::before,
  .cast-copy .dots::after, .pf-phase.is-active::after, .pf-progress::after, .spin, .pf-toast { animation: none; }
}

/* ---- API docs (/api/docs) ---- */
.pf-code { background: var(--pf-surface-2); border: 1px solid var(--pf-line); border-radius: var(--pf-radius-sm);
           padding: 12px 14px; margin: 10px 0 0; font-family: var(--pf-mono); font-size: 12.5px;
           line-height: 1.6; color: var(--pf-ink); overflow-x: auto; white-space: pre; }
.pf-endpoint { display: flex; align-items: baseline; gap: 10px; font-family: var(--pf-mono); font-size: 14px; }
.pf-method { font-family: var(--pf-sans); font-size: 11.5px; font-weight: 700; letter-spacing: .1em;
             color: var(--pf-navy); background: color-mix(in srgb, var(--pf-navy) 10%, transparent);
             border-radius: 6px; padding: 2px 8px; }
.pf-docs-table { width: 100%; border-collapse: collapse; font-size: 13px; margin-top: 10px; }
.pf-docs-table th, .pf-docs-table td { text-align: left; padding: 7px 12px 7px 0;
             border-bottom: 1px solid var(--pf-line); vertical-align: top; }
.pf-docs-table th { font-size: 11.5px; font-weight: 600; text-transform: uppercase;
             letter-spacing: .12em; color: var(--pf-faint); }

/* ---- "Advanced" disclosure (Brain detail page) ----
   Collapsed by default: a quiet mono summary in the page's footer voice; the
   body only exists once opened. Deliberately undersells what's inside. */
.pf-adv { margin-top: 26px; }
.pf-adv > summary { cursor: pointer; font-family: var(--pf-mono); font-size: 12px;
                    color: var(--pf-faint); user-select: none; width: fit-content; }
.pf-adv > summary:hover { color: var(--pf-muted); }
.pf-adv-body { margin-top: 12px; background: var(--pf-surface); border: 1px solid var(--pf-line);
               border-radius: var(--pf-radius); padding: 18px 20px; }

/* ---- the model, and the switch ----
   The owner asked to see whether Opus or Fable is doing the work. The label is
   read from the transcript (what ran), never from the config (what was asked
   for) — those disagree the moment somebody types /model. */
.pf-model { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pf-model-now { font-weight: 600; }
.pf-model-swap { display: flex; gap: 6px; flex-wrap: wrap; }

/* ---- plain data table (settings: usage, keys) — the docs-table skin ---- */
.pf-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.pf-table th, .pf-table td { text-align: left; padding: 7px 12px 7px 0;
             border-bottom: 1px solid var(--pf-line); vertical-align: top; }
.pf-table th { font-size: 11.5px; font-weight: 600; text-transform: uppercase;
             letter-spacing: .12em; color: var(--pf-faint); }

/* ---- phone ---- */
@media (max-width: 760px) {
  /* At 24px the default hostname breaks mid-word ("primef / oundry.ai"). */
  .pf-url-value { font-size: 16px; overflow-wrap: anywhere; }
  /* Wide tables scroll in place rather than pushing the page sideways. */
  .pf-table-scroll { overflow-x: auto; }
}

/* ---- the door row (settings hero): chat first, boards second ---- */
.pf-door-row { display: flex; gap: 10px; flex-wrap: wrap; }
@media (max-width: 760px) {
  /* One thumb, one door: the buttons take the full card width and stack. */
  .pf-door-row { flex-direction: column; }
  .pf-door-row .pf-btn { width: 100%; justify-content: center; min-height: 46px; box-sizing: border-box; }
}

/* ---- phone bar: the Hub's labels are longer than the Cockpit's ----
   "Prime Foundry" + "My Foundry" + "Sign out" outgrow a 390px bar with the
   desktop paddings and pill icons. The icons go first (the words are the
   affordance), then the paddings tighten. Scoped to the Hub: the Cockpit's
   shorter labels fit as they are, and its bar stays untouched. */
@media (max-width: 760px) {
  body.pf-hub .pf-bar { gap: 8px; }
  body.pf-hub .pf-acct-plain .pf-baract svg { display: none; }
  body.pf-hub .pf-baract { padding: 8px 9px; font-size: 12.5px; }
}

/* The Cockpit chat page moved the phone match-count into the search BAR
   ("3/12") and hides the meta row; the Hub Desk keeps the classic meta row —
   its bar has no counter to take over. */
@media (max-width: 900px) {
  body.pf-hub .chat-search-meta { display: flex; }
  body.pf-hub .chat-search-meta[hidden] { display: none; }
}

@keyframes pf-toast-in-bottom { from { opacity: 0; transform: translateY(10px); } }
