/*
 * The Screens view, "the living wall" (approved concept C). A control-room view of the pairs:
 * two ceiling rails, row A is one face of every pair and row B the face behind it. Each face is
 * a black device showing its live content. All colours are tokens from /brand.css: the wall is
 * black and lit from the right edge in dark, warm paper lit by the brand's light gradient in
 * light; the devices stay black in both. Motion: transform and opacity only (docs/MOTION.md).
 */

.wall-view {
  --side-w: 300px;
  --side-gap: 24px;
  /* Device size: 176x313 at 1440x900, smaller when the viewport is short (two rows must fit). */
  --dev-w: min(176px, calc((100vh - 274px) / 2 * 176 / 313));
  position: relative;
}
@media (max-width: 1279px) { .wall-view { --side-w: 260px; } }

.wall {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: calc(100vh - var(--topbar-h));
  background: linear-gradient(to bottom, var(--fm-wall-top), var(--fm-wall-bottom));
  color: var(--fm-text);
}
/* The light enters from the right edge (inline start in RTL); grain only where it is lit. */
.wall::before, .wall::after { content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none; }
.wall::before { background: var(--fm-wall-light); }
.wall::after {
  background-image: var(--fm-wall-grain);
  opacity: var(--fm-wall-grain-opacity);
  mix-blend-mode: var(--fm-wall-grain-blend);
  -webkit-mask-image: var(--fm-wall-grain-mask);
  mask-image: var(--fm-wall-grain-mask);
}

/* Room for the side panel at the inline start and the floating action bar at the bottom
   (--bar-clear, panels.css). */
.wall-scroll {
  overflow-x: auto;
  padding-block: 0 var(--bar-clear);
  padding-inline: calc(var(--side-w) + var(--side-gap) + 16px) 14px;
}

/* ---------- The grid: pair columns, then a narrow column for the row labels ---------- */
.wall-grid {
  --cols: 4;
  display: grid;
  grid-template-columns: repeat(var(--cols), minmax(150px, 1fr)) 34px;
  /* Headers, row A, row B, and a row for the column actions (arrange mode only, else empty). */
  grid-template-rows: 40px auto auto auto;
  align-content: start;
  min-width: 0;
  /* The wall takes the screen down to the floating bar, so what follows it (new screens) starts
     at the fold, never behind or around the bar. */
  min-height: calc(100vh - var(--topbar-h) - var(--bar-clear));
}
.wall-rail {
  grid-row: 2; align-self: start;
  height: 8px; margin-block-start: 2px;
  border-radius: 2px;
  background: linear-gradient(to bottom, var(--fm-rail-hi), var(--fm-rail-lo));
  box-shadow: var(--fm-rail-shadow);
}
.wall-rail--b { grid-row: 3; margin-block-start: 15px; }
.wall-tag { grid-row: 2; position: relative; }
.wall-tag--b { grid-row: 3; }
.wall-tag span {
  /* Physical offsets: logical ones would follow the vertical writing mode. */
  position: absolute; top: 40px; left: 0;
  writing-mode: vertical-rl; transform: rotate(180deg);
  white-space: nowrap; font-size: 12px; line-height: 16px;
  color: var(--fm-text-secondary);
}

