/* ─────────────── Topbar (overhauled 2026-09-28) ───────────────
   Direction: "hearthside instrument panel" — the app's dark violet glass,
   with the painted wood-and-brass icon set (renderer/icons/topbar/, same hand
   as the right-click menu's renderer/icons/menu/) and ember for anything that
   wants attention. Loaded after styles.css and scoped to .topbar, so it only
   restyles the bar; the popovers' own look lives where it always did.

   Vocabulary (markup: index.html, behaviour: topbar.js):
     .tb-group   glass capsule of related controls, 38px tall
     .tb-btn     32px control inside a capsule, painted 22px icon
     .tb-reveal  its label slides out inline on hover / keyboard focus
     .tb-menu    a dropdown: .tb-trigger + .tb-pop (painted 28px icons, 44px rows)
   Every top-level item (search, Add, capsules, Steam account) is 38px tall. */

.topbar {
  --tb-h: 38px;
  --tb-inner: 32px;
  --tb-glass: rgba(255, 255, 255, .028);
  --tb-glass-hover: rgba(255, 255, 255, .07);
  --tb-ember: #f59e0b;
  --tb-ember-soft: rgba(245, 158, 11, .14);
  --tb-live: #34d399;
  --tb-live-soft: rgba(52, 211, 153, .13);
  --tb-alarm: #f87171;
  --tb-alarm-soft: rgba(248, 113, 113, .14);
  --tb-pop-bg: rgba(15, 17, 23, .97);
  padding-top: 11px;
  padding-bottom: 11px;
}
.topbar .search { height: var(--tb-h); padding-top: 0; padding-bottom: 0; }

.topbar-actions { gap: 8px; }

/* The web-only reveal rule (styles.css) is `!important` at (0,2,2), which beat
   `.hidden` — so every hidden web-only pill (Mute, Downloads, Rips) was drawn
   on the web whether or not it had anything to say. Hidden means hidden. */
body.hearth-web .topbar .web-only.hidden,
.topbar .tb-empty { display: none !important; }

/* ── Primary: Add ──
   The one control that wants attention, so it takes the bar's attention colour
   (ember) instead of the old purple→cyan gradient pill that belonged to no
   other part of the bar. Painted wood-and-brass plaque icon, same hand as every
   capsule icon; an ember-lit glass capsule the same height as its neighbours. */
.topbar-actions .btn.primary {
  height: var(--tb-h);
  padding: 0 16px 0 13px;
  gap: 7px;
  border-radius: calc(var(--tb-h) / 2);
  font-size: 13px;
}
.topbar-actions .btn.primary.tb-add {
  padding: 0 16px 0 7px;
  gap: 8px;
  border: 1px solid rgba(245, 158, 11, .55);
  background:
    radial-gradient(90px 38px at 20% 0%, rgba(253, 186, 116, .28), transparent 70%),
    linear-gradient(180deg, rgba(245, 158, 11, .24) 0%, rgba(180, 83, 9, .16) 100%);
  background-size: auto;
  color: #fde7c0;
  font-weight: 700;
  letter-spacing: .2px;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .55);
  box-shadow:
    inset 0 1px 0 rgba(255, 237, 213, .16),
    inset 0 -1px 0 rgba(0, 0, 0, .25),
    0 2px 10px rgba(245, 158, 11, .18);
  transition: border-color .2s, box-shadow .2s, background .2s, transform .08s ease;
}
.topbar-actions .btn.primary.tb-add::before { display: none; }   /* the old glossy sheen */
.topbar-actions .btn.primary.tb-add .tb-add-ico {
  width: 26px;
  height: 26px;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .6));
  transition: transform .28s cubic-bezier(.3, 1.6, .5, 1), filter .2s;
}
.topbar-actions .btn.primary.tb-add:hover,
.topbar-actions .btn.primary.tb-add:focus-visible,
.topbar-actions .btn.primary.tb-add[aria-expanded="true"] {
  border-color: rgba(251, 191, 36, .9);
  background:
    radial-gradient(90px 38px at 20% 0%, rgba(253, 186, 116, .38), transparent 70%),
    linear-gradient(180deg, rgba(245, 158, 11, .34) 0%, rgba(180, 83, 9, .22) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 237, 213, .22),
    inset 0 -1px 0 rgba(0, 0, 0, .25),
    0 4px 18px rgba(245, 158, 11, .34);
  filter: none;
}
.topbar-actions .btn.primary.tb-add:focus-visible { outline: 2px solid var(--tb-ember); outline-offset: 2px; }
.topbar-actions .btn.primary.tb-add:hover .tb-add-ico,
.topbar-actions .btn.primary.tb-add:focus-visible .tb-add-ico {
  transform: rotate(-9deg) scale(1.12);
  filter: drop-shadow(0 2px 6px rgba(245, 158, 11, .55));
}
.topbar-actions .btn.primary.tb-add:active { transform: translateY(1px); }
@media (prefers-reduced-motion: reduce) {
  .topbar-actions .btn.primary.tb-add,
  .topbar-actions .btn.primary.tb-add .tb-add-ico { transition: none; }
}

