/* =========================================================
   Christo Screen â€” Prototype design system
   Brand: gold #E3A100 Â· charcoal #333333 Â· white Â· Montserrat
   ========================================================= */

:root {
  --gold: #E3A100;
    --gold-strong: #C78D00;
    --gold-deep: #9A6E00;
    --gold-60: #EEC766;
    --gold-15: #FBF3DD;
    --ink: #333333;
    --ink-2: #5C5C60;
    --ink-3: #97979D;
    --line: #E9E6DF;
    --bg: #F7F5F0;
    --card: #FFFFFF;
    --ok: #2E9E5B;
    --ok-bg: #E7F5EC;
    --warn: #B96F00;
    --warn-bg: #FCF1DC;
    --err: #D64545;
    --err-bg: #FBEAEA;
    --info-bg: #EAF1FB;
    --radius: 14px;
    --radius-s: 9px;
    --shadow: 0 1px 2px rgba(30,25,10,.05), 0 8px 24px rgba(30,25,10,.07);
    --shadow-lg: 0 12px 40px rgba(30,25,10,.16);
    --font: 'Montserrat', 'Segoe UI', system-ui, -apple-system, sans-serif;
  
    /* Operator dark scope (default) */
    --obg: #17181C;
    --opanel: #1F2026;
    --opanel-2: #26272E;
    --oline: #33343C;
    --ofg: #EDEDEA;
    --ofg-2: #A8A8B0;
    --ofg-3: #74747C;
    --goldtx: #EEC766;      /* gold text that must stay readable on the operator surface */
}

/* Operator light scope â€” toggled from the operator top bar */

/*
 * Light operator theme. These are darker than a first pass would suggest
 * because --ofg-3 carries every field label, section heading and hint at
 * 11.5-12px: at the original #8E8E98 that was 3.2:1 on white, under the 4.5:1
 * floor and genuinely hard to read in a bright hall. All three now clear AA.
 */

body.op-light {
  --obg: #EFEDE7;
    --opanel: #FFFFFF;
    --opanel-2: #F6F4EF;
    --oline: #D8D3C8;
    --ofg: #26262A;
    --ofg-2: #46464C;   /* 9.4:1 on panel */
    --ofg-3: #61616A;   /* 6.1:1 on panel */
    --goldtx: #7A5600;  /* 6.7:1 on panel */
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html,
body { height: 100%; }

body { font-family: var(--font); background: var(--bg); color: var(--ink); font-size: 14.5px; line-height: 1.5; -webkit-font-smoothing: antialiased; }

img { max-width: 100%; }

a { color: var(--gold-deep); text-decoration: none; }

a:hover { text-decoration: underline; }

button { font-family: inherit; }

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    padding: 10px 18px; border-radius: 10px; border: 1px solid transparent;
    font-weight: 600; font-size: 14px; cursor: pointer; user-select: none;
    transition: transform .06s, background .15s, box-shadow .15s, border-color .15s;
    white-space: nowrap;
}

.btn:active { transform: translateY(1px); }

.btn-primary { background: var(--gold); color: #2A2208; box-shadow: 0 2px 10px rgba(227,161,0,.35); }

.btn-primary:hover { background: #F0AE0A; }

.btn-ghost { background: transparent; border-color: var(--line); color: var(--ink); }

.btn-ghost:hover { border-color: var(--gold); color: var(--gold-deep); }

.btn-danger { background: var(--err-bg); color: var(--err); }

.btn-danger:hover { background: #F5D8D8; }

.btn-lg { padding: 13px 24px; font-size: 15.5px; border-radius: 12px; }

.btn-sm { padding: 6px 12px; font-size: 12.5px; border-radius: 8px; }

.btn[disabled] { opacity: .5; cursor: not-allowed; }

/* ---------- Cards / panels ---------- */

.card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); }

.card-pad { padding: 22px; }

/* ---------- Forms ---------- */

.field { margin-bottom: 15px; }

.field label { display: block; font-size: 12.5px; font-weight: 600; color: var(--ink-2); margin-bottom: 6px; letter-spacing: .02em; }

.input,
.select {
  width: 100%; padding: 10px 13px; border: 1.5px solid var(--line); border-radius: 10px;
    font-family: inherit; font-size: 14px; background: #fff; color: var(--ink);
    transition: border-color .15s, box-shadow .15s;
}

.input:focus,
.select:focus { outline: none; border-color: var(--gold); box-shadow: 0 0 0 3px rgba(227,161,0,.18); }

/* ---------- Badges & pills ---------- */

.badge { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; font-weight: 700; letter-spacing: .03em; padding: 3px 9px; border-radius: 99px; }

.badge-gold { background: var(--gold-15); color: var(--gold-deep); }

.badge-ok { background: var(--ok-bg); color: var(--ok); }

.badge-err { background: var(--err-bg); color: var(--err); }

.badge-grey { background: #EFEEE9; color: var(--ink-2); }

/* .badge-live is gone with the LIVE badge it styled â€” the projection button
   carries that signal now. The keyframe stays: that button uses it. */

@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .55; } }

/* ---------- Topbar (light pages) ---------- */

