/* music.garryhall.me — page-specific styles.
   Everything reusable (base, .card, .tag, header/footer, scrollbars) lives
   in app.css, shared verbatim with hub.garryhall.me. The boot overlay and
   status bar are carried over from hub.css unchanged so both sites share
   the same terminal entrance. What's new here is the mixing-console
   layout: one channel strip per tool, a master bus, and a transport bar. */

/* reserve the status-bar's footprint from first paint so its fade-in
   never causes a reflow */
body {
  padding-bottom: 24px;
}

main {
  max-width: 1120px;
}

/* ── header ── */

.mark {
  width: 40px;
  height: 40px;
  filter: drop-shadow(0 0 6px rgba(0, 240, 255, 0.6));
}

/* same two-line break as hub: app.css's 0.55em letter-spacing can't fit
   "GARRYHALL // CONSOLE" on one line at 360px */
.app-header h1 {
  font-size: clamp(1rem, 5.6vw, 26px);
}

.app-header h1 .title-line {
  display: block;
  white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════════════════════
   Transport bar
   ═══════════════════════════════════════════════════════════════════════ */

.transport {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 18px;
  border-radius: 12px;
}

.tp-cell {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.tp-label {
  font-size: 8px;
  letter-spacing: 0.3em;
  color: var(--ink-dim);
}

.tp-value {
  font-size: 15px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.06em;
  color: var(--cyan);
  text-shadow: 0 0 8px rgba(0, 240, 255, 0.5);
  white-space: nowrap;
}

.tp-value small {
  font-size: 9px;
  font-weight: 400;
  letter-spacing: 0.2em;
  color: var(--ink-dim);
  text-shadow: none;
}

.tp-beats {
  flex-direction: row;
  align-items: center;
  gap: 7px;
}

.beat {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: rgba(125, 138, 165, 0.22);
  transition: background 0.08s, box-shadow 0.08s;
}

.beat.is-on {
  background: var(--cyan);
  box-shadow: var(--glow-cyan);
}

.beat:first-child.is-on {
  background: var(--magenta);
  box-shadow: var(--glow-magenta);
}

/* ═══════════════════════════════════════════════════════════════════════
   Console — mobile-first: each channel is a horizontal row
   ═══════════════════════════════════════════════════════════════════════ */

.console {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px;
}

.bus-label {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0 0;
  font-size: 9px;
  font-weight: 400;
  letter-spacing: 0.3em;
  color: var(--ink-dim);
}

.bus-label:first-of-type {
  margin-top: 0;
}

.bus-label::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, rgba(0, 240, 255, 0.25), transparent);
}

.strip {
  --accent: var(--cyan);
  --accent-soft: color-mix(in srgb, var(--accent) 28%, transparent);

  display: grid;
  grid-template-columns: 56px minmax(0, 1fr) auto;
  grid-template-areas:
    "icon head tag"
    "icon scr  scr"
    "ins  ins  open"
    "mid  mid  mid";
  align-items: center;
  column-gap: 12px;
  row-gap: 8px;
  padding: 12px;
  border: 1px solid rgba(0, 240, 255, 0.12);
  border-radius: 12px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.025), rgba(0, 0, 0, 0.22));
  color: var(--ink);
  text-decoration: none;
  transition: border-color 0.2s, box-shadow 0.2s, opacity 0.35s, filter 0.35s, transform 0.35s;
}

.strip-master {
  --accent: var(--violet);
  border-color: rgba(123, 92, 255, 0.3);
}

a.strip:hover,
a.strip:focus-visible,
.strip-master:hover,
.strip-master:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent-soft), 0 0 22px var(--accent-soft);
  outline: none;
}

/* solo: whichever strip you're on, the rest of the desk drops back */
.console:has(.strip:hover, .strip:focus-within) .strip:not(:hover):not(:focus-within) {
  opacity: 0.5;
  filter: saturate(0.6);
}

/* power-on: strips light up one by one after the boot log (gated on JS
   so the page is never left dim if the script doesn't run) */
.js-power .strip:not(.is-on) {
  opacity: 0.15;
  transform: translateY(6px);
}

