/* THE TWO NEW STYLESHEETS RIDE IN HERE AS WELL (2026-08-29, evening).
   Nick saw the picker and the chat with no styling at all: the page's
   index.html was stale (cached) while the JS modules loaded fresh, so the
   new <link>s for chat.css and picker.css never reached the browser. This
   file has been linked since round three, so importing them from its top
   makes the new surfaces styled wherever this file loads. Order is kept:
   this file sits after motion.css, so picker.css's site-wide `.lib-mine`
   rule still wins. The index.html links stay; a second load is harmless. */
@import url("chat.css?v=20260906d");
@import url("picker.css?v=20260906d");
@import url("mediacard.css?v=20260907b");

/* ===========================================================================
   Peltify — the dashboard.  REBUILT 2026-08-29 to infrastructure/2026-08-29/
   dashboard/ (SPEC.md + SPEC-profile.md). Owned by src/ui/dashboard.js.

   THE PAGE IS SETTINGS-SHAPED: `.stg` from settings.css gives the two-column
   frame (left submenus, one pane on the right); `.db-*` here is what the
   Dashboard adds to it — a wider pane, and a nav that turns into a two-tab
   row on a phone rather than hiding the pane behind a list.

   THE PROFILE PANE, top to bottom: the purple header (greeting, Reload /
   Rebuild, the sources ring, floating real covers behind), the genre
   treemap, the cover strip with its "Browse & add" box, the ring + kind
   tiles and the word field, then From.

   Tokens from tokens.css. Boxy (--r-box) except covers (--r-art) and the
   segmented switch; the `.stg` scope restores its own older radii for the
   nav rows, which is the "similar UI" Nick asked for. Motion: only `.rise`
   inside `.is-fresh`, the covers' drift, the strip's own horizontal scroll
   and the dropdown's height. Nothing here repaints on its own.
   =========================================================================== */

/* ---- the frame ---- */
/* THE PANE'S ONE TRACK MUST BE ALLOWED TO SHRINK. `.stg-pane` is a grid, and
   an implicit `auto` track is sized from its item's min-content — the cover
   strip is a scroll container whose min-content is every cover laid end to
   end (six covers = 856px), so the pane grew past its column and the whole
   page scrolled sideways. Found by the lane's hide-one-at-a-time probe, not
   by reading the stylesheet. `minmax(0, 1fr)` and `min-width: 0` on the
   bodies keep the strip scrolling inside itself. */
