/* Chirps — mobile first. Every size below is a thumb target before it is a
   layout decision. */

:root{
  --deep:#0A0A0A; --elev:#141414; --card:#1A1A1A;
  --line:rgba(255,255,255,.08); --line2:rgba(255,255,255,.20);
  --fg:#fff; --dim:rgba(255,255,255,.66); --faint:rgba(255,255,255,.40);
  --teal:#64FFDA; --amber:#FFAB40; --violet:#B388FF; --blue:#82B1FF;
  --mono:ui-monospace,'SF Mono',Menlo,Consolas,monospace;
  --ui:system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  /* Deliberately NOT env(safe-area-inset-*): the PublicOS in-app browser
     DOUBLE-COUNTS the top inset (a real bug the Tequio board hit), so a fixed
     pad is correct in both a normal browser and the webview. Revisit only with
     a measurement on both. */
  --padb:10px;
}

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
/* The UA's [hidden] is `display:none` at UA priority, which ANY author
   `display:` beats -- so a `.previewRow{display:flex}` stayed visible with
   `hidden` set and the publish sheet showed a blank still to a signed-out user.
   Restating it here with !important makes `el.hidden = true` mean what it says
   for every element, whatever its display. */
[hidden]{display:none!important}
html,body{margin:0;height:100%;overscroll-behavior:none}
body{
  background:var(--deep);color:var(--fg);font-family:var(--ui);font-size:14px;
  -webkit-font-smoothing:antialiased;
  /* the whole app is a fixed frame; only the grid scrolls */
  overflow:hidden;
  touch-action:manipulation;
}
button,input{font:inherit;color:inherit}
button{border:0;background:none;cursor:pointer;user-select:none}

/* ----------------------------------------------------------------- icons -- */
/* One sprite, one stroke style. The sprite is parked off-screen rather than
   display:none -- some engines drop <use> references to a hidden SVG. */
.sprite{position:absolute;width:0;height:0;overflow:hidden}
.ic{
  width:18px;height:18px;flex:0 0 auto;display:inline-block;vertical-align:middle;
  fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;
}
.ic.sm{width:13px;height:13px;stroke-width:2.4}
.ic.hd{width:16px;height:16px;margin-right:8px;color:var(--teal)}