/* ── Capsules ── */
.tb-group {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  height: var(--tb-h);
  padding: 2px;
  border-radius: calc(var(--tb-h) / 2);
  background: var(--tb-glass);
  border: 1px solid var(--border);
  /* No backdrop-filter here: it would make the capsule the containing block of
     the fixed-position dropdowns inside it (they would be placed relative to
     the capsule and land off-screen). The bar behind it is already blurred. */
  -webkit-app-region: no-drag;
  flex: 0 0 auto;
}
.tb-group > .tb-menu,
.tb-group > .autolock-wrap,
.tb-group > .narrator-orb-wrap { display: inline-flex; position: relative; }

/* ── Controls inside a capsule ──
   Resets the three older looks that used to share this bar (standalone
   bordered pill, action-group pill, gradient narrator orb) to one. */
.topbar .tb-btn.btn.icon-pill,
.topbar .autolock-wrap > .btn.icon-pill.tb-btn,
.topbar .narrator-orb.tb-btn {
  height: var(--tb-inner);
  min-width: var(--tb-inner);
  width: auto;
  padding: 0 5px;
  gap: 0;
  border: 0;
  border-radius: calc(var(--tb-inner) / 2);
  background: transparent;
  box-shadow: none;
  color: var(--text-dim);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  animation: none;
  filter: none;
  transform: none;
}
.topbar .tb-btn.btn.icon-pill:hover,
.topbar .tb-btn.btn.icon-pill:focus-visible,
.topbar .tb-btn.btn.icon-pill[aria-expanded="true"],
.topbar .autolock-wrap > .btn.icon-pill.tb-btn:hover,
.topbar .narrator-orb.tb-btn:hover {
  background: var(--tb-glass-hover);
  color: var(--text);
}
.topbar .tb-btn.btn.icon-pill:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.topbar .tb-btn:active { transform: translateY(1px); }

.topbar .tb-ico {
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
  object-fit: contain;
  pointer-events: none;
  user-select: none;
  filter: drop-shadow(0 1px 1.5px rgba(0, 0, 0, .55));
  transition: transform .22s cubic-bezier(.4, 0, .2, 1), filter .22s;
}
.topbar .tb-btn:hover .tb-ico,
.topbar .tb-btn:focus-visible .tb-ico {
  transform: translateY(-1px) scale(1.08);
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .55)) drop-shadow(0 0 6px rgba(245, 158, 11, .28));
}

/* Real services wear their own logo (Patreon, Moonlight), not a painted
   stand-in. A flat mark fills its box edge to edge where the painted icons
   carry their own margin, so it is inset a touch to sit at the same weight. */
.topbar .tb-ico.tb-brand,
.tb-pop .tb-ico.tb-brand { padding: 2px; box-sizing: border-box; }
.topbar .tb-btn .tb-ico.tb-brand { padding: 2.5px; }

/* Labels: only .tb-reveal controls slide theirs out. The others (Settings,
   Narrator, Window, Mute at rest) are read by their icon + tooltip. A state
   worth seeing — Mute on, an automation off — pins its label open (below). */
.topbar .tb-btn .label { font-size: 12.5px; font-weight: 600; letter-spacing: .1px; }
.topbar .tb-btn:not(.tb-reveal):not([aria-pressed="true"]) .label { display: none; }
.topbar .tb-btn.tb-reveal:hover .label,
.topbar .tb-btn.tb-reveal:focus-visible .label { margin-left: 7px; margin-right: 3px; }

/* ── Badges: counts, ember, tucked on the icon's shoulder ── */
.topbar .activity-badge {
  top: -3px;
  right: -3px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  font-size: 9.5px;
  border-radius: 8px;
  box-shadow: 0 1px 4px rgba(239, 68, 68, .45), 0 0 0 2px var(--bg);
}

/* ── States ── */
/* HOOKER: the pill itself says what is going on — no status dot. */
.topbar .hk-tb.is-live.tb-btn { color: var(--tb-live); background: var(--tb-live-soft); }
.topbar .hk-tb.is-running.tb-btn { color: var(--tb-ember); background: var(--tb-ember-soft); }
.topbar .hk-tb.is-down.tb-btn { color: var(--tb-alarm); }
.topbar .hk-tb.is-down .tb-ico { filter: grayscale(.85) brightness(.8) drop-shadow(0 1px 1.5px rgba(0,0,0,.55)); }
.topbar .hk-tb.is-live .label,
.topbar .hk-tb.is-running .label { max-width: 180px; opacity: 1; margin-left: 7px; margin-right: 3px; }
.topbar .hk-tb.is-live .tb-ico { animation: tb-glow-live 2.4s ease-in-out infinite; }
@keyframes tb-glow-live {
  0%, 100% { filter: drop-shadow(0 1px 1.5px rgba(0,0,0,.55)) drop-shadow(0 0 0 rgba(52,211,153,0)); }
  50%      { filter: drop-shadow(0 1px 1.5px rgba(0,0,0,.55)) drop-shadow(0 0 6px rgba(52,211,153,.7)); }
}

