/* rack.css — one enclosure, knobs on top, pattern display below (portrait) or beside
   it (landscape). Panel is monochrome; the theme accent is reserved for live state.
   Reuses the FM-1 theme variables from style.css. */

/* Panel typeface: Barlow Semi Condensed (SIL OFL), self-hosted so the app still
   works offline. A condensed grotesk is what a panel legend is printed in; the
   system sans was reading as a web dashboard. */
@font-face { font-family: "Panel"; src: url("fonts/barlow-sc-400.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Panel"; src: url("fonts/barlow-sc-600.woff2") format("woff2"); font-weight: 600; font-style: normal; font-display: swap; }
@font-face { font-family: "Panel"; src: url("fonts/barlow-sc-700.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; }

body { padding: 12px; font-family: "Panel", ui-sans-serif, system-ui, sans-serif; }

/* ---- panel grid: everything sits on the same 6-rail column ---- */
.rack {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 7px;
  align-items: start;
}
/* Sections draw their box with an inset shadow, NOT a border/padding: a real
   border would consume width, and a 2-rail box and a 6-rail box then produce
   different cell widths so the rails would not line up. Shadows cost no layout. */
.sect {
  border-radius: 3px;
  background-color: rgba(0, 0, 0, .07);
  box-shadow: inset 0 0 0 1px var(--line), inset 0 1px 0 rgba(255,255,255,.06);
  padding: 5px 0 7px;   /* horizontal padding must be 0 or the rails drift */
  min-width: 0;
}
.sect > h3 {
  margin: 0 2px 6px; font-size: 8.5px; letter-spacing: 2.2px; text-transform: uppercase;
  color: var(--dim); font-weight: 700; border-bottom: 1px solid var(--line); padding-bottom: 3px;
}
/* the internal gap MUST equal the panel gap, or the rails drift */
.sgrid { display: grid; gap: 8px 7px; align-items: start; }

/* controls scale with the rail so 6 columns fit a phone too */
.rack *, .rack *::before, .rack *::after { box-sizing: border-box; }
.sgrid > * { max-width: 100%; min-width: 0; }
.knob { min-width: 0; }
.knob svg { width: 100%; height: auto; }
.knob.k-lg svg { max-width: 60px; }
.knob.k-md svg { max-width: 52px; }
.knob.k-sm svg { max-width: 44px; }
.k-lab { max-width: 100%; }
/* a rotary switch shows a name, not a number, and names are longer */
.k-smallval .k-val { font-size: 8.5px; font-weight: 700; letter-spacing: .2px; }
/* Every control must fit ONE rail. The fixed pixel widths here were tuned for the
   old font and are what overflowed, so they are all rail-relative now. */
.sel { width: calc(100% - 8px); min-width: 0; margin-inline: auto; }
.sw { width: calc(100% - 8px); margin: 0 auto; }
.sw-body { max-width: 100%; width: 100%; }
.sw-arrow { flex: 0 0 auto; padding: 5px 2px 6px; }
.toggle {
  width: calc(100% - 8px); margin-inline: auto;
  font-size: 8.5px; letter-spacing: .7px; padding: 6px 7px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sw-val {
  flex: 1 1 auto; min-width: 0;
  height: 23px; line-height: 1.1;
  display: flex; align-items: center; justify-content: center;
  font-size: 9.5px; color: var(--fg); padding: 5px 1px 6px;
  text-align: center; word-break: break-word; overflow: hidden;
  font-variant-numeric: tabular-nums;
}

/* The panel grain: an SVG fractal-noise tile, blended over the panel colour at low
   strength. This is what stops the surface reading as a flat CSS rectangle. */
:root {
  --grain: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='180'%20height='180'%3E%3Cfilter%20id='n'%3E%3CfeTurbulence%20type='fractalNoise'%20baseFrequency='0.85'%20numOctaves='3'%20stitchTiles='stitch'/%3E%3CfeColorMatrix%20type='matrix'%20values='0%200%200%200%201%200%200%200%200%201%200%200%200%200%201%200.021%200.021%200.021%200%20-0.021'/%3E%3C/filter%3E%3Crect%20width='180'%20height='180'%20filter='url(%23n)'/%3E%3C/svg%3E");
  --grain-dark: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='180'%20height='180'%3E%3Cfilter%20id='d'%3E%3CfeTurbulence%20type='fractalNoise'%20baseFrequency='0.7'%20numOctaves='3'%20stitchTiles='stitch'/%3E%3CfeColorMatrix%20type='matrix'%20values='0%200%200%200%200%200%200%200%200%200%200%200%200%200%200%200.018%200.018%200.018%200%20-0.018'/%3E%3C/filter%3E%3Crect%20width='180'%20height='180'%20filter='url(%23d)'/%3E%3C/svg%3E");
}

/* Rack-only themes, rebuilt from the REAL hardware.

   THE PANEL IS THE CASE. On the real FM-1 the plastic body carries the colour
   and the knobs and screen are dark; painting every surface near-black with a
   small accent (the previous approach) measured 79% near-black on screen and
   read as dull. So --panel is the case colour itself, with --fg chosen as
   whichever of dark/light ink actually contrasts best with it (orange wanted
   dark ink at 5.4:1 while light ink only managed 3.6:1). The screen keeps its
   own dark palette, applied locally on .display, so lit steps stay readable. (the MVP's style.css is left
   alone). The seven FM-1 variants, per the seven body colourways:
     purple  pink-lavender case   + purple keys    case #c5a1da  keys #8567a8
     black   dark grey case       + black keys     case #4a4a4a  keys #222222
     grey    off-white case       + black keys     case #e3ded4  keys #4b4d4f
     orange  terracotta case      + brown keys     case #b86948  keys #b08063
     green   black case           + bright teal keys case #1e1e1e keys #85d9cd
     blue    off-white case       + navy keys      case #e8e4df  keys #607e9a
     brown   off-white case       + brown keys     case #e8e4df  keys #96714f
   Case and key colours were read off M-VAVE's own product photos (white studio
   background masked out), then calibrated against photos of real units for
   'blue' (buttons #59718e, shell #ede8e4), 'brown' (keys #91613d at the 75th
   percentile, shell #eee9e5) and 'green' (teal pads #7bd1c6, charcoal shell #232426). blue/brown/green/orange/purple were then re-derived by k-means clustering each
   close-up into 4 colours and reading the two dominant non-shadow clusters as
   the case and the keys (the variant list tells you which is which, so no
   guessing about position). 'black' and 'grey' are still product-shot estimates. Both landed within a few points of the product
   shots, which is why the product-shot values are trusted for the rest.
   Surfaces are tinted from each variant's signature colour; accents are lifted
   until they clear 4.5:1 on the background they sit on, legends 4.5:1 on the
   panel, and dividers 3:1. */
[data-theme="purple"] { --bg: #322637; --panel: #bf94d5; --panel2: #a47fb7; --line: #624c6d; --fg: #17121a; --dim: #44354c; --accent: #8072b7; --accent2: #a69ccd; --on-accent: #000000; }
[data-theme="black"]  { --bg: #131313; --panel: #4a4a4a; --panel2: #404040; --line: #979797; --fg: #f4f4f4; --dim: #b9b9b9; --accent: #7d7d7d; --accent2: #a4a4a4; --on-accent: #000000; }
[data-theme="grey"]   { --bg: #3b3a37; --panel: #e3ded4; --panel2: #c3bfb6; --line: #817e79; --fg: #1b1b19; --dim: #64625d; --accent: #7a7b7d; --accent2: #a2a3a4; --on-accent: #000000; }
[data-theme="orange"] { --bg: #37190f; --panel: #d25f3b; --panel2: #b55233; --line: #5d2a1a; --fg: #000000; --dim: #2b140c; --accent: #ab6b5f; --accent2: #c4978f; --on-accent: #000000; }
[data-theme="green"]  { --bg: #080a0a; --panel: #202526; --panel2: #1c2021; --line: #797c7d; --fg: #f2f2f2; --dim: #9b9d9d; --accent: #7acfc3; --accent2: #a2ddd5; --on-accent: #000000; }
[data-theme="blue"]   { --bg: #3d3c3b; --panel: #ece8e4; --panel2: #cbc8c4; --line: #888584; --fg: #1c1c1b; --dim: #6a6867; --accent: #667e9a; --accent2: #94a5b8; --on-accent: #000000; }
[data-theme="brown"]  { --bg: #3e3d3c; --panel: #eeeae5; --panel2: #cdc9c5; --line: #898684; --fg: #1d1c1b; --dim: #6b6967; --accent: #9c745b; --accent2: #ba9e8c; --on-accent: #000000; }

.layout { display: block; }
.module { display: flex; flex-direction: column; }

/* ---- the enclosure: a textured plate with fasteners, not a floating card ---- */
.case {
  width: 100%;
  max-width: 470px;
  margin: 0 auto;
  background-color: var(--panel);
  background-image:
    radial-gradient(circle at 15px 15px, rgba(255,255,255,.30) 0 1.5px, rgba(0,0,0,.8) 2.1px 3.4px, rgba(255,255,255,.07) 3.8px, transparent 4.4px),
    radial-gradient(circle at calc(100% - 15px) 15px, rgba(255,255,255,.30) 0 1.5px, rgba(0,0,0,.8) 2.1px 3.4px, rgba(255,255,255,.07) 3.8px, transparent 4.4px),
    radial-gradient(circle at 15px calc(100% - 15px), rgba(255,255,255,.30) 0 1.5px, rgba(0,0,0,.8) 2.1px 3.4px, rgba(255,255,255,.07) 3.8px, transparent 4.4px),
    radial-gradient(circle at calc(100% - 15px) calc(100% - 15px), rgba(255,255,255,.30) 0 1.5px, rgba(0,0,0,.8) 2.1px 3.4px, rgba(255,255,255,.07) 3.8px, transparent 4.4px),
    var(--grain),
    var(--grain-dark),
    linear-gradient(180deg, rgba(255,255,255,.03), rgba(0,0,0,.12));
  background-repeat: no-repeat, no-repeat, no-repeat, no-repeat, repeat, repeat, no-repeat;
  background-size: auto, auto, auto, auto, 180px 180px, 180px 180px, auto;
  border: 1px solid var(--line);
  border-radius: 5px;
  box-shadow:
    0 1px 0 rgba(255,255,255,.07) inset,
    0 -1px 0 rgba(0,0,0,.55) inset,
    0 10px 26px rgba(0,0,0,.4);
  padding: 12px;
}

.brand {
  display: flex; align-items: baseline; gap: 10px;
  padding: 0 2px 6px; border-bottom: 1px solid var(--line);
}
/* the title is the product name: it should be the loudest thing in the header */
.brand h1 {
  font-size: 18px; margin: 0; letter-spacing: 3.6px; font-weight: 700;
  color: var(--fg); line-height: 1; white-space: nowrap;
}
.brand h1 b { color: var(--accent); }
/* MIDI status is a small readout, not a form control */
.brand .dev {
  margin-left: auto; display: flex; align-items: center; gap: 5px; min-width: 0;
  font-size: 10px; letter-spacing: .6px; color: var(--dim);
}
.brand .dev #devname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 42vw; }
.brand .led { width: 7px; height: 7px; border-radius: 50%; background: var(--line); flex: 0 0 auto; }
.brand .led.ok { background: var(--accent); box-shadow: 0 0 6px var(--accent); }
.statusrow { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; padding: 3px 2px 6px; }
.statusrow .glink { flex: 0 0 auto; font-size: 9px; letter-spacing: 1px; text-transform: uppercase; color: var(--dim); text-decoration: none; }
.statusrow .glink:hover { color: var(--accent); }
/* the status text fills the leftover width and ellipsizes, so the links on the
   left never move when the message length changes */
.statusrow .status { flex: 1 1 auto; min-width: 0; text-align: right; font-size: 9px; letter-spacing: .5px; color: var(--dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.statusrow .status.ok { color: var(--fg); }
.statusrow .status.err { color: var(--err); }

.knob {
  display: flex; flex-direction: column; align-items: center;
  cursor: ns-resize; touch-action: none; user-select: none;
  outline: none; padding: 1px 2px;
}
.knob:focus-visible .k-cap { stroke: var(--accent); }
.knob svg { display: block; }
.k-tick { stroke: var(--dim); stroke-width: 1.3; }
.k-tick.major { stroke: var(--line); stroke-width: 2; }
.k-base { fill: rgba(0,0,0,.45); stroke: rgba(0,0,0,.6); stroke-width: 1; filter: drop-shadow(0 2px 3px rgba(0,0,0,.75)); }
.k-cap { stroke: rgba(0,0,0,.6); stroke-width: 1.4; filter: drop-shadow(0 1.5px 2px rgba(0,0,0,.6)); }
.k-ptr { stroke: #ededf0; stroke-width: 3.2; stroke-linecap: round; }
.knob.dragging .k-ptr { stroke: var(--accent); }
.k-end { fill: var(--dim); font-size: 12px; font-family: inherit; }
.k-lab {
  font-size: 9px; letter-spacing: 1px; text-transform: uppercase; color: var(--dim);
  text-align: center; line-height: 1.2; max-width: 78px; font-weight: 700;
}
.k-val {
  font-size: 11px; color: var(--fg); font-variant-numeric: tabular-nums;
  line-height: 1.2; text-align: center; margin-top: 1px; font-weight: 600;
}

/* ---- encoder switch (replaces native select) ---- */
/* Fixed width on purpose: the value area must not resize with the option name,
   or a long one like 'smoothRandom' shoves the neighbouring knob sideways. */
.sw { display: flex; flex-direction: column; align-items: center; flex: 0 0 auto; }
.sw-lab {
  font-size: 9px; letter-spacing: 1px; text-transform: uppercase; color: var(--dim);
  font-weight: 700; margin-bottom: 3px; text-align: center;
}
.sw-body {
  display: flex; align-items: stretch; border: 1px solid var(--line); border-radius: 3px;
  background: var(--panel2); overflow: hidden;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.10), inset 0 -1px 0 rgba(0,0,0,.5), 0 2px 3px rgba(0,0,0,.5);
}
.sw-body:focus-within { border-color: var(--accent); }
.sw-arrow {
  font: inherit; font-size: 11px; line-height: 1; color: var(--dim); background: none;
  border: 0; padding: 5px 3px 6px; cursor: pointer;
}
.sw-arrow:hover { color: var(--fg); }

/* ---- toggle ---- */
.toggle {
  font: inherit; font-size: 9px; letter-spacing: 1.1px; text-transform: uppercase;
  color: var(--dim); background: var(--panel2); border: 1px solid var(--line);
  border-radius: 3px; padding: 6px 9px; cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.10), inset 0 -1px 0 rgba(0,0,0,.5), 0 2px 3px rgba(0,0,0,.5);
}
.toggle:active { transform: translateY(1px); box-shadow: inset 0 2px 4px rgba(0,0,0,.6); }
.sel { display: flex; flex-direction: column; align-items: center; }
.sel span {
  font-size: 9px; letter-spacing: 1px; text-transform: uppercase; color: var(--dim);
  font-weight: 700; margin-top: 3px;
}
.sel input {
  font: inherit; font-size: 10px; color: var(--fg); background: var(--panel2);
  border: 1px solid var(--line); border-radius: 3px; padding: 5px 3px;
  width: 100%; text-align: center; font-variant-numeric: tabular-nums;
}
.sel input:focus { outline: none; border-color: var(--accent); }
.toggle.on { color: var(--bg); background: var(--accent); border-color: var(--accent); font-weight: 700; }

/* ---- transport: Play is the primary action, utilities are secondary ---- */
.transport { display: flex; gap: 5px; flex-wrap: wrap; align-items: center; justify-content: center; margin: 0 0 8px; }
.transport button {
  font: inherit; font-size: 9.5px; letter-spacing: .8px; text-transform: uppercase;
  color: var(--dim); background: var(--panel2); border: 1px solid var(--line);
  border-radius: 3px; padding: 5px 7px; cursor: pointer;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.10),
    inset 0 -1px 0 rgba(0,0,0,.55),
    0 2px 3px rgba(0,0,0,.55),
    0 1px 1px rgba(0,0,0,.4);
  transition: box-shadow .08s, transform .08s;
}
.transport button:active {
  transform: translateY(1px);
  box-shadow: inset 0 2px 4px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.03);
}
.transport button:hover { color: var(--fg); border-color: var(--dim); }
/* the preview-sound switch sits inline in the button bar: label dropped, width
   and padding pulled in so it never wraps onto its own row */
.transport .sw { width: auto; flex: 0 0 auto; flex-direction: row; align-items: center; gap: 3px; margin: 0; }
.transport .sw-lab { display: none; }
.transport .sw-body { width: auto; max-width: none; align-self: stretch; }
.transport .sw-arrow { padding: 3px 3px 4px; font-size: 10px; }
.transport .sw-val { height: auto; padding: 2px 4px 3px; font-size: 9px; }
/* local preset slots: a quiet row under the transport */
.presets { display: flex; gap: 4px; align-items: center; justify-content: center; margin: 0 0 8px; }
.presets button {
  font: inherit; font-size: 9px; letter-spacing: .8px; text-transform: uppercase;
  color: var(--dim); background: var(--panel2); border: 1px solid var(--line);
  border-radius: 3px; padding: 4px 8px; cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.10), inset 0 -1px 0 rgba(0,0,0,.5);
}
.presets button:hover { color: var(--fg); border-color: var(--dim); }
.presets button.armed { color: var(--fg); border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.presets .pslot.filled { color: var(--accent); border-color: var(--accent); font-weight: 700; }
.transport button#audition {
  color: var(--fg); font-weight: 700; padding: 6px 16px; border-color: var(--dim);
}
.transport button#audition.playing { color: var(--bg); background: var(--accent); border-color: var(--accent); }
.themebar { display: flex; justify-content: center; margin-top: 9px; }
.themebar .swatches { display: flex; gap: 4px; align-items: center; }
.themebar .swatches::before { content: "THEME"; font-size: 8px; letter-spacing: 1.1px; color: var(--dim); margin-right: 5px; }
.themebar .swatch { width: 15px; height: 15px; padding: 0; border-radius: 2px; border: 1px solid var(--line); cursor: pointer; }
.themebar .swatch.active { border-color: var(--fg); }

/* ---- pattern display: the screen inside the case ---- */
/* ---- pattern display: the screen inside the case. It carries its OWN dark palette
   so the step grid stays a dark TFT even when the panel is a light case colour. ---- */
.display {
  --panel: #121216; --panel2: #1c1c22; --line: #4a4a52;
  --fg: #ececf0; --dim: #9a9aa2;
  margin-top: 9px; padding: 8px; border-radius: 4px;
  background-color: #0f0f12;
  border: 1px solid rgba(0,0,0,.55);
  box-shadow:
    inset 0 4px 14px rgba(0,0,0,.66),
    inset 0 -1px 0 rgba(255,255,255,.04),
    0 1px 0 rgba(255,255,255,.05);
}
.display h2 { margin: 0 0 6px; font-size: 8px; letter-spacing: 1.8px; text-transform: uppercase; color: var(--dim); font-weight: 700; }
.display h2 small { color: var(--fg); letter-spacing: .4px; font-weight: 400; text-transform: none; }

/* two unambiguous states: a step is lit or it is not. The circle lives INSIDE the
   cell, so the grid can stretch to any shape while every step stays round. */
.display .steps { padding: 8px; border-radius: 3px; gap: 6px; grid-template-columns: repeat(8, 1fr); }
/* min-width: 0 — a grid item's automatic minimum is its min-content size, and the dot's
   size is derived from the (height-driven) cell, so the 1fr tracks used to grow past the
   screen: the last column hung out of the TFT on the right. Pinning the tracks' minimum
   to 0 makes the 8 columns always divide the container exactly. */
.display .cell { display: grid; place-items: center; background: none; border: 0; padding: 0; min-width: 0; }
.display .cell > .dot {
  aspect-ratio: 1; height: 100%; max-width: 100%;
  border-radius: 50%; border: 1px solid var(--line);
  display: grid; place-items: center; line-height: 1;
  font-size: 9px; color: transparent; font-variant-numeric: tabular-nums;
}
.display .cell.on > .dot { background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 700; }
.display .cell.off > .dot { border-color: transparent; opacity: .25; }
.display .cell.now > .dot { box-shadow: 0 0 0 2px var(--fg); }
.display .cell.locked > .dot { border-color: var(--fg); border-style: dashed; border-width: 2px; }
.display .cell.edit > .dot { box-shadow: 0 0 0 2px var(--accent); }
/* Loop region: the DOT itself carries the highlight — loop notes keep their
   full brightness and gain an accent ring, loop rests lift out of the dim,
   and the region's first step gets a bright fg ring. The ring is a
   pseudo-element, so it never fights the playhead/edit/lock box-shadows. */
.display .cell.loop > .dot { position: relative; }
.display .cell.loop > .dot::after {
  content: ""; position: absolute; inset: -3px; border-radius: 50%;
  border: 2px solid color-mix(in srgb, var(--accent) 70%, transparent);
  pointer-events: none;
}
.display .cell.loop.off > .dot { opacity: .5; }
.display .cell.loopstart > .dot::after { border-color: var(--fg); }
.display .cell.loopstart.off > .dot { opacity: .6; }

.display .wave { display: block; width: 100%; height: 72px; margin-top: 6px; border-radius: 3px; background: #0b0b0e; border: 1px solid rgba(0,0,0,.55); }
.display .bank { gap: 4px; }
.display .bankcell { padding: 4px 2px; border-radius: 3px; background: transparent; }
.display .bankcell.sel { border-color: var(--accent); box-shadow: none; }
.display .editor { margin-top: 6px; padding: 6px 8px; border-radius: 3px; }
.display .editor .elab { color: var(--dim); }
.display .enote { color: var(--fg); }

/* ---- landscape: module left, pattern display right ---- */
@media (min-aspect-ratio: 1/1) {
  body { padding: 10px; }
  .case { max-width: 1080px; }
  .layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
    gap: 11px;
    align-items: stretch;   /* both panels end on the same line */
  }
  /* the screen fills its column, so both panels end on the same line. The 8x8 grid
     stretches to any shape and every step stays round because the circle is
     inscribed in its cell rather than being the cell. */
  .display { display: flex; flex-direction: column; margin-top: 0; }
  .display .steps { flex: 1 1 auto; min-height: 0; grid-auto-rows: 1fr; }
  .display .bank { grid-template-columns: repeat(16, 1fr); }
}

@media (max-width: 400px) {
  .display .steps { gap: 5px; }
  .display .bank { grid-template-columns: repeat(8, 1fr); }
  .k-lab { max-width: 62px; }
}
