/* jGLAM — dark instrument-panel theme. Single deliberate dark mode. */

:root {
  --bg: #0e0e14;
  --surface: #14141c;
  --surface-raised: #1a1a24;
  --border: #262635;
  --ink: #e8e6e3;
  --ink-secondary: #a9a7b0;
  --ink-muted: #737180;
  --accent: #f98e09;
  --accent-soft: rgba(249, 142, 9, 0.14);
  --error: #ef6a6a;
  /* Height the track strip claims while it floats over the focus layer —
     the chip row (0.28rem padding + ~1.2rem line) plus its own top padding. */
  --focus-strip-h: 2.5rem;
  /* …and how much of it the focus layer has to pay for. Zero outside focus
     mode and at one track; set to --focus-strip-h by the focus rules. */
  --focus-strip-allowance: 0rem;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
    Arial, sans-serif;
  font-size: 14px;
  line-height: 1.5;
}

header {
  padding: 1.4rem 2rem 0.6rem;
}

h1 {
  margin: 0;
  font-size: 1.7rem;
  letter-spacing: 0.04em;
}

h1::after {
  content: "";
  display: inline-block;
  width: 0.7em;
  height: 0.7em;
  margin-left: 0.45em;
  background: url("../assets/jglam-mark.svg") center / contain no-repeat;
}

.tagline {
  margin: 0.2rem 0 0;
  color: var(--ink-secondary);
  max-width: 60ch;
}

main {
  display: grid;
  grid-template-columns: minmax(300px, 380px) 1fr;
  gap: 1.2rem;
  padding: 1.2rem 2rem;
  align-items: start;
}

@media (max-width: 900px) {
  main {
    grid-template-columns: 1fr;
  }
}

/* View switcher (Wavetable ↔ Pattern) — only exists on narrow screens;
   above the breakpoint every panel is visible and the switch is inert. */
.view-switch {
  display: none;
}

/* Track chrome (TM-277 Multi-Track) — chip strip + the active track's row,
   global (above main), so the Wavetable view shows whose recipe is being
   edited too. Two compact rows at most; at one track everything except the
   unobtrusive "+ Track" collapses away, which is the condition the whole
   boundary decision rests on (README, "Where this is going"). */
.track-chrome {
  padding: 0.4rem 2rem 0;
}

.track-strip {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
  padding-bottom: 0.15rem;
}

.track-strip button,
.track-row button {
  padding: 0.28rem 0.6rem;
  border-radius: 7px;
  font-size: 0.78rem;
  white-space: nowrap;
  flex: none;
}

.track-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
}

.track-chip[aria-pressed="true"] {
  border-color: var(--accent);
  background: var(--accent-soft);
  font-weight: 600;
}

.track-chip.is-muted .track-chip-label,
.track-chip.is-muted .track-dot {
  opacity: 0.4;
}

.track-dot {
  width: 0.6em;
  height: 0.6em;
  border-radius: 50%;
  background: var(--ink-muted);
  flex: none;
}

/* Mute/solo indicators: text, not colour alone. */
.track-chip-flag {
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  color: var(--ink-muted);
}

.track-chip.is-solo .track-chip-flag {
  color: var(--accent);
}

#track-add {
  color: var(--ink-secondary);
}

.track-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0 0.1rem;
  flex-wrap: nowrap;
  overflow-x: auto;
}

.track-row-name {
  color: var(--ink-secondary);
  font-size: 0.78rem;
  white-space: nowrap;
}

.track-row .track-level {
  flex: 1 1 6rem;
  min-width: 4.5rem;
  flex-direction: row;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.78rem;
}

.track-row .track-level input[type="range"] {
  flex: 1;
  min-width: 3.5rem;
}

#track-level-value {
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  color: var(--ink-secondary);
  width: 2.4em;
  flex: none;
}

#track-mute[aria-pressed="true"],
#track-solo[aria-pressed="true"] {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent);
}