/* Mute: at rest an icon; muted = warm pill, "Unmute" pinned, horn struck through. */
.topbar #btn-mute-topbar.is-muted { color: var(--tb-ember); background: var(--tb-ember-soft); }
.topbar #btn-mute-topbar.is-muted .label { max-width: 180px; opacity: 1; margin-left: 7px; margin-right: 3px; }
.topbar #btn-mute-topbar.is-muted .tb-ico { filter: grayscale(.6) drop-shadow(0 1px 1.5px rgba(0,0,0,.55)); }
.topbar #btn-mute-topbar.is-muted::after {
  content: "";
  position: absolute;
  left: 7px; top: 50%;
  width: 22px; height: 2.5px;
  border-radius: 2px;
  background: var(--tb-ember);
  box-shadow: 0 0 0 1.5px var(--bg);
  transform: translateY(-50%) rotate(-40deg);
  pointer-events: none;
}

/* Auto-lock keeps its own ON/partial/OFF rules (styles.css); inside a capsule
   the resting pill is transparent like its neighbours. */
.topbar .autolock-wrap > .btn.icon-pill#btn-autolock.tb-btn.is-off { color: var(--tb-ember); background: var(--tb-ember-soft); }
.topbar .autolock-wrap > .btn.icon-pill#btn-autolock.tb-btn.is-partial { color: var(--tb-ember); background: rgba(245, 158, 11, .08); }

/* Narrator running: a live glow on the microphone instead of the old
   gradient orb. */
.topbar .narrator-orb.tb-btn.narrator-active { background: var(--tb-live-soft); }
.topbar .narrator-orb.tb-btn.narrator-active .tb-ico { animation: tb-glow-live 1.6s ease-in-out infinite; }

/* Downloads chip + auto-update bell animations, re-pointed at the painted icon. */
.topbar #btn-grabs-topbar.is-busy .tb-ico { animation: tb-bob 1.6s ease-in-out infinite; }
.topbar #btn-grabs-topbar.is-error { color: var(--tb-alarm); }
.topbar #btn-aupd.aupd-ringing .tb-ico { animation: aupd-ring 1.1s ease 1; transform-origin: 50% 15%; }
@keyframes tb-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(2px); } }

/* ── Dropdown triggers ── */
.tb-trigger .tb-caret {
  flex: 0 0 auto;
  margin-left: 2px;
  opacity: .55;
  transition: transform .18s, opacity .18s;
}
.tb-trigger:hover .tb-caret { opacity: .9; }
.tb-trigger[aria-expanded="true"] .tb-caret { transform: rotate(180deg); opacity: 1; }
.topbar .tb-trigger.tb-btn.btn.icon-pill { padding: 0 7px 0 5px; }

/* Play mode: the trigger reads out the current choice. */
.tb-trigger-text {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  margin: 0 3px 0 7px;
  line-height: 1.05;
  text-align: left;
  white-space: nowrap;
}
.tb-trigger-kicker {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-mute);
}
.tb-trigger-value { font-size: 12.5px; font-weight: 600; color: var(--text); }

/* Library upkeep running (Fetch covers swaps its item to "Stop fetch"): the
   closed trigger says so. */
.tb-menu:has(#btn-fetch-all[data-running="1"]) .tb-trigger { background: var(--tb-ember-soft); color: var(--tb-ember); }
.tb-menu:has(#btn-fetch-all[data-running="1"]) .tb-trigger .tb-ico { animation: tb-bob 1.4s ease-in-out infinite; }

/* ── Dropdown panels ──
   Fixed-position; topbar.js places each one under its trigger, flips it at the
   right edge and caps its height to the viewport, so it is never cut off. */
.tb-pop {
  position: fixed;
  top: 64px;
  left: 0;
  z-index: 9999;
  min-width: 290px;
  max-width: min(360px, calc(100vw - 16px));
  overflow-y: auto;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--tb-pop-bg);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  box-shadow: 0 16px 40px rgba(0, 0, 0, .6), 0 0 0 1px rgba(167, 139, 250, .08);
  animation: narrator-menu-in 120ms ease-out;
  -webkit-app-region: no-drag;
}
.tb-pop.hidden { display: none !important; }
.tb-pop-head {
  padding: 6px 10px 4px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-mute);
}

