/* THE MUSIC ROOM — the Groove page (view-music): the record held large with its
   own colour bloomed behind it, the search card, the rails, an artist's own page,
   and the Up Next tray. Moved out of app.css on 15 Oct as part of the rebuild;
   same pixels. Loaded straight after app.css (see room-css in index.html). The
   floating jacket (.dock), the kind-of-thing chips (.music-types) and the
   speaker line (.speaker-status) stay in app.css: other pages draw them too. */

/* ==========================================================================
   GROOVE — the Listening page.
   --------------------------------------------------------------------------
   "I think I like Music Groove… I like the dark elegance, maybe add a little
    glassy/glossy effect to make look premium."

   The premium read comes from three things and none of them is more blur:
   ONE glass layer, a 1px specular edge along the top of raised surfaces, and
   depth from shadow. All three survive reduced effects, which blur does not —
   and Lucid drops to reduced effects on a machine that is struggling.

   THE BLOOM is the cover's own colour, pulled out of the artwork and thrown
   across the whole page behind everything. It is what makes the page feel
   like the record rather than like a page with a record on it, and it costs
   one canvas read.
   ========================================================================== */
#view-music{ position:relative; padding-top:var(--space-6); }
.gv-bloom{ position:fixed; inset:0; z-index:0; pointer-events:none;
  opacity:0; transition:opacity var(--dur-ambient) var(--ease-out);
  background:
    radial-gradient(58% 46% at 22% 18%, var(--gv-a, transparent), transparent 62%),
    radial-gradient(52% 44% at 82% 30%, var(--gv-b, transparent), transparent 60%);
  filter:blur(70px) saturate(1.25); }
.gv-bloom.on{ opacity:.55; }
[data-fx="lite"] .gv-bloom{ filter:none; opacity:.3; }
.gv-wrap{ position:relative; z-index:1; display:grid;
  grid-template-columns:minmax(0,1fr) 330px; gap:var(--space-6); align-items:start; }
.gv-main{ min-width:0; }

/* ---- now playing ---- */
.gv-head{ display:flex; gap:var(--space-8); align-items:flex-end; margin-bottom:var(--space-6); }
/* 12 September: was var(--radius-pill), which made a 230px square album
   cover a circle. Same sweep fault as .life-page — 20px is a panel corner,
   not a capsule. */
.gv-cover{ width:230px; height:230px; flex:none; border-radius:var(--radius-card);
  object-fit:cover; background:var(--glass-bg);
  box-shadow:var(--elev-floating); }
.gv-meta{ min-width:0; padding-bottom:var(--space-1); }
.gv-kicker{ font-size:var(--type-label); letter-spacing:.2em; text-transform:uppercase;
  color:var(--accent); margin-bottom:var(--space-3); font-weight:700; }
.gv-title{ font-family:var(--font-display); font-size:var(--type-display); line-height:1.03;
  letter-spacing:-.02em; font-weight:600; margin:0; }
.gv-by{ font-size:var(--type-lead); color:var(--text-dim); margin-top:var(--space-2); }
.gv-badges{ display:flex; gap:var(--space-2); margin-top:var(--space-4); flex-wrap:wrap; }
.gv-badge{ font-size:var(--type-body); padding:var(--space-2) var(--space-3); border-radius:var(--radius-pill);
  border:1px solid var(--glass-border); background:var(--glass-bg);
  color:var(--text-dim); }
.gv-acts{ display:flex; align-items:center; gap:var(--space-3); margin-top:var(--space-5); }
.gv-scrub{ margin:var(--space-1) 0 var(--space-6); }
/* The speakers sit with the record, not above the search box — they are a
   fact about what is playing, and the search is a different job. */
.gv-devices{ display:flex; gap:var(--space-2); flex-wrap:wrap; margin-top:var(--space-4); }

/* THE WAVEFORM. Ninety-six bars, the played half lit. Only drawn when
   Spotify actually gave us the analysis — otherwise the ordinary progress
   line stands, and nothing is invented. */
.gv-wave{ display:flex; align-items:flex-end; gap:var(--space-hair); height:56px;
  cursor:pointer; margin-bottom:var(--space-3); }
