/* App shell: topbar (Web-Portal look-alike), page header, content. */

/* ── Topbar ──
 * Three columns: logo + app name, the controller search centred on the
 * page (Web Portal style), the account menu. The side columns share the rest
 * equally, so the search sits in the middle; when the left side needs more,
 * it pushes the search right rather than running under it (on a phone,
 * responsive.css shrinks the search to its icon). */
.topbar{
  display:grid; grid-template-columns:1fr auto 1fr; align-items:center; gap:24px; height:56px; padding:0 24px;
  background:#fff; border-bottom:1px solid var(--border); position:sticky; top:0; z-index:40;
}
.topbar-start{ display:flex; align-items:center; gap:28px; }
.topbar .brand{ display:flex; align-items:center; gap:10px; flex-shrink:0; }
.topbar .brand img{ height:26px; width:auto; }
.topbar .app-name{ font-size:15px; font-weight:700; color:var(--slt-navy-700); white-space:nowrap; }
.topbar .account-menu{ justify-self:end; }
/* "DEV" beside the app name (and on the login screen) in debug mode, so a
 * development page is never mistaken for the one clients see. */
.env-badge{
  display:inline-flex; align-items:center; height:20px; padding:0 8px; flex-shrink:0; vertical-align:middle;
  border:1px solid var(--slt-orange-border); border-radius:999px; background:var(--slt-orange-bg);
  color:var(--slt-orange-600); font-size:10.5px; font-weight:700; letter-spacing:.08em; line-height:1;
}
.topbar-start .env-badge{ margin-left:-16px; }
/* The tool's version beside the app name (main.js); its build is in the tooltip. */
.app-version{
  margin-left:-18px; color:var(--text-secondary); font-size:11.5px; font-weight:600;
  font-variant-numeric:tabular-nums; white-space:nowrap; cursor:default;
}

/* Controller search ("Search installations", controllerSearch.js): a white
 * button that drops down a search field over the list of controllers,
 * centred under it. */
.controller-search{ position:relative; }
.cs-btn{
  display:flex; align-items:center; gap:8px; height:34px; padding:0 12px;
  border:1px solid var(--border-strong); border-radius:4px; background:#fff; box-shadow:var(--shadow-sm);
  color:var(--text-primary); font-size:12.5px; font-weight:500; white-space:nowrap; cursor:pointer;
}
.cs-btn:hover, .cs-btn[aria-expanded="true"]{ background:var(--gray-50); border-color:var(--gray-400); }
.cs-btn:focus-visible{ outline:2px solid var(--slt-blue-500); outline-offset:1px; }
.cs-icon{ width:14px; height:14px; flex-shrink:0; }
.cs-chevron{ width:12px; height:12px; flex-shrink:0; }
.cs-panel{
  position:absolute; top:calc(100% + 6px); left:50%; transform:translateX(-50%); z-index:50;
  width:380px; max-width:calc(100vw - 24px); padding:8px;
  background:var(--bg-card); border:1px solid var(--border); border-radius:var(--radius-sm); box-shadow:var(--shadow-md);
}
.cs-panel[hidden]{ display:none; }
.cs-field{ position:relative; margin-bottom:6px; }
.cs-field .cs-icon{ position:absolute; left:10px; top:50%; transform:translateY(-50%); color:var(--gray-500); pointer-events:none; }
.cs-field input{
  width:100%; height:34px; padding:0 10px 0 32px;
  border:1px solid var(--border-strong); border-radius:4px; background:#fff;
  color:var(--text-primary); font-size:13px; font-family:inherit;
}
.cs-field input:focus{ outline:none; border-color:var(--slt-blue-500); box-shadow:0 0 0 3px var(--focus-ring); }
/* position:relative so each option's offsetTop is measured from the list
 * (controllerSearch.js scrolls by it). */