.tb-pop .tb-item,
.tb-pop .pm-seg {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 44px;
  height: auto;
  padding: 7px 10px;
  border: 0;
  border-radius: 9px;
  background: transparent;
  box-shadow: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background .14s;
}
/* The web-only reveal forces inline-flex; a full-width row still lays out right. */
body.hearth-web .tb-pop .tb-item.web-only { width: 100%; }
.tb-pop .tb-item:hover,
.tb-pop .pm-seg:hover,
.tb-pop .tb-item:focus-visible,
.tb-pop .pm-seg:focus-visible {
  background: rgba(167, 139, 250, .12);
  outline: none;
}
.tb-pop .tb-item:focus-visible,
.tb-pop .pm-seg:focus-visible { box-shadow: inset 0 0 0 2px rgba(167, 139, 250, .6); }
.tb-pop .tb-ico {
  width: 28px;
  height: 28px;
  flex: 0 0 auto;
  object-fit: contain;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .5));
}
.tb-item-text { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.tb-item-title { font-size: 13px; font-weight: 600; line-height: 1.25; }
.tb-item-sub { font-size: 11.5px; line-height: 1.3; color: var(--text-dim); }
.tb-item-key {
  flex: 0 0 auto;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10.5px;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--surface-3);
  border: 1px solid var(--border);
  color: var(--text-dim);
}
/* "Stop fetch" state: app.js replaces the row's markup with an svg + text. */
.tb-pop .tb-item[data-running="1"] { color: var(--tb-ember); font-weight: 600; }