.db .stg-pane.db-pane { max-width: 1020px; grid-template-columns: minmax(0, 1fr); }
.db-profile { display: flex; flex-direction: column; gap: 28px; padding-bottom: 40px; min-width: 0; }
.db-suggestions { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.db-pane-h { margin-bottom: 2px; }

/* THE FULL LAYOUT ON SUGGESTIONS (2026-08-29, dashboard/RAW.md entry 5).
   "menus that have submenus are too far apart… which therefor makes the body
   not as big… the dashboard needs more space to make this feel like a real
   AI chatbox… id like the dashboard submenu to smoothly animate and move
   closer to the main menus when opened on the suggestion page."
   The page column the shell centres at 1180px opens to the full width, the
   submenu column narrows, and the gap closes — all three as transitions on
   the live nodes, so the submenu visibly flows left when the row is pressed
   and back when Profile is. Profile keeps its centred column. On a phone the
   submenu is already a row of tabs, so nothing moves. */
@media (min-width: 721px) {
  .surface-wide:has(> .stg.db) { width: 100%; max-width: 1180px; transition: max-width 460ms var(--ease); }
  .surface-wide:has(> .stg.db[data-pane="suggestions"]) { max-width: 100%; }
  .stg.db { transition: grid-template-columns 460ms var(--ease), gap 460ms var(--ease); }
  .stg.db[data-pane="suggestions"] { grid-template-columns: 220px minmax(0, 1fr); gap: clamp(14px, 2vw, 28px); }
  .stg.db[data-pane="suggestions"] .stg-pane.db-pane { max-width: none; }
}
/* THE CHAT MEASURES ITS OWN FLOOR (2026-08-30, suggestions entry 7), against
   the fixed bars at every width, and leaves its own breathing room above them.
   Any padding under it here is added to a box that already ends where it
   should — which is exactly how much the page then scrolls. So: none. */
.surface:has(> .surface-wide > .stg.db[data-pane="suggestions"]) { padding-bottom: 0; }
@media (prefers-reduced-motion: reduce) {
  .surface-wide:has(> .stg.db), .stg.db { transition: none; }
}

@media (max-width: 720px) {
  /* THE SUBMENUS SIT AT THE BOTTOM, ABOVE THE MAIN MENUS (2026-08-30, entry
     7: "The chatbox is TINY on mobile cause submenus take up like majority
     of the space. Also shouldnt the submenus be on the bottom? above the
     MAIN menus?"). The two tabs are a fixed bar directly on top of the rail;
     the pane gets the whole screen above them. */
  .db.stg { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .db .stg-nav {
    /* `top: auto` — settings.css's sticky rule sets top: 12px, which would
       stretch a fixed bar to the whole screen. */
    position: fixed; top: auto; left: 0; right: 0; bottom: calc(64px + env(safe-area-inset-bottom, 0px)); z-index: 39;
    padding: 5px 8px; background: var(--paper); border-top: 1px solid var(--line);
  }
  .db .stg-nav-h { display: none; }
  .db .stg-group { display: none; }
  .db .stg-navlist { display: flex; gap: 6px; }
  .db .stg-navrow { width: auto; flex: 1 1 0; justify-content: center; padding: 8px 10px; }
  /* settings.css hides `.stg .stg-pane` on a phone until a row is picked and
     it loads AFTER this file, so the override has to outrank it, not merely
     follow it. */
  .stg.db .stg-pane.db-pane { display: grid; }
  /* room for the two fixed bars under the page */
  .db-profile { padding-bottom: 64px; }
  /* the pane heading duplicates the lit tab below; the chat needs the room */
  .db-suggestions .db-pane-h { display: none; }
}

/* ---- the header: "purple ish background, a nice little rectangle, not TOO big" ---- */
.db-hero {
  /* NO `overflow: hidden` HERE, and that absence is load-bearing (2026-08-30).
     It used to be on this rule, and it was what clipped the Rebuild ▾ dropdown:
     the menu is `position: absolute` under the toolbar INSIDE this box, so an
     overflow clip on the box cut it off at the header's bottom edge — "The
     rebuild profile menu is UNDER the platform thing. What the hell, I cant
     even press it." The clip was only ever needed for the floating covers, and
     `.db-orbs` has its own (with this box's radius), so it is enforced where it
     belongs rather than over the whole header. */
  position: relative; isolation: isolate;
  padding: 22px 24px;
  border-radius: var(--r-box);
  background:
    radial-gradient(120% 140% at 100% 0%, rgba(255, 255, 255, 0.14), transparent 55%),
    linear-gradient(135deg, var(--violet) 0%, var(--spine) 100%);
  color: var(--hero-ink);
  box-shadow: var(--raise);
}
/* z-index 3, ABOVE `.db-kinds` (2026-08-30). Both used to be 2, and `.db-kinds`
   comes later in the DOM — so the tiles painted over the toolbar's dropdown, and
   `z-index: 5` inside the menu could never help: `.db-hero-in` is itself a
   stacking context, so the menu's 5 only ever ranked it against its own
   siblings. The half of the bug that was not the overflow clip is this line. */
.db-hero-in { position: relative; z-index: 3; display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 22px; align-items: center; }
/* the kind tiles, in the header (entry 5): "37 Music · read from Spotify" */
.db-kinds { position: relative; z-index: 2; display: flex; flex-wrap: wrap; gap: 8px; margin: 16px 0 0; padding: 0; list-style: none; }
.db-kind { flex: 1 1 150px; max-width: 260px; min-width: 0; }
.db-kind-hit {
  display: grid; grid-template-columns: auto auto minmax(0, 1fr); grid-template-areas: "chip n name" "chip sub sub";
  column-gap: 8px; row-gap: 1px; align-items: center; width: 100%; padding: 8px 12px 8px 10px;
  border: 1px solid var(--hero-rule); border-radius: var(--r-box); background: rgba(251, 247, 255, 0.12);
  color: var(--hero-ink); font: inherit; text-align: left; cursor: pointer; box-shadow: none;
  transition: background var(--fast) var(--ease), transform var(--fast) var(--ease);
}
.db-kind-hit:hover { background: rgba(251, 247, 255, 0.2); transform: translateY(-1px); box-shadow: none; }
/* 15.8 — AN INFERRED TILE ON THE HERO IS STILL ON PURPLE. The tile carries
   `.mtile` as well as `.db-kind`, and `app.css`'s
   `.mtile[data-tone="inferred"] .mtile-hit` sets `background: var(--paper)` at
   a higher specificity than the plain `.db-kind-hit` above — so a tile Peltify
   worked out rather than read came back cream, and white-on-purple text on a
   cream ground is the near-invisible "14 Music" Nick pointed at. The dashed
   edge is the whole of what "inferred" needs to say here. */
.db-kind[data-tone="inferred"] .db-kind-hit {
  border-style: dashed;
  background: rgba(251, 247, 255, 0.12);
  color: var(--hero-ink);
}
.db-kind[data-tone="inferred"] .db-kind-hit:hover { background: rgba(251, 247, 255, 0.2); }
.db-kind[data-tone="inferred"] .db-kind-chip { background: rgba(255, 255, 255, 0.18); }
.db-kind-chip { grid-area: chip; display: grid; place-items: center; width: 30px; height: 30px; border-radius: var(--r-art); background: rgba(255, 255, 255, 0.18); }
.db-kind-n { grid-area: n; font-size: 18px; font-weight: 800; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; line-height: 1.1; }
.db-kind-name { grid-area: name; font-size: 14px; font-weight: 700; line-height: 1.1; }
.db-kind-sub { grid-area: sub; font-size: 11px; color: var(--hero-ink-soft); line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.db-hero-main { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.db-hero .tb-hi { color: var(--hero-ink); }
.db-hero .tb-line { color: var(--hero-ink); }
.db-hero .tb-line.is-faint { color: var(--hero-ink-soft); }
.db-hero .tb-when { color: var(--hero-ink-faint); }
.db-hero .dsh-chip { color: var(--hero-ink); }
.db-hero .tb-hello-tools { margin-top: 6px; }
.db-hero .dsh-bar-note { color: var(--hero-ink-soft); text-align: left; }
.db-hero .dsh-bar-note.is-bad { color: #ffd6cf; }
.tb-hi { margin: 0; font-size: clamp(28px, 3.6vw, 40px); line-height: 1; font-weight: 800; letter-spacing: -0.035em; }
.tb-line { margin: 0; font-size: clamp(15px, 1.5vw, 18px); line-height: 1.35; max-width: 46ch; }
.tb-when { display: flex; gap: 10px; align-items: center; margin: 0; font-size: 12px; }
.tb-hello-tools { flex: none; }

/* the floating covers — decoration only, and only real ones */
/* The clip the header used to carry, now where it is actually needed: a cover
   drifting past the edge is cut off by the decoration layer, and `inherit`
   keeps it cut to the header's rounded corners rather than to a square. */
.db-orbs { position: absolute; inset: 0; z-index: 1; pointer-events: none;
           overflow: hidden; border-radius: inherit; }
.db-orbs .hb {
  position: absolute; left: var(--x); top: var(--y);
  width: calc(58px * var(--s, 1)); height: calc(58px * var(--s, 1));
  transform: translate(-50%, -50%);
  opacity: 0; transition: opacity 600ms var(--ease);
  animation: db-drift var(--dur, 16s) ease-in-out var(--dly, 0s) infinite alternate;
}
.db-orbs .hb[data-has="art"] { opacity: 0.34; }
.db-orbs .hb-face { display: block; width: 100%; height: 100%; border-radius: var(--r-art); overflow: hidden;
                    box-shadow: 0 10px 24px -12px rgba(0, 0, 0, 0.6); transform: rotate(calc(var(--i, 0) * 7deg - 21deg)); }
.db-orbs .hb-face img { width: 100%; height: 100%; object-fit: cover; display: block; }
@keyframes db-drift {
  from { translate: 0 0; }
  to   { translate: var(--dx, 6px) var(--dy, -7px); }
}

/* the sources ring */
.db-src { margin: 0; padding: 12px 14px; border-radius: var(--r-box);
          background: rgba(251, 247, 255, 0.12); border: 1px solid var(--hero-rule); min-width: 0; }
.db-src-h { margin: 0 0 8px; font-size: 11px; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; color: var(--hero-ink-soft); }
.db-src-body { display: flex; align-items: center; gap: 14px; }
.db-src-ring { position: relative; width: 132px; height: 132px; flex: none; }
.db-src-ring .donut-svg { width: 132px; height: 132px; display: block; }
.db-src-ring .donut-track { stroke: rgba(251, 247, 255, 0.16); }
/* FILLED IN WHEN IT APPEARS, AND ALIVE UNDER THE POINTER (entry 6) — as ONE
   CLOCKWISE SWEEP (2026-08-31, DASH-6): "the circle to animate by starting at
   the top and circling ALL THE WAY AROUND like a clock." Each wedge draws for
   its fraction of one 900ms revolution (`--f`), starting exactly when the
   wedges before it finish (`--f0`), linear — a single hand sweeping from 12
   o'clock, never each platform animating from its own start. charts.js
   writes both fractions. A hovered wedge — or its key row — still grows its
   stroke a little and the logo beside it grows with it. */
.db-src-ring .donut-seg { animation: db-fill calc(var(--f, 1) * 900ms) linear both;
                          animation-delay: calc(var(--f0, 0) * 900ms + 120ms);
                          transition: stroke-width 180ms var(--ease), filter 180ms var(--ease); }
@keyframes db-fill { from { stroke-dasharray: 0 var(--c, 1000); } }
.db-src-ring .donut-seg:hover, .db-src-ring .donut-seg.is-hot { stroke-width: 24; filter: brightness(1.08); }
.db-src-ring .donut-svg { overflow: visible; }
@media (prefers-reduced-motion: reduce) { .db-src-ring .donut-seg { animation: none; } }
.db-src-mid { position: absolute; inset: 0; display: grid; place-items: center; align-content: center; gap: 0; text-align: center; pointer-events: none; }
.db-src-mid b { font-size: 24px; font-weight: 800; letter-spacing: -0.03em; line-height: 1; font-variant-numeric: tabular-nums; }
.db-src-mid span { font-size: 10.5px; color: var(--hero-ink-soft); }
.db-src-key { margin: 0; padding: 0; list-style: none; display: grid; gap: 6px; }
.db-src-row { display: flex; align-items: center; font-size: 12.5px; }
.db-src-hit { display: flex; align-items: center; gap: 8px; width: 100%; padding: 3px 8px 3px 3px; margin: 0 -3px;
              border: 0; border-radius: var(--r-box); background: none; color: inherit; font: inherit; text-align: left;
              cursor: pointer; transition: background var(--fast) var(--ease); }
.db-src-hit:hover, .db-src-row.is-hot .db-src-hit { background: rgba(251, 247, 255, 0.14); }
.db-src-logo { display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: var(--r-art);
               background: var(--white); border: 2px solid var(--c, var(--violet)); color: var(--ink);
               transition: transform 180ms var(--ease); }
.db-src-hit:hover .db-src-logo, .db-src-row.is-hot .db-src-logo { transform: scale(1.18); }
.db-src-name { font-weight: 700; }
.db-src-n { color: var(--hero-ink-soft); font-variant-numeric: tabular-nums; }
/* "nothing read yet" is a sentence, not a number — quieter, and not tabular. */
.db-src-n.is-none { color: var(--hero-ink-faint); font-variant-numeric: normal; font-style: italic; }
/* WHAT THE WEDGES MEAN, under the ring. The wedges are equal — one per platform
   you connected — and without this line a reader supplies the old meaning (a
   share of your things) themselves. */
.db-src-note { margin: 10px 0 0; font-size: 11px; line-height: 1.4; color: var(--hero-ink-faint); }

/* [UI-3] 2026-09-01: the ring panel used to float OVER the hero copy and clip
   its counts at ~1280px with the rail open. Below 1200px of viewport the ring
   stacks BELOW the copy; the key rows may shrink their labels instead of
   pushing the count off the panel. */
.db-src-key { min-width: 0; }
.db-src-row { min-width: 0; }
.db-src-hit { min-width: 0; }
.db-src-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.db-src-n { flex: none; white-space: nowrap; }
.db-hero-main .tb-line { overflow-wrap: anywhere; }
@media (max-width: 1200px) {
  .db-hero-in { grid-template-columns: minmax(0, 1fr); }
  .db-src { width: 100%; }
  .db-src-body { flex-wrap: wrap; }
}
@media (max-width: 860px) {
  .db-hero-in { grid-template-columns: minmax(0, 1fr); }
  .db-src-body { flex-wrap: wrap; }
}
/* [DASH-17] every row wraps or scrolls INSIDE its own box; the page never
   scrolls sideways. min-width:0 down the grid chain is what lets a flex/grid
   child shrink instead of stretching its parent past the viewport. */
.db, .db-pane, .db-profile, .tb-strip, .dsh-genres, .gr-field, .db-into, .tb-things { min-width: 0; max-width: 100%; }
.tb-covers { max-width: 100%; }

/* ---- strips ---- */
.tb-strip { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.tb-strip-h { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.tb-strip-t { margin: 0; font-size: 20px; font-weight: 800; letter-spacing: -0.02em; color: var(--ink); }
.tb-strip-aside { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.tb-info {
  width: 20px; height: 20px; padding: 0; border: 1px solid var(--line-strong); border-radius: 50%;
  background: var(--white); color: var(--ink-soft); font: inherit; font-size: 11px; font-weight: 800;
  font-family: var(--font-serif); font-style: italic; cursor: pointer; line-height: 1;
}
.tb-info:hover { border-color: var(--ink); color: var(--ink); }
.tb-info-p { margin: 0; font-size: 15px; line-height: 1.55; color: var(--ink); max-width: 60ch; }
.tb-count { font-size: 13px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.tb-count b { font-size: 18px; font-weight: 800; color: var(--ink); letter-spacing: -0.02em; }
.tb-gone { color: var(--ink-faint); font-weight: 600; }
.tb-more { height: 32px; border-radius: var(--r-box); }
.tb-seg button.is-on { background: var(--ink); color: var(--white); }
.tb-seg-one { font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); }
.db-into-wrap { display: flex; flex-direction: column; gap: 28px; }

/* ---- the reload control and its smooth dropdown ---- */
.dsh-bar-note { margin: 0 0 6px; min-width: 0; font-size: 12px; line-height: 1.45; color: var(--ink-soft); }
.dsh-bar-note.is-bad { color: var(--coral-dark); }
.dsh-reload { position: relative; flex: none; display: flex; align-items: center; }
.dsh-reload-b,
.dsh-reload-m {
  display: inline-flex; align-items: center; gap: 7px;
  height: 32px; padding: 0 13px;
  border: 1px solid var(--line); background: var(--white); color: var(--ink-soft);
  font-size: 12.5px; font-weight: 650;
  cursor: pointer;
  transition: border-color var(--fast) var(--ease), color var(--fast) var(--ease);
}
.dsh-reload-b { border-radius: var(--r-box) 0 0 var(--r-box); }
.dsh-reload-m { border-radius: 0 var(--r-box) var(--r-box) 0; border-left: 0; padding: 0 8px; }
.dsh-reload-m svg { transition: transform var(--med) var(--ease); }
.dsh-reload-m[aria-expanded="true"] svg { transform: rotate(180deg); }
.dsh-reload-b:hover,
.dsh-reload-m:hover { border-color: var(--violet); color: var(--spine); }
.dsh-reload-b[disabled] { cursor: default; color: var(--ink-faint); }
.dsh-reload-b[disabled]:hover { border-color: var(--line-soft); color: var(--ink-faint); }

/* ALWAYS IN THE DOM; the height is what animates. A menu that is created on
   open has nothing to transition from — that was the "ugly and messy" arrow. */
.dsh-reload-menu {
  position: absolute; left: 0; top: calc(100% + 6px); z-index: 5;
  min-width: 240px;
  display: grid; grid-template-rows: 0fr;
  opacity: 0; transform: translateY(-4px);
  transition: grid-template-rows var(--med) var(--ease), opacity var(--med) var(--ease), transform var(--med) var(--ease);
  pointer-events: none;
}
.dsh-reload-menu.is-open { grid-template-rows: 1fr; opacity: 1; transform: none; pointer-events: auto; }
.dsh-reload-menu-in {
  min-height: 0; overflow: hidden;
  border: 1px solid var(--line); border-radius: var(--r-box);
  background: var(--white); color: var(--ink); box-shadow: var(--raise);
}
.dsh-reload-menu.is-open .dsh-reload-menu-in { padding: 6px; }
.dsh-rebuild {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 8px 10px; border: 0; border-radius: var(--r-box);
  background: none; color: var(--ink); text-align: left;
  font-size: 13px; font-weight: 600; cursor: pointer;
}
.dsh-rebuild:hover { background: var(--violet-wash); color: var(--spine); }
.dsh-rebuild[disabled] { color: var(--ink-faint); cursor: default; background: none; }
.dsh-reload-n { margin: 2px 10px 6px; font-size: 11.5px; line-height: 1.45; color: var(--ink-faint); white-space: nowrap; }
.dsh-sub { margin: 10px 0 0; font-size: 12.5px; color: var(--ink-soft); max-width: 62ch; }

/* ---- your genres: the treemap ---- */
/* AREA IS THE COUNT. Every block is placed in percent of the field, so one
   layout scales to any width; the type inside is sized in the block's OWN
   container units (see nameFit() in dashboard.js), so a word never clips. */
.dsh-genres { display: flex; flex-direction: column; gap: 10px; }
.gr-field { position: relative; width: 100%; aspect-ratio: 16 / 7; min-height: 220px; max-height: 420px; }
.gr-block {
  position: absolute; left: var(--x); top: var(--y); width: var(--w); height: var(--h);
  container-type: size;
  display: flex; flex-direction: column; justify-content: flex-end; align-items: flex-start; gap: 0;
  padding: clamp(6px, 4cqw, 14px);
  border: 3px solid var(--paper); border-radius: var(--r-box);
  background: color-mix(in srgb, var(--violet) var(--tint, 50%), var(--white));
  background-clip: padding-box;
  color: var(--ink); font: inherit; text-align: left; cursor: pointer; overflow: hidden;
  transition: filter var(--fast) var(--ease);
}
.gr-block[data-ink="light"] { color: var(--white); }
.gr-block:hover { filter: brightness(1.06); }
.gr-block[data-tone="inferred"] { outline: 2px dashed rgba(255, 255, 255, 0.85); outline-offset: -7px; }
.gr-block[data-tone="more"] { color: var(--ink); background: var(--paper-deep); }
.gr-b-name {
  /* "i worry big words getting overflowed or cut off" (entry 7): a word too
     wide for its block breaks with a hyphen rather than clipping. */
  font-weight: 800; letter-spacing: -0.02em; line-height: 1.02; overflow-wrap: break-word; word-break: normal; hyphens: auto;
  font-size: clamp(11px, min(var(--fw, 20) * 1cqw, var(--fh, 30) * 1cqh), 44px);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.gr-b-n { font-size: clamp(10px, 9cqw, 16px); font-weight: 700; opacity: 0.85; font-variant-numeric: tabular-nums; margin-top: 2px; }
.gr-b-from { font-size: clamp(9px, 6cqw, 12px); opacity: 0.8; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.gr-block[data-size="s"] .gr-b-n, .gr-block[data-size="s"] .gr-b-from { display: none; }
.gr-block[data-size="m"] .gr-b-from { display: none; }
/* [DASH-18] THE NAME WINS. A short block used to push its name out of the top
   of the box (flex-end + overflow hidden) and leave only the count showing —
   "2" with no word. Measured against the block's REAL box: under 64px the
   name is one ellipsised line and the count goes; the tooltip keeps both. */
.gr-block { justify-content: flex-start; }
.gr-b-name { order: 0; flex: 0 1 auto; max-width: 100%; }
.gr-b-n, .gr-b-from { order: 1; }
@container (max-height: 64px) {
  .gr-b-name { display: block; -webkit-line-clamp: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; hyphens: none; }
  .gr-b-n, .gr-b-from { display: none; }
}
@container (max-width: 72px) {
  .gr-b-name { display: block; -webkit-line-clamp: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; hyphens: none; }
  .gr-b-n, .gr-b-from { display: none; }
}
.gr-note { display: flex; align-items: center; gap: 8px; margin: 0; font-size: 12.5px; color: var(--ink-soft); }
.gr-more { margin: 0; padding: 0; list-style: none; display: grid; gap: 4px; }
.gr-more-b { display: flex; justify-content: space-between; gap: 12px; width: 100%; padding: 8px 10px; border: 0;
             border-radius: var(--r-box); background: none; color: var(--ink); font: inherit; cursor: pointer; text-align: left; }
.gr-more-b:hover { background: var(--violet-wash); }
.gr-more-n { font-weight: 600; }
.gr-more-c { font-variant-numeric: tabular-nums; }

/* ---- your things: a flickable row of covers, and the box that opens it all ---- */
.tb-covers {
  display: flex; gap: 12px; margin: 0; padding: 4px 2px 10px; list-style: none;
  overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x proximity;
  scrollbar-width: thin;
}
.tb-cover { flex: 0 0 auto; width: 132px; scroll-snap-align: start; }
.tb-cover-b { display: flex; flex-direction: column; gap: 6px; width: 100%; padding: 0; border: 0; background: none; font: inherit; cursor: pointer; text-align: left; color: var(--ink); }
.tb-cover-art {
  display: block; width: 132px; height: 132px; border-radius: var(--r-art); overflow: hidden;
  background: var(--paper-deep, var(--paper)); border: 1px solid var(--line);
  box-shadow: 0 8px 18px -12px rgba(20, 8, 40, 0.5);
  transition: transform 160ms var(--soft, ease);
}
.tb-cover-b:hover .tb-cover-art { transform: translateY(-2px); }
.tb-cover-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.tb-cover-art.is-blank { display: grid; place-items: center; padding: 10px; }
.tb-cover-t { font-size: 12px; font-weight: 700; line-height: 1.2; color: var(--ink-soft); text-align: center;
              display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
.tb-cover-n { font-size: 12px; font-weight: 600; line-height: 1.25; color: var(--ink);
              display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.db-things-open {
  display: inline-flex; align-items: center; gap: 12px; padding: 6px 12px 6px 14px;
  border: 1px solid var(--line-strong); border-radius: var(--r-box); background: var(--white);
  font: inherit; color: var(--ink); cursor: pointer;
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.db-things-open:hover { border-color: var(--violet); box-shadow: var(--raise); }
.db-things-open-l { display: inline-flex; align-items: center; gap: 4px; font-size: 12.5px; font-weight: 700; color: var(--spine); }

/* ---- everything you're into: the word map, then the quiet tail ---- */
/* "a brain graph of words clumped into a cool little map. Not a literal
   list." The field's height and every position are written by the layout
   in dashboard.js, in pixels of the measured width; the words are the same
   buttons the field used, so a word still opens what carries it. */
.db-everything { display: flex; flex-direction: column; gap: 14px; }
.db-everything .dsh-interests { display: flex; flex-direction: column; gap: 10px; }
.wm { position: relative; width: 100%; min-width: 0; }
.wm-field { position: relative; width: 100%; min-height: 120px; overflow: hidden; border-radius: var(--r-box);
            background:
              radial-gradient(60% 55% at 50% 50%, var(--violet-wash), transparent 70%),
              var(--paper); }
.wm-cell { position: absolute; transition: left 420ms var(--ease), top 420ms var(--ease); }
.wm .wf-w { white-space: nowrap; padding: 2px 6px; transform-origin: center;
            transition: transform 160ms var(--ease), background var(--fast) var(--ease), color var(--fast) var(--ease); }
.wm .wf-w:hover, .wm .wf-w:focus-visible { transform: scale(1.1); background: var(--white); box-shadow: var(--raise); z-index: 2; position: relative; }
.wm .wf-l { text-wrap: nowrap; }
@media (prefers-reduced-motion: reduce) { .wm-cell, .wm .wf-w { transition: none; } }
.db-tail { display: flex; flex-direction: column; gap: 8px; padding-top: 12px; border-top: 1px solid var(--line-soft); }
.db-tail-h { margin: 0; font-size: 13.5px; font-weight: 700; color: var(--ink-soft); }
.db-tail-pills { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; }
.db-tail-pill {
  display: inline-flex; align-items: baseline; gap: 6px; padding: 5px 10px;
  border: 1px solid var(--line); border-radius: var(--r-box); background: var(--white);
  font: inherit; font-size: 12.5px; font-weight: 600; color: var(--ink); cursor: pointer;
}
.db-tail-pill:hover { border-color: var(--violet); color: var(--spine); }
.db-tail-pill-n { font-size: 11px; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.db-seeall { align-self: stretch; justify-content: center; height: 40px; border: 1px solid var(--line); background: var(--white); }

/* ---- from: the apps ---- */
.tb-from { display: flex; flex-wrap: wrap; gap: 10px; margin: 0; padding: 0; list-style: none; }
.tb-src { display: inline-flex; align-items: center; gap: 10px; padding: 8px 14px 8px 8px; border: 1px solid var(--line-strong); border-radius: var(--r-box); background: var(--white); }
.tb-src-logo { display: inline-grid; place-items: center; width: 34px; height: 34px; border-radius: var(--r-art); background: var(--paper); border: 1px solid var(--line); }
.tb-src-name { font-size: 14px; font-weight: 800; }
.tb-src-when { font-size: 12px; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.tb-src-when.is-faint { color: var(--ink-faint); }

@media (max-width: 720px) {
  .db-profile { gap: 22px; }
  .db-hero { padding: 18px 16px; }
  .tb-cover, .tb-cover-art { width: 112px; }
  .tb-cover-art { height: 112px; }
  .gr-field { aspect-ratio: 4 / 3; }
}

/* ===========================================================================
   Kept from the previous board: notices, the word field and the evidence
   lists the sheets draw.
   =========================================================================== */
.dsh-notices:empty { display: none; margin: 0; }
.dsh-waiting { display: grid; gap: var(--gap-2); justify-items: start; }
.dsh-first { text-align: center; padding: var(--gap-6) var(--gap-3); }
.dsh-first h1 { margin: 0 0 var(--gap-2); font-size: clamp(24px, 3.4vw, 34px); }
.dsh-first .lede { max-width: 52ch; margin: 0 auto var(--gap-4); color: var(--ink-soft); }
.dsh-first-actions { display: flex; justify-content: center; gap: var(--gap-2); }
.wf-cell { min-width: 0; }
.wf-w {
  display: inline-flex; align-items: baseline; gap: 5px;
  padding: 2px 2px; margin: 0;
  border: 0; background: none; cursor: pointer;
  color: var(--wf-ink, var(--ink));
  font-size: var(--fs, 15px);
  font-weight: var(--fw, 600);
  line-height: 1.18;
  letter-spacing: -0.02em;
  border-radius: var(--r-box);
  transition: color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.wf-w:hover { background: var(--wf-wash, var(--violet-wash)); }
.wf-l { text-wrap: balance; }
.wf-w[data-badge="film"],      .wf-key-i[data-badge="film"] { --wf-ink: var(--m-film);  --wf-wash: var(--m-film-wash); }
.wf-w[data-badge="tv"],        .wf-key-i[data-badge="tv"] { --wf-ink: var(--m-tv);    --wf-wash: var(--m-tv-wash); }
.wf-w[data-badge="book"],      .wf-key-i[data-badge="book"] { --wf-ink: var(--m-books); --wf-wash: var(--m-books-wash); }
.wf-w[data-badge="game"],      .wf-key-i[data-badge="game"] { --wf-ink: var(--m-games); --wf-wash: var(--m-games-wash); }
.wf-w[data-badge="community"], .wf-key-i[data-badge="community"] { --wf-ink: var(--ink); }
.wf-w[data-badge="theme"],     .wf-key-i[data-badge="theme"] { --wf-ink: var(--ink-soft); }
/* the legend breathes — "This is also bunched up together" (entry 7) */
.wf-key { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 18px; margin: 0; padding: 0; list-style: none; }
.wf-key-i {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 700; letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--wf-ink, var(--ink-soft));
}
.wf-key-dot { width: 9px; height: 9px; border-radius: var(--r-box); flex: none; background: var(--wf-ink, var(--ink-soft)); }
.wf-field { list-style: none; margin: 0; padding: 0; }
@media (max-width: 560px) { .wf-field { gap: 3px 12px; } }
.ev-row { min-width: 0; }
.ev-open {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 8px 10px; border: 0; border-radius: var(--r-box);
  background: none; color: inherit; text-align: left; cursor: pointer;
  transition: background var(--fast) var(--ease);
}
.ev-open:hover { background: var(--m-wash, var(--violet-wash)); }
.ev-art { flex: none; width: 46px; height: 46px; border-radius: var(--r-art); overflow: hidden; display: grid; place-items: center; background: var(--paper-deep); }
.ev-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ev-art.is-blank { background: var(--paper); border: 1px dashed var(--line); color: var(--ink-faint); }
.ev-main { min-width: 0; display: grid; gap: 1px; }
.ev-t { font-size: 14px; font-weight: 600; line-height: 1.3; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ev-c, .ev-e { font-size: 11.5px; color: var(--ink-faint); line-height: 1.35; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ev-src { margin-left: auto; flex: none; font-size: 10.5px; color: var(--ink-faint); padding: 2px 8px; border-radius: var(--r-box); background: var(--paper); }
@media (max-width: 520px) { .ev-src { display: none; } }

/* --- the build panel (2026-08-31, DASH-2 refined) --------------------------
   Five real steps, the live one carrying its real count and a bar whose
   width is that fraction. Concrete, quiet, nothing spinning that is not
   actually running. */
.dsh-build {
  max-width: 560px; margin: 18px 0; padding: 18px 20px;
  border: 1px solid var(--line); border-radius: var(--r-lg, 10px);
  background: var(--white);
}
.dsh-build-h { display: flex; align-items: center; gap: 9px; margin: 0 0 12px;
               font-size: 14.5px; font-weight: 800; letter-spacing: -0.01em; }
.dsh-build-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.dsh-build-step { display: grid; grid-template-columns: 18px 1fr; column-gap: 10px;
                  align-items: center; font-size: 13.5px; color: var(--ink-faint); }
.dsh-build-step[data-state="now"] { color: var(--ink); font-weight: 650; }
.dsh-build-step[data-state="done"] { color: var(--ink-soft); }
.dsh-build-dot { width: 18px; height: 18px; border-radius: 50%; display: grid;
                 place-items: center; border: 1.5px solid var(--line-strong);
                 color: var(--white); }
.dsh-build-step[data-state="done"] .dsh-build-dot { background: var(--violet); border-color: var(--violet); }
.dsh-build-step[data-state="now"] .dsh-build-dot { border-color: var(--violet); }
.dsh-build-n { font-weight: 750; font-variant-numeric: tabular-nums; }
.dsh-build-bar { grid-column: 2; height: 4px; border-radius: 2px; margin-top: 5px;
                 background: var(--violet-wash-strong); overflow: hidden; }
.dsh-build-bar i { display: block; height: 100%; background: var(--violet);
                   border-radius: 2px; transition: width 300ms var(--ease); }

/* --- Your things, logically sorted (2026-08-31, DASH-3) -------------------- */
.db-things-sections { display: grid; gap: 16px; }
.db-things-sec-h { display: flex; align-items: baseline; gap: 8px; margin: 0 0 8px;
                   font-size: 12px; font-weight: 800; letter-spacing: 0.05em;
                   text-transform: uppercase; color: var(--ink-soft); }
.db-things-sec-n { font-size: 11px; font-weight: 700; color: var(--ink-faint);
                   font-variant-numeric: tabular-nums; }

/* --- the clusters (2026-08-31, DASH-7) -------------------------------------
   Worked-out interest groups, cross-platform on purpose. Cards on hairlines;
   the "worked out" tag is the honesty label and is always drawn. */
.db-clusters { margin: 0 0 18px; }
.db-cluster-list { list-style: none; margin: 0; padding: 0; display: grid;
                   grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; }
.db-cluster { border: 1px solid var(--line); border-radius: var(--r-lg, 10px);
              background: var(--white); padding: 14px 16px; min-width: 0; }
.db-cluster-name { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
                   margin: 0 0 4px; font-size: 14.5px; font-weight: 750;
                   letter-spacing: -0.01em; }
.db-cluster-tag { font-size: 10px; font-weight: 750; letter-spacing: 0.04em;
                  text-transform: uppercase; color: var(--violet);
                  border: 1px dashed var(--violet); border-radius: var(--r-box);
                  padding: 1.5px 6px; cursor: help; }
.db-cluster-why { margin: 0 0 9px; font-size: 12.5px; line-height: 1.45;
                  color: var(--ink-faint); }
.db-cluster-members { list-style: none; margin: 0; padding: 0; display: flex;
                      flex-wrap: wrap; gap: 6px; }
.db-cluster-m { display: inline-flex; align-items: center; gap: 6px; max-width: 100%;
                border: 1px solid var(--line); border-radius: var(--r-box);
                background: none; padding: 4px 9px; font-size: 12px; cursor: pointer;
                transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease); }
.db-cluster-m:hover { background: var(--violet-wash); border-color: var(--line-strong); }
.db-cluster-mt { font-weight: 600; white-space: nowrap; overflow: hidden;
                 text-overflow: ellipsis; max-width: 180px; }
.db-cluster-ms { flex: none; font-size: 10px; color: var(--ink-faint); }


/* ---- covers inside a genre block (2026-09-07) — the login collage's grid, no
   angle: a straight strip of the rows behind the block, faded under the name. */
.gr-block { overflow: hidden; }
.gr-covers { position: absolute; inset: auto 6px 6px auto; display: grid; grid-auto-flow: column; gap: 4px; z-index: 0; pointer-events: none; }
.gr-cover { width: 34px; height: 34px; border-radius: 6px; overflow: hidden; background: rgba(255,255,255,.18); opacity: .92; box-shadow: 0 1px 4px rgba(20,12,28,.18); }
.gr-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gr-cover.is-blank { display: none; }
.gr-block[data-size="s"] .gr-covers { display: none; }
.gr-block[data-size="l"] .gr-cover { width: 46px; height: 46px; }
.gr-b-name, .gr-b-n, .gr-b-from { position: relative; z-index: 1; }
.gr-block[data-custom="1"] { outline: 2px solid rgba(255,255,255,.55); outline-offset: -4px; }
.tb-genres-aside { display: flex; align-items: center; gap: 8px; }

/* ---- the platform badge, bottom-left of a cover, overflowing outside it */
.tb-cover-b { overflow: visible; }
.tb-cover-art { position: relative; overflow: visible; }
.tb-cover-src { position: absolute; left: -7px; bottom: -7px; display: flex; z-index: 2; pointer-events: none; }
.tb-cover-src-i { width: 24px; height: 24px; border-radius: 50%; background: var(--white); box-shadow: 0 1px 4px rgba(20,12,28,.25); display: grid; place-items: center; margin-left: calc(var(--k, 0) * -6px); }
.tb-cover-src-i svg, .tb-cover-src-i img { width: 14px; height: 14px; }

/* ---- the genre edit forms, inside the sheet */
.gx-form { display: flex; flex-direction: column; gap: 10px; }
.gx-row { display: grid; grid-template-columns: 72px 1fr; align-items: center; gap: 8px; }
.gx-input, .gx-select { font: inherit; padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px; background: var(--white); color: var(--ink); }
.gx-items, .gx-picked { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; max-height: 40vh; overflow: auto; }
.gx-item, .gx-picked-i { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 8px; border-radius: 8px; background: var(--paper-deep, #eee6d9); }
.gx-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 10px; flex-wrap: wrap; }
.gx-note { margin: 0; color: var(--mute); font-size: 13px; }

/* 2026-09-07: the genre sheet's Edit sits at the top, above the list. */
.gx-actions.is-top { margin: 0 0 10px; justify-content: flex-end; }