.topbar {
  display: flex; align-items: center; gap: 16px;
    padding: 12px 26px; background: #fff; border-bottom: 1px solid var(--line);
    position: sticky; top: 0; z-index: 40;
}

.topbar .brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 16px; color: var(--ink); }

.topbar .brand img { height: 34px; }

.topbar .brand small { display: block; font-size: 10.5px; font-weight: 600; color: var(--gold-deep); letter-spacing: .12em; text-transform: uppercase; }

.topbar .spacer,
.op-top .spacer { flex: 1; }

.lang-toggle { display: inline-flex; border: 1.5px solid var(--line); border-radius: 99px; overflow: hidden; }

.lang-toggle button { border: 0; background: transparent; padding: 6px 13px; font-weight: 700; font-size: 12px; cursor: pointer; color: var(--ink-3); letter-spacing: .04em; }

.lang-toggle button.active { background: var(--ink); color: #fff; }

.conn-pill { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 600; color: var(--ink-2); padding: 6px 12px; border: 1px solid var(--line); border-radius: 99px; }

.conn-pill .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ok); }

.conn-pill.off .dot { background: var(--ink-3); }

.conn-pill.off { color: var(--warn); border-color: var(--warn-bg); background: var(--warn-bg); }

.avatar { width: 34px; height: 34px; border-radius: 50%; background: var(--gold); color: #2A2208; display: inline-flex; align-items: center; justify-content: center; font-weight: 700; font-size: 13px; cursor: pointer; }

/* ---------- Account menu (avatar, top right) ----------
   Built from the light-page tokens on purpose. They are declared on bare :root
   and neither .op-body nor body.op-light redefines them, so this one card is
   correct on the dashboard, the admin panel and both operator themes without a
   second colour set to keep in step â€” the same reasoning that already puts a
   white .modal on the operator's dark bar. */

.acct-menu {
  position: fixed; z-index: 210; display: none; width: 232px; padding: 12px;
    background: var(--card); border: 1px solid var(--line);
    border-radius: 13px; box-shadow: var(--shadow-lg);
}

.acct-menu.show { display: block; }

.acct-menu .am-who { padding: 2px 4px 10px; border-bottom: 1px solid var(--line); margin-bottom: 10px; }

.acct-menu .am-who b { display: block; font-size: 13.5px; color: var(--ink); }

.acct-menu .am-who span { display: block; font-size: 11.5px; color: var(--ink-3); word-break: break-all; }

.acct-menu .am-sec { font-size: 10.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); margin: 0 0 6px 4px; }

.acct-menu .am-seg { display: flex; gap: 6px; margin-bottom: 12px; }

