/* Modus — phone layout.
 *
 * Loaded only under 760px (see the media attribute on the <link> in
 * index.html), so nothing in this file can affect the desktop layout.
 * Desktop rules live in css/app.css and are not overridden here beyond
 * what a phone genuinely needs.
 *
 * Two things drive the whole file:
 *   - body is flex, not grid. position:sticky cannot move inside a grid
 *     area sized to the element itself, so the header and transport used
 *     to scroll away. Flex gives them a tall containing block and they
 *     stick properly.
 *   - the neck stays horizontal, like a guitar in your hands, and scrolls
 *     sideways in its own box when it is wider than the screen.
 */

:root {
  --ctl-h: 40px;          /* every control on this page is this tall */
  --gap: 8px;
  --pad: 12px;
}

html, body { height: auto; }

body {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  font-size: 14px;
  overscroll-behavior: auto;   /* let scrolling feel native */
}

.topbar, main, .transport { min-width: 0; }

/* ------------------------------------------------------------------ topbar */
/* One thin line: the wordmark and the view switch. This bar is pinned to the
   top of the screen the whole time you work, so it is the most expensive
   place to put anything — everything else moved into the panel head. */

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: var(--gap);
  padding: calc(6px + env(safe-area-inset-top)) var(--pad) 8px;
}

.brand { gap: 8px; padding: 0; }
.brand-text { flex-direction: row; align-items: baseline; gap: 6px; }
.brand-logo { width: 26px; height: 26px; }
.brand-mark { font-size: 15px; letter-spacing: .14em; }
.brand-sub { display: none; }

.viewseg { margin-left: auto; }
.viewseg button { height: var(--ctl-h); padding: 0 11px; font-size: 12px; }

/* ------------------------------------------------------ panel head controls */

.field { min-width: 0; }
/* A basis of 60, not auto: with auto the chord menu's base size is its widest
   option, which overflowed the line and pushed the families button off it. */
#chord-field { flex: 1 1 60px; min-width: 0; }
#scales-field { margin-left: auto; }

.field select { height: var(--ctl-h); }
#root { min-width: 72px; }
/* The chord menu takes what is left of the line, and prints just the symbol
   there — see labelQuality() in ui.js. */
#quality { width: 100%; max-width: none; }

.families button { height: var(--ctl-h); padding: 0 11px; font-size: 11.5px; }

/* Everything on one bar at 390px, so the pieces give what they can. The
   connective goes: "Parallel modes of F" needs 55px this bar does not have,
   and the toggle reads as a label for the controls beside it without one. */
.of { display: none; }
.panel-head { gap: 6px; }
.shelfseg button { padding: 0 8px; font-size: 11px; height: var(--ctl-h); }
#fams-btn { height: var(--ctl-h); padding: 0 9px; font-size: 11.5px; }
#root { min-width: 62px; }
#quality { min-width: 60px; }

/* -------------------------------------------------------------------- main */

main {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 8px;
  flex: 1 1 auto;
}

.panel { border-radius: 10px; }

/* ------------------------------------------------------------- candidates */

.candidates-panel { padding: 9px var(--pad) 9px; }
.panel-head { margin-bottom: 7px; gap: 6px; }
.panel-key { flex-basis: 100%; font-size: 11px; }

.candidates {
  margin: 0 calc(var(--pad) * -1);
  padding: 0 var(--pad) 4px;
  gap: var(--gap);
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
}
.card {
  flex: 0 0 auto;
  min-width: 168px;
  max-width: 196px;
  scroll-snap-align: start;
  padding: 9px 11px 9px;
}
.card-name { font-size: 13.5px; }
.card-parent { font-size: 10px; margin-bottom: 5px; }
.card-notes { font-size: 10.5px; margin-bottom: 5px; }
.card-row { margin-top: 2px; font-size: 10px; gap: 4px; }
.card-row .chips { gap: 3px; }
.chip { font-size: 9.5px; padding: 0 5px; line-height: 1.6; }
.card-character { display: none; }   /* prose is the first thing a phone can spare */
.card-flag { font-size: 9.5px; margin-top: 5px; }

