/* Designed against a 1920x1080 viewport, which is what webOS reports to an app * on both a 1080p and a 4K panel. Sizes are absolute px for that reason. * * Two rules shape everything here: text is read from the sofa, so nothing is * smaller than 22px; and focus is the only cursor, so the focused element has * to be unmistakable across the room. */ * { box-sizing: border-box; } html, body { margin: 0; padding: 0; width: 1920px; height: 1080px; overflow: hidden; background: #0b0e13; color: #e8ecf3; font-family: "LG Smart UI", "Museo Sans", "Helvetica Neue", Arial, sans-serif; font-size: 26px; line-height: 1.4; /* The remote is the pointer. A caret blinking somewhere off-screen is only * ever confusing. */ -webkit-user-select: none; user-select: none; } #app { display: flex; flex-direction: column; height: 100%; /* Overscan safe area: older sets crop up to 5% of each edge. */ padding: 40px 60px 30px; } /* --- header --------------------------------------------------------------- */ #header { display: flex; align-items: center; flex: none; gap: 30px; padding-bottom: 22px; border-bottom: 2px solid #1d2430; } .brand h1 { margin: 0; font-size: 46px; font-weight: 300; letter-spacing: 0.5px; } .subtitle { color: #7c8798; font-size: 22px; } .header-status { display: flex; align-items: center; gap: 18px; margin-left: auto; } .pill { display: inline-block; padding: 8px 24px; border-radius: 999px; background: #1d2430; color: #9aa6b8; font-size: 24px; white-space: nowrap; } .pill.running { background: #123a24; color: #57d98a; } .pill.starting { background: #3a3212; color: #e2c657; } .pill.error { background: #3d1a1c; color: #ff7b7b; } .uptime { color: #7c8798; font-size: 22px; min-width: 110px; } /* --- tabs ----------------------------------------------------------------- */ #tabs { display: flex; flex: none; gap: 14px; padding: 20px 0; } .tab { padding: 12px 34px; border: 2px solid transparent; border-radius: 12px; background: #151b25; color: #9aa6b8; font: inherit; cursor: default; } .tab.active { background: #1e2a3d; color: #ffffff; } /* --- content -------------------------------------------------------------- */ #content { flex: 1; overflow-y: auto; padding-right: 14px; /* Room to scroll the last card clear of the bottom edge. */ padding-bottom: 120px; } #content::-webkit-scrollbar { width: 10px; } #content::-webkit-scrollbar-thumb { border-radius: 5px; background: #2a3444; } .panel { display: flex; flex-direction: column; gap: 22px; } .card { padding: 26px 32px; border: 2px solid #1d2430; border-radius: 16px; background: #121722; } .card h2 { margin: 0 0 6px; color: #cfd8e6; font-size: 30px; font-weight: 400; } .card.error { border-color: #5a2226; background: #1c1215; color: #ff9d9d; } .blurb { margin: 0 0 14px; max-width: 1200px; color: #7c8798; font-size: 22px; } .muted { color: #7c8798; } .hidden { display: none !important; } /* --- fields --------------------------------------------------------------- */ .field { display: flex; align-items: center; gap: 30px; padding: 14px 0; border-top: 1px solid #1a212c; } .field:first-child { border-top: none; } .field-text { flex: 1; min-width: 0; } .field-label { font-size: 26px; } .field-hint { color: #7c8798; font-size: 21px; } .field-control { flex: none; } .actions { display: flex; flex-wrap: wrap; gap: 16px; padding-top: 16px; } /* --- controls ------------------------------------------------------------- */ .btn { min-width: 150px; padding: 12px 30px; border: 2px solid #2c3646; border-radius: 12px; background: #1c2432; color: #e8ecf3; font: inherit; text-align: center; cursor: default; } .btn.primary { background: #1f4d76; border-color: #2b6ba6; } .btn.danger { border-color: #5a2226; background: #2a171a; color: #ff9d9d; } .btn.toggle { min-width: 120px; } .btn.toggle.on { border-color: #2f7a4d; background: #143324; color: #6ee29a; } .btn.choice { min-width: 300px; } .input { width: 360px; padding: 12px 18px; border: 2px solid #2c3646; border-radius: 12px; background: #0d1119; color: #e8ecf3; font: inherit; /* Text fields are the one place typing happens. */ -webkit-user-select: text; user-select: text; } .input.wide { width: 620px; } /* One focus treatment for every control: a bright ring plus a lift. Visible * from across the room on both an OLED and a dim LCD. */ .focusable:focus { outline: none; border-color: #4aa3ff; box-shadow: 0 0 0 4px rgba(74, 163, 255, 0.35); } .btn.focusable:focus, .tab.focusable:focus { background: #2b6ba6; color: #ffffff; } .btn.toggle.on.focusable:focus { background: #2f7a4d; color: #ffffff; } .btn.danger.focusable:focus { background: #8a2f36; color: #ffffff; } /* --- meter ---------------------------------------------------------------- */ .meter { display: flex; flex-direction: column; gap: 12px; padding: 10px 0 18px; } .meter-row { display: flex; align-items: center; gap: 20px; } .meter-label { width: 90px; color: #7c8798; font-size: 22px; } .meter-db { width: 130px; color: #9aa6b8; font-size: 22px; text-align: right; /* dB numbers jitter constantly; tabular digits stop the label dancing. */ font-variant-numeric: tabular-nums; } .bar { flex: 1; height: 26px; overflow: hidden; border-radius: 13px; background: #0d1119; } .bar-fill { width: 0; height: 100%; border-radius: 13px; background: linear-gradient(90deg, #3aa76d, #7bd44f 70%, #e2c657 88%, #ff5f5f); /* Short enough to feel live at the service's 100 ms notify interval. */ transition: width 80ms linear; } .bar.rms .bar-fill { background: linear-gradient(90deg, #2b6ba6, #4aa3ff); } .bands { display: flex; align-items: flex-end; gap: 8px; height: 180px; padding: 12px 0 0; border-top: 1px solid #1a212c; } .band { flex: 1; min-height: 3px; border-radius: 5px 5px 2px 2px; background: linear-gradient(180deg, #4aa3ff, #1f4d76); transition: height 80ms linear; } .clip { margin-top: 14px; color: #ff7b7b; font-size: 24px; } /* --- info grid ------------------------------------------------------------ */ .info-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px 30px; padding-top: 12px; } .info-item { min-width: 0; } .info-key { color: #7c8798; font-size: 21px; } .info-value { overflow: hidden; font-size: 27px; text-overflow: ellipsis; white-space: nowrap; } /* --- sink status ---------------------------------------------------------- */ .sink-status { display: flex; flex-direction: column; gap: 14px; padding-top: 12px; } .sink-line { display: flex; align-items: baseline; gap: 18px; } .dot { flex: none; width: 16px; height: 16px; border-radius: 50%; background: #4b5666; } .dot.ok { background: #57d98a; } .dot.bad { background: #ff5f5f; } .sink-name { min-width: 320px; } .sink-detail { color: #7c8798; font-size: 22px; } /* --- sink cards ----------------------------------------------------------- */ #sink-cards { display: flex; flex-direction: column; gap: 22px; } .sink-card .sink-head { display: flex; align-items: center; gap: 30px; } .sink-card .sink-head h2 { margin: 0; } .sink-card .sink-head .field-control { margin-left: auto; } .sink-card.off .sink-body { opacity: 0.45; } .badge { padding: 4px 16px; border-radius: 999px; background: #1f4d76; color: #9fd0ff; font-size: 20px; } /* --- output / logs -------------------------------------------------------- */ .output { max-height: 520px; margin: 18px 0 0; padding: 20px; overflow: auto; border-radius: 12px; background: #0d1119; color: #b8c4d4; font-family: "Courier New", monospace; font-size: 20px; line-height: 1.5; white-space: pre-wrap; word-break: break-word; -webkit-user-select: text; user-select: text; } /* --- toast ---------------------------------------------------------------- */ .toast { position: fixed; left: 50%; bottom: 48px; z-index: 10; padding: 16px 40px; transform: translateX(-50%); border: 2px solid #2c3646; border-radius: 14px; background: #1c2432; box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6); font-size: 24px; } .toast.bad { border-color: #5a2226; background: #2a171a; color: #ff9d9d; }