/* ── strip parts ── */

.strip-head {
  grid-area: head;
  display: flex;
  align-items: center;
  gap: 8px;
}

.ch-num {
  font-size: 9px;
  letter-spacing: 0.25em;
  color: var(--ink-dim);
}

.led {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(125, 138, 165, 0.3);
  transition: background 0.2s, box-shadow 0.2s;
}

.strip.is-on .led {
  background: color-mix(in srgb, var(--accent) 45%, transparent);
}

.strip:hover .led,
.strip:focus-within .led {
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
}

.strip-icon {
  grid-area: icon;
  align-self: start;
  width: 56px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  background: var(--bg-2);
  border: 1px solid rgba(125, 138, 165, 0.18);
  overflow: hidden;
  transition: box-shadow 0.2s, border-color 0.2s;
}

.strip-icon img {
  width: 48px;
  height: 48px;
  border-radius: 9px;
}

.strip:hover .strip-icon,
.strip:focus-within .strip-icon {
  border-color: var(--accent-soft);
  box-shadow: 0 0 14px var(--accent-soft);
}

.tag-ch {
  grid-area: tag;
  justify-self: end;
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
}

.inserts {
  grid-area: ins;
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  min-width: 0;
}

.insert {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 7px;
  font-size: 9px;
  letter-spacing: 0.12em;
  white-space: nowrap;
  color: var(--ink-dim);
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(125, 138, 165, 0.2);
  border-radius: 4px;
}

.insert::before {
  content: "";
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 5px var(--accent);
  flex-shrink: 0;
}

.scribble {
  grid-area: scr;
  min-width: 0;
}

.strip-name {
  display: block;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.16em;
  color: var(--ink);
  text-shadow: 0 0 12px var(--accent-soft);
}

.strip-desc {
  display: block;
  margin-top: 3px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink-dim);
}