/* The ladder is the same shelf as the cards, so it scrolls the same way. */
.ladder {
  margin: 0 calc(var(--pad) * -1);
  padding: 0 var(--pad) 4px;
  gap: var(--gap);
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
}
.rung {
  flex: 0 0 auto;
  min-width: 152px;
  max-width: 180px;
  scroll-snap-align: start;
  padding: 10px 11px 11px;
}
.rung-name { font-size: 13px; }
.rung-chord { font-size: 10px; margin-bottom: 5px; }
.rung-notes { font-size: 10.5px; margin-bottom: 5px; }
.rung-step { font-size: 10px; }

/* ------------------------------------------------------------------- board */

/* A fixed share of the viewport, not "whatever is left". Letting it flex
   looked right in a headless test and collapsed the neck to about 90px on a
   real phone: main hands out no free space there, so the panel sat on its
   floor and six strings shared what the head, the shape bar and the legend
   left over. A page that scrolls beats a fretboard you cannot read. */
.board-panel { height: 47vh; min-height: 310px; padding: 6px 6px 10px; }

/* The neck scrolls sideways inside its own box; the page never does. */
.board-wrap { overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch; }
.board-wrap::-webkit-scrollbar { height: 0; }

/* pan-x pan-y so a drag on the neck still scrolls the neck and the page.
   touch-action:none here made the page feel stuck, since the board covers
   most of the screen. */
.fretboard { touch-action: pan-x pan-y; }

/* In box mode the neck fits, so there is no sideways pan to preserve — and
   leaving pan-x on meant the browser claimed every horizontal drag, cancelled
   the pointer, and the swipe never arrived. Vertical still scrolls the page. */
body[data-shape="box"] .fretboard,
body[data-shape="box"] .board-wrap { touch-action: pan-y; }

.boardbar {
  flex-direction: column;
  align-items: stretch;
  gap: var(--gap);
  padding: var(--gap) 4px 0;
}

/* Above the neck: tuning at the left, how-you-are-looking at the right.
   Three controls is a squeeze at 390px, so let them wrap rather than push the
   page sideways. */
.board-head { gap: var(--gap); padding: 0 2px 8px; margin-bottom: 6px; flex-wrap: wrap; }
/* "Drop D" needs no caption on a phone. */
.tuningctl > span { display: none; }
/* A row of its own, or it starves the three controls beside it at 390px. */
.board-title { flex: 1 1 100%; font-size: 12.5px; }
.board-head .tuningctl { margin-left: 0; }
.board-head .seg { margin-left: auto; }
.board-head #whole-neck { height: var(--ctl-h); }

/* Below it, one row: which box, and the octave shift. */
.boardctl {
  order: -1;
  display: flex;
  align-items: center;
  /* One row. A select is as wide as its longest option unless told otherwise,
     and that pushed +12 onto a line of its own. */
  flex-wrap: nowrap;
  gap: var(--gap);
  width: 100%;
  margin-left: 0;
}
.selctl select { width: 100%; max-width: none; height: var(--ctl-h); }
.seg { height: var(--ctl-h); }
.seg button { min-height: var(--ctl-h); padding: 0 12px; }
#octave { height: var(--ctl-h); flex: 0 0 auto; }
.stepper { flex: 1 1 auto; min-width: 0; gap: 6px; }
.stepper #shape-ctl { flex: 1 1 auto; min-width: 0; }
.stepper select { max-width: none; min-width: 0; }
.stepper button { width: 44px; height: var(--ctl-h); }
.stepper output { min-width: 0; flex: 1 1 auto; }

.rangectl { display: none; }   /* the shape picker covers this */

.legend { gap: 6px 12px; width: 100%; }
.legend li { font-size: 10.5px; }


/* --------------------------------------------------------------- transport */

.transport {
  position: sticky;
  bottom: 0;
  z-index: 20;
  gap: var(--gap);
  padding: var(--gap) var(--pad) calc(var(--gap) + env(safe-area-inset-bottom));
}
.tbtn { flex: 1 1 0; min-width: 0; height: 44px; padding: 0 6px; font-size: 13px; }