.wcol-head {
  grid-row: 1; align-self: center; justify-self: center;
  display: flex; align-items: baseline; gap: var(--space-2);
  max-width: 100%; min-height: 32px; padding: 0 var(--space-2);
  border: 0; border-radius: var(--fm-radius); background: none; color: var(--fm-text);
  font: 600 13px/20px var(--fm-font); cursor: pointer;
}
.wcol-head b { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wcol-head .num { color: var(--fm-text-secondary); font-size: 11px; font-weight: 400; }
@media (hover: hover) and (pointer: fine) { .wcol-head:hover b { text-decoration: underline; text-underline-offset: 5px; } }

/* A slot: where one face hangs. The rod and cap drop from the rail to the device. */
.wslot {
  grid-row: 2;
  position: relative;
  display: grid; justify-items: center; align-content: start;
  padding-block-start: 28px;
  container-type: inline-size;
  min-width: 0;
}
.wslot--b { grid-row: 3; margin-block-start: 13px; }
/* The link between the two faces of a pair, from face A down to rail B. */
.wslot--b::before {
  content: ''; position: absolute; inset-block-start: -13px; inset-inline-start: calc(50% - 1px);
  width: 2px; height: 15px;
  background: var(--fm-pair-link);
}

/* ---------- The device ---------- */
.dev {
  container: dev / inline-size;
  position: relative; z-index: 1; display: block;
  width: min(var(--dev-w), 68cqi);
  aspect-ratio: 176 / 313;
  border: 4px solid var(--fm-device-bezel); border-radius: 7px;
  background: var(--fm-device-bg);
  box-shadow: var(--fm-device-shadow);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.dev.is-disabled { cursor: not-allowed; }
.dev-rod, .dev-cap { position: absolute; left: 50%; transform: translateX(-50%); }
.dev-rod { inset-block-start: -32px; width: 3px; height: 28px; background: linear-gradient(to bottom, var(--fm-rod-hi), var(--fm-rod-lo)); }
.dev-cap { inset-block-start: -10px; width: 54px; height: 6px; border-radius: 2px; background: var(--fm-cap); }
/* Edge lighting on select: the rod, the cap and the bezel light up (an overlay fades in). */
.dev-rod::after, .dev-cap::after { content: ''; position: absolute; inset: 0; border-radius: inherit; opacity: 0; transition: opacity var(--motion-slow) var(--ease-out); }
.dev-rod::after { background: linear-gradient(to bottom, var(--fm-rod-lit-hi), var(--fm-rod-lit-lo)); box-shadow: 0 0 12px var(--fm-rod-lit-lo); }
.dev-cap::after { background: var(--fm-rod-lit-lo); box-shadow: 0 0 10px var(--fm-rod-lit-lo); }
.dev-glow {
  position: absolute; inset: -4px; border-radius: 7px; pointer-events: none;
  box-shadow: 0 0 46px 8px var(--fm-select-edge);
  opacity: 0; transition: opacity var(--motion-slow) var(--ease-out);
}

.dev-px { position: absolute; inset: 0; overflow: hidden; border-radius: 3px; background: var(--fm-device-bg); contain: paint; }
.dev-content { position: absolute; inset: 0; }
.face-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.face-img.is-entering { opacity: 0; transition: opacity var(--motion-content) var(--ease-standard); }
.face-img.is-entering.is-in { opacity: 1; }
/* The player's real idle frame: black, lit from the right, white logo. */
.face-idle {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  background: var(--fm-device-bg) url('/stage-light.webp') right center / 100% 100% no-repeat;
}
.face-idle img { width: 46%; height: auto; }
.face-video { position: absolute; inset: 0; display: grid; place-items: center; background: var(--fm-device-bg) url('/stage-light.webp') right center / 100% 100% no-repeat; color: var(--fm-stage-text); }
.face-video .icon { width: 32px; height: 32px; }
.dev-glare { position: absolute; inset: 0; pointer-events: none; background: linear-gradient(112deg, var(--fm-device-glare), transparent 42%); }

/* Status chip (inline start) and live counter (inline end), always on black. */
.dev-st, .dev-live {
  position: absolute; inset-block-start: 8px;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 8px; border-radius: 999px;
  background: var(--fm-device-scrim); color: var(--fm-stage-text);
  font: 600 12px/16px var(--fm-font);
}
.dev-st { inset-inline-start: 8px; }
.dev-st i { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--st, var(--fm-stage-online)); }
.dev[data-kind='playing'] .dev-st i { --st: var(--fm-stage-playing); box-shadow: 0 0 8px var(--fm-stage-playing); }
.dev[data-kind='idle'] .dev-st i { --st: var(--fm-stage-online); }
.dev[data-kind='downloading'] .dev-st i { --st: var(--fm-device-download); box-shadow: 0 0 8px var(--fm-device-download); }
.dev[data-kind='warning'] .dev-st i { --st: var(--fm-stage-warning); border-radius: 0; transform: rotate(45deg) scale(.85); }
.dev[data-kind='offline'] .dev-st i { background: transparent; box-shadow: inset 0 0 0 1.5px var(--fm-device-ring-text); }
.dev-live {
  inset-inline-end: 8px;
  gap: 5px; padding: 3px 6px; border-radius: 4px;
  font: 500 10px/14px 'Inter', var(--fm-font); letter-spacing: .08em; font-variant-numeric: tabular-nums;
}
.dev-live i { width: 5px; height: 5px; border-radius: 50%; background: var(--fm-device-live); order: 1; }
.dev-live-t { direction: ltr; unicode-bidi: isolate; }

/* Name bar: the place and face, what it shows (or why it is offline), and the face code. */
.dev-name {
  position: absolute; inset-inline: 0; inset-block-end: 0;
  display: flex; justify-content: space-between; align-items: flex-end; gap: var(--space-2);
  padding: 22px 9px 8px;
  background: linear-gradient(to top, var(--fm-device-fade), transparent);
  color: var(--fm-stage-text);
}
.dev-name b { display: grid; min-width: 0; font: 600 14px/18px var(--fm-font); }
.dev-name b > span, .dev-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dev-sub { margin-block-start: 1px; font: 400 11px/15px var(--fm-font); color: var(--fm-stage-text-secondary); }
.dev-end { flex: none; display: grid; justify-items: end; gap: 4px; }
.dev-letter { flex: none; font: 600 11px/15px 'Inter', var(--fm-font); color: var(--fm-stage-playing); }

/* Player update mark: only while the app is not on the latest build (title says what is going on). */
.dev-upd {
  --upd: var(--fm-stage-text-secondary);
  display: grid; place-items: center;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--fm-device-scrim); color: var(--upd);
  box-shadow: inset 0 0 0 1.5px var(--upd);
}
.dev-upd .icon { width: 12px; height: 12px; }
.dev-upd[data-state='downloading'] { --upd: var(--fm-device-download); }
.dev-upd[data-state='awaiting_install'] { --upd: var(--fm-stage-warning); }
.dev-upd[data-state='failed'] { --upd: var(--fm-stage-offline); box-shadow: none; }
.dev-upd[data-state='failed'] .icon { width: 18px; height: 18px; }
.dev-upd[data-state='offline'] { --upd: var(--fm-device-ring-text); }