/* Play-mode radiogroup, rehoused as a list. */
body.hearth-web .tb-pop .play-mode-seg.web-only,
.tb-pop .play-mode-seg {
  display: flex !important;
  flex-direction: column;
  gap: 2px;
  height: auto;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  backdrop-filter: none;
}
.tb-pop .pm-seg[aria-checked="true"] {
  background: rgba(167, 139, 250, .16);
  box-shadow: inset 0 0 0 1px rgba(167, 139, 250, .45);
}
.tb-pop .pm-seg[aria-checked="true"] .tb-item-title { color: var(--accent); }
.tb-pop .pm-seg[aria-checked="true"]::after {
  content: "";
  flex: 0 0 auto;
  width: 6px; height: 11px;
  margin: 0 4px 3px 0;
  border: solid var(--accent);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

/* ── Steam account: same height and glass as a capsule ── */
.topbar .steam-account-btn {
  height: var(--tb-h);
  padding: 3px 12px 3px 4px;
  border-radius: calc(var(--tb-h) / 2);
  background: var(--tb-glass);
}
.topbar .steam-switch-avatar { width: 30px; height: 30px; }

/* ── Narrow windows: give width back in the order it is least missed ── */
@media (max-width: 1280px) {
  .tb-trigger-kicker { display: none; }
}
@media (max-width: 1100px) {
  .topbar-actions { gap: 6px; }
  .topbar .steam-switch-name { display: none; }
  .topbar .steam-account-btn { padding-right: 8px; }
}
@media (max-width: 980px) {
  .tb-playmode .tb-trigger-text { display: none; }
  .topbar-actions .btn.primary { padding: 0 12px 0 11px; }
}
/* Phone-width web: mark + search share the first row; the capsules wrap,
   centred, on the rows beneath instead of being pushed off the right edge. */
@media (max-width: 760px) {
  .topbar { flex-wrap: wrap; row-gap: 10px; }
  .topbar .search { order: 2; flex: 1 1 0; min-width: 0; max-width: none; }
  .topbar .window-controls { order: 2; }
  .topbar-actions { order: 3; flex: 1 1 100%; margin-left: 0; flex-wrap: wrap; justify-content: center; row-gap: 8px; }
}
/* ── Measured fit (topbar.js "Measured fit") ──
   The breakpoints above guess from the WINDOW's width, but what the bar holds
   is decided by data: the name chip, how many activity pills have something to
   say, a pinned "Privacy off", the shell's extra maximize button. A full bar
   in a 1400px window overflowed with none of those rules in force, and the
   last thing in the row — the window's own – □ ✕ — went off the right edge.
   topbar.js now measures the row and sets data-tb-fit to the steps it needs
   ("1 2 3" = the first three), each giving width back in the order it is
   least missed. Nothing here depends on the window's width. */
.topbar[data-tb-fit~="1"] .tb-trigger-kicker,
.topbar[data-tb-fit~="1"] .logo .logo-text { display: none; }

.topbar[data-tb-fit~="2"] { gap: 10px; padding-left: 14px; padding-right: 14px; }
.topbar[data-tb-fit~="2"] .topbar-actions { gap: 6px; }
.topbar[data-tb-fit~="2"] .search { min-width: 96px; }
.topbar[data-tb-fit~="2"] .tb-me-name,
.topbar[data-tb-fit~="2"] .steam-switch-name { display: none; }
.topbar[data-tb-fit~="2"] .tb-me { padding: 3px 4px; max-width: none; }
.topbar[data-tb-fit~="2"] .steam-account-btn { padding-right: 8px; }

/* Play's read-out and Add's word: both controls still say what they are by
   their painted icon, and the tooltip names them. */
.topbar[data-tb-fit~="3"] .tb-playmode .tb-trigger-text,
.topbar[data-tb-fit~="3"] .tb-add-label { display: none; }
.topbar[data-tb-fit~="3"] .topbar-actions .btn.primary.tb-add { padding: 0 6px; }

/* Pinned labels ("Privacy off", "Unmute", a live hook) fold to their icon. The
   state is still on the pill: its ember / green tint stays. */
.topbar[data-tb-fit~="4"] .tb-btn .label { display: none; }

/* Last step, a window narrower than the bar's own floor: the search may rest
   as its lens (it opens again while you type), carets and inner padding go,
   and the capsule row itself may finally give way, clipped at its right end —
   the window controls never do. */
.topbar[data-tb-fit~="5"] { gap: 6px; padding-left: 10px; padding-right: 10px; }
.topbar[data-tb-fit~="5"] .topbar-actions { gap: 4px; flex: 0 1 auto; min-width: 0; overflow-x: clip; }
.topbar[data-tb-fit~="5"] .tb-trigger .tb-caret { display: none; }
.topbar[data-tb-fit~="5"] .tb-btn.btn.icon-pill,
.topbar[data-tb-fit~="5"] .autolock-wrap > .btn.icon-pill.tb-btn,
.topbar[data-tb-fit~="5"] .narrator-orb.tb-btn { min-width: 28px; padding: 0 3px; }
.topbar[data-tb-fit~="5"] .window-controls { margin-left: 0; padding-left: 6px; }
.topbar[data-tb-fit~="5"] .search.tb-search { min-width: var(--tb-h); padding: 0 2px; gap: 0; }
.topbar[data-tb-fit~="5"] .search.tb-search input { text-indent: 8px; }
.topbar[data-tb-fit~="5"] .search.tb-search:focus-within { flex: 1 0 200px; padding-right: 8px; }
/* A search still in force while the box rests as a lens: the lens stays lit. */
.topbar[data-tb-fit~="5"] .search.tb-search:not(:focus-within):has(input:not(:placeholder-shown)) {
  border-color: rgba(251, 191, 36, .78);
}
.topbar[data-tb-fit~="5"] .search.tb-search:not(:focus-within):has(input:not(:placeholder-shown)) .tb-search-lens {
  background: radial-gradient(circle at 50% 30%, rgba(245, 158, 11, .32), rgba(245, 158, 11, .06) 72%);
  box-shadow: inset 0 0 0 1px rgba(251, 191, 36, .5), 0 0 10px rgba(245, 158, 11, .3);
}

/* No room for a label to slide out: it would push the row, and the row has
   nowhere to go but over the window controls. The control's tooltip card names
   it instead (display: none is what lets topbar.js show that card). Labels a
   state has pinned open are not hover reveals and stay. */
.topbar[data-tb-noreveal] .tb-btn.tb-reveal:not(.is-live):not(.is-running):not(.is-off):not(.is-partial) .label { display: none; }

@media (pointer: coarse) {
  .topbar { --tb-h: 44px; --tb-inner: 38px; }
  .topbar .tb-btn.btn.icon-pill { padding: 0 8px; }
}

@media (prefers-reduced-motion: reduce) {
  .topbar .tb-ico,
  .topbar .tb-btn .tb-ico,
  .tb-pop { animation: none !important; transition: none; }
  .topbar .tb-btn:hover .tb-ico { transform: none; }
}

/* ── Kind picker (Add, Rescan): pictures instead of tinted line glyphs ──
   The picture carries its own shape, so the tile behind it goes. */
.kind-picker-icon:has(> .kind-picker-img),
.kind-picker-item.is-default .kind-picker-icon:has(> .kind-picker-img) {
  background: none;
  border: 0;
  width: 30px; height: 30px;
}
.kind-picker-img {
  width: 30px; height: 30px;
  object-fit: contain;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .5));
}
.kind-picker-img.is-brand { padding: 4px; box-sizing: border-box; }

/* ── Search capsule ──
   The search box was the last control in the bar still wearing the old look
   (a square-cornered field with a line-art magnifier). It is now a capsule the
   same height and glass as its neighbours, fronted by the painted brass lens
   from the icon set, and it lights ember — the bar's attention colour — while
   you type, the way Add does on hover. */