.gv-wave i{ flex:1; min-width:1px; border-radius:var(--radius-tight);
  background:color-mix(in srgb, var(--text) 20%, transparent);
  transition:background var(--dur-fast) linear; }
.gv-wave i.p{ background:var(--accent); }
.gv-wave:hover i{ background:color-mix(in srgb, var(--text) 30%, transparent); }
.gv-wave:hover i.p{ background:var(--accent-2, var(--accent)); }

/* ---- search ---- */
.gv-search{ position:relative; padding:var(--space-4) var(--space-5) var(--space-2); border-radius:var(--radius-card);
  border:1px solid var(--glass-border); background:var(--glass-bg);
  backdrop-filter:blur(20px); margin-bottom:var(--space-5); }
.gv-search::before{ content:''; position:absolute; inset:0 0 auto 0; height:1px;
  border-radius:var(--radius-card) var(--radius-card) 0 0;
  background:linear-gradient(90deg, transparent, rgba(255,255,255,.15) 24%,
    rgba(255,255,255,.15) 76%, transparent); pointer-events:none; }
[data-fx="lite"] .gv-search{ backdrop-filter:none; }
.gv-input{ margin:0 0 var(--space-1); background:transparent;
  border:0 !important; font-size:var(--type-lead); padding-left:0; }
.gv-input:focus{ box-shadow:none !important; }

/* ---- results ---- */
.gv-rowlabel{ font-size:var(--type-label); letter-spacing:.14em; text-transform:uppercase;
  color:var(--text-faint); margin:var(--space-5) 0 var(--space-3); font-weight:700; }
.gv-rail{ display:flex; gap:var(--space-4); overflow-x:auto; padding-bottom:var(--space-2);
  scrollbar-width:none; }
.gv-rail::-webkit-scrollbar{ display:none; }
.gv-card{ flex:none; width:154px; cursor:pointer; }
.gv-card-art{ width:154px; height:154px; border-radius:var(--radius-card); object-fit:cover;
  background:var(--glass-bg); display:block;
  box-shadow:var(--elev-raised);
  transition:transform var(--dur-base) var(--ease-out); }