/* Downloading: the incoming content, dimmed, with the progress. */
.dev-over { position: absolute; inset: 0; display: none; }
.dev[data-kind='downloading'] .dev-over { display: block; background: var(--fm-device-scrim); }
.dev-dl { position: absolute; inset-inline: 0; inset-block-start: 50%; transform: translateY(-50%); display: grid; justify-items: center; text-align: center; font-size: 12px; color: var(--fm-stage-text); }
.dev-dl b { font: 600 22px/28px 'Inter', var(--fm-font); color: var(--fm-device-download); direction: ltr; }
.dev-bar { position: absolute; inset-inline: 0; inset-block-end: 0; height: 4px; overflow: hidden; background: var(--fm-device-track); z-index: 1; }
.dev-bar i { position: absolute; inset: 0; background: var(--fm-device-download); transform-origin: right; transform: scaleX(var(--p, 0)); }
[dir='ltr'] .dev-bar i { transform-origin: left; }
/* No percentage from the player yet: a light segment sweeps instead (the "processing" motion). */
.dev-bar.is-indeterminate i { inset-inline-end: auto; width: 30%; transform: none; animation: fm-sweep 1200ms var(--ease-standard) infinite; }
@keyframes fm-sweep { from { transform: translateX(0); } to { transform: translateX(calc(var(--dir) * 340%)); } }
.dev[data-kind='warning'] .dev-bar { background: var(--fm-stage-warning); height: 2px; }

/* Offline: a dark void with a hollow ring. Calm: it never blinks. */
.dev[data-kind='offline'] .dev-px { background: var(--fm-device-void); }
.dev[data-kind='offline'] .dev-over { display: grid; place-items: center; align-content: center; gap: 12px; }
.dev-ring { width: 54px; height: 54px; border-radius: 50%; border: 2px solid var(--fm-device-ring); }
.dev-ring-label { font-size: 11px; color: var(--fm-device-ring-text); }

/* Selection: a frame with two corners and a check, plus the edge lighting above. */
.dev-sel {
  position: absolute; inset: -9px; border-radius: 12px; pointer-events: none;
  border: 2px solid var(--fm-select-frame);
  box-shadow: 0 0 22px 3px var(--fm-select-glow), inset 0 0 18px var(--fm-select-inner);
  opacity: 0; transform: scale(1.08);
  transition: opacity var(--motion-slow) var(--ease-out), transform var(--motion-slow) var(--ease-light);
}
.dev-sel::before, .dev-sel::after { content: ''; position: absolute; width: 14px; height: 14px; border: 2px solid var(--fm-select-corner); border-radius: 3px; }
.dev-sel::before { top: -2px; right: -2px; border-left: 0; border-bottom: 0; }
.dev-sel::after { bottom: -2px; left: -2px; border-right: 0; border-top: 0; }
.dev-check {
  position: absolute; z-index: 2; top: -16px; left: -16px;
  display: grid; place-items: center;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--fm-primary); color: var(--fm-on-primary);
  opacity: 0; transform: scale(.4);
  transition: opacity var(--motion-base) var(--ease-out), transform var(--motion-slow) var(--ease-light);
}
.dev-check .icon { width: 16px; height: 16px; }
.dev:has(input:checked) :is(.dev-sel, .dev-check) { opacity: 1; transform: none; }
.dev:has(input:checked) .dev-glow, .dev:has(input:checked) .dev-rod::after, .dev:has(input:checked) .dev-cap::after { opacity: 1; }
/* The screen picked to move lights up like a selected one, without the check. */
.dev.is-picked .dev-sel { opacity: 1; transform: none; }
.dev.is-picked .dev-glow, .dev.is-picked .dev-rod::after, .dev.is-picked .dev-cap::after { opacity: 1; }
.dev:has(input:focus-visible)::after {
  content: ''; position: absolute; inset: -20px; z-index: 3; pointer-events: none;
  border: 2px solid var(--fm-focus); border-radius: 14px;
}
@media (hover: hover) and (pointer: fine) { .dev:not(.is-disabled):not(.dev--empty):hover .dev-glow { opacity: .4; } }

/* An empty slot: a hollow outline. */
.dev--empty { background: transparent; border: 1px dashed var(--fm-border-strong); box-shadow: none; cursor: default; }
.dev--empty .dev-px { background: transparent; display: grid; place-items: center; }
.dev--empty :is(.dev-st, .dev-live, .dev-name, .dev-glare, .dev-content, .dev-over) { display: none; }
.dev-empty-label { font-size: 12px; color: var(--fm-text-secondary); }
.dev:not(.dev--empty) .dev-empty-label { display: none; }

/* Narrow devices (laptops, many pairs): keep the essentials. */
@container dev (max-width: 140px) {
  .dev-live { display: none; }
  .dev-name { padding: 16px 6px 6px; }
  .dev-name b { font-size: 12px; line-height: 16px; }
  .dev-st { inset-block-start: 6px; inset-inline-start: 6px; padding: 2px 6px; font-size: 11px; }
  .dev-ring { width: 40px; height: 40px; }
}