/* One track: no chip strip, no track row — only "+ Track". */
body[data-tracks="1"] .track-chip,
body[data-tracks="1"] #track-duplicate,
body[data-tracks="1"] .track-row {
  display: none;
}

body[data-tracks="1"] .track-chrome {
  padding-bottom: 0;
}

/* Compact mobile frame: less chrome, tighter rhythm, one section at a time. */
@media (max-width: 700px) {
  header {
    padding: 0.8rem 0.8rem 0.3rem;
  }

  h1 {
    font-size: 1.3rem;
  }

  .tagline {
    display: none;
  }

  main {
    padding: 0.6rem 0.6rem 0.9rem;
    gap: 0.7rem;
  }

  .panel {
    padding: 0.7rem 0.75rem 0.9rem;
  }

  footer {
    padding: 0.2rem 0.8rem 1rem;
    font-size: 0.72rem;
  }

  .view-switch {
    display: flex;
    position: sticky;
    top: 0.4rem;
    z-index: 5;
    margin: 0 0.6rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
    background: var(--surface);
  }

  .view-switch button {
    flex: 1;
    border: none;
    border-radius: 0;
    padding: 0.5rem;
    background: var(--surface);
    color: var(--ink-secondary);
  }

  .view-switch button[aria-pressed="true"] {
    background: var(--accent-soft);
    color: var(--accent);
    font-weight: 600;
  }

  body[data-view="wavetable"] .panel.pattern {
    display: none;
  }

  body[data-view="pattern"] .panel.params,
  body[data-view="pattern"] .panel.output {
    display: none;
  }

  .track-chrome {
    padding: 0.4rem 0.6rem 0;
  }

  /* Phone width: the track name and the "Level" caption are the two things
     the active chip and the slider already say, so they go first and the
     row's four controls all fit without scrolling. */
  .track-row-name,
  .track-level-label {
    display: none;
  }
}

.panel {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1rem 1.2rem 1.2rem;
}

h2 {
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--ink-secondary);
  margin: 0.4rem 0 0.6rem;
}

h2 .hint {
  text-transform: none;
  letter-spacing: normal;
  color: var(--ink-muted);
  font-weight: normal;
  margin-left: 0.5em;
}

/* Panel collapse: the heading itself is the toggle. Resets the global
   button chrome so it reads as a heading with a chevron. */
h2 .collapse-toggle {
  background: none;
  border: none;
  border-radius: 0;
  padding: 0;
  margin: 0;
  color: inherit;
  font: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 0.45em;
  width: 100%;
  text-align: left;
}

h2 .collapse-toggle:hover:not(:disabled) {
  background: none;
  border: none;
  color: var(--ink);
}

h2 .collapse-toggle::before {
  content: "▾";
  font-size: 0.9em;
  color: var(--ink-muted);
}

h2 .collapse-toggle[aria-expanded="false"]::before {
  content: "▸";
}

fieldset {
  border: 1px solid var(--border);
  border-radius: 8px;
  margin: 0 0 0.9rem;
  padding: 0.6rem 0.8rem 0.8rem;
}

legend {
  color: var(--ink-secondary);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: 0 0.4em;
}

.field-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.6rem 0.9rem;
}

label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  color: var(--ink-secondary);
  font-size: 0.8rem;
}

input,
select,
output {
  font: inherit;
  color: var(--ink);
}

input[type="number"],
select {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.35rem 0.5rem;
}