#app{
  height:100dvh;height:100vh;
  display:flex;flex-direction:column;
}
@supports (height:100dvh){ #app{height:100dvh} }

/* ------------------------------------------------------------------ bars -- */
.bar{display:flex;align-items:center;gap:8px;padding:8px 10px;background:var(--elev);flex:0 0 auto}
.bar.top{border-bottom:1px solid var(--line)}
.bar.strip{border-top:1px solid var(--line)}
.bar.bottom{border-top:1px solid var(--line);padding-bottom:calc(8px + var(--padb));gap:6px}

.icon{
  width:40px;height:40px;flex:0 0 40px;border-radius:11px;
  border:1px solid var(--line);background:var(--card);color:var(--dim);
  display:flex;align-items:center;justify-content:center;font-size:15px;line-height:1;
}
.icon.sm{width:34px;height:34px;flex:0 0 34px;border-radius:9px;font-size:13px}
.icon.sm .ic{width:16px;height:16px}
.icon.primary{border-color:rgba(100,255,218,.42);background:rgba(100,255,218,.10);color:var(--teal)}
.icon.primary .ic{width:20px;height:20px}
.icon.primary.on{background:var(--teal);color:#04120e}
.icon:active{transform:scale(.94)}

/* The account button: a wallet glyph with a status dot pinned to its corner --
   grey signed out, teal signed in, red when sign-in could not load. */
.acctbtn{position:relative}
.acctbtn .adot{position:absolute;right:-3px;top:-3px;width:10px;height:10px;border-radius:50%;
  background:var(--elev);border:2px solid var(--faint);display:block}
.acctbtn.in{color:var(--teal);border-color:rgba(100,255,218,.42)}
.acctbtn.in .adot{background:var(--teal);border-color:var(--elev);
  box-shadow:0 0 7px rgba(100,255,218,.75)}
.acctbtn.off .adot{border-color:var(--elev);background:#FF5252}

.name{
  flex:1;min-width:0;background:none;border:0;outline:none;
  font-weight:600;font-size:14.5px;padding:6px 2px;
}
.name:focus{border-bottom:1px solid var(--line2)}

.stepper{display:flex;align-items:center;gap:4px;flex:0 0 auto}
.stepper .val{font-family:var(--mono);font-size:12px;min-width:26px;text-align:center;color:var(--dim)}
.bar .lbl{font-family:var(--mono);font-size:10px;text-transform:uppercase;letter-spacing:.07em;color:var(--faint)}
.bar .spacer{flex:1}
.win{font-family:var(--mono);font-size:11px;color:var(--faint);min-width:44px;text-align:center}

/* ------------------------------------------------------------------ tabs -- */
.tabs{display:flex;gap:5px;padding:8px 10px;background:var(--elev);border-bottom:1px solid var(--line);flex:0 0 auto}
/* A tab is the voice's wave glyph in the voice's colour, then its name. Selected
   fills with the colour: the wave stays readable because it flips to ink. */
.tab{
  --vc:#fff;
  flex:1;min-width:0;padding:7px 4px;border-radius:10px;
  border:1px solid var(--line);background:var(--card);color:var(--faint);
  font-family:var(--mono);font-size:9px;text-transform:uppercase;letter-spacing:.05em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  display:flex;align-items:center;justify-content:center;gap:5px;
}
.tab .wave{width:22px;height:14px;color:var(--vc);stroke-width:2.4}
.tab.sel{background:var(--vc);color:#04120e;font-weight:700;border-color:transparent}
.tab.sel .wave{color:#04120e}

/* ------------------------------------------------------------------ grid -- */
.gridarea{flex:1 1 auto;min-height:0;display:flex;background:var(--deep)}
/* The row gutter: 26px, which is two-thirds of a step column. Labels sit on
   the same translateY as the grid (editor.js applyOffset), so scrolling the
   window moves them together and they can never point at the wrong row. */
.gutter{flex:0 0 26px;overflow:hidden;position:relative;
  border-right:1px solid rgba(255,255,255,.10);background:var(--elev);z-index:2}
.gutrows{will-change:transform}
.grow{
  display:flex;align-items:center;justify-content:center;
  font-family:var(--mono);font-size:8.5px;letter-spacing:.02em;color:var(--faint);
  border-bottom:1px solid rgba(255,255,255,.045);
}
.grow.root{color:var(--teal);font-weight:700}
.grow.drum{color:var(--dim)}
.gridwrap{
  flex:1 1 auto;min-width:0;min-height:0;overflow-x:auto;overflow-y:hidden;
  background:var(--deep);
  /* pan-x only: the grid scrolls sideways, and a vertical drag must never be
     ambiguous with placing a note */
  touch-action:pan-x;
  -webkit-overflow-scrolling:touch;
  /* The native bar is replaced by .mini below, which says strictly more: where
     the notes are, not just where the viewport is. Hidden in both engines --
     Firefox honours scrollbar-width, WebKit/Blink need the pseudo-element. */
  scrollbar-width:none;
  -ms-overflow-style:none;
}
.gridwrap::-webkit-scrollbar{display:none;width:0;height:0}

/* the loop map — our scrollbar */
.mini{
  display:block;width:100%;height:22px;flex:0 0 auto;
  background:var(--deep);border-top:1px solid var(--line);
  touch-action:none;            /* we own the drag; never let it scroll the page */
  cursor:grab;
}
.mini:active{cursor:grabbing}
.grid{position:relative;display:grid;will-change:transform}
/* Cross-fade used only when the RULER changes (pitched <-> drums), where a
   slide would misdescribe what moved. */
.grid.swap{animation:gswap .18s ease-out}
@keyframes gswap{from{opacity:0}to{opacity:1}}
.cell{
  border-right:1px solid rgba(255,255,255,.045);
  border-bottom:1px solid rgba(255,255,255,.045);
  position:relative;
}
.cell.beat{background:rgba(255,255,255,.030)}
.cell.blk{border-right-color:rgba(255,255,255,.14)}
.cell.root{background:rgba(255,255,255,.055)}
/* A note band. `top`/`height` are set inline because a cell may hold more than
   one voice and they share the height; left/right stay in CSS. */
.cell .nt{position:absolute;left:3px;right:3px;border-radius:4px}
.cell.on:active .nt{filter:brightness(1.3)}
.playhead{position:absolute;top:0;bottom:0;width:2px;background:var(--teal);box-shadow:0 0 9px var(--teal);pointer-events:none;opacity:0;z-index:3}

/* ---------------------------------------------------------------- footer -- */
/* Four destinations, icon over label, equal width. The icon is what you aim at
   with a thumb; the label is what tells a first-timer which is which. */
.nav{
  flex:1;min-width:0;padding:7px 4px 6px;border-radius:11px;border:1px solid var(--line);
  background:var(--card);color:var(--dim);
  display:flex;flex-direction:column;align-items:center;gap:4px;
  font-family:var(--mono);font-size:9px;text-transform:uppercase;letter-spacing:.05em;
  white-space:nowrap;overflow:hidden;line-height:1;
}
.nav .ic{width:20px;height:20px}
.nav:active{transform:scale(.97)}
.nav.go{border-color:rgba(100,255,218,.42);background:rgba(100,255,218,.10);color:var(--teal);font-weight:700}

/* Text buttons inside sheets. */
.txt{
  flex:1;padding:11px 8px;border-radius:11px;border:1px solid var(--line);
  background:var(--card);color:var(--dim);
  font-family:var(--mono);font-size:10px;text-transform:uppercase;letter-spacing:.05em;
  /* nowrap is the structural fix, not just a fix for one label: a button whose
     text wraps grows taller than its siblings and breaks the row. */
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.2;
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
}
.txt .ic{width:15px;height:15px}
.txt:active{transform:scale(.97)}
.txt.go{border-color:rgba(100,255,218,.42);background:rgba(100,255,218,.10);color:var(--teal);font-weight:700}
.txt.wide{flex:none;width:100%;margin-top:16px;padding:14px}
.txt:disabled{opacity:.5}
.btnrow{display:flex;gap:8px}

/* ---------------------------------------------------------------- sheets -- */
.scrim{position:fixed;inset:0;background:rgba(0,0,0,.62);z-index:20}
.sheet{
  position:fixed;left:0;right:0;bottom:0;z-index:21;
  background:var(--elev);border-top:1px solid var(--line);
  border-radius:18px 18px 0 0;
  padding:8px 18px calc(20px + var(--padb));
  max-height:86dvh;max-height:86vh;overflow-y:auto;
}
/* The native bar is replaced by a floating thumb (see floatingBar in app.js).
   A styled ::-webkit-scrollbar still RESERVES layout width, which is exactly
   what "floating" is meant to avoid -- so the native one is hidden outright. */
.sheet{scrollbar-width:none;-ms-overflow-style:none}
.sheet::-webkit-scrollbar{display:none;width:0}

/* A zero-height sticky rail pinned to the top of the scrollport. Sticky rather
   than absolute because an absolutely positioned child of a scrolling box
   scrolls away with the content -- the same trap the grid playhead hit. */
.sbar{position:sticky;top:0;height:0;z-index:6;pointer-events:none}
.sbar i{
  position:absolute;right:4px;width:4px;border-radius:2px;display:block;
  background:rgba(255,255,255,.30);
  opacity:0;transition:opacity .3s ease-out;
}
.sbar.on i{opacity:1}

.sheet .grab{width:38px;height:4px;border-radius:2px;background:var(--line2);margin:0 auto 12px}
.sheet h2{font-size:17px;margin:0 0 6px;display:flex;align-items:center}
.sheet h3{font-size:11px;font-family:var(--mono);text-transform:uppercase;letter-spacing:.08em;color:var(--faint);margin:20px 0 9px}
.sheetlead{color:var(--dim);font-size:12.5px;line-height:1.6;margin:0}
.sheetlead.err{margin-top:12px;color:#FF5252}

/* Theme cards: a real render of each theme's still, not a named chip. */
.tcards{display:flex;gap:10px;margin-top:14px}
.tcard{
  flex:1;min-width:0;padding:8px;border-radius:14px;border:1px solid var(--line);
  background:var(--card);color:var(--dim);
  display:flex;flex-direction:column;align-items:center;gap:8px;
}
.tcard canvas{width:100%!important;height:auto!important;border-radius:9px;display:block;aspect-ratio:96/56}
.tcard span{display:flex;align-items:center;gap:6px;font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:.06em}
.tcard.sel{border-color:rgba(100,255,218,.5);background:rgba(100,255,218,.08);color:var(--teal);font-weight:700}

/* A switch row. The input stays a real checkbox (keyboard, screen readers, the
   label makes the whole row the thumb target); the <i> is only its drawing. */
.tog{position:relative;display:flex;align-items:center;gap:12px;margin-top:12px;cursor:pointer;
  border:1px solid var(--line);background:var(--card);border-radius:12px;padding:11px 12px}
.togtxt{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}
.togtxt b{font-size:13px}
.togtxt small{color:var(--faint);font-size:11px;line-height:1.45}
.tog input{position:absolute;opacity:0;width:1px;height:1px;margin:0}
.tog i{flex:0 0 40px;height:24px;border-radius:12px;background:var(--line2);position:relative;transition:background .15s}
.tog i::after{content:'';position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:#fff;transition:transform .15s}
.tog input:checked + i{background:var(--teal)}
.tog input:checked + i::after{transform:translateX(16px);background:var(--deep)}
.tog input:focus-visible + i{outline:2px solid var(--teal);outline-offset:2px}

.previewRow{display:flex;justify-content:center;align-items:flex-end;gap:12px;flex-wrap:wrap;min-height:120px;background:var(--deep);border:1px solid var(--line);border-radius:14px;margin:12px 0 6px;padding:12px}
.pv{display:flex;flex-direction:column;align-items:center;gap:6px;max-width:100%}
.pv span{font-family:var(--mono);font-size:9px;text-transform:uppercase;letter-spacing:.07em;color:var(--faint)}
/* Real card pixel sizes (87px cell), so what you see is what the grid draws.
   The one exception: a 4-wide card is 360px and a phone sheet is 354 inside
   its padding, so it may shrink by a hair rather than overflow. */
.previewRow canvas{border-radius:10px;border:1px solid rgba(255,255,255,.10);display:block;max-width:100%}

/* --------------------------------------------------------------- library -- */
.acct{display:flex;align-items:center;gap:8px;margin:10px 0 4px;
  border:1px solid var(--line);background:var(--card);border-radius:12px;padding:10px 12px}
.acct .mono{flex:1;min-width:0;font-family:var(--mono);font-size:10.5px;color:var(--dim);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dotok{width:7px;height:7px;border-radius:50%;background:var(--teal);flex:0 0 7px}
.empty{font-family:var(--mono);font-size:10.5px;color:var(--faint);text-align:center;padding:16px 0}

/* --------------------------------------------------------------- presets -- */
.plist{display:flex;flex-direction:column;gap:7px;margin-top:12px}
.prow{
  display:flex;align-items:center;gap:10px;
  border:1px solid var(--line);background:var(--card);border-radius:12px;padding:9px 10px;
}
.pplay{
  width:36px;height:36px;flex:0 0 36px;border-radius:10px;
  border:1px solid rgba(100,255,218,.35);background:rgba(100,255,218,.08);
  color:var(--teal);font-size:13px;display:flex;align-items:center;justify-content:center;
}
.pplay.on{background:var(--teal);color:#04120e}
.picon{width:36px;height:36px;flex:0 0 36px;border-radius:10px;border:1px solid var(--line);
  color:var(--faint);display:flex;align-items:center;justify-content:center}
.prow.cur{border-color:rgba(100,255,218,.35)}
.prow.cur .picon{color:var(--teal);border-color:rgba(100,255,218,.35);background:rgba(100,255,218,.08)}
.pmeta{flex:1;min-width:0}
.pmeta b{display:block;font-size:13.5px;font-weight:600}
.pmeta span{
  display:block;font-family:var(--mono);font-size:9.5px;color:var(--faint);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px;
}
.pload{
  flex:0 0 auto;padding:8px 12px;border-radius:9px;
  border:1px solid var(--line2);background:transparent;color:var(--dim);
  font-family:var(--mono);font-size:9.5px;text-transform:uppercase;letter-spacing:.05em;
}
/* Second tap confirms, because the first one would silently destroy the chirp
   the user is in the middle of writing. */
.pload.arm{border-color:rgba(255,82,82,.6);color:#FF5252;background:rgba(255,82,82,.08);font-weight:700}

.pstep{display:flex;align-items:center;gap:9px;font-family:var(--mono);font-size:10.5px;
  color:var(--faint);padding:6px 2px}
.pstep .mark{width:15px;flex:0 0 15px;display:flex;align-items:center;justify-content:center}
.pstep.done{color:var(--dim)} .pstep.done .mark{color:var(--teal)}
.pstep.now{color:var(--fg)} .pstep.bad{color:#FF5252}
.pstep .dotm{width:4px;height:4px;border-radius:50%;background:currentColor;opacity:.5}
.pstep .pulse{width:8px;height:8px;border-radius:50%;background:var(--teal);animation:pulse 1s ease-in-out infinite}
@keyframes pulse{0%,100%{transform:scale(.7);opacity:.6}50%{transform:scale(1.15);opacity:1}}

/* ------------------------------------------------------------------ zoom -- */
/* One cell, blown up, with a slot for every voice that could sit in it. Opens
   when a cell is too crowded to split legibly, or on a long press. */
.zscrim{position:fixed;inset:0;z-index:24;background:transparent}
.zoom{
  position:fixed;z-index:25;
  background:#0d0d0d;border:1px solid var(--line2);border-radius:14px;
  padding:9px 10px 8px;
  box-shadow:0 14px 40px rgba(0,0,0,.75);
  animation:zpop .12s ease-out;
}
@keyframes zpop{from{opacity:0;transform:scale(.86)}to{opacity:1;transform:scale(1)}}
.zhead{
  font-family:var(--mono);font-size:9.5px;text-transform:uppercase;letter-spacing:.07em;
  color:var(--faint);text-align:center;margin-bottom:7px;white-space:nowrap;
}
.zslots{display:flex;gap:6px}
.zslot{
  width:52px;height:60px;border-radius:9px;
  border:1px solid var(--line);background:var(--card);
  display:flex;flex-direction:column;align-items:center;justify-content:flex-end;
  padding-bottom:5px;position:relative;overflow:hidden;
}
.zslot .fillbar{position:absolute;left:0;right:0;top:0;bottom:0;opacity:0;transition:opacity .1s}
.zslot.on .fillbar{opacity:1}
.zslot .zwave{position:relative;width:26px;height:16px;color:var(--dim);margin-bottom:4px}
.zslot.on .zwave{color:#04120e}
.zslot .zname{
  position:relative;font-family:var(--mono);font-size:8.5px;text-transform:uppercase;
  letter-spacing:.04em;color:var(--faint);
}
.zslot.on .zname{color:#04120e;font-weight:700}
.zslot.hot{outline:2px solid #fff;outline-offset:-2px}
.zhint{
  font-family:var(--mono);font-size:8.5px;color:var(--faint);
  text-align:center;margin-top:7px;white-space:nowrap;
}

/* ----------------------------------------------------------------- toast -- */
.toast{
  position:fixed;left:50%;transform:translateX(-50%);bottom:calc(78px + var(--padb));
  background:#000;border:1px solid var(--line2);border-radius:10px;
  padding:9px 14px;font-family:var(--mono);font-size:11px;color:var(--fg);
  z-index:30;max-width:88vw;text-align:center;
}

/* Wide screens: the app fills the window, framed. (Until 2026-09-13 this was a
   430px phone column, on the argument that a 2000px-wide step grid is not a
   better one -- true of a STRETCHED grid, not of one that shows more of the
   loop. The columns now fit the loop to the width, editor.js colWidth(), and
   the rows already fit the height.) Controls keep thumb-sized proportions and
   stop growing, so the extra room goes to the grid. */
@media (min-width:760px){
  body{display:flex;align-items:center;justify-content:center;background:#050505}
  #app{width:min(1280px,calc(100vw - 32px));height:calc(100vh - 32px);
       border:1px solid var(--line);border-radius:20px;overflow:hidden;
       box-shadow:0 24px 60px rgba(0,0,0,.6)}
  @supports (height:100dvh){ #app{height:calc(100dvh - 32px)} }
  .bar.top,.tabs,.bar.strip,.bar.bottom{padding-left:14px;padding-right:14px}
  .name{font-size:16px}
  .tabs{justify-content:flex-start;gap:6px}
  .tab{flex:0 1 168px;font-size:10px;padding:8px 6px}
  .bar.bottom{justify-content:center;gap:8px}
  .nav{flex:0 1 150px}
  .gutter{flex-basis:34px}
  .grow{font-size:9.5px}
  /* The sheets stay position:fixed -- they are siblings of #app, so absolute
     would resolve against the viewport anyway and span its full width. Centre
     and cap them instead. */
  .sheet{left:50%;right:auto;transform:translateX(-50%);width:430px;
         bottom:24px;border-radius:18px;max-height:min(760px,84dvh)}
}