.strip-open {
  grid-area: open;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 8px 14px;
  font-size: 10px;
  letter-spacing: 0.25em;
  text-indent: 0.25em;
  white-space: nowrap;
  color: var(--accent);
  text-decoration: none;
  text-shadow: 0 0 8px var(--accent-soft);
  background: color-mix(in srgb, var(--accent) 7%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  border-radius: 8px;
  transition: box-shadow 0.2s, background 0.2s;
}

a.strip:hover .strip-open,
a.strip:focus-visible .strip-open,
.master-links .strip-open:hover,
.master-links .strip-open:focus-visible {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  box-shadow: 0 0 12px var(--accent-soft);
  outline: none;
}

.master-links {
  grid-area: open;
  display: flex;
  gap: 6px;
}

/* ── meters ──
   --lvl and --peak (0–1) are written by console.js. The fill is always
   full-size with the whole colour ramp painted on it, then clipped down to
   the current level, so the cyan → violet → magenta ramp stays pinned to
   the meter instead of squashing as the level falls. */

.strip-mid {
  grid-area: mid;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.meter {
  --ramp: linear-gradient(90deg, var(--cyan) 0%, var(--cyan) 55%, var(--violet) 78%, var(--magenta) 100%);
  --segments: repeating-linear-gradient(90deg, #000 0 6px, transparent 6px 8px);
  position: relative;
  display: block;
  height: 6px;
  border-radius: 2px;
  background: rgba(0, 0, 0, 0.45);
  overflow: hidden;
}

.meter::before,
.meter-fill {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--ramp);
  -webkit-mask-image: var(--segments);
  mask-image: var(--segments);
}

.meter::before {
  opacity: 0.1;
}

.meter-fill {
  clip-path: inset(0 calc((1 - var(--lvl, 0)) * 100%) 0 0);
}

.meter-peak {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 2px;
  left: calc(var(--peak, 0) * 100% - 2px);
  background: #fff;
  opacity: calc(var(--peak, 0) * 1.4);
  box-shadow: 0 0 6px var(--accent);
}

.fader {
  display: none;
}

/* ═══════════════════════════════════════════════════════════════════════
   Desktop: a real desk — vertical strips side by side, faders and all
   ═══════════════════════════════════════════════════════════════════════ */

@media (min-width: 980px) {
  .console {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    column-gap: 10px;
    row-gap: 10px;
    padding: 16px;
  }

  .bus-label {
    grid-row: 1;
    margin: 0;
    justify-content: center;
  }

  .bus-label::before,
  .bus-label::after {
    content: "";
    flex: 1;
    height: 1px;
    background: rgba(0, 240, 255, 0.22);
  }

  .bus-compose { grid-column: 1 / 5; }
  .bus-process { grid-column: 5 / 7; }
  .bus-out     { grid-column: 7 / 8; }

  .strip {
    grid-row: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 12px 10px;
  }

  .strip-head {
    width: 100%;
    justify-content: space-between;
  }

  .tag-ch {
    justify-self: auto;
  }

  .inserts {
    width: 100%;
    flex-direction: column;
    flex-wrap: nowrap;
    gap: 4px;
  }

  .insert {
    justify-content: flex-start;
  }

  .strip-mid {
    flex-direction: row;
    justify-content: center;
    gap: 6px;
    height: 200px;
    width: 100%;
  }

  .meter {
    --ramp: linear-gradient(0deg, var(--cyan) 0%, var(--cyan) 55%, var(--violet) 78%, var(--magenta) 100%);
    --segments: repeating-linear-gradient(0deg, #000 0 5px, transparent 5px 7px);
    width: 10px;
    height: 100%;
    border: 1px solid rgba(125, 138, 165, 0.16);
  }

  .meter-fill {
    clip-path: inset(calc((1 - var(--lvl, 0)) * 100%) 0 0 0);
  }

  .meter-peak {
    top: auto;
    left: 0;
    right: 0;
    width: auto;
    height: 2px;
    bottom: calc(var(--peak, 0) * 100% - 2px);
  }

  /* ── fader ── */

  .fader {
    --cap-h: 14px;
    position: relative;
    display: block;
    width: 48px;
    height: 100%;
  }

  .fader-scale span {
    position: absolute;
    left: 0;
    width: 15px;
    bottom: calc(var(--cap-h) / 2 + var(--at) * (100% - var(--cap-h)));
    transform: translateY(50%);
    font-size: 8px;
    line-height: 1;
    text-align: right;
    color: rgba(125, 138, 165, 0.7);
  }

  .fader-scale span::after {
    content: "";
    position: absolute;
    left: 18px;
    top: 50%;
    width: 5px;
    height: 1px;
    background: rgba(125, 138, 165, 0.4);
  }

  .fader-track {
    position: absolute;
    left: 31px;
    top: calc(var(--cap-h) / 2);
    bottom: calc(var(--cap-h) / 2);
    width: 4px;
    border-radius: 2px;
    background: rgba(0, 0, 0, 0.65);
    box-shadow: inset 0 0 0 1px rgba(125, 138, 165, 0.15);
  }

  .fader-cap {
    position: absolute;
    left: 19px;
    width: 28px;
    height: var(--cap-h);
    bottom: calc(var(--fader-pos, var(--fader)) * (100% - var(--cap-h)));
    border-radius: 3px;
    background: linear-gradient(180deg, #2b3448, #121826);
    border: 1px solid rgba(232, 244, 255, 0.22);
    box-shadow: 0 3px 8px rgba(0, 0, 0, 0.6);
    transition: bottom 0.5s cubic-bezier(0.2, 0.8, 0.2, 1);
  }

  .fader-cap::after {
    content: "";
    position: absolute;
    left: 3px;
    right: 3px;
    top: 50%;
    height: 2px;
    margin-top: -1px;
    background: var(--accent);
    box-shadow: 0 0 6px var(--accent);
  }

  /* push the soloed channel's fader up to unity */
  .strip:hover,
  .strip:focus-within {
    --fader-pos: 0.86;
  }

  /* ── scribble strip ── */

  .scribble {
    width: 100%;
    padding: 9px 7px;
    text-align: center;
    background: rgba(0, 0, 0, 0.4);
    border: 1px solid color-mix(in srgb, var(--accent) 22%, transparent);
    border-radius: 6px;
  }

  .strip-name {
    font-size: 13px;
    letter-spacing: 0.14em;
    text-indent: 0.14em;
  }

  .strip-desc {
    margin-top: 5px;
    font-size: 10.5px;
    min-height: 5.8em; /* 4 lines — keeps every strip the same height while descriptions type in */
  }

  .strip-open,
  .master-links {
    width: 100%;
    margin-top: auto;
  }

  .master-links .strip-open {
    flex: 1;
    padding: 8px 4px;
    letter-spacing: 0.15em;
    text-indent: 0.15em;
  }
}

/* ── keyboard hint (desktop only) ── */

.key-hint {
  display: none;
  margin: 0;
  text-align: center;
  font-size: 10px;
  letter-spacing: 0.12em;
  color: rgba(125, 138, 165, 0.6);
}

kbd {
  font-family: inherit;
  font-size: 9px;
  padding: 1px 5px;
  border-radius: 4px;
  border: 1px solid rgba(125, 138, 165, 0.35);
  color: var(--ink-dim);
}

@media (min-width: 980px) and (hover: hover) {
  .key-hint {
    display: block;
  }
}

/* ── narrow phones ── */

@media (max-width: 560px) {
  .transport {
    padding: 10px 14px;
  }

  .tp-wide {
    display: none;
  }

  .tp-value {
    font-size: 13px;
  }

  .strip {
    grid-template-columns: 48px minmax(0, 1fr) auto;
    column-gap: 10px;
  }

  .strip-icon {
    width: 48px;
    height: 48px;
    border-radius: 10px;
  }

  .strip-icon img {
    width: 40px;
    height: 40px;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   Boot overlay + status bar — identical to hub.garryhall.me
   ═══════════════════════════════════════════════════════════════════════ */

#boot-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: var(--bg);
  cursor: pointer;
  opacity: 1;
  transition: opacity 0.35s ease;
}

#boot-overlay.is-collapsed {
  opacity: 0;
  pointer-events: none;
}

.boot-log-wrap {
  width: 100%;
  max-width: 460px;
}

.boot-log {
  font-size: 13px;
  line-height: 1.8;
}

.boot-log .line {
  display: flex;
  gap: 10px;
  color: var(--ink-dim);
  white-space: pre;
}

.boot-log .line.is-indent {
  padding-left: 1.5em;
}

.boot-log .line .path {
  flex: 1;
}

.boot-log .line .status {
  color: var(--cyan);
  text-shadow: 0 0 8px rgba(0, 240, 255, 0.5);
  opacity: 0;
  transition: opacity 0.15s;
}

.boot-log .line .status.is-shown {
  opacity: 1;
}

.boot-log .line.is-ready .path {
  color: var(--ink);
}

.boot-cursor {
  display: inline-block;
  width: 0.55em;
  margin-left: 2px;
  background: var(--cyan);
  box-shadow: var(--glow-cyan);
  animation: caretBlink 0.9s step-end infinite;
}

.boot-hint {
  margin-top: 18px;
  font-size: 9px;
  letter-spacing: 0.2em;
  color: rgba(125, 138, 165, 0.5);
  text-align: center;
}

@keyframes caretBlink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}

#status-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: 24px;
  z-index: 90;
  display: flex;
  align-items: center;
  overflow: hidden;
  background: rgba(10, 14, 23, 0.85);
  border-top: 1px solid rgba(0, 240, 255, 0.12);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s ease;
}

#status-bar.is-active {
  opacity: 1;
}

.status-track {
  white-space: nowrap;
  font-size: 10px;
  letter-spacing: 0.05em;
  color: rgba(125, 138, 165, 0.55);
  padding-left: 100%;
  animation: statusScroll 26s linear infinite;
}

.status-track.is-static {
  padding-left: 12px;
  animation: none;
}

@keyframes statusScroll {
  from { transform: translateX(0); }
  to { transform: translateX(-100%); }
}

@media (prefers-reduced-motion: reduce) {
  #boot-overlay {
    display: none;
    transition: none;
  }
  .boot-cursor,
  .status-track {
    animation: none;
  }
  #status-bar,
  .strip,
  .fader-cap {
    transition: none;
  }
}
