FLUX

Midsummer
Celebrating the Solstice
Select your role
🎼
Music Director
🎻
Cello
🎻
Violin
🎶
Harp
🎸
Pedal Steel
🎧
Sound Engineer
🎥
Camera / Film
💪
Crew
Connecting...
FLUX Midsummer
0:00
60:00
--
--
--:--
Set
Starting...
FLUX — MD
--:--
--
--:--
Room
----
Share performer link
--
--
--:--
Full set
Connecting...
FLUX — Crew
0:00
60:00
--
--
--:--
Set
Connecting...
FLUX — Sound (Vicente)
0:00
60:00
--
--
--:--
Set
Connecting...
FLUX — Camera
0:00
60:00
--
--
--:--
Set
<style>
  .flux-app * { margin: 0; padding: 0; box-sizing: border-box; }
  .flux-app {
    width: 100%; min-height: 80vh;
    background: #F5F3EE; color: #141414;
    font-family: Georgia, 'Times New Roman', serif;
    -webkit-tap-highlight-color: transparent;
    -webkit-user-select: none; user-select: none;
  }
  .flux-app button, .flux-app input, .flux-app textarea {
    font-family: 'Helvetica Neue', Arial, sans-serif;
    -webkit-appearance: none; appearance: none;
  }
  .flux-app .fx-screen { display: none; }
  .flux-app .fx-screen.active { display: block; }
  .flux-app .fx-role {
    min-height: 70vh; display: flex; flex-direction: column;
    justify-content: center; align-items: center; padding: 2.5rem;
  }
  .flux-app .fx-role-label {
    font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
    color: #4A6B5A; margin-bottom: 0.5rem;
    font-family: 'Helvetica Neue', Arial, sans-serif;
  }
  .flux-app .fx-role-title {
    font-size: 28px; font-weight: 400; margin-bottom: 2rem; color: #141414;
  }
  .flux-app .fx-role-btn {
    width: 280px; padding: 18px 20px; border-radius: 4px; margin-bottom: 12px;
    font-size: 15px; font-weight: 500; cursor: pointer; text-align: center;
    border: none; transition: transform 0.1s;
    font-family: 'Helvetica Neue', Arial, sans-serif;
  }
  .flux-app .fx-role-btn:active { transform: scale(0.97); }
  .flux-app .fx-rb-primary { background: #2A4A3C; color: #E8F0EC; }
  .flux-app .fx-rb-secondary { background: transparent; color: #141414; border: 1px solid rgba(20,20,20,0.15); }
  .flux-app .fx-rb-sub { font-size: 11px; font-weight: 300; opacity: 0.5; margin-top: 4px; }
  .flux-app .fx-status {
    padding: 8px 20px; font-size: 11px; letter-spacing: 0.1em;
    text-align: center; text-transform: uppercase;
    font-family: 'Helvetica Neue', Arial, sans-serif;
  }
  .flux-app .fx-status.on { background: rgba(42,74,60,0.08); color: #2A4A3C; }
  .flux-app .fx-status.off { background: rgba(160,60,60,0.08); color: #a03c3c; }
  .flux-app .fx-status.wait { background: rgba(160,140,60,0.06); color: #8a7a30; }
  .flux-app .fx-topbar {
    display: flex; justify-content: space-between; align-items: center;
    padding: 10px 1.5rem; border-bottom: 0.5px solid rgba(20,20,20,0.12);
  }
  .flux-app .fx-topbar .fx-tl {
    font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
    color: #4A6B5A; font-family: 'Helvetica Neue', Arial, sans-serif;
  }
  .flux-app .fx-exit {
    padding: 4px 14px; border-radius: 2px; border: 1px solid rgba(20,20,20,0.12);
    background: transparent; font-size: 11px; cursor: pointer; color: #5A5A5A;
  }
  .flux-app .fx-room {
    padding: 1.25rem 1.5rem; text-align: center;
    border-bottom: 0.5px solid rgba(20,20,20,0.08);
  }
  .flux-app .fx-room-label {
    font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
    color: #7A7A7A; margin-bottom: 4px;
    font-family: 'Helvetica Neue', Arial, sans-serif;
  }
  .flux-app .fx-room-code {
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 32px; font-weight: 700; letter-spacing: 8px; color: #2A4A3C;
  }
  .flux-app .fx-room-hint {
    font-size: 12px; color: #7A7A7A; margin-top: 4px;
    font-family: 'Helvetica Neue', Arial, sans-serif;
  }
  .flux-app .fx-peers {
    font-size: 12px; color: #4A6B5A; margin-top: 6px;
    font-family: 'Helvetica Neue', Arial, sans-serif;
  }
  .flux-app .fx-join {
    min-height: 70vh; display: flex; flex-direction: column;
    justify-content: center; align-items: center; padding: 2.5rem;
  }
  .flux-app .fx-join-input {
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 28px; text-align: center; padding: 14px 20px; width: 200px;
    border: 1.5px solid rgba(20,20,20,0.15); border-radius: 4px;
    background: #fff; color: #141414; letter-spacing: 6px;
    outline: none; text-transform: uppercase;
  }
  .flux-app .fx-join-input:focus { border-color: #2A4A3C; }
  .flux-app .fx-join-input::placeholder { color: rgba(20,20,20,0.15); }
  .flux-app .fx-join-btn {
    margin-top: 16px; padding: 14px 40px; border-radius: 4px;
    background: #2A4A3C; color: #E8F0EC; border: none;
    font-size: 14px; font-weight: 500; cursor: pointer;
  }
  .flux-app .fx-join-btn:disabled { opacity: 0.3; }
  .flux-app .fx-join-err {
    color: #a03c3c; font-size: 13px; margin-top: 12px;
    font-family: 'Helvetica Neue', Arial, sans-serif;
  }
  .flux-app .fx-md-current { padding: 1.5rem; text-align: center; }
  .flux-app .fx-part-tag {
    font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
    color: #4A6B5A; margin-bottom: 4px;
    font-family: 'Helvetica Neue', Arial, sans-serif;
  }
  .flux-app .fx-sec-name {
    font-size: 26px; font-weight: 400; line-height: 1.2; margin-bottom: 8px; color: #141414;
  }
  .flux-app .fx-sec-inst {
    font-size: 14px; color: #5A5A5A; line-height: 1.7;
    max-width: 460px; margin: 0 auto;
  }
  .flux-app .fx-nav { display: flex; gap: 12px; padding: 1rem 1.5rem; justify-content: center; }
  .flux-app .fx-nav-btn {
    flex: 1; max-width: 200px; padding: 16px 12px; border-radius: 4px;
    font-size: 14px; font-weight: 500; cursor: pointer;
    text-align: center; transition: transform 0.1s;
  }
  .flux-app .fx-nav-btn:active:not(:disabled) { transform: scale(0.96); }
  .flux-app .fx-nav-btn:disabled { opacity: 0.2; cursor: default; }
  .flux-app .fx-nb-prev { background: transparent; border: 1px solid rgba(20,20,20,0.12); color: #141414; }
  .flux-app .fx-nb-next { border: none; background: #2A4A3C; color: #E8F0EC; }
  .flux-app .fx-nb-sub { font-size: 11px; font-weight: 300; opacity: 0.6; margin-top: 4px; }
  .flux-app .fx-setlist { padding: 0.5rem 1.5rem 2.5rem; }
  .flux-app .fx-sl-label {
    font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
    color: #7A7A7A; margin-bottom: 8px;
    font-family: 'Helvetica Neue', Arial, sans-serif;
  }
  .flux-app .fx-track {
    display: flex; justify-content: space-between; align-items: center;
    padding: 10px 12px; border-radius: 4px; margin-bottom: 3px;
    cursor: pointer; border-left: 3px solid transparent; transition: all 0.15s;
  }
  .flux-app .fx-track:active { transform: scale(0.99); }
  .flux-app .fx-track.active { background: rgba(42,74,60,0.06); border-left-color: #2A4A3C; }
  .flux-app .fx-track.past { opacity: 0.3; }
  .flux-app .fx-tn { font-size: 14px; font-weight: 400; color: #141414; }
  .flux-app .fx-track.active .fx-tn { font-weight: 600; }
  .flux-app .fx-tp { font-size: 11px; color: #7A7A7A; margin-top: 2px; font-family: 'Helvetica Neue', Arial, sans-serif; }
  .flux-app .fx-tpart { font-size: 10px; color: #7A7A7A; font-family: 'Helvetica Neue', Arial, sans-serif; }
  .flux-app .fx-perf-main {
    padding: 3rem 1.5rem; text-align: center;
    min-height: 50vh; display: flex; flex-direction: column;
    justify-content: center; align-items: center;
  }
  .flux-app .fx-perf-name {
    font-size: min(10vw, 42px); font-weight: 400;
    line-height: 1.15; margin-bottom: 1.25rem; color: #141414;
  }
  .flux-app .fx-perf-inst {
    font-size: min(4.5vw, 18px); color: #5A5A5A; line-height: 1.7; max-width: 520px;
  }
  .flux-app .fx-perf-next {
    padding: 1.25rem 1.5rem;
    border-top: 0.5px solid rgba(20,20,20,0.08);
    border-bottom: 0.5px solid rgba(20,20,20,0.08);
  }
  .flux-app .fx-pn-label {
    font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
    color: #7A7A7A; margin-bottom: 6px;
    font-family: 'Helvetica Neue', Arial, sans-serif;
  }
  .flux-app .fx-pn-name { font-size: 18px; color: #141414; margin-bottom: 4px; }
  .flux-app .fx-pn-inst { font-size: 13px; color: #7A7A7A; line-height: 1.5; }
  .flux-app .fx-edit-bg {
    display: none; position: fixed; inset: 0; z-index: 9999;
    background: rgba(0,0,0,0.35); justify-content: center; align-items: center; padding: 20px;
  }
  .flux-app .fx-edit-bg.open { display: flex; }
  .flux-app .fx-edit-card {
    background: #F5F3EE; border-radius: 6px; padding: 1.5rem; width: 100%; max-width: 400px;
  }
  .flux-app .fx-edit-card h3 { font-size: 16px; font-weight: 600; margin-bottom: 14px; color: #141414; }
  .flux-app .fx-edit-card input {
    width: 100%; padding: 10px 12px; margin-bottom: 10px; border-radius: 4px;
    border: 1px solid rgba(20,20,20,0.15); font-size: 15px; background: #fff; color: #141414;
  }
  .flux-app .fx-edit-card textarea {
    width: 100%; padding: 10px 12px; margin-bottom: 14px; border-radius: 4px;
    border: 1px solid rgba(20,20,20,0.15); font-size: 14px; resize: vertical;
    min-height: 80px; line-height: 1.5; background: #fff; color: #141414;
  }
  .flux-app .fx-edit-card input:focus, .flux-app .fx-edit-card textarea:focus { outline: none; border-color: #2A4A3C; }
  .flux-app .fx-eb { display: flex; gap: 8px; }
  .flux-app .fx-eb-save {
    padding: 8px 20px; border-radius: 4px; border: none;
    background: #2A4A3C; color: #E8F0EC; font-size: 13px; font-weight: 500; cursor: pointer;
  }
  .flux-app .fx-eb-cancel {
    padding: 8px 20px; border-radius: 4px;
    border: 1px solid rgba(20,20,20,0.12); background: transparent;
    font-size: 13px; cursor: pointer; color: #5A5A5A;
  }
  @media (max-width: 767px) {
    .flux-app .fx-role-btn { width: 100%; max-width: 300px; }
    .flux-app .fx-nav-btn { padding: 14px 8px; }
  }
</style>

<div class="flux-app" id="fluxApp">
  <div class="fx-screen active" id="fxRole">
    <div class="fx-role">
      <div class="fx-role-label">FLUX</div>
      <div class="fx-role-title">Live Setlist</div>
      <button class="fx-role-btn fx-rb-primary" id="btnStartMD">I'm the MD<div class="fx-rb-sub">Control the setlist</div></button>
      <button class="fx-role-btn fx-rb-secondary" id="btnShowJoin">I'm a Performer<div class="fx-rb-sub">Follow the MD's cues</div></button>
    </div>
  </div>
  <div class="fx-screen" id="fxJoin">
    <div class="fx-join">
      <div class="fx-role-label">FLUX</div>
      <div class="fx-role-title" style="margin-bottom:1.5rem;">Join Session</div>
      <div style="font-size:13px; color:#7A7A7A; margin-bottom:1rem; font-family:'Helvetica Neue',Arial,sans-serif;">Enter the code from the MD</div>
      <input class="fx-join-input" id="fxJoinInput" type="text" placeholder="XXXX" maxlength="4" autocomplete="off" autocorrect="off" autocapitalize="characters" spellcheck="false">
      <button class="fx-join-btn" id="fxJoinBtn">Connect</button>
      <div class="fx-join-err" id="fxJoinErr"></div>
      <button id="btnJoinBack" style="margin-top:1.5rem; background:none; border:none; font-size:12px; color:#7A7A7A; cursor:pointer;">Back</button>
    </div>
  </div>
  <div class="fx-screen" id="fxMD">
    <div class="fx-status wait" id="fxMdStatus">Waiting for performers</div>
    <div class="fx-topbar">
      <span class="fx-tl">FLUX — MD</span>
      <button class="fx-exit" id="btnMdExit">Exit</button>
    </div>
    <div class="fx-room">
      <div class="fx-room-label">Room Code</div>
      <div class="fx-room-code" id="fxRoomCode">----</div>
      <div class="fx-room-hint">Share this code with your performers</div>
      <div class="fx-peers" id="fxPeers"></div>
    </div>
    <div class="fx-md-current">
      <div class="fx-part-tag" id="fxMdPart">--</div>
      <div class="fx-sec-name" id="fxMdName">--</div>
      <div class="fx-sec-inst" id="fxMdInst"></div>
    </div>
    <div class="fx-nav">
      <button class="fx-nav-btn fx-nb-prev" id="fxBtnPrev">◂ PREV<div class="fx-nb-sub" id="fxPrevLabel"></div></button>
      <button class="fx-nav-btn fx-nb-next" id="fxBtnNext">NEXT ▸<div class="fx-nb-sub" id="fxNextLabel"></div></button>
    </div>
    <div class="fx-setlist">
      <div class="fx-sl-label">Full set — tap to jump, double-tap to edit</div>
      <div id="fxMdList"></div>
    </div>
  </div>
  <div class="fx-screen" id="fxPerf">
    <div class="fx-status off" id="fxPerfStatus">Connecting...</div>
    <div class="fx-topbar">
      <span class="fx-tl">FLUX — Performer</span>
      <button class="fx-exit" id="btnPerfExit">Exit</button>
    </div>
    <div class="fx-perf-main">
      <div class="fx-part-tag" id="fxPerfPart">--</div>
      <div class="fx-perf-name" id="fxPerfName">Waiting for MD...</div>
      <div class="fx-perf-inst" id="fxPerfInst"></div>
    </div>
    <div class="fx-perf-next" id="fxPerfNext" style="display:none;">
      <div class="fx-pn-label">Up Next</div>
      <div class="fx-pn-name" id="fxPerfNextName"></div>
      <div class="fx-pn-inst" id="fxPerfNextInst"></div>
    </div>
    <div class="fx-setlist" style="padding-top:1rem;">
      <div class="fx-sl-label">Set Overview</div>
      <div id="fxPerfList"></div>
    </div>
  </div>
  <div class="fx-edit-bg" id="fxEditBg">
    <div class="fx-edit-card">
      <h3>Edit Section</h3>
      <input id="fxEditName" placeholder="Section name">
      <textarea id="fxEditInst" placeholder="Instructions for performers"></textarea>
      <div class="fx-eb">
        <button class="fx-eb-save" id="btnEditSave">Save</button>
        <button class="fx-eb-cancel" id="btnEditCancel">Cancel</button>
      </div>
    </div>
  </div>
</div>