input[type="number"]:focus-visible,
select:focus-visible,
button:focus-visible,
input[type="range"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.macro-panel {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.macro-row {
  display: grid;
  grid-template-columns: 9.5em 1fr 3em;
  align-items: center;
  gap: 0.6rem;
  flex-direction: row;
}

.macro-name {
  color: var(--ink-secondary);
}

.macro-value {
  text-align: right;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

input[type="range"] {
  accent-color: var(--accent);
  height: 1.1rem;
}

button {
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.5rem 1rem;
  cursor: pointer;
}

button:hover:not(:disabled) {
  border-color: var(--accent);
  background: var(--accent-soft);
}

button:disabled {
  opacity: 0.45;
  cursor: default;
}

button.primary {
  width: 100%;
  background: var(--accent);
  border-color: var(--accent);
  color: #16110a;
  font-weight: 600;
  letter-spacing: 0.03em;
}

button.primary:hover {
  background: #ffa42e;
}

button kbd {
  font: inherit;
  font-size: 0.7rem;
  line-height: 1;
  padding: 0.1em 0.35em;
  border: 1px solid currentColor;
  border-radius: 4px;
  opacity: 0.65;
  margin-left: 0.3em;
}

#status {
  min-height: 1.2em;
  margin: 0.5rem 0 0.9rem;
  color: var(--ink-muted);
  font-size: 0.8rem;
}

#status.error {
  color: var(--error);
}

canvas {
  display: block;
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  margin-bottom: 0.9rem;
}

#waveform {
  height: 170px;
}

#heatmap {
  height: 240px;
  image-rendering: pixelated;
}

.info {
  color: var(--ink-secondary);
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
  margin: 0 0 1rem;
}

.player-bar,
.export-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  align-items: end;
  padding-top: 0.8rem;
  border-top: 1px solid var(--border);
}

.export-bar {
  margin-top: 0.9rem;
}

.player-bar label {
  min-width: 5.2em;
}

.player-bar input[type="number"] {
  width: 6em;
}

#play-toggle {
  min-width: 6.5em;
}

/* Pattern Lab */

.panel.pattern {
  grid-column: 1 / -1;
}

.pattern-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  align-items: end;
  margin: 0 0 0.6rem;
}

.pattern-bar label {
  min-width: 5.2em;
}

.pattern-bar input[type="number"] {
  width: 6em;
}

#pattern-play {
  min-width: 6.5em;
}

/* Sharing v0 (TM-267) — status line and manual-copy fallback live in the
   pattern panel itself (not the shared #status above) so both stay visible
   from the Pattern view on narrow screens, where body[data-view="pattern"]
   hides .panel.params (see the @media rule above). */
#share-status {
  min-height: 1.2em;
  margin: 0 0 0.6rem;
  color: var(--ink-muted);
  font-size: 0.8rem;
}

#share-status.error {
  color: var(--error);
}

/* :not([hidden]) rather than a plain selector: an unconditional `display`
   here would beat the UA stylesheet's [hidden] { display: none } on
   specificity-tie-goes-to-later-sheet, keeping the field visibly present
   (empty) even while the `hidden` attribute is set — see js/main.js's
   showShareLinkFallback()/hideShareLinkFallback() toggling it. */
.share-link-fallback:not([hidden]) {
  display: block;
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--accent);
  border-radius: 6px;
  padding: 0.35rem 0.5rem;
  margin: 0 0 0.6rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.78rem;
}

/* Amp envelope graph — the primary control for the four env values; the
   number inputs below it stay as display + fine entry. Capped width: a
   full-bleed envelope on a wide desktop spreads the handles absurdly far. */
.env-graph-wrap {
  max-width: 560px;
  margin-top: 0.9rem;
}

#env-graph {
  height: 120px;
  margin-bottom: 0.5rem;
  touch-action: none; /* handle drags must never page-scroll */
}

.roll-scroll {
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  margin: 0.9rem 0 0.4rem;
}

#pattern-roll {
  /* Fixed-size viewport onto the virtual roll; roll.js pans the content
     internally (height is set by roll.js, width tracks the container). */
  border: none;
  border-radius: 0;
  margin-bottom: 0;
  touch-action: none;
}

.roll-hint {
  color: var(--ink-muted);
  font-size: 0.78rem;
  margin: 0 0 0.4rem;
}

/* Roll focus mode (CSS-only "fullscreen" — iPhone Safari has no element
   Fullscreen API): a body class turns the pattern panel into a fixed
   100dvh layer holding just the roll plus a floating transport. main.js
   fits the roll viewport height to the .roll-scroll box. */

.focus-controls {
  display: none;
}