/* ---------- Floor ripple under each live pair (faint, travels pair to pair) ---------- */
.wfloor { position: absolute; inset-block-end: 8px; inset-inline-start: 50%; width: 0; height: 0; pointer-events: none; }
.wslot:not(.is-live) .wfloor { display: none; }
.wfloor i {
  position: absolute; top: -49.5cqi; left: -49.5cqi;
  width: 99cqi; height: 99cqi; border-radius: 50%;
  border: 2px solid var(--fm-ripple);
  box-shadow: 0 0 24px var(--fm-ripple-glow), inset 0 0 24px var(--fm-ripple-glow);
  opacity: 0; transform: rotateX(74deg) scale(.15);
  animation: fm-floor 4800ms cubic-bezier(.2, .6, .2, 1) infinite;
  animation-delay: var(--d, 0s);
}
.wfloor i + i { border-width: 1px; animation-delay: calc(var(--d, 0s) + 350ms); }
@keyframes fm-floor {
  0% { transform: rotateX(74deg) scale(.15); opacity: 0; }
  8% { opacity: .9; }
  42%, 100% { transform: rotateX(74deg) scale(1); opacity: 0; }
}
html.is-hidden :is(.wfloor i, .dev-bar i) { animation-play-state: paused; }

/* ---------- New screens without a place, and the empty wall ---------- */
/* No screen yet: the message sits over the hollow outlines. */
.wall-scroll { position: relative; }
.wall-empty {
  position: absolute; z-index: 2; inset-block-start: 38%;
  inset-inline: calc(var(--side-w) + var(--side-gap) + 16px) 48px; margin-inline: auto;
  width: max-content; max-width: min(46ch, 80%);
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--fm-border); border-radius: 12px;
  background: var(--fm-surface-raised); color: var(--fm-text);
  text-align: center;
}
/* Below the wall, clear of the floating bar: it starts under the fold instead of peeking out
   behind the bar, and scrolls fully into view above it. */
.wall-new { display: grid; gap: var(--space-2); margin-block-start: var(--bar-clear); padding-block-start: var(--space-5); border-block-start: 1px solid var(--fm-border); }
.wall-new-title { font: 600 15px/24px var(--fm-font); }
.wall-new-hint { font-size: 13px; color: var(--fm-text-secondary); }
.wall-new-list { display: flex; flex-wrap: wrap; gap: var(--space-6) var(--space-5); padding-block-start: var(--space-4); }
.wslot--loose { --dev-w: 110px; grid-row: auto; padding-block-start: var(--space-4); gap: var(--space-2); container-type: normal; }
.wslot--loose .dev { width: var(--dev-w); }
.wslot--loose :is(.dev-rod, .dev-cap) { display: none; }
.wslot--loose .wcol-head { order: -1; font-size: 12px; }
.loose-place { height: 32px; padding: 0 12px; font: 600 12px/16px var(--fm-font); }

/* ---------- Arrange mode (admin): place screens, rename and reorder the columns ---------- */
.side-arrange { flex: none; min-height: 40px; height: 40px; border-radius: 10px; font: 600 13px/20px var(--fm-font); }
/* «أضف شاشة» and «رتّب الجدار» side by side; one fills the row when the other is hidden. */
.side-actions { flex: none; display: flex; gap: 8px; }
.side-actions .side-arrange { flex: 1 1 0; min-width: 0; padding: 0 10px; }
.side-actions .side-arrange[hidden] { display: none; }
.side-arrange .icon, .arrangebar .btn .icon { width: 16px; height: 16px; }
/* The side panel scrolls; its buttons keep their height instead of shrinking under their text. */
.side-new { flex: none; }
.side-arrange[aria-pressed='true'] { border-color: var(--fm-primary-text); color: var(--fm-primary-text); background: var(--fm-primary-tint); }

/* The header becomes: move right, the place name, move left. */
.wcol-edit { grid-row: 1; align-self: center; display: none; align-items: center; gap: 4px; width: 100%; max-width: 240px; justify-self: center; padding-inline: 4px; }
.is-arranging .wcol-edit { display: flex; }
.is-arranging .wall-grid > .wcol-head { display: none; }
.wcol-name {
  flex: 1; min-width: 0; height: 32px; padding: 0 8px;
  border: 1px solid var(--fm-border-strong); border-radius: 8px;
  background: var(--fm-surface-raised); color: var(--fm-text);
  font: 600 13px/20px var(--fm-font); text-align: center;
}
.wcol-name::placeholder { color: var(--fm-text-secondary); font-weight: 400; }
.wcol-move {
  display: grid; place-items: center; flex: none;
  width: 32px; height: 32px; padding: 0;
  border: 1px solid var(--fm-border); border-radius: 8px;
  background: var(--fm-surface); color: var(--fm-text); cursor: pointer;
}
.wcol-move .icon { width: 18px; height: 18px; }
.wcol-move:disabled { opacity: .35; cursor: default; }
.icon--flip { transform: scaleX(-1); }
@media (hover: hover) and (pointer: fine) { .wcol-move:not(:disabled):hover { border-color: var(--fm-primary-text); color: var(--fm-primary-text); } }