.topbar .search.tb-search {
  height: var(--tb-h);
  padding: 0 6px 0 2px;
  gap: 8px;
  border-radius: calc(var(--tb-h) / 2);
  border: 1px solid var(--border);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .035), rgba(255, 255, 255, .012)),
    var(--tb-glass);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04), inset 0 -1px 0 rgba(0, 0, 0, .22);
  cursor: text;
  -webkit-app-region: no-drag;
  transition: border-color .2s, box-shadow .2s, background .2s;
}
.tb-search-lens {
  flex: none;
  display: grid;
  place-items: center;
  width: var(--tb-inner);
  height: var(--tb-inner);
  border-radius: 50%;
  background: radial-gradient(circle at 50% 30%, rgba(245, 158, 11, .17), rgba(245, 158, 11, .03) 72%);
  box-shadow: inset 0 0 0 1px rgba(245, 158, 11, .2);
  transition: box-shadow .2s, background .2s;
}
.topbar .tb-search .tb-search-lens .tb-ico { width: 22px; height: 22px; }
.topbar .search.tb-search input {
  font-size: 13.5px;
  color: var(--text);
  caret-color: var(--tb-ember);
}
.topbar .search.tb-search input::placeholder { color: rgba(240, 222, 196, .46); }
.topbar .search.tb-search:hover { border-color: rgba(245, 158, 11, .32); }
.topbar .search.tb-search:hover .tb-ico { transform: rotate(-8deg) scale(1.06); }
.topbar .search.tb-search:focus-within {
  border-color: rgba(251, 191, 36, .78);
  background:
    radial-gradient(160px 38px at 6% 0%, rgba(245, 158, 11, .16), transparent 70%),
    linear-gradient(180deg, rgba(255, 255, 255, .05), rgba(255, 255, 255, .02)),
    var(--tb-glass);
  box-shadow:
    0 0 0 3px rgba(245, 158, 11, .13),
    0 4px 16px rgba(245, 158, 11, .12),
    inset 0 1px 0 rgba(255, 237, 213, .08);
}
.topbar .search.tb-search:focus-within .tb-search-lens {
  background: radial-gradient(circle at 50% 30%, rgba(245, 158, 11, .32), rgba(245, 158, 11, .06) 72%);
  box-shadow: inset 0 0 0 1px rgba(251, 191, 36, .5), 0 0 10px rgba(245, 158, 11, .3);
}
.topbar .search.tb-search:focus-within .tb-ico {
  transform: rotate(-14deg) scale(1.12);
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .6)) drop-shadow(0 0 6px rgba(245, 158, 11, .45));
}
/* The "/" hint as a small brass keycap; it steps aside while you type. */
.topbar .search.tb-search kbd {
  display: grid;
  place-items: center;
  min-width: 22px;
  height: 22px;
  padding: 0 5px;
  box-sizing: border-box;
  border-radius: 6px;
  font-size: 11.5px;
  font-weight: 700;
  color: #fcd9a0;
  background: linear-gradient(180deg, rgba(245, 158, 11, .2), rgba(180, 83, 9, .12));
  border: 1px solid rgba(245, 158, 11, .34);
  box-shadow: inset 0 -2px 0 rgba(0, 0, 0, .28), inset 0 1px 0 rgba(255, 237, 213, .12);
  transition: opacity .15s;
}
.topbar .search.tb-search:focus-within kbd { opacity: 0; }
/* The box answers to its OWN width, whatever squeezed it: the keycap goes
   before it crowds the words (a `.search kbd` window-width rule in styles.css
   was meant to do this and has been outranked by the keycap's look since the
   capsule landed), and a sliver too thin to read hides its text. */
.topbar .search.tb-search { container: tb-search / inline-size; }
@container tb-search (max-width: 210px) {
  .topbar .search.tb-search kbd { display: none; }
}
@container tb-search (max-width: 84px) {
  .topbar .search.tb-search input { opacity: 0; }
}
.topbar .search.tb-search input::-webkit-search-cancel-button { filter: sepia(1) saturate(4) hue-rotate(-12deg); cursor: pointer; }

/* ── Bar tooltips (topbar.js "Tooltips") ──
   The bar's controls used to explain themselves through the OS tooltip — a
   pale system box that belonged to no part of Hearth. They now share one
   ember-lit card: a bold first line (the name) and, when the description has
   more to say, a softer second line. Placed under the control, flipped above
   and slid sideways at the window edges so it is never cut off. */