.acct-menu .am-seg button {
  flex: 1; min-width: 0; padding: 7px 6px; border-radius: 9px; border: 1.5px solid var(--line);
    background: transparent; font-family: inherit; font-size: 12px; font-weight: 700;
    color: var(--ink-2); cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.acct-menu .am-seg button:hover { border-color: var(--gold-60); }

.acct-menu .am-seg button.on { background: var(--gold); border-color: var(--gold); color: #2A2208; }

.acct-menu .am-item {
  display: block; width: 100%; text-align: left; padding: 9px 10px; border-radius: 9px;
    border: 0; background: transparent; font-family: inherit; font-size: 13px; font-weight: 600;
    color: var(--ink); cursor: pointer;
}

.acct-menu .am-item:hover { background: var(--bg); }

/* ---------- Toast ---------- */

#toasts { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%); z-index: 300; display: flex; flex-direction: column; gap: 8px; align-items: center; }

.toast {
  background: var(--ink); color: #fff; font-size: 13.5px; font-weight: 500;
    padding: 11px 20px; border-radius: 99px; box-shadow: var(--shadow-lg);
    animation: toast-in .25s ease; max-width: min(90vw, 480px); text-align: center;
}

.toast.gold { background: var(--gold); color: #2A2208; }

/* ---------- auto-sync progress beside "My files" (session page) ---------- */

.fsync { display: inline-flex; align-items: center; gap: 8px; min-width: 0; max-width: 70%; font-size: 11.5px; font-weight: 600; letter-spacing: 0; text-transform: none; }

.fsync[hidden] { display: none; }

.fsync .fsync-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.fsync .fsync-bar { flex: none; width: 64px; height: 4px; border-radius: 4px; background: rgba(128,128,128,.28); overflow: hidden; }

.fsync .fsync-bar u { display: block; height: 100%; width: 0; background: var(--gold); text-decoration: none; transition: width .25s ease; }

.fsync[data-state="done"] .fsync-bar u { background: #5BC97A; }

.fsync[data-state="fail"] .fsync-bar u { background: #FF8080; }

/* aligned to the title's line rather than centred on the block, so it still
   reads as a marker beside the heading when the hint wraps to two lines */

@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* ---------- Modal ---------- */

.modal-back { position: fixed; inset: 0; background: rgba(20,18,10,.45); z-index: 200; display: none; align-items: center; justify-content: center; padding: 20px; }

.modal-back.show { display: flex; }

.modal { background: #fff; border-radius: 16px; box-shadow: var(--shadow-lg); width: 100%; max-width: 440px; padding: 26px; animation: toast-in .2s ease; }

.modal h3 { font-size: 18px; margin-bottom: 18px; }

/* =========================================================
   DASHBOARD
   ========================================================= */

.page { max-width: 1180px; margin: 0 auto; padding: 30px 26px 80px; }

.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin: 8px 0 20px; flex-wrap: wrap; }

.page-head h1 { font-size: 24px; }

.page-head .sub { color: var(--ink-2); font-size: 13.5px; margin-top: 4px; }

.section-title { font-size: 17px; font-weight: 700; margin: 34px 0 6px; display: flex; align-items: center; gap: 10px; }

.section-sub { color: var(--ink-2); font-size: 13px; margin-bottom: 16px; }

.sessions-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 16px; }

.session-card { padding: 18px; display: flex; flex-direction: column; gap: 8px; transition: box-shadow .15s, border-color .15s; cursor: pointer; }

.session-card:hover { border-color: var(--gold); box-shadow: var(--shadow-lg); }

.session-card .nm { font-weight: 700; font-size: 15.5px; }

.session-card .meta { color: var(--ink-3); font-size: 12.5px; display: flex; gap: 10px; }

/* wraps because a local session carries a fourth button ("Save to cloud") and
   the row is only as wide as a grid column */

.session-card .row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }

.session-card .row .btn { flex: 0 1 auto; }

/* Buka/Duplikat/Hapus fill the row evenly instead of sizing to their own label width (which made
   "Hapus" look tiny next to "Duplikat") — the offline-pending indicator stays its own natural size,
   it's a status line, not an action to weight equally. */

.session-card .row .btn:not(.actUpload) { flex: 1 1 0; min-width: 64px; }

.session-card .row .actUpload { flex: 1 1 100%; }

.session-new {
  border: 2px dashed var(--line); border-radius: var(--radius); display: flex; flex-direction: column;
    align-items: center; justify-content: center; gap: 8px; color: var(--ink-3); cursor: pointer;
    min-height: 128px; font-weight: 600; transition: border-color .15s, color .15s; background: transparent;
}

.session-new:hover { border-color: var(--gold); color: var(--gold-deep); }

.session-new .plus { width: 40px; height: 40px; border-radius: 50%; background: var(--gold-15); color: var(--gold-deep); font-size: 22px; display: flex; align-items: center; justify-content: center; }

/* Nine libraries as full-width bars left a long ladder of mostly-empty rows.
   As a card grid they read as a set you scan, and each one has room to stack
   its name, counts and action instead of stretching them across the page.
   Since the cards became one per LANGUAGE there are only three, so auto-fit
   rather than auto-fill: auto-fill would hold empty tracks open and leave the
   three sitting narrow against a gap. */

.lib-table { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; }

.lib-row { display: flex; flex-direction: column; align-items: flex-start; gap: 9px; padding: 16px; min-height: 168px; }

.lib-row .ic { width: 42px; height: 42px; border-radius: 11px; background: var(--gold-15); display: flex; align-items: center; justify-content: center; font-size: 19px; flex: none; }

.lib-row .nm { font-weight: 600; font-size: 14px; line-height: 1.35; }

.lib-row .meta { color: var(--ink-3); font-size: 12px; display: flex; flex-direction: column; gap: 3px; align-items: flex-start; }

.lib-row .lock { font-size: 11px; color: var(--ok); display: inline-flex; gap: 4px; align-items: center; }

/* the action sits on the card floor so every card's button lines up; the
   column's align-items:flex-start would otherwise shrink it to its content */

.lib-row .right { margin-top: auto; align-self: stretch; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }

.lib-row .right .btn { flex: 1; justify-content: center; }

.lib-row .right .badge { flex: 1; justify-content: center; text-align: center; }

/* the session list is a saved copy â€” stated, not implied */

.storage-bar { height: 8px; border-radius: 99px; background: #EDEBE4; overflow: hidden; margin-top: 8px; }

/* width is set from the measured figure in pages.js â€” never in the markup */

.storage-bar i { display: block; height: 100%; width: 0; background: var(--gold); border-radius: 99px; transition: width .3s; }

/* A language card names its books, so the operator does not have to know that
   "hymnts" is è£œå……æœ¬ to understand what they are about to download. */

.lib-row .lang-badge { font-weight: 800; font-size: 15px; letter-spacing: .02em; color: var(--gold-deep); }

.lib-members { font-size: 11.5px; color: var(--ink-3); line-height: 1.45; }

/* =========================================================
   Files (dashboard)
   ========================================================= */

.files-bar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

.files-hint { font-size: 12px; color: var(--ink-3); }

.files-list { display: flex; flex-direction: column; gap: 10px; }

.file-row { display: flex; align-items: center; gap: 13px; padding: 13px 16px; }

.file-row .ic {
  width: 40px; height: 40px; border-radius: 11px; background: var(--gold-15);
    display: flex; align-items: center; justify-content: center; font-size: 18px; flex: none;
}

/* min-width:0 so a long filename ellipsises instead of pushing the delete
   button off the card â€” the same trap as a bare 1fr grid track */

.file-main { flex: 1; min-width: 0; }

.file-row .nm { font-weight: 600; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.file-row .meta { color: var(--ink-3); font-size: 12px; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-top: 3px; }

.file-row .right { display: flex; align-items: center; gap: 8px; flex: none; }

/* Upload progress, shared by the dashboard and the public page. */

/* v35 — slim bar (was 26px tall with the label inside it): 5px track, label underneath. CSS-only, both pages. */

.up-bar { position: relative; height: 5px; border-radius: 99px; background: #EDEBE4; margin-top: 12px; margin-bottom: 24px; }

.up-bar i { display: block; height: 100%; width: 0; background: var(--gold); border-radius: 99px; transition: width .2s; }

.up-bar span {
  position: absolute; top: 11px; left: 0; right: 0; display: block;
    font-size: 11.5px; font-weight: 500; color: var(--ink-3); padding: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* =========================================================
   Public upload page (upload.html)
   Someone else's phone, once. Single column at every width.
   ========================================================= */

@keyframes upspin { to { transform: rotate(360deg); } }

/* =========================================================
   User manual
   ========================================================= */

.manual { max-width: 860px; }

.manual h2 { font-size: 17px; margin: 0 0 10px; display: flex; align-items: center; gap: 10px; }

.manual p { margin: 0 0 9px; font-size: 14px; line-height: 1.66; color: var(--ink-2); }

.manual p:last-child { margin-bottom: 0; }

.manual b { color: var(--ink); font-weight: 600; }

/* Two tabs, same pill shape as the operator's add-content tabs so the guide
   does not introduce a second idea of what a tab looks like. */

.man-tabs { display: flex; gap: 8px; margin: 0 0 18px; }

.kbd {
  display: inline-block; min-width: 20px; text-align: center; padding: 1px 6px; margin: 0 1px;
    border: 1px solid var(--line); border-bottom-width: 2px; border-radius: 5px;
    background: #fff; font-size: 12px; font-weight: 700; color: var(--ink);
}

.man-keys { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 8px 18px; margin: 12px 0 4px; font-size: 13px; color: var(--ink-2); }

/* ---- ways to use: device arrangements ----
   Device glyphs are inline SVG rather than images: they carry no text, so they
   need no second language, and nothing to re-download when Cloudflare is
   holding a cached copy of an asset. Colour follows the same op/pj language as
   the hero above â€” grey for the operator screen, gold for the projection. */

.setup { padding: 16px 18px; }

.setup + .setup { margin-top: 10px; }

.setup h3 { font-size: 14.5px; font-weight: 700; color: var(--ink); margin: 3px 0 3px; }

/* the connector carries the meaning: solid grey = a cable, dashed gold = the network */

@media print {
  .topbar,
#printBtn,
#toasts,
.man-tabs { display: none !important; }
  .manual { max-width: none; }
  .card { break-inside: avoid; box-shadow: none; border: 1px solid #ddd; }
  /* Cetak prints the guide, not the tab you happen to be looking at */
  /* ...except the video, which is the one panel paper cannot carry. Without
     this the rule above prints a poster frame and a dead player as page one. */
}

.howto { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }

.howto .card { padding: 16px; font-size: 13px; color: var(--ink-2); }

.howto .n { width: 26px; height: 26px; border-radius: 8px; background: var(--gold); color: #2A2208; font-weight: 700; font-size: 13px; display: inline-flex; align-items: center; justify-content: center; margin-bottom: 10px; }

/* =========================================================
   OPERATOR (dark)
   ========================================================= */

.op-body { background: var(--obg); color: var(--ofg); height: 100vh; display: flex; flex-direction: column; overflow: hidden; }

.op-top { display: flex; align-items: center; gap: 14px; padding: 10px 16px; background: var(--opanel); border-bottom: 1px solid var(--oline); flex: none; }

.op-top .brand img { height: 30px; }

.op-top .sess-name { font-weight: 700; font-size: 15.5px; background: transparent; border: 1px solid transparent; color: var(--ofg); border-radius: 8px; padding: 5px 9px; min-width: 120px; max-width: 320px; }

.op-top .sess-name:hover,
.op-top .sess-name:focus { border-color: var(--oline); outline: none; background: var(--opanel-2); }

.op-top .clock { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--ofg-2); font-size: 13px; }

.op-top .lang-toggle { border-color: var(--oline); }

.op-top .lang-toggle button { color: var(--ofg-3); }

.op-top .lang-toggle button.active { background: var(--gold); color: #2A2208; }

/* The guide button is the first thing to give when the bar runs out of room:
   it drops its label at 1260 and leaves entirely at 1140. It is the only
   top-bar item not needed mid-meeting, and the guide is still one click from
   the dashboard. Both breakpoints were measured against a bar that still
   carried the projection-status pill; that pill is gone, so they are now
   conservative rather than tight â€” the bar has room to spare at both widths. */

@media (max-width: 1260px) {
  #manualBtn span { display: none; }
}

@media (max-width: 1140px) {
  #manualBtn { display: none; }
}

.icon-btn {
  background: transparent; border: 1px solid var(--oline); color: var(--ofg-2); border-radius: 9px;
    padding: 8px 11px; cursor: pointer; font-size: 13px; display: inline-flex; align-items: center; gap: 7px;
}

.icon-btn:hover { border-color: var(--gold); color: var(--goldtx); }

.op-main { flex: 1; display: grid; grid-template-columns: 290px 1fr clamp(420px, 34vw, 660px); min-height: 0; }

.op-col { min-height: 0; display: flex; flex-direction: column; border-right: 1px solid var(--oline); }

.op-col:last-child { border-right: 0; }

.op-col-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px 10px; font-size: 12px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--ofg-3); flex: none; }

.op-scroll { overflow-y: auto; flex: 1; padding: 0 12px 16px; }

.op-scroll::-webkit-scrollbar { width: 9px; }

.op-scroll::-webkit-scrollbar-thumb { background: var(--oline); border-radius: 99px; }

/* Playlist */

.pl-item {
  display: flex; gap: 10px; align-items: center; padding: 10px 11px; border-radius: 11px;
    border: 1px solid transparent; cursor: pointer; margin-bottom: 7px; background: var(--opanel);
    transition: border-color .12s, background .12s; position: relative;
}

.pl-item:hover { border-color: var(--oline); }

.pl-item.live { border-color: var(--gold); background: linear-gradient(0deg, rgba(227,161,0,.10), rgba(227,161,0,.10)), var(--opanel); box-shadow: 0 0 0 1px var(--gold), 0 4px 18px rgba(227,161,0,.15); }

.pl-item .ic { width: 36px; height: 36px; border-radius: 9px; display: flex; align-items: center; justify-content: center; font-size: 16px; flex: none; }

.pl-item .ic.verse { background: rgba(88,146,255,.15); }

.pl-item .ic.hymn { background: rgba(227,161,0,.16); }

.pl-item .ic.slides { background: rgba(255,120,80,.14); }

.pl-item .ic.pdf { background: rgba(230,70,70,.14); }

.pl-item .ic.image { background: rgba(70,190,120,.14); }

.pl-item .tx { min-width: 0; flex: 1; }

.pl-item .t1 { font-weight: 600; font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.pl-item .t2 { font-size: 11.5px; color: var(--ofg-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.pl-item .grip { color: var(--ofg-3); cursor: grab; font-size: 14px; padding: 4px 2px; }

.pl-item .del { position: absolute; right: 8px; top: 8px; display: none; background: var(--err); color: #fff; border: 0; width: 20px; height: 20px; border-radius: 6px; font-size: 11px; cursor: pointer; line-height: 1; }

.pl-item:hover .del { display: block; }

.pl-item .mv { display: none; flex-direction: column; gap: 3px; flex: none; }

.pl-item .mv button { background: var(--opanel-2); border: 1px solid var(--oline); color: var(--ofg-2); border-radius: 6px; width: 26px; height: 22px; font-size: 10px; cursor: pointer; }

.pl-item.dragging { opacity: .4; }

.pl-empty { color: var(--ofg-3); font-size: 13px; padding: 18px 10px; text-align: center; border: 1.5px dashed var(--oline); border-radius: 12px; margin-top: 6px; }

/* Add-content tabs */

.op-tabs { display: flex; gap: 6px; padding: 0 14px 10px; flex: none; }

.op-tab {
  flex: 1; display: flex; align-items: center; justify-content: center; gap: 6px;
    padding: 9px 6px; border-radius: 10px; border: 1px solid var(--oline);
    background: transparent; color: var(--ofg-2); font-weight: 600; font-size: 13px; cursor: pointer;
}

.op-tab.active { background: var(--gold); border-color: var(--gold); color: #2A2208; }

/* Button icons sit slightly small and never shrink the label out of the row. */

.op-tab .ico,
.btn .ico { flex: none; font-size: 12.5px; line-height: 1; }

.op-tab .ico { font-size: 14px; }

.op-tab > span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.op-panel { display: none; }

.op-panel.active { display: block; }

.op-field { margin-bottom: 12px; }

.op-field label { display: block; font-size: 11.5px; font-weight: 600; color: var(--ofg-3); margin-bottom: 5px; }

.op-input,
.op-select {
  width: 100%; padding: 9px 12px; background: var(--opanel-2); color: var(--ofg);
    border: 1.5px solid var(--oline); border-radius: 9px; font-family: inherit; font-size: 13.5px;
}

.op-input:focus,
.op-select:focus { outline: none; border-color: var(--gold); }

.op-row { display: flex; gap: 9px; }

.op-row > * { flex: 1; min-width: 0; }

.op-check { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; color: var(--ofg-2); cursor: pointer; padding: 6px 10px; border: 1px solid var(--oline); border-radius: 9px; }

.op-check input { accent-color: var(--gold); }

.op-check.on { border-color: var(--gold); color: var(--goldtx); background: rgba(227,161,0,.08); }

.op-hint { font-size: 11.5px; color: var(--ofg-3); margin-top: 5px; }

/* Keyword hits under Ketik cepat. Capped and scrolled inside its own box so a
   long result list cannot push the Kitab/Pasal fields off the panel â€” the
   operator needs both the results and the boxes they fill in view at once. */

.q-results { margin-top: 8px; border: 1px solid var(--oline); border-radius: 11px; overflow: hidden; }

.q-results[hidden] { display: none; }

.q-note { padding: 8px 12px; font-size: 11.5px; font-weight: 600; color: var(--ofg-3); background: var(--opanel-2); }

.q-note.bad { color: var(--err); }

.q-list { max-height: 260px; overflow-y: auto; }

.q-res {
  display: block; width: 100%; text-align: left; padding: 8px 12px; cursor: pointer;
    background: none; border: none; border-top: 1px solid var(--oline);
    font-family: inherit; color: var(--ofg);
}

.q-list .q-res:first-child { border-top: none; }

.q-res:hover,
.q-res:focus-visible { background: rgba(227,161,0,.09); outline: none; }

.q-res.on { background: rgba(227,161,0,.14); box-shadow: inset 2px 0 0 var(--gold); }

.q-res .q-ref { font-size: 11.5px; font-weight: 800; color: var(--goldtx); letter-spacing: .02em; }

/* two lines, then ellipsis: enough to recognise the verse, never enough for one
   long result to hide the next three */

.q-res .q-txt {
  font-size: 12.5px; line-height: 1.5; color: var(--ofg-2); margin-top: 2px;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

.q-res mark { background: rgba(227,161,0,.28); color: inherit; border-radius: 3px; padding: 0 1px; }

/* hymn rows: which field matched, then the title, then the line if it was a
   lyric hit. One line each â€” three short rows read faster than two wrapped. */

.q-where {
  margin-left: 7px; font-size: 9.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
    color: var(--ofg-3); border: 1px solid var(--oline); border-radius: 99px; padding: 1px 7px;
}

.q-res .q-one { -webkit-line-clamp: 1; }

.q-res .q-sub {
  font-size: 11.5px; line-height: 1.45; color: var(--ofg-3); margin-top: 1px;
    display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;
}

.preview-box {
  background: var(--opanel-2); border: 1px solid var(--oline); border-radius: 11px;
    padding: 13px 15px; margin: 12px 0; font-size: 13px; color: var(--ofg-2);
    max-height: 220px; overflow-y: auto;
}

.preview-box .ref { color: var(--goldtx); font-weight: 700; font-size: 12.5px; margin-bottom: 6px; }

.preview-box .vtag { display: inline-block; font-size: 10px; font-weight: 700; color: var(--goldtx); border: 1px solid rgba(227,161,0,.4); padding: 1px 6px; border-radius: 5px; margin-right: 6px; vertical-align: 2px; }

.linked-badges { display: flex; gap: 7px; flex-wrap: wrap; margin: 8px 0 4px; }

.linked-badge { font-size: 11.5px; font-weight: 700; color: var(--goldtx); background: rgba(227,161,0,.1); border: 1px solid rgba(227,161,0,.35); border-radius: 99px; padding: 3px 11px; }

.sec-chip {
  display: inline-flex; align-items: center; justify-content: center; min-width: 34px; padding: 6px 10px;
    border-radius: 9px; border: 1px solid var(--oline); background: var(--opanel-2); color: var(--ofg-2);
    font-size: 12.5px; font-weight: 700; cursor: pointer; user-select: none;
}

.sec-chip.on { background: var(--gold); border-color: var(--gold); color: #2A2208; }

.sec-chips { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }

.drop-zone {
  border: 2px dashed var(--oline); border-radius: 13px; padding: 26px 16px; text-align: center;
    color: var(--ofg-3); cursor: pointer; transition: border-color .15s; margin-bottom: 12px;
}

.drop-zone:hover { border-color: var(--gold); color: var(--goldtx); }

.drop-zone .big { font-size: 26px; margin-bottom: 8px; }

.file-note { font-size: 11.5px; color: var(--ofg-3); background: var(--opanel-2); border-radius: 9px; padding: 9px 12px; margin-bottom: 12px; display: flex; gap: 8px; }

.drop-zone.over { border-color: var(--gold); color: var(--goldtx); background: rgba(227,161,0,.07); }

.drop-zone:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

.file-row { display: flex; align-items: center; gap: 10px; padding: 9px 11px; border: 1px solid var(--oline); border-radius: 10px; margin-bottom: 8px; }

.file-row .fi { font-size: 17px; flex: none; }

.file-row .fmeta { flex: 1; min-width: 0; }

.file-row .fnm { font-size: 13px; font-weight: 600; color: var(--ofg); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.file-row .fsub { font-size: 11.5px; color: var(--ofg-3); }

.file-row .btn-sm { flex: none; padding: 5px 10px; }

/* upload progress */

.up-row { display: flex; align-items: center; gap: 10px; padding: 8px 11px; border: 1px solid var(--oline); border-radius: 10px; margin-bottom: 8px; }

.up-row .unm { flex: 1; min-width: 0; font-size: 12.5px; color: var(--ofg-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.up-row .ubar { flex: none; width: 84px; height: 5px; border-radius: 3px; background: var(--opanel-2); overflow: hidden; }

.up-row .ubar i { display: block; height: 100%; background: var(--gold); transition: width .2s; }

.up-row .upct { flex: none; width: 34px; text-align: right; font-size: 11.5px; color: var(--ofg-3); }

.up-row.ok .ubar i { background: var(--ok); }

.up-row.bad { border-color: var(--err); }

.up-row.bad .ubar { display: none; }

.up-row.bad .unm { color: var(--err); white-space: normal; }

/* text pushed past the stage by the size slider â€” only shown in the operator's
   mini preview, never on the projection itself */

#miniWrap .proj.overflowing::after {
  content: "\26A0"; position: absolute; right: 6px; bottom: 4px; z-index: 6;
    font-size: 13px; color: var(--warn); background: rgba(0,0,0,.45);
    border-radius: 5px; padding: 0 5px; pointer-events: none;
}

/* the projected-file styles live in PROJ_CSS in operator.js â€” the projection
   window is a separate document and never loads this stylesheet */

/* a file still converting, or that failed to convert */

.file-row.busy { opacity: .72; }

@keyframes ysspin { to { transform: rotate(360deg); } }

/* Live column */

#colLive { overflow-y: auto; }

.live-head { display: flex; align-items: center; gap: 10px; padding: 12px 16px 9px; flex: none; }

.live-head .lt { font-size: 14px; font-weight: 700; color: var(--ofg); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.stage-wrap { padding: 0 16px; flex: none; }

.stage-16x9 {
  position: relative; width: 100%; aspect-ratio: 16/9; border-radius: 13px; overflow: hidden;
    border: 1px solid var(--oline); background: #000; box-shadow: 0 10px 30px rgba(0,0,0,.28);
}

.live-meta { padding: 11px 16px 4px; font-size: 13px; font-weight: 600; color: var(--ofg-2); display: flex; align-items: center; gap: 8px; min-height: 32px; }

.live-nav { display: flex; gap: 9px; padding: 4px 16px; align-items: center; }

.live-nav .nav-btn {
  flex: 1; padding: 13px; border-radius: 11px; border: 1px solid var(--oline); background: var(--opanel);
    color: var(--ofg); font-size: 13.5px; font-weight: 700; cursor: pointer;
}

.live-nav .nav-btn:hover { border-color: var(--gold); color: var(--goldtx); }

.live-sub { padding: 6px 16px 8px; }

/* read-only: the playlist still presents, it just cannot be rearranged */

.quick-row { display: flex; gap: 8px; padding: 6px 16px; }

.disp-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; padding: 2px 16px 6px; align-items: end; }

.quick-btn {
  flex: 1; padding: 10px 6px; border-radius: 10px; border: 1px solid var(--oline); background: var(--opanel);
    color: var(--ofg-2); font-size: 12px; font-weight: 700; cursor: pointer; text-align: center;
}

.quick-btn.on { background: #E33F3F; border-color: #E33F3F; color: #fff; }

.quick-btn.on-gold { background: var(--gold); border-color: var(--gold); color: #2A2208; }

/* Announcement composer. Sits under the quick row rather than over the live
   preview, so the operator can watch the banner appear while typing it. */

.ann-panel { padding: 0 16px 8px; }

.ann-foot { display: flex; align-items: center; gap: 8px; margin-top: 7px; }

.ann-count { font-size: 11px; font-weight: 700; color: var(--ofg-3); font-variant-numeric: tabular-nums; }

.ann-tip { font-size: 11px; color: var(--ofg-3); flex: 1; min-width: 0; line-height: 1.35; }

.ann-foot .btn { flex: none; }

/* âˆ’ and + carry no word to read, so the glyph has to do the work: at the 12px
   the labelled buttons use they were nearly invisible. Fixed width instead of
   flex:1 keeps them from stealing the row now that they are large. */

.quick-btn.q-sym { flex: 0 0 46px; font-size: 21px; font-weight: 700; line-height: 1; padding: 6px 0; color: var(--ofg); }

.quick-btn.q-zoomval { flex: 0 0 62px; font-variant-numeric: tabular-nums; }

.theme-cards { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; padding: 4px 16px 8px; }

.theme-card { border-radius: 10px; border: 2px solid var(--oline); overflow: hidden; cursor: pointer; text-align: center; background: var(--opanel); padding-bottom: 5px; }

.theme-card.on { border-color: var(--gold); }

.theme-card .sw { height: 40px; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 800; }

.theme-card .nm { font-size: 10px; color: var(--ofg-3); font-weight: 600; padding-top: 4px; display: block; }

.slider-row { display: flex; align-items: center; gap: 10px; padding: 2px 16px 10px; }

.slider-row input[type=range] { flex: 1; accent-color: var(--gold); }

.slider-row .val { font-size: 12px; color: var(--ofg-2); min-width: 42px; text-align: right; font-variant-numeric: tabular-nums; }

/* the keyboard shortcuts are the fastest way to drive the screen, so this line
   is worth reading â€” it was set at 11px in the faintest ink on the page */

.keys-hint { padding: 10px 16px 14px; font-size: 12.5px; line-height: 1.65; color: var(--ofg-2); border-top: 1px solid var(--oline); margin-top: 6px; }

/* Full hymn text in the Add-content column */

.hymn-full { margin-top: 4px; }

.hymn-sec {
  border: 1px solid var(--oline); border-radius: 11px; padding: 10px 13px; margin-bottom: 8px;
    cursor: pointer; background: var(--opanel); transition: border-color .12s, background .12s;
}

.hymn-sec:hover { border-color: var(--gold); }

.hymn-sec.on { border-color: var(--gold); background: rgba(227,161,0,.09); box-shadow: 0 0 0 1px var(--gold); }

.hs-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-bottom: 6px; }

.hs-label { font-size: 10.5px; font-weight: 800; letter-spacing: .12em; color: var(--goldtx); text-transform: uppercase; }

.hs-go { font-size: 10.5px; font-weight: 700; color: var(--ofg-3); opacity: 0; white-space: nowrap; }

.hymn-sec:hover .hs-go,
.hymn-sec.on .hs-go { opacity: 1; }

.hs-text { font-size: 13px; line-height: 1.6; color: var(--ofg); }

/* One block per display line, matching the stage: the parts of a printed line
   are a group, so the gap falls between groups and not inside one. */

.hs-part.h-start { margin-top: .3em; }

.hs-part.h-start:first-child { margin-top: 0; }

.hs-cols { display: grid; gap: 14px; grid-template-columns: repeat(var(--hcols, 1), 1fr); }

.hs-lang { font-size: 9.5px; font-weight: 800; letter-spacing: .1em; color: var(--ofg-3); margin-bottom: 4px; }

/* The projection control, live state. It replaced both a status pill in the top
   bar and the LIVE badge over the preview, so this button is now the only thing
   that says whether the projection window is open â€” hence red and moving rather
   than a quiet tint. Same 1.6s pulse the old badge used, so nothing about the
   signal is new to an operator; it has only moved.
   Still a button in this state: clicking focuses a projection window that has
   slipped behind the browser, which is the one way back to it mid-meeting. */

#openProjBtn.btn-live { background: #E33F3F; color: #fff; letter-spacing: .06em; box-shadow: 0 2px 10px rgba(227, 63, 63, .35); animation: pulse 1.6s infinite; }

#openProjBtn.btn-live:hover { background: #D43636; }

/* the emoji slot becomes the badge dot; updateProjStatus() empties its text */

#openProjBtn.btn-live #openProjIco { display: inline-block; width: 9px; height: 9px; border-radius: 50%; background: #fff; }

/* Mobile op tabs */

.mob-tabbar { display: none; }

/* touch devices have no hover â€” keep item delete visible */

@media (hover: none) {
  .pl-item .del { display: block; }
}

/* Unconditional, not only on a narrow screen. A table that outgrows its card
   must scroll inside it; spilling past the card edge is silent and looks like
   a broken page rather than a full one. */

.table { width: 100%; border-collapse: collapse; font-size: 13.5px; }

.table th { text-align: left; font-size: 11.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); padding: 10px 14px; border-bottom: 1px solid var(--line); }

.table td { padding: 13px 14px; border-bottom: 1px solid var(--line); vertical-align: middle; }

.table tr:last-child td { border-bottom: 0; }

.table .who { font-weight: 600; }

/* the users table's name edits in place; the pencil stays quiet until its row is hovered */

.table .sub { color: var(--ink-3); font-size: 12px; }

/* =========================================================
   Responsive
   ========================================================= */

@media (max-width: 1260px) {
  .op-main { grid-template-columns: 250px 1fr clamp(340px, 32vw, 420px); }
}

@media (max-width: 920px) {
  .howto { grid-template-columns: 1fr; }
  /* Two chart columns become one; the funnel loses its fixed label gutter,
     which at this width was squeezing the bar to nothing. */
  /* Operator becomes tabbed single-column */
  .op-main { display: block; overflow-y: auto; padding-bottom: 64px; }
  .op-col { border-right: 0; border-bottom: 1px solid var(--oline); display: none; }
  .op-col.mob-show { display: flex; }
  .mob-tabbar { display: flex; position: fixed; bottom: 0; left: 0; right: 0; z-index: 90; background: var(--opanel); border-top: 1px solid var(--oline); }
  .mob-tabbar button {
    flex: 1; padding: 12px 8px; background: transparent; border: 0; color: var(--ofg-3);
        font-family: inherit; font-size: 12px; font-weight: 700; cursor: pointer;
  }
  .mob-tabbar button.active { color: var(--gold); }
  .op-top { flex-wrap: wrap; }
  .pl-item .del { display: block; }
  /* no hover on touch devices */
  .pl-item .mv { display: flex; }
  /* touch reorder = up/down buttons */
  .pl-item .grip { display: none; }
  .disp-grid { grid-template-columns: 1fr; }
}

@media (max-width: 560px) {
  .page { padding: 20px 14px 80px; }
  .lib-table { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
  .lib-row { min-height: 156px; padding: 13px; }
  .sessions-grid { grid-template-columns: 1fr; }
  .topbar { padding: 10px 14px; }
  .topbar .brand .nm-wrap { display: none; }
}