.cs-list{ position:relative; max-height:270px; overflow-y:auto; margin:0; padding:0; list-style:none; }
.cs-list [role="option"]{
  padding:6px 10px; border-radius:4px; font-size:12.5px; line-height:1.35; color:var(--text-primary);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; cursor:pointer;
}
.cs-list [role="option"].is-active{ background:var(--gray-100); }
/* The controller on screen. */
.cs-list [role="option"][aria-selected="true"]{ font-weight:600; color:var(--slt-navy-700); }
.cs-empty{ padding:8px 10px; font-size:12.5px; color:var(--text-muted); }

/* Account menu: an initials avatar in the topbar; its dropdown (an
 * .export-list, see components.css) names the user and holds Sign out. */
.account-btn{
  display:flex; align-items:center; gap:6px; padding:3px 7px 3px 3px; flex-shrink:0;
  border:1px solid transparent; border-radius:999px; background:transparent; color:var(--gray-500); cursor:pointer;
}
.account-btn:hover, .account-btn[aria-expanded="true"]{ background:var(--gray-100); color:var(--text-primary); }
.account-btn:focus-visible{ outline:2px solid var(--slt-blue-500); outline-offset:1px; }
.avatar{
  display:inline-flex; align-items:center; justify-content:center; width:30px; height:30px; flex-shrink:0;
  border-radius:50%; background:var(--slt-navy-600); color:#fff; font-size:12px; font-weight:700; letter-spacing:.02em;
}
.avatar-lg{ width:38px; height:38px; font-size:14px; }
.account-list{ min-width:240px; max-width:min(320px, calc(100vw - 24px)); }
.account-info{ display:flex; align-items:center; gap:10px; padding:8px 10px 10px; }
.account-text{ display:flex; flex-direction:column; gap:1px; min-width:0; }
.account-caption{ font-size:11px; color:var(--text-secondary); }
.account-name{ font-size:13px; font-weight:600; color:var(--text-primary); overflow-wrap:anywhere; }
.menu-sep{ height:1px; margin:2px 4px 6px; background:var(--border); }

/* ── Page header: title + report period bar, then the tab bar ──
 * A full-width strip above the content. Pinned under the topbar while
 * scrolling: every chart and figure depends on the controller, period and timezone
 * shown here, so they stay in view, and so do the tabs, to switch view
 * without scrolling back up. Opaque so content scrolls beneath it;
 * stickyHeader.js adds `.is-stuck` (a shadow) once it is pinned. z-index sits
 * under the topbar (40, so the controller search drops down over it) and
 * above the content and its dropdowns' own layers. */
.page-header{
  display:flex; flex-direction:column; gap:16px;
  padding:20px 28px 12px; transition:box-shadow .15s ease;
  position:sticky; top:56px; z-index:35; background:var(--bg-page);
}
.page-header.is-stuck{ box-shadow:0 1px 0 var(--border), 0 4px 10px -6px rgba(16,24,40,.18); }
.page-heading{ display:flex; align-items:center; flex-wrap:wrap; gap:14px 24px; }
/* Device name, with "Serial: <id>" + copy button under it (Web Portal style). */
.page-title-block{ display:flex; flex-direction:column; gap:3px; min-width:0; }
.page-title{ font-size:24px; font-weight:700; line-height:1.2; color:var(--text-primary); }
.page-serial{ display:flex; align-items:center; gap:4px; font-size:12px; color:var(--text-secondary); }
.copy-btn{
  display:inline-flex; align-items:center; justify-content:center; width:20px; height:20px; padding:0;
  border:none; border-radius:4px; background:transparent; color:var(--gray-500); cursor:pointer;
}
.copy-btn:hover{ color:var(--text-primary); background:var(--gray-100); }
.copy-btn:focus-visible{ outline:2px solid var(--slt-blue-500); outline-offset:1px; }
.copy-btn svg{ width:13px; height:13px; }
.copy-btn .icon-copied, .copy-btn.is-copied .icon-copy{ display:none; }
.copy-btn.is-copied .icon-copied{ display:block; color:var(--text-primary); }