.tb-tip {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 10050;
  max-width: min(300px, calc(100vw - 16px));
  padding: 7px 12px 8px;
  border-radius: 10px;
  background:
    radial-gradient(150px 54px at 0% 0%, rgba(245, 158, 11, .17), transparent 72%),
    linear-gradient(180deg, rgba(40, 29, 23, .97), rgba(21, 17, 22, .97));
  border: 1px solid rgba(245, 158, 11, .4);
  box-shadow: 0 12px 30px rgba(0, 0, 0, .55), inset 0 1px 0 rgba(255, 237, 213, .09);
  color: #fde7c0;
  font-size: 12.5px;
  line-height: 1.38;
  pointer-events: none;
  opacity: 0;
  transform: translateY(-4px) scale(.97);
  transform-origin: var(--tip-x, 50%) 0;
  transition: opacity .13s ease-out, transform .18s cubic-bezier(.3, 1.4, .5, 1);
}
.tb-tip.above { transform: translateY(4px) scale(.97); transform-origin: var(--tip-x, 50%) 100%; }
.tb-tip.on { opacity: 1; transform: none; }
.tb-tip-head {
  display: block;
  font-weight: 700;
  letter-spacing: .15px;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
}
.tb-tip-body { display: block; margin-top: 2px; color: rgba(253, 231, 192, .7); font-weight: 500; }
/* The pointer: a square turned 45°, borders on the two sides that face out. */
.tb-tip::before {
  content: '';
  position: absolute;
  left: var(--tip-x, 50%);
  top: -5px;
  width: 9px;
  height: 9px;
  margin-left: -5px;
  background: rgb(40, 29, 23);
  border-left: 1px solid rgba(245, 158, 11, .4);
  border-top: 1px solid rgba(245, 158, 11, .4);
  transform: rotate(45deg);
}
.tb-tip.above::before {
  top: auto;
  bottom: -5px;
  background: rgb(21, 17, 22);
  border: 0;
  border-right: 1px solid rgba(245, 158, 11, .4);
  border-bottom: 1px solid rgba(245, 158, 11, .4);
}
@media (prefers-reduced-motion: reduce) {
  .tb-tip, .tb-tip.above { transition: opacity .1s; transform: none; }
  .topbar .search.tb-search .tb-ico { transition: none; transform: none !important; }
}

/* ── Who is signed in, beside the Hearth mark ────────────────────────────────
   A face + name chip at the far left (renderer/index.html .logo), filled and
   wired by renderer/admin/admin.js from users:me. It is the shortcut to
   everything about you: click it for your profile, the People room and sign
   out. Hidden until there is an answer, so the desktop build — one user by
   construction — never shows an empty chip.

   It sits INSIDE .logo, which is a drag region in the shell; .tb-me therefore
   opts out (-webkit-app-region: no-drag) or the click would only move the
   window. Same reason .logo-mark already does. */