/* Each face says what pressing it does: "انقل", "ضعها هنا" (and who moves out), or cancel. */
.dev-act {
  position: absolute; inset: 0; z-index: 4;
  display: grid; place-items: center; align-content: center; gap: 8px;
  padding: 10px; border: 0; border-radius: 3px;
  background: transparent; color: var(--fm-stage-text);
  font: 600 13px/18px var(--fm-font); text-align: center; cursor: pointer;
}
.dev-act:focus-visible { outline: 2px solid var(--fm-focus); outline-offset: 8px; }
/* A drop target dims its content so the label and the "moves out" note read clearly. */
.dev-act[data-mode='target'] { background: var(--fm-device-scrim); }
.dev--empty .dev-act[data-mode='target'] { background: transparent; }
.dev-act-chip {
  display: inline-flex; align-items: center; min-height: 32px; padding: 6px 14px; border-radius: 999px;
  background: var(--fm-device-bezel); box-shadow: inset 0 0 0 1px var(--fm-stage-line-strong);
}
.dev-act[data-mode='target'] .dev-act-chip { background: var(--fm-primary); color: var(--fm-on-primary); box-shadow: none; }
.dev-act-note { max-width: 100%; padding: 4px 8px; border-radius: 6px; background: var(--fm-device-scrim); font: 400 11px/15px var(--fm-font); }
@media (hover: hover) and (pointer: fine) {
  .dev-act:hover .dev-act-chip { box-shadow: inset 0 0 0 1.5px var(--fm-stage-text); }
  .dev-act[data-mode='target']:hover .dev-act-chip { background: var(--fm-primary-dark); }
}
/* Empty slots light up as places to drop the picked screen. */
.is-arranging .dev--empty.is-target { border: 2px dashed var(--fm-primary-text); cursor: pointer; }
/* The slot planned for a new screen in «أضف شاشة» (ADR 0022), also outside arrange mode. */
.dev--empty.is-planned { border: 2px dashed var(--fm-primary-text); }
.dev--empty.is-planned .dev-empty-label { padding-inline: 8px; text-align: center; color: var(--fm-primary-text); font-weight: 600; }
/* While a face says what pressing it does, an empty slot's own label steps aside. */
.dev--empty:has(.dev-act:not([hidden])) .dev-empty-label { visibility: hidden; }

/* Under each column in arrange mode: remove it (an empty one; the server refuses the others). */
.wcol-foot { grid-row: 4; display: none; justify-content: center; padding-block: 16px 4px; }
.is-arranging .wcol-foot { display: flex; }
.wcol-del {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 32px; padding: 0 10px;
  border: 1px solid var(--fm-border); border-radius: 8px;
  background: var(--fm-surface); color: var(--fm-text-secondary);
  font: 600 12px/16px var(--fm-font); cursor: pointer;
}
.wcol-del .icon { width: 16px; height: 16px; }
@media (hover: hover) and (pointer: fine) { .wcol-del:hover { border-color: var(--fm-offline); color: var(--fm-offline); } }
@media (pointer: coarse) { .wcol-del { min-height: 44px; } }
.is-arranging .loose-place { display: none; }
.is-arranging .dev { cursor: default; }

/* ---------- Composing a connected group (js/groups.js): order numbers on the faces ---------- */
.dev-order {
  position: absolute; z-index: 2; top: -17px; left: -17px;
  display: grid; place-items: center; min-width: 30px; height: 30px; padding: 0 8px;
  border-radius: 15px; background: var(--fm-primary); color: var(--fm-on-primary);
  font: 700 15px/1 'Inter', var(--fm-font);
}
.is-composing .dev-check { display: none; }
/* A screen that cannot join says why, on its face. */
.dev-note {
  position: absolute; z-index: 3; inset-inline: 8px; top: 50%; transform: translateY(-50%);
  padding: 6px 8px; border-radius: 8px;
  background: var(--fm-device-scrim); color: var(--fm-stage-text);
  box-shadow: inset 0 0 0 1px var(--fm-stage-warning);
  font: 600 11px/16px var(--fm-font); text-align: center;
}
.is-composing .dev:has(input:disabled) .dev-content { opacity: .4; }