/* One row. The tempo is a number rather than a slider, and what the drone
   holds only appears while it is running, which is what buys the width. */
.transport { flex-wrap: nowrap; }
.dronevoicing { flex: 0 0 auto; margin-left: 0; }
.dronevoicing button { min-height: 40px; padding: 0 9px; font-size: 11.5px; }
.bpm { flex: 0 0 auto; }
#bpm-btn { height: 44px; padding: 0 10px; font-size: 11.5px; }
.tselect { display: none; }
.audio-badge { left: var(--pad); right: var(--pad); text-align: center; }

/* ------------------------------------------------------- phone, sideways */
/* Held sideways there is width to spare and no height at all, so the cards
   move beside the neck instead of above it and everything gets shorter. */

@media (orientation: landscape) and (max-height: 560px) {
  /* Sideways there is width for all five, so the two bars become one. */
  .topbar { padding: 4px var(--pad) 6px; }
  #quality { width: auto; min-width: 104px; }
  .families button { padding: 0 10px; }
  .brand-mark { font-size: 14px; }
  .field select, .families button, .viewseg button { height: 34px; }

  main {
    display: grid;
    grid-template-columns: minmax(230px, 290px) minmax(0, 1fr);
    grid-template-rows: auto auto;
    gap: var(--gap);
    padding: var(--gap);
    min-height: 0;
  }

  /* main sizes to its content, so a 1fr row cannot resolve against the
     viewport — pin the working row to what is left after the two bars.
     89px header + 51px transport + 18px of padding and gap. */
  .candidates-panel, .board-panel { height: calc(100dvh - 158px); min-height: 190px; }

  /* Cards stack and scroll in their own column — both shelves alike. */
  .candidates-panel { grid-column: 1; grid-row: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; }
  .candidates, .ladder {
    flex-direction: column;
    overflow-x: hidden;
    overflow-y: auto;
    margin: 0;
    padding: 0 0 4px;
    scroll-snap-type: none;
  }
  .card, .rung { width: 100%; max-width: none; min-width: 0; }

  .board-panel { grid-column: 2; grid-row: 1; }

  /* Every row costs the neck 40px, so the head strip does not get one of its
     own: it sits beside the bar under the neck instead of above it. */
  .board-panel {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr) auto;
    grid-template-areas: "neck neck" "head bar";
  }
  .board-head {
    grid-area: head;
    gap: 6px;
    padding: var(--gap) 8px 0 0;
    margin: 0;
    border-bottom: 0;
    align-self: center;
  }
  .board-wrap { grid-area: neck; }
  .boardbar { grid-area: bar; }

  /* Sideways there is no height to spare, so the shape menu goes: the stepper
     walks between the same boxes and names the one you are on, and losing it
     is what keeps every control on one row. Wrapping is still allowed as a
     seatbelt — the neck is the 1fr row above, so it gives up the height. */
  #shape-ctl { display: none; }
  .stepper output { display: block; }   /* stands in for the hidden menu */
  /* The cards are beside the neck sideways, so the selected one already says
     this — and a row here costs the neck 20px it does not have. */
  .board-title { display: none; }
  .board-head { flex-wrap: wrap; }
  .board-head .seg button { padding: 0 9px; font-size: 11px; }
  .boardctl {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 6px;
    width: auto;
  }
  .stepper { flex: 0 0 auto; }
  #octave { padding: 0 8px; }
  .stepper { gap: 4px; }
  .stepper button { width: 36px; }
  .stepper output { min-width: 52px; font-size: 10.5px; white-space: nowrap; }

  /* Every pixel of height goes to the neck. */
  .legend { display: none; }
  .panel-head { margin-bottom: 6px; }
  .panel-key { display: none; }

  .transport { padding: 6px var(--pad) calc(6px + env(safe-area-inset-bottom)); }
  .tbtn { height: 38px; }
  /* Sideways everything fits on one line again, and a second transport row
     would come straight out of the neck's height. */
  .dronevoicing button { min-height: 34px; }
  #bpm-btn { height: 38px; }
}