.tb-me {
  -webkit-app-region: no-drag;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 34px;
  max-width: 190px;
  margin-left: 4px;
  padding: 3px 12px 3px 4px;
  border-radius: 999px;
  border: 1px solid rgba(245, 158, 11, .22);
  background: linear-gradient(180deg, rgba(245, 158, 11, .10), rgba(0, 0, 0, .22));
  color: var(--text-dim);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: border-color .15s ease, color .15s ease, background .15s ease;
}
.tb-me.hidden { display: none; }
.tb-me-face {
  width: 26px; height: 26px;
  flex: none;
  border-radius: 50%;
  object-fit: cover;
  background: #14161f;
  border: 1px solid rgba(245, 158, 11, .45);
}
.tb-me-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tb-me:hover, .tb-me[aria-expanded="true"] {
  color: var(--text);
  border-color: rgba(245, 158, 11, .55);
  background: linear-gradient(180deg, rgba(245, 158, 11, .2), rgba(0, 0, 0, .22));
}
.tb-me:focus-visible { outline: 2px solid var(--accent-warm, #f59e0b); outline-offset: 2px; }

/* The name is the first thing to go when the bar is tight — the face still says
   who you are, and .logo-text ("Hearth") already drops out below 900px. */
@media (max-width: 1100px) { .tb-me-name { display: none; } .tb-me { padding: 3px 4px; max-width: none; } }
@media (prefers-reduced-motion: reduce) { .tb-me { transition: none; } }

/* ─────────────── The bar, regrouped (2026-10-13) ───────────────
   Rober: "how can we overhaul this bar? Without losing any space? … i like
   custom icons but it can be kinda overwhelming, grouping, framing, dropdowns,
   sleek", then "removal of stuff that is old, or condensing". Same height, same
   painted icon set, fewer things asking to be looked at:
     • you + your libraries in one capsule beside the mark (.tb-id);
     • the six activity pills as one hub with one badge (.tb-hub, topbar.js
       "The Activity hub's face"), each still a row with its own count;
     • Library ▾, Window ▾ and Settings as one Hearth menu behind the gear,
       in titled sections (.tb-pop-sec).
   At rest the painted icons sit a shade quieter; a pointer brings each one up
   to full colour, so the bar reads as one calm instrument panel and the thing
   you are reaching for lights. */

/* Quieter at rest; full colour on hover / focus / open (the hover rule above
   sets the whole filter, so it wins back the saturation). */
.topbar .tb-group .tb-ico,
.topbar .tb-id .media-profile-button img {
  filter: saturate(.72) brightness(.9) drop-shadow(0 1px 1.5px rgba(0, 0, 0, .55));
}
.topbar .tb-btn[aria-expanded="true"] .tb-ico {
  filter: drop-shadow(0 1px 1.5px rgba(0, 0, 0, .55)) drop-shadow(0 0 6px rgba(245, 158, 11, .28));
}

/* Capsules: one frame language — a hairline edge, a faint lit top. */
.topbar .tb-group,
.tb-id {
  border-color: rgba(255, 255, 255, .075);
  background: linear-gradient(180deg, rgba(255, 255, 255, .035), rgba(255, 255, 255, .012));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04), 0 1px 0 rgba(0, 0, 0, .25);
}

/* ── Identity capsule: you, then which libraries ── */
.tb-id {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  height: var(--tb-h);
  margin-left: 8px;
  padding: 2px;
  border: 1px solid rgba(255, 255, 255, .075);
  border-radius: calc(var(--tb-h) / 2);
  -webkit-app-region: no-drag;
  flex: 0 0 auto;
}
/* Nothing to show (the desktop app: one user, no personal libraries). */
.tb-id:not(:has(.tb-me:not(.hidden))):not(:has(.media-profile-switch)) { display: none; }
.tb-id .tb-me {
  margin-left: 0;
  min-height: var(--tb-inner);
  height: var(--tb-inner);
  padding: 2px 11px 2px 3px;
  border-color: transparent;
  background: transparent;
}
.tb-id .tb-me:hover, .tb-id .tb-me[aria-expanded="true"] { background: var(--tb-glass-hover); border-color: transparent; }
.tb-id .tb-me-face { width: 26px; height: 26px; }
/* The switch sits after a hairline, as the capsule's second half. */
.tb-id-switch:not(:empty) { display: inline-flex; align-items: center; }
.tb-id .tb-me:not(.hidden) + .tb-id-switch:not(:empty) { margin-left: 2px; padding-left: 4px; border-left: 1px solid rgba(255, 255, 255, .09); }
.topbar .tb-id .media-profile-button {
  width: var(--tb-inner);
  height: var(--tb-inner);
  padding: 4px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  box-shadow: none;
}
.topbar .tb-id .media-profile-button img { width: 24px; height: 24px; transition: transform .22s cubic-bezier(.4, 0, .2, 1), filter .22s; }
@media (hover: hover) {
  .topbar .tb-id .media-profile-button:hover { background: var(--tb-glass-hover); }
  .topbar .tb-id .media-profile-button:hover img { transform: translateY(-1px) scale(1.08); filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .55)) drop-shadow(0 0 6px rgba(245, 158, 11, .28)); }
}
.topbar[data-tb-fit~="2"] .tb-id .tb-me { padding: 2px 3px; }

/* ── Activity hub ── */
.topbar .tb-hub .tb-trigger { position: relative; }
.topbar .tb-hub-badge { top: -2px; right: auto; left: 19px; }
.topbar .tb-hub-badge.is-alarm { background: var(--tb-alarm); box-shadow: 0 1px 4px rgba(248, 113, 113, .5), 0 0 0 2px var(--bg); }
.topbar #btn-activity-hub.is-busy .tb-ico { animation: tb-bob 1.6s ease-in-out infinite; }
.topbar #btn-activity-hub.is-ringing .tb-ico { animation: aupd-ring 1.1s ease 1; transform-origin: 50% 15%; }
.topbar #btn-activity-hub.is-error { color: var(--tb-alarm); }
/* The rows: each count sits at the row's end, not on an icon's shoulder. */
.tb-pop.tb-hub-pop { min-width: 320px; }
.tb-pop .activity-btn { position: relative; }
.tb-pop .activity-btn .activity-badge {
  position: static;
  flex: 0 0 auto;
  margin-left: auto;
  min-width: 24px;
  height: 20px;
  padding: 0 7px;
  border-radius: 10px;
  font-size: 11px;
  box-shadow: none;
  transform: none;
}
.tb-pop .activity-btn .activity-badge.hidden { display: none; }
.tb-pop #btn-automations .activity-badge:not(.hidden),
.tb-pop .activity-btn.is-error .activity-badge { background: var(--tb-alarm); }
.tb-pop .activity-btn.is-error .tb-item-title { color: var(--tb-alarm); }

/* ── Hearth menu: Settings first, then titled sections ── */
.tb-pop.tb-hearth-pop { min-width: 310px; }
.tb-pop .tb-item-lead .tb-item-title { font-size: 13.5px; }
.tb-pop-sec { display: flex; flex-direction: column; gap: 2px; margin-top: 4px; padding-top: 4px; border-top: 1px solid rgba(255, 255, 255, .07); }
.tb-pop-sec > .tb-pop-head { padding-top: 8px; }