/* ---------- Side panel ---------- */
.wall-side {
  position: fixed; z-index: 40;
  inset-block: calc(var(--topbar-h) + 24px) 108px; inset-inline-start: var(--side-gap);
  width: var(--side-w);
  display: flex; flex-direction: column; gap: 12px;
  padding: 14px; overflow-y: auto;
  border: 1px solid var(--fm-border); border-radius: 16px;
  /* Nearly opaque instead of a backdrop blur: a blur over the animated wall costs frames. */
  background: color-mix(in srgb, var(--fm-surface) 92%, transparent);
  font-size: 13px;
}
.side-title { display: flex; justify-content: space-between; align-items: center; gap: var(--space-2); font: 600 15px/24px var(--fm-font); }
.side-title small, .side-sub { color: var(--fm-text-secondary); font: 400 12px/18px var(--fm-font); }
.side-sub { font-size: 13px; }
.side-rows { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.side-row { display: grid; gap: 4px; align-content: start; padding: 10px; border: 1px solid var(--fm-border); border-radius: 10px; background: var(--fm-surface-raised); }
.side-row b { font: 600 13px/20px var(--fm-font); }
.side-row-stats { display: flex; flex-wrap: wrap; gap: 2px 8px; color: var(--fm-text-secondary); font-size: 11px; line-height: 16px; }
.side-row-stats > span { display: inline-flex; align-items: center; gap: 4px; }
.sd { width: 7px; height: 7px; flex: none; border-radius: 50%; }
.sd--playing { background: var(--fm-playing); }
.sd--idle { background: var(--fm-online); }
.sd--downloading { background: var(--fm-accent); }
.sd--warning { background: var(--fm-warning); border-radius: 0; transform: rotate(45deg) scale(.85); }
.sd--offline { box-shadow: inset 0 0 0 1.5px var(--fm-wall-offline); }

.side-sends { list-style: none; padding: 0; display: grid; gap: 6px; }
.send { display: flex; align-items: center; gap: 10px; padding: 8px; border: 1px solid var(--fm-border); border-radius: 10px; font-size: 12px; }
.send-thumb { width: 26px; height: 46px; flex: none; border-radius: 3px; overflow: hidden; background: var(--fm-device-bg); color: var(--fm-stage-text); display: grid; place-items: center; }
.send-thumb img { width: 100%; height: 100%; object-fit: cover; }
.send-thumb .icon { width: 14px; height: 14px; }
.send-text { display: grid; min-width: 0; }
.send-text b { font: 600 13px/20px var(--fm-font); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.send-text small { color: var(--fm-text-secondary); font-size: 11px; line-height: 16px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.send time { margin-inline-start: auto; flex: none; color: var(--fm-text-secondary); font-size: 11px; }
.side-empty { color: var(--fm-text-secondary); font-size: 12px; }
.side-new {
  min-height: 40px; padding: 8px 12px;
  border: 1px solid var(--fm-primary-text); border-radius: 10px;
  background: var(--fm-primary-tint); color: var(--fm-primary-text);
  font: 600 13px/20px var(--fm-font); text-align: start; cursor: pointer;
}

.side-legend { margin-block-start: auto; padding: 12px; border: 1px solid var(--fm-border); border-radius: 14px; background: var(--fm-surface-raised); }
.side-legend-head { display: flex; justify-content: space-between; align-items: center; margin-block-end: 10px; font: 600 12px/18px var(--fm-font); color: var(--fm-text-secondary); }
.side-legend-head span:last-child { font-weight: 400; color: var(--fm-text); }
.side-legend-devices { display: flex; justify-content: center; align-items: flex-end; gap: 14px; padding-block: 18px 2px; }
.mini { position: relative; width: 62px; height: 110px; border: 2px solid var(--fm-device-bezel); border-radius: 5px; overflow: visible; background: var(--fm-device-bg); box-shadow: var(--fm-device-shadow); }
.mini::before { content: ''; position: absolute; inset-inline-start: calc(50% - 1px); top: -18px; width: 2px; height: 16px; background: var(--fm-rod-lo); }
.mini > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border-radius: 3px; }
.mini .face-idle { border-radius: 3px; }
.mini--off { background: var(--fm-device-void); }
.mini-ring { position: absolute; left: calc(50% - 11px); top: calc(50% - 11px); width: 22px; height: 22px; border-radius: 50%; border: 1.5px solid var(--fm-device-ring); }
.mini-label { position: absolute; inset-inline: 0; bottom: 6px; text-align: center; font-size: 9px; line-height: 12px; color: var(--fm-device-ring-text); }
.mini:not(.mini--off) .mini-label { color: var(--fm-stage-text); }
.side-legend-note { margin-block-start: 8px; text-align: center; font-size: 11px; line-height: 1.5; color: var(--fm-text-secondary); }

/* ---------- Connected groups in the side panel: live runs and the saved groups ---------- */
.side-sync { flex: none; display: grid; gap: 8px; }
.side-sync-head { display: flex; justify-content: space-between; align-items: center; gap: var(--space-2); }
.side-sync-new {
  min-height: 32px; padding: 0 12px;
  border: 1px solid var(--fm-primary-text); border-radius: 8px;
  background: var(--fm-primary-tint); color: var(--fm-primary-text);
  font: 600 12px/16px var(--fm-font); cursor: pointer;
}
.sync-runs { display: grid; gap: 8px; }
.sync-runs:empty { display: none; }
.sync-list { list-style: none; padding: 0; display: grid; gap: 6px; }
.sg { display: flex; gap: 6px; }
.sg-play {
  flex: none; display: grid; place-items: center; width: 40px;
  border: 1px solid var(--fm-border); border-radius: 10px;
  background: var(--fm-surface-raised); color: var(--fm-primary-text); cursor: pointer;
}
.sg-play .icon { width: 16px; height: 16px; }
.sg.is-running .sg-play { border-color: var(--fm-primary); background: var(--fm-primary); color: var(--fm-on-primary); }
.sg-edit { flex: 1; min-width: 0; padding: 0; border: 0; background: none; color: var(--fm-text); text-align: start; cursor: pointer; }
.sg-text { display: grid; min-width: 0; padding: 6px 10px; border: 1px solid var(--fm-border); border-radius: 10px; }
.sg-text b { font: 600 13px/20px var(--fm-font); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sg-text small { color: var(--fm-text-secondary); font-size: 11px; line-height: 16px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (hover: hover) and (pointer: fine) {
  .sg-play:hover, .sg-edit:hover .sg-text, .side-sync-new:hover { border-color: var(--fm-primary-text); }
}

/* One run: its state, then each screen in play order with how it is doing. */
.run { display: grid; gap: 8px; padding: 10px; border: 1px solid var(--fm-border); border-radius: 12px; background: var(--fm-surface-raised); }
.run--preparing, .run--playing { border-color: var(--fm-primary-text); }
.run--failed { border-color: var(--fm-warning); }
.run-head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-2); }
.run-head b { flex: 1; min-width: 0; font: 600 13px/20px var(--fm-font); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* An ended run's card can be deleted for everyone; a live one only stopped. */
.run-dismiss {
  flex: none; align-self: center; display: grid; place-items: center;
  width: 32px; height: 32px; margin-block: -6px; margin-inline-end: -4px; padding: 0;
  border: 1px solid transparent; border-radius: 8px; background: none;
  color: var(--fm-text-secondary); cursor: pointer;
  transition: color var(--motion-fast) ease, border-color var(--motion-fast) ease;
}
.run-dismiss .icon { width: 16px; height: 16px; }
.runs-clear {
  justify-self: end; min-height: 32px; padding: 0 10px;
  border: 1px solid var(--fm-border-strong); border-radius: 8px; background: none;
  color: var(--fm-text); font: 600 12px/16px var(--fm-font); cursor: pointer;
  transition: border-color var(--motion-fast) ease;
}
@media (hover: hover) and (pointer: fine) {
  .run-dismiss:hover { color: var(--fm-offline); border-color: var(--fm-border-strong); }
  .runs-clear:hover { border-color: var(--fm-text); }
}
@media (pointer: coarse) {
  .run-dismiss { width: 44px; height: 44px; margin-block: -12px; }
  .runs-clear { min-height: 44px; }
}
.run-state { flex: none; color: var(--fm-text-secondary); font-size: 11px; line-height: 16px; }
.run-rows { list-style: none; padding: 0; display: grid; gap: 4px; }
.run-row { display: grid; grid-template-columns: 18px minmax(0, 1fr) auto; align-items: center; gap: 6px; font-size: 11px; line-height: 16px; }
.run-n { display: grid; place-items: center; width: 18px; height: 18px; border-radius: 50%; background: var(--fm-primary-tint); color: var(--fm-primary-text); font: 600 10px/1 'Inter', var(--fm-font); }
.run-screen { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.run-st { display: inline-flex; align-items: center; gap: 5px; color: var(--fm-text-secondary); white-space: nowrap; }
.run-foot { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 8px; }
.run-stop { height: 32px; padding: 0 12px; border-radius: 8px; font: 600 12px/16px var(--fm-font); }
.run-link { min-height: 32px; font: 600 12px/16px var(--fm-font); }
.run-help { color: var(--fm-text-secondary); font-size: 11px; line-height: 16px; }

/* The composer replaces the side panel's content while active. */
.is-composing .wall-side > :not(.compose) { display: none; }
.compose { display: grid; gap: 14px; align-content: start; }
.compose .field { gap: 6px; }
.compose .field label, .compose .field-label { font: 600 13px/20px var(--fm-font); }
.compose .input { min-height: 40px; font-size: 14px; }
.compose fieldset { margin: 0; padding: 0; border: 0; min-width: 0; }
.compose-modes { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.compose-modes legend { margin-block-end: 6px; }
.compose-mode { position: relative; display: block; cursor: pointer; }
.compose-mode input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.compose-mode span { display: grid; gap: 2px; height: 100%; padding: 10px; border: 1px solid var(--fm-border-strong); border-radius: 10px; background: var(--fm-surface-raised); }
.compose-mode b { font: 600 13px/20px var(--fm-font); }
.compose-mode small { color: var(--fm-text-secondary); font-size: 11px; line-height: 16px; }
.compose-mode input:checked + span { border-color: var(--fm-primary); background: var(--fm-primary-tint); box-shadow: inset 0 0 0 1px var(--fm-primary); }
.compose-mode input:focus-visible + span { outline: 2px solid var(--fm-focus); outline-offset: 2px; }
.compose-parts { list-style: none; padding: 0; display: grid; gap: 10px; }
.cp { display: grid; grid-template-columns: 22px 30px minmax(0, 1fr); grid-template-areas: 'n thumb name' 'n thumb select'; align-items: center; gap: 2px 8px; }
.cp-n { grid-area: n; display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%; background: var(--fm-primary); color: var(--fm-on-primary); font: 700 11px/1 'Inter', var(--fm-font); }
.cp-thumb { grid-area: thumb; display: grid; place-items: center; width: 30px; height: 53px; overflow: hidden; border-radius: 3px; background: var(--fm-device-bg); color: var(--fm-stage-text); }
.cp-thumb img { width: 100%; height: 100%; object-fit: cover; }
.cp-thumb .icon { width: 14px; height: 14px; }
.cp-name { grid-area: name; font: 600 12px/16px var(--fm-font); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.compose .cp-select { grid-area: select; min-height: 34px; padding: 0 8px; font-size: 13px; }
.compose-wave { display: grid; gap: 12px; }
.compose-delay { display: flex; align-items: center; gap: 8px; color: var(--fm-text-secondary); font-size: 13px; }
.compose-delay .input { width: 120px; }
.compose-dir { display: grid; gap: 4px; font-size: 13px; line-height: 20px; }
.compose-dir label, .compose-loop { display: flex; align-items: center; gap: 8px; cursor: pointer; }
.compose-loop { font: 600 13px/20px var(--fm-font); }
.compose-warn { display: grid; gap: 6px; padding: 10px; border: 1px solid var(--fm-warning); border-radius: 10px; background: var(--fm-surface-raised); font-size: 12px; line-height: 18px; }
.compose-warn .text-link { min-height: 0; font: 600 12px/18px var(--fm-font); }
.compose-delete { justify-self: start; height: 36px; padding: 0 14px; font: 600 13px/20px var(--fm-font); }

/* A short viewport keeps the side panel to the live information. */
@media (max-height: 820px) { .side-legend { display: none; } }

/* ---------- Smaller screens: the side panel moves under the wall ---------- */
@media (max-width: 959px) {
  .wall-view { --side-gap: 16px; --dev-w: 150px; }
  .wall-scroll { padding-inline: 16px 8px; padding-block-end: var(--space-5); }
  .wall-grid { min-height: 0; }
  .wall-new { margin-block-start: var(--space-6); }
  .wall { min-height: 0; }
  .wall-side { position: static; width: auto; margin: var(--space-4) 16px 120px; }
  .wall-empty { inset-inline: 16px; }
  .side-legend { display: none; }
}
@media (max-width: 639px) {
  .wall-side { margin-block-end: 200px; }
}

/* ---------- «أضف شاشة» (js/addscreen.js, ADR 0022): place, USB kit, installer's steps ---------- */
.dialog--add[open] { grid-template-columns: minmax(0, 1fr); width: min(560px, calc(100vw - 2 * var(--margin))); max-height: calc(100vh - 48px); overflow-y: auto; }
.add-body { display: grid; gap: var(--space-4); padding: var(--space-5); }
.add-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
.add-step { display: grid; gap: var(--space-4); }
.add-step[hidden] { display: none; }
.add-step h3 { margin: 0; }
/* Where the dialog is: three numbered steps, the current one lit. */
.add-progress { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; counter-reset: add; }
.add-progress li {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  padding: 6px 10px; border: 1px solid var(--fm-border); border-radius: 999px;
  color: var(--fm-text-secondary); font: 600 12px/18px var(--fm-font); counter-increment: add;
}
.add-progress li::before {
  content: counter(add); flex: none; display: grid; place-items: center; width: 20px; height: 20px; border-radius: 50%;
  background: var(--fm-surface); box-shadow: inset 0 0 0 1px var(--fm-border-strong); font: 600 11px/1 'Inter', var(--fm-font);
}
.add-progress li[aria-current='step'] { border-color: var(--fm-primary-text); background: var(--fm-primary-tint); color: var(--fm-primary-text); }
.add-progress li[aria-current='step']::before { background: var(--fm-primary); color: var(--fm-on-primary); box-shadow: none; }
.add-where { border: 0; padding: 0; margin: 0; display: grid; gap: 8px; min-width: 0; }
.add-where legend { margin-block-end: 8px; }
.add-option { position: relative; display: block; cursor: pointer; }
.add-option input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.add-option > span { display: grid; gap: 2px; padding: 12px 14px; border: 1px solid var(--fm-border-strong); border-radius: 10px; background: var(--fm-surface-raised); }
.add-option b { font: var(--type-label); }
.add-option small { color: var(--fm-text-secondary); font: var(--type-small); }
.add-option input:checked + span { border-color: var(--fm-primary); background: var(--fm-primary-tint); box-shadow: inset 0 0 0 1px var(--fm-primary); }
.add-option input:focus-visible + span { outline: 2px solid var(--fm-focus); outline-offset: 2px; }
.add-option input:disabled + span { color: var(--fm-disabled-text); background: var(--fm-disabled-bg); border-color: transparent; cursor: not-allowed; }
.add-option input:disabled + span small { color: var(--fm-disabled-text); }
.add-planned { font: var(--type-small); color: var(--fm-text-secondary); }
.add-file { white-space: nowrap; }
.add-step .kit-form .field { flex: 1 1 180px; }
/* The installer's steps, numbered like the readme. */
.add-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 8px; counter-reset: addstep; }
.add-list li { display: grid; grid-template-columns: 24px minmax(0, 1fr); gap: 10px; align-items: start; font: var(--type-small); counter-increment: addstep; }
.add-list li > span { padding-block-start: 2px; }
.add-list li::before {
  content: counter(addstep); display: grid; place-items: center; width: 24px; height: 24px; border-radius: 50%;
  background: var(--fm-primary-tint); color: var(--fm-primary-text); font: 600 12px/1 'Inter', var(--fm-font);
}
.add-arrive { padding: 12px 14px; border: 1px solid var(--fm-primary-text); border-radius: 10px; background: var(--fm-primary-tint); font: 600 14px/22px var(--fm-font); }
@media (max-width: 639px) { .add-body { padding: var(--space-4); } }