body.roll-focus {
  overflow: hidden;
}

body.roll-focus header,
body.roll-focus footer,
body.roll-focus .view-switch,
body.roll-focus .panel.params,
body.roll-focus .panel.output {
  display: none;
}

body.roll-focus .panel.pattern {
  display: flex;
  flex-direction: column;
  position: fixed;
  inset: 0;
  z-index: 20;
  height: 100dvh;
  margin: 0;
  border: none;
  border-radius: 0;
  /* The top pays for the floating track strip; --focus-strip-allowance is
     0 when there is no strip (see below). Every rule that sets this
     element's padding must add the allowance, or the strip lands on top of
     the roll's bar ruler — which is exactly what the landscape rule below
     used to do (review F1). */
  padding: calc(0.4rem + var(--focus-strip-allowance)) 0.4rem 0.4rem;
  background: var(--bg);
}

body.roll-focus .panel.pattern h2,
body.roll-focus .pattern-bar,
body.roll-focus .env-graph-wrap,
body.roll-focus .roll-hint,
body.roll-focus .panel.pattern .export-bar,
body.roll-focus #share-status,
body.roll-focus .share-link-fallback {
  display: none;
}

/* Focus mode keeps the chip strip (switching tracks while the song plays is
   the point of the mode) but not the track row. The pattern panel is a
   fixed 100dvh layer, so the strip has to float above it and the panel pays
   for it with matching top padding — main.js's fitRollToFocus measures the
   .roll-scroll box afterwards, so the roll fits whatever is left. At one
   track there is nothing to switch between, so the strip goes away and the
   padding with it. */
body.roll-focus .track-chrome {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 22;
  height: var(--focus-strip-h);
  padding: 0.3rem max(0.4rem, env(safe-area-inset-left)) 0
    max(0.4rem, env(safe-area-inset-right));
  background: var(--bg);
}

body.roll-focus .track-row {
  display: none;
}

/* How much vertical room the floating strip claims. Carried as a custom
   property on <body> rather than as a padding rule on the panel, so that
   *every* padding rule for the focus layer (including the landscape one
   further down, which uses the padding shorthand and would otherwise reset
   a padding-top set here) composes with it instead of racing it on
   specificity. At one track there is no strip and the allowance is zero,
   which also makes the focus layer's padding identical to what it was
   before tracks existed. */
body.roll-focus {
  --focus-strip-allowance: var(--focus-strip-h);
}

body.roll-focus[data-tracks="1"] {
  --focus-strip-allowance: 0rem;
}

body.roll-focus[data-tracks="1"] .track-chrome {
  display: none;
}

body.roll-focus .roll-scroll {
  flex: 1;
  min-height: 0;
  margin: 0;
}

body.roll-focus .focus-controls {
  display: flex;
  gap: 0.6rem;
  position: fixed;
  right: max(0.7rem, env(safe-area-inset-right));
  bottom: max(0.7rem, env(safe-area-inset-bottom));
  z-index: 21;
}

.focus-controls button {
  background: rgba(26, 26, 36, 0.88);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
  min-height: 2.7em; /* comfortable touch target */
}

/* Landscape refinement: shave the frame to the safe-area insets so the
   roll gets the full width beside a notch. The top still has to pay for the
   floating track strip — this is a padding shorthand, so leaving the
   allowance out silently reset it and put the strip on top of the bar ruler
   (review F1). */
@media (orientation: landscape) {
  body.roll-focus .panel.pattern {
    padding: calc(0.25rem + var(--focus-strip-allowance))
      max(0.25rem, env(safe-area-inset-right)) 0.25rem
      max(0.25rem, env(safe-area-inset-left));
  }
}

.tooltip {
  position: fixed;
  z-index: 10;
  pointer-events: none;
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.25rem 0.55rem;
  font-size: 0.78rem;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
}

footer {
  padding: 0.6rem 2rem 1.6rem;
  color: var(--ink-muted);
  font-size: 0.8rem;
  max-width: 70ch;
}