.gv-card:hover .gv-card-art{ transform:translateY(-3px); }
.gv-card.round .gv-card-art{ border-radius:var(--radius-round); }
.gv-card-t{ font-size:var(--type-body); font-weight:650; margin-top:var(--space-2);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.gv-card-s{ font-size:var(--type-body); color:var(--text-faint); margin-top:var(--space-hair);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

/* ---- an artist's own page ---- */
.gv-artist{ display:flex; gap:var(--space-6); align-items:center; margin:var(--space-2) 0 var(--space-1);
  position:relative; padding-top:var(--space-6); }
.gv-back{ position:absolute; top:0; left:0; font-size:var(--type-body); color:var(--text-dim);
  cursor:pointer; }
.gv-back:hover{ color:var(--text); }
.gv-artist-art{ width:118px; height:118px; border-radius:var(--radius-round); object-fit:cover;
  flex:none; background:var(--glass-bg);
  box-shadow:var(--elev-raised); }
.gv-artist-name{ font-family:var(--font-display); font-size:var(--type-figure);
  letter-spacing:-.02em; margin:0; line-height:1.05; }
.gv-artist-sub{ font-size:var(--type-body); color:var(--text-faint); margin-top:var(--space-2); }

/* ---- the queue ---- */
.gv-side{ position:sticky; top:14px; border-radius:var(--radius-card); padding:var(--space-4) var(--space-4);
  border:1px solid var(--glass-border); background:var(--glass-bg);
  backdrop-filter:blur(20px); }
[data-fx="lite"] .gv-side{ backdrop-filter:none; }
.gv-side-h{ font-size:var(--type-label); letter-spacing:.16em; text-transform:uppercase;
  color:var(--text-faint); font-weight:700; margin-bottom:var(--space-3); padding:0 var(--space-1); }
.gv-q{ display:flex; align-items:center; gap:var(--space-3); padding:var(--space-2) var(--space-2);
  border-radius:var(--radius-card); cursor:pointer; }
.gv-q:hover{ background:color-mix(in srgb, var(--accent) 10%, transparent); }
.gv-q.on{ background:color-mix(in srgb, var(--accent) 15%, transparent); }
.gv-q-n{ width:16px; font-size:var(--type-body); color:var(--text-faint);
  font-variant-numeric:tabular-nums; flex:none; text-align:right; }
.gv-q-art{ width:36px; height:36px; border-radius:var(--radius-control); flex:none; object-fit:cover;
  background:var(--glass-bg); }
.gv-q-b{ min-width:0; flex:1; }
/* Titles wrap to two lines rather than running off the side — a live Dead
   track name is forty characters before it reaches the venue. */
.gv-q-t{ font-size:var(--type-body); font-weight:600; overflow:hidden; text-overflow:ellipsis;
  white-space:normal; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
  line-height:1.28; }
.gv-q.on .gv-q-t{ color:var(--accent); }
.gv-q-s{ font-size:var(--type-label); color:var(--text-faint); white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; }

@media(max-width:1100px){
  .gv-wrap{ grid-template-columns:minmax(0,1fr); }
  .gv-side{ position:static; }
  .gv-head{ flex-direction:column; align-items:flex-start; gap:var(--space-5); }
  .gv-cover{ width:170px; height:170px; }
  .gv-title{ font-size:var(--type-figure); }
}

/* ---- the Up Next tray -------------------------------------------------
   "Can we make the up next a tray with a button to popout if selected?
    Looks great but it is so wide to see the song titles, it overpowers the
    rest of the screen. Make the tray even a little bit wider since we can
    conceal it."
   So: shut by default, wider than it was when open, and the page takes the
   room back when it is closed. */
.gv-wrap.q-open{ grid-template-columns:minmax(0,1fr) 390px; }
.gv-wrap.q-shut{ grid-template-columns:minmax(0,1fr); }
.gv-wrap.q-shut .gv-side{ display:none; }
.gv-qtab{ position:fixed; right:0; top:120px; z-index:60; display:flex;
  align-items:center; gap:var(--space-2); padding:var(--space-3) var(--space-3) var(--space-3) var(--space-4);
  border-radius:var(--radius-card) 0 0 var(--radius-card); border:1px solid var(--glass-border); border-right:0;
  background:var(--glass-bg); backdrop-filter:blur(20px); color:var(--text-dim);
  font-size:var(--type-label); letter-spacing:.14em; text-transform:uppercase; font-weight:700;
  cursor:pointer; writing-mode:vertical-rl; }
.gv-qtab:hover{ color:var(--text); }
[data-fx="lite"] .gv-qtab{ backdrop-filter:none; }
.gv-side-top{ display:flex; align-items:center; gap:var(--space-2); margin-bottom:var(--space-3);
  padding:0 var(--space-1); }
.gv-side-top .gv-side-h{ margin:0; flex:1; }
.gv-x{ width:24px; height:24px; border-radius:var(--radius-control); display:grid; place-items:center;
  color:var(--text-faint); cursor:pointer; font-size:15px; line-height:1; flex:none; }
.gv-x:hover{ color:var(--text); background:color-mix(in srgb, var(--accent) 14%, transparent); }

/* THE ONE BOX THE RULE ABOVE CANNOT REACH, and after this was fixed once and
   measured again, the reason it needs an !important.

   `.field:focus` turns the outline off — correct for every other field in the
   app, because the same rule lights the border instead. The music search box
   is the exception: its own block sets `border:0 !important` and
   `box-shadow:none !important` to sit flush inside the search card, so there
   is no border to light and no shadow to draw, and focused it was the last
   control in the app that showed a person nothing at all.

   The first attempt at this was the two declarations without the !important,
   and the sweep went on reporting the fault, because the rule that turns the
   outline off is `:root:not([data-mode="light"]) .field:focus` — four classes
   deep, where this is two. Weight, not order. Three of the four declarations
   this box already carries are !important for the same reason and against the
   same rule; the ring is the fourth. */
.gv-input:focus-visible{
  outline:var(--ring-width) solid var(--ring) !important;
  outline-offset:var(--ring-gap);
}