/* ── Tab bar: plain rectangular report buttons, black on white with line
 * icons; the active one filled dark slate (Web Portal device-page tabs).
 * The page header's second row, so it lines up with the title and stays
 * pinned with it; the report status sits at its right end. ── */
.tab-row{ display:flex; align-items:center; gap:16px; }
.tabbar{ display:flex; gap:8px; padding:0; flex-shrink:0; }
.tab-btn{
  display:flex; align-items:center; gap:7px; height:34px; padding:0 13px;
  border:1px solid var(--border-strong); border-radius:4px; background:#fff; box-shadow:var(--shadow-sm);
  color:var(--text-primary); font-size:12.5px; font-weight:600; font-family:inherit; white-space:nowrap; cursor:pointer;
}
.tab-btn svg{ width:14px; height:14px; flex-shrink:0; }
.tab-btn:hover{ background:var(--gray-50); border-color:var(--gray-400); }
.tab-btn:focus-visible{ outline:2px solid var(--slt-blue-500); outline-offset:2px; }
.tab-btn.is-active{ background:var(--slt-navy-600); border-color:var(--slt-navy-600); color:#fff; }
/* A controller with neither PV nor a battery has no report to switch between. */
.tab-btn:disabled{ opacity:.45; cursor:not-allowed; background:#fff; border-color:var(--border-strong); color:var(--text-primary); }

/* Report status (reportRunner.js): "Fetching…" with a spinner, an error, or,
 * in debug mode, the data window loaded. One line, cut short with "…" when
 * it doesn't fit (its tooltip has it all). */
.report-status{
  flex:1 1 0; min-width:0; text-align:right; font-size:12.5px; color:var(--text-secondary);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.report-status.is-error{ color:var(--status-bad-text); font-weight:600; }
.report-status.is-loading::before{
  content:''; display:inline-block; width:10px; height:10px; margin-right:7px; vertical-align:-1px;
  border:2px solid var(--gray-300); border-top-color:var(--slt-navy-600); border-radius:50%;
  animation:status-spin .8s linear infinite;
}
@keyframes status-spin{ to{ transform:rotate(360deg); } }
@media (prefers-reduced-motion:reduce){ .report-status.is-loading::before{ animation:none; } }

/* ── Content ──
 * Not width-capped: it fills the window, so charts get the full benefit of a
 * large screen. */
.app-content{ padding:20px 28px 60px; }

.section{ margin-bottom:22px; }
.section-title{
  font-size:13px; font-weight:700; color:var(--text-primary); margin-bottom:10px;
  display:flex; align-items:center; gap:10px;
}
.section-title .hint{ margin-left:auto; font-weight:500; color:var(--text-muted); font-size:11.5px; }
/* A chart's period, on hovering its title (chartPeriods.js): a dark tip under
 * the title, clear of the pinned header above. */
.section-title > [data-tip]{ position:relative; cursor:help; }
.section-title > [data-tip]::after{
  content:attr(data-tip); position:absolute; top:calc(100% + 6px); left:0; z-index:5;
  transform:translateY(-4px); padding:6px 10px; border-radius:6px; white-space:nowrap;
  background:var(--slt-navy-700); color:#fff; font-size:11.5px; font-weight:500; box-shadow:var(--shadow-md);
  opacity:0; pointer-events:none; transition:opacity .15s ease, transform .15s ease;
}
.section-title > [data-tip]:hover::after{ opacity:1; transform:none; }
@media (prefers-reduced-motion:reduce){
  .section-title > [data-tip]::after{ transition:none; }
}

/* Two columns when the content area fits two >=460px charts, otherwise one.
   min-width:0 lets a column shrink below the width Plotly last rendered at,
   instead of overflowing into a horizontal scroll. */
.grid-2{ display:grid; grid-template-columns:repeat(auto-fit, minmax(min(100%, 460px), 1fr)); gap:18px; }
.grid-2 > *{ min-width:0; }
