Files
HomeAssistantVS/custom_components/maintenance_supporter/frontend-src/panel-styles.ts
T
2026-07-08 10:43:39 -04:00

1394 lines
36 KiB
TypeScript

/** Component-specific styles for the maintenance-supporter-panel. */
import { css } from "lit";
export const panelStyles = css`
:host {
display: block;
height: 100%;
background: var(--primary-background-color);
}
.panel {
height: 100%;
display: flex;
flex-direction: column;
}
.header {
display: flex;
align-items: center;
gap: 4px;
background: var(--app-header-background-color, var(--primary-color));
color: var(--app-header-text-color, white);
padding: 12px 16px;
font-size: 16px;
}
.header ha-menu-button {
margin-right: 4px;
color: var(--app-header-text-color, white);
}
.header ha-icon-button {
--mdc-icon-button-size: 36px;
--mdc-icon-size: 20px;
color: var(--app-header-text-color, white);
}
.breadcrumbs { display: flex; align-items: center; gap: 4px; }
.breadcrumbs a { color: inherit; opacity: 0.8; cursor: pointer; text-decoration: none; }
.breadcrumbs a:hover { opacity: 1; text-decoration: underline; }
.breadcrumbs .sep { opacity: 0.5; margin: 0 4px; }
.breadcrumbs .current { font-weight: 500; }
.content { flex: 1; overflow-y: auto; padding: 0 16px 16px; }
.filter-bar {
display: flex;
justify-content: space-between;
align-items: flex-end;
padding: 8px 0;
gap: 8px;
}
.filter-field {
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
}
.filter-label {
font-size: 11px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.4px;
color: var(--secondary-text-color);
padding-left: 2px;
}
.filter-bar select {
padding: 8px;
border: 1px solid var(--divider-color);
border-radius: 4px;
background: var(--card-background-color, #fff);
color: var(--primary-text-color);
}
/* Desktop: the LIST owns the 7-column grid and every row is a subgrid
spanning all columns. Sharing the tracks across rows is what actually
keeps the title (and every other column) aligned regardless of which
optional badges/chips a given row carries. A per-row grid can't: each
row would size its auto badges column independently, so a row with an
NFC badge pushed its title right of the others (issue #66). */
.task-table {
display: grid;
grid-template-columns:
auto /* badges */
minmax(100px, 180px) /* object-name */
minmax(120px, 1fr) /* task-name */
minmax(0, 220px) /* task-sub (chips) */
100px /* type */
150px /* due-cell */
auto; /* row-actions */
column-gap: 12px;
}
.task-row {
display: grid;
grid-template-columns: subgrid;
grid-column: 1 / -1;
align-items: center;
column-gap: 12px;
padding: 10px 12px;
border-bottom: 1px solid var(--divider-color);
cursor: pointer;
transition: background 0.15s;
}
/* Virtualized task table (large installs): only the scroll window of rows
is in the DOM. The spacers span all columns and carry the off-window
height so the scrollbar stays honest. The sizer row is invisible and
zero-height but its badge cell still participates in subgrid track
sizing — pinning the content-sized badge column to the widest badge set
across ALL rows, so columns can't jitter while scrolling. */
.virt-spacer { grid-column: 1 / -1; }
.task-row.virt-sizer {
height: 0;
min-height: 0;
padding-top: 0;
padding-bottom: 0;
border: none;
overflow: hidden;
visibility: hidden;
pointer-events: none;
}
/* Bulk selection: a leading checkbox column while selecting. */
.task-table.bulk { grid-template-columns: auto auto minmax(100px, 180px) minmax(120px, 1fr) minmax(0, 220px) 100px 150px auto; }
.bulk-check { display: flex; align-items: center; justify-content: center; cursor: pointer; }
.bulk-check input, .bulk-selectall input { width: 17px; height: 17px; cursor: pointer; accent-color: var(--primary-color); }
.task-row.bulk-selected { background: color-mix(in srgb, var(--primary-color) 12%, transparent); }
.bulk-bar {
display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
padding: 8px 12px; margin-bottom: 8px; border-radius: 8px;
background: var(--secondary-background-color); border: 1px solid var(--divider-color);
position: sticky; top: 0; z-index: 5;
}
.bulk-selectall { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; font-size: 13px; }
.bulk-count { color: var(--secondary-text-color); font-size: 13px; }
.bulk-actions { margin-left: auto; display: inline-flex; gap: 8px; }
.bulk-toggle.active { --mdc-theme-primary: var(--primary-color); }
/* Collapsible analysis sections on the task-detail overview tab. The header
owns the title, so the wrapped card's own title row is hidden to avoid
showing it twice. */
.collapsible { margin: 8px 0; border: 1px solid var(--divider-color); border-radius: 10px; overflow: hidden; }
.collapsible-head {
display: flex; align-items: center; gap: 8px; width: 100%;
font: inherit; font-weight: 600; font-size: 14px; text-align: left;
padding: 10px 12px; cursor: pointer; background: var(--secondary-background-color);
border: none; color: var(--primary-text-color);
}
.collapsible-head:hover { background: var(--table-row-alternative-background-color, rgba(0,0,0,.04)); }
.collapsible-head ha-icon { --mdc-icon-size: 20px; color: var(--secondary-text-color); }
.collapsible-body { padding: 4px 12px 12px; }
.collapsible-body > .weibull-section > .weibull-title,
.collapsible-body > .seasonal-chart > .seasonal-chart-title { display: none; }
/* "Today" focus view — mobile-first list grouped by urgency. */
.today-view { display: flex; flex-direction: column; gap: 16px; padding: 4px 0 12px; }
.today-section { border: 1px solid var(--divider-color); border-radius: 12px; overflow: hidden; }
.today-section-header {
display: flex; align-items: center; justify-content: space-between;
padding: 10px 14px; font-weight: 600; font-size: 14px;
background: var(--secondary-background-color);
border-left: 4px solid var(--divider-color);
}
.today-section-header.overdue { border-left-color: var(--error-color, #f44336); }
.today-section-header.due_soon { border-left-color: var(--warning-color, #ff9800); }
.today-badge {
min-width: 22px; text-align: center; padding: 1px 8px; border-radius: 11px;
background: var(--primary-color); color: var(--text-primary-color, #fff); font-size: 12.5px;
}
.today-row {
display: flex; align-items: center; gap: 12px; padding: 11px 14px;
border-top: 1px solid var(--divider-color); cursor: pointer;
content-visibility: auto; contain-intrinsic-size: auto 46px;
}
.today-row:hover { background: var(--table-row-alternative-background-color, rgba(0,0,0,.04)); }
.today-dot { width: 10px; height: 10px; border-radius: 50%; flex: none; background: var(--success-color, #4caf50); }
.today-dot.overdue { background: var(--error-color, #f44336); }
.today-dot.due_soon { background: var(--warning-color, #ff9800); }
.today-dot.triggered { background: #ff5722; }
.today-main { flex: 1; min-width: 0; }
.today-task { font-weight: 600; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.today-object { color: var(--secondary-text-color); font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.today-row .btn-complete { color: var(--success-color, #4caf50); flex: none; }
.today-empty {
display: flex; flex-direction: column; align-items: center; gap: 10px;
padding: 48px 16px; color: var(--secondary-text-color); text-align: center;
}
.today-empty ha-icon { --mdc-icon-size: 56px; color: var(--success-color, #4caf50); }
/* Command palette (Ctrl/Cmd+K). */
.palette-backdrop {
position: fixed; inset: 0; z-index: 1100; background: rgba(0,0,0,.4);
display: flex; align-items: flex-start; justify-content: center; padding-top: 12vh;
animation: toast-in .15s ease;
}
.palette {
width: min(620px, 92vw); max-height: 66vh; display: flex; flex-direction: column;
background: var(--card-background-color, #fff); border-radius: 12px; overflow: hidden;
box-shadow: 0 12px 48px rgba(0,0,0,.4);
}
.palette-input {
font: inherit; font-size: 16px; padding: 16px 18px; border: none; outline: none;
background: transparent; color: var(--primary-text-color);
border-bottom: 1px solid var(--divider-color);
}
.palette-results { overflow-y: auto; }
.palette-item {
display: flex; align-items: center; gap: 10px; padding: 10px 16px; cursor: pointer;
}
.palette-item.active { background: color-mix(in srgb, var(--primary-color) 14%, transparent); }
.palette-item ha-icon { --mdc-icon-size: 20px; color: var(--secondary-text-color); flex: none; }
.palette-label { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.palette-sub { margin-left: auto; color: var(--secondary-text-color); font-size: 12.5px; flex: none; padding-left: 10px; }
.palette-empty { padding: 20px 16px; color: var(--secondary-text-color); text-align: center; }
.palette-hint { padding: 8px 16px; font-size: 12px; color: var(--secondary-text-color); border-top: 1px solid var(--divider-color); }
/* Template gallery. */
.template-gallery {
width: min(720px, 94vw); max-height: 80vh; display: flex; flex-direction: column;
background: var(--card-background-color, #fff); border-radius: 12px; overflow: hidden;
box-shadow: 0 12px 48px rgba(0,0,0,.4);
}
.template-gallery-head {
display: flex; align-items: center; justify-content: space-between;
padding: 12px 8px 12px 18px; font-weight: 600; font-size: 16px;
border-bottom: 1px solid var(--divider-color);
}
.template-gallery-body { overflow-y: auto; padding: 8px 16px 16px; }
.template-cat { margin-top: 12px; }
.template-cat-head {
display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 13px;
color: var(--secondary-text-color); margin-bottom: 8px;
}
.template-cat-head ha-icon { --mdc-icon-size: 20px; }
.template-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 10px; }
.template-card {
display: flex; flex-direction: column; gap: 4px; text-align: left; cursor: pointer;
padding: 12px 14px; border: 1px solid var(--divider-color); border-radius: 10px;
background: var(--card-background-color); font: inherit; color: var(--primary-text-color);
}
.template-card:hover { border-color: var(--primary-color); background: color-mix(in srgb, var(--primary-color) 6%, transparent); }
.template-card[disabled] { opacity: .5; pointer-events: none; }
.template-card-name { font-weight: 600; font-size: 14px; }
.template-card-count { font-size: 12px; color: var(--secondary-text-color); }
.empty-onboard-hint { color: var(--secondary-text-color); font-size: 13px; margin: 4px 0 12px; }
.empty-onboard-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.task-row:hover {
background: var(--table-row-alternative-background-color, rgba(0, 0, 0, 0.04));
}
/* Wrapper for status + optional disabled/NFC badges so they share one grid column */
.cell-badges {
display: flex;
align-items: center;
gap: 6px;
}
.cell { font-size: 14px; }
.cell.object-name { color: var(--primary-color); cursor: pointer; }
.cell.task-name { font-weight: 500; }
.cell.type { color: var(--secondary-text-color); }
/* Task subline chips (group / area / assigned user) — desktop shows inline, mobile wraps below */
.task-sub {
display: flex;
gap: 6px;
align-items: center;
font-size: 12px;
color: var(--secondary-text-color);
flex-wrap: wrap;
justify-content: flex-end;
}
/* Empty subline still occupies its grid slot so neighbouring columns line up */
.task-sub-empty { min-height: 1px; }
.sub-chip {
display: inline-flex;
align-items: center;
gap: 4px;
white-space: nowrap;
padding: 2px 8px;
border-radius: 10px;
background: var(--secondary-background-color, rgba(127, 127, 127, 0.1));
line-height: 1.4;
}
.sub-chip ha-icon {
--mdc-icon-size: 14px;
opacity: 0.75;
}
/* Row action buttons (Complete / Skip): right-aligned in their column and a
bit larger — the default mwc glyph reads small inside its padded button. */
.row-actions {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 2px;
}
.row-actions mwc-icon-button {
--mdc-icon-button-size: 44px;
--mdc-icon-size: 26px;
}
.detail-section { padding: 16px 0; }
.detail-header {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 8px;
}
.detail-header h2 { margin: 0; font-size: 22px; }
h3 { margin: 16px 0 8px; font-size: 16px; font-weight: 500; }
.meta { color: var(--secondary-text-color); margin: 4px 0; }
/* v1.4.10 (#46): per-object free-form notes block */
.object-notes {
margin: 12px 0 4px;
padding: 12px 14px;
background: var(--card-background-color, var(--ha-card-background, #1c1c1c));
border-left: 3px solid var(--primary-color, #03a9f4);
border-radius: 4px;
}
.object-notes-label {
font-size: 12px;
font-weight: 500;
color: var(--secondary-text-color);
text-transform: uppercase;
letter-spacing: 0.4px;
margin-bottom: 6px;
}
.object-notes-body {
color: var(--primary-text-color);
white-space: pre-wrap;
word-break: break-word;
line-height: 1.45;
}
.empty { color: var(--secondary-text-color); font-style: italic; }
.analysis-empty-state { text-align: center; padding: 24px 16px; }
.analysis-empty-state .empty { font-size: 15px; margin-bottom: 8px; }
.analysis-empty-state .empty-icon {
--mdc-icon-size: 48px;
color: var(--secondary-text-color);
opacity: 0.4;
display: block;
margin: 0 auto 12px;
}
.empty-hint { color: var(--secondary-text-color); font-size: 13px; margin: 4px 0; }
.analysis-progress {
width: 120px; margin: 12px auto 4px; height: 6px;
background: var(--divider-color, #e0e0e0); border-radius: 3px; overflow: hidden;
}
.analysis-progress-bar {
height: 100%; background: var(--primary-color); border-radius: 3px;
}
.info-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 8px;
}
.info-item {
display: flex;
flex-direction: column;
padding: 8px;
background: var(--card-background-color, #fff);
border-radius: 8px;
}
.info-item .label {
font-size: 12px;
color: var(--secondary-text-color);
margin-bottom: 2px;
}
/* Dashboard redesign styles */
.task-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
background: var(--card-background-color, #fff);
border-radius: 8px;
margin-bottom: 16px;
gap: 12px;
flex-wrap: wrap;
}
.task-header-title {
display: flex;
align-items: center;
gap: 8px;
flex: 1;
}
.task-name-breadcrumb,
.object-name-breadcrumb {
cursor: pointer;
color: var(--primary-text-color);
text-decoration: none;
}
.task-name-breadcrumb:hover,
.object-name-breadcrumb:hover {
text-decoration: underline;
}
.breadcrumb-separator {
color: var(--secondary-text-color);
margin: 0 4px;
}
.status-chip {
display: inline-block;
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
text-transform: uppercase;
}
.status-chip.ok {
background: #4caf50;
color: white;
}
.status-chip.warning {
background: #ff9800;
color: white;
}
.status-chip.overdue {
background: #f44336;
color: white;
}
.status-chip.done {
background: #78909c;
color: white;
}
/* (#67) Warranty status chip — object detail meta + objects table */
.warranty-chip {
display: inline-block;
padding: 2px 8px;
border-radius: 10px;
font-size: 12px;
font-weight: 500;
white-space: nowrap;
}
.warranty-valid {
background: rgba(76, 175, 80, 0.15);
color: var(--success-color, #2e7d32);
}
.warranty-expiring {
background: rgba(255, 152, 0, 0.18);
color: var(--warning-color, #e65100);
}
.warranty-expired {
background: rgba(244, 67, 54, 0.16);
color: var(--error-color, #c62828);
}
.warranty-none {
color: var(--secondary-text-color);
}
/* (#67) All-Objects view-mode toggle (cards / table) */
.view-toggle {
display: inline-flex;
border: 1px solid var(--divider-color);
border-radius: 8px;
overflow: hidden;
align-self: end;
}
.view-toggle-btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 6px 10px;
background: var(--card-background-color, #fff);
color: var(--secondary-text-color);
border: none;
cursor: pointer;
}
.view-toggle-btn + .view-toggle-btn { border-left: 1px solid var(--divider-color); }
.view-toggle-btn.active {
background: var(--primary-color);
color: var(--text-primary-color, #fff);
}
.view-toggle-btn ha-icon { --mdc-icon-size: 18px; }
/* (#67) Objects table (desktop All-Objects view) */
.objects-table-wrap {
overflow-x: auto;
border: 1px solid var(--divider-color);
border-radius: 8px;
}
.objects-table {
width: 100%;
border-collapse: collapse;
font-size: 14px;
}
.objects-table th,
.objects-table td {
text-align: left;
padding: 8px 12px;
border-bottom: 1px solid var(--divider-color);
white-space: nowrap;
}
.objects-table thead th {
font-weight: 600;
color: var(--secondary-text-color);
background: var(--secondary-background-color, rgba(0, 0, 0, 0.03));
position: sticky;
top: 0;
}
.objects-table tbody tr { cursor: pointer; }
.objects-table tbody tr:hover {
background: var(--secondary-background-color, rgba(0, 0, 0, 0.04));
}
.objects-table tbody tr:last-child td { border-bottom: none; }
.objects-table-name { font-weight: 500; color: var(--primary-text-color); }
.doc-badge {
display: inline-flex; align-items: center; gap: 2px; vertical-align: middle;
margin-left: 8px; padding: 1px 7px 1px 5px; border-radius: 10px;
font-size: 12px; font-weight: 600;
background: var(--secondary-background-color, rgba(0, 0, 0, 0.06));
color: var(--secondary-text-color, #888);
}
.doc-badge ha-icon { --mdc-icon-size: 14px; }
/* v2.20 (N3): paused marker on object cards + the detail meta line. */
.paused-badge {
display: inline-flex; align-items: center; vertical-align: middle;
margin-left: 8px; color: var(--info-color, #2196f3);
}
.paused-badge ha-icon { --mdc-icon-size: 16px; }
.paused-meta {
display: flex; align-items: center; gap: 6px;
color: var(--info-color, #2196f3); font-weight: 500;
}
.paused-meta ha-icon { --mdc-icon-size: 16px; }
.objects-table .oc-notes {
max-width: 220px;
overflow: hidden;
text-overflow: ellipsis;
}
.objects-table .oc-task_count,
.objects-table .oc-actions { text-align: center; }
.user-badge {
display: inline-flex;
align-items: center;
gap: 3px;
padding: 2px 8px;
margin-left: 8px;
background: var(--primary-color);
color: var(--text-primary-color);
border-radius: 10px;
font-size: 11px;
font-weight: 500;
line-height: 1.4;
}
.user-badge ha-icon {
--mdc-icon-size: 12px;
}
.nfc-badge {
display: inline-flex;
align-items: center;
gap: 3px;
padding: 3px 8px;
margin-left: 6px;
background: var(--secondary-background-color, #e8e8e8);
color: var(--primary-text-color);
border-radius: 12px;
font-size: 11px;
font-weight: 500;
}
.priority-badge {
display: inline-flex;
align-items: center;
margin-left: 6px;
border-radius: 12px;
padding: 2px;
}
.priority-badge ha-icon {
--mdc-icon-size: 16px;
}
.priority-high {
color: var(--error-color, #db4437);
}
.priority-low {
color: var(--secondary-text-color, #888);
}
.label-chip {
background: var(--primary-color, #03a9f4);
color: var(--text-primary-color, #fff);
opacity: 0.85;
}
.label-chip ha-icon {
--mdc-icon-size: 13px;
}
.nfc-badge ha-icon {
--mdc-icon-size: 14px;
}
.nfc-badge.unlinked {
opacity: 0.4;
cursor: pointer;
border: 1px dashed var(--divider-color);
background: transparent;
}
.nfc-badge.unlinked:hover {
opacity: 0.7;
}
.task-header-actions {
display: flex;
gap: 8px;
}
.more-menu-wrapper {
position: relative;
}
.popup-menu {
position: absolute;
top: 100%;
right: 0;
background: var(--card-background-color, #fff);
border: 1px solid var(--divider-color);
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
z-index: 100;
min-width: 180px;
overflow: hidden;
}
.popup-menu-item {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 16px;
cursor: pointer;
font-size: 14px;
color: var(--primary-text-color);
}
.popup-menu-item:hover {
background: var(--table-row-alternative-background-color, rgba(0, 0, 0, 0.04));
}
.popup-menu-item.danger {
color: var(--error-color, #f44336);
}
.popup-menu-item ha-icon {
--mdc-icon-size: 18px;
}
.popup-menu-divider {
height: 1px;
background: var(--divider-color);
margin: 4px 0;
}
.tab-bar {
display: flex;
gap: 4px;
border-bottom: 2px solid var(--divider-color);
margin-bottom: 16px;
}
.tab {
padding: 12px 24px;
cursor: pointer;
font-weight: 500;
color: var(--secondary-text-color);
border-bottom: 2px solid transparent;
margin-bottom: -2px;
transition: all 0.2s;
}
.tab:hover {
color: var(--primary-text-color);
}
.tab.active {
color: var(--primary-color);
border-bottom-color: var(--primary-color);
}
.tab-content {
padding: 16px 0;
}
.kpi-bar {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 12px;
margin-bottom: 24px;
}
.kpi-card {
background: var(--card-background-color, #fff);
border-radius: 8px;
padding: 16px 12px;
text-align: center;
border: 1px solid var(--divider-color);
}
.kpi-card.warning {
border-color: #ff9800;
background: rgba(255, 152, 0, 0.1);
}
.kpi-card.overdue {
border-color: #f44336;
background: rgba(244, 67, 54, 0.1);
}
.kpi-label {
font-size: 11px;
color: var(--secondary-text-color);
margin-bottom: 6px;
text-transform: uppercase;
font-weight: 500;
}
.kpi-value {
font-size: 16px;
font-weight: 500;
color: var(--primary-text-color);
}
.kpi-value-large {
font-size: 22px;
font-weight: 600;
color: var(--primary-text-color);
}
.kpi-subtext {
font-size: 10px;
color: var(--secondary-text-color);
margin-top: 4px;
}
.two-column-layout {
display: grid;
grid-template-columns: 40% 60%;
gap: 16px;
margin-bottom: 24px;
}
.two-column-layout.single-column {
grid-template-columns: 1fr;
}
.left-column,
.right-column {
display: flex;
flex-direction: column;
gap: 16px;
}
.recent-activities {
background: var(--card-background-color, #fff);
border-radius: 8px;
padding: 16px;
border: 1px solid var(--divider-color);
}
.recent-activities h3 {
margin: 0 0 12px 0;
}
.activity-item {
display: flex;
align-items: center;
gap: 12px;
padding: 8px 0;
border-bottom: 1px solid var(--divider-color);
}
.activity-item:last-of-type {
border-bottom: none;
}
.activity-icon {
font-size: 18px;
width: 24px;
text-align: center;
}
.activity-date {
font-size: 12px;
color: var(--secondary-text-color);
min-width: 120px;
}
.activity-note {
flex: 1;
font-size: 14px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.activity-badge {
font-size: 12px;
padding: 2px 8px;
background: var(--primary-color);
color: white;
border-radius: 12px;
}
.activity-show-all {
margin-top: 12px;
text-align: center;
}
.history-filters-new {
display: flex;
justify-content: space-between;
gap: 12px;
margin-bottom: 16px;
flex-wrap: wrap;
}
.filter-chips {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.filter-controls {
display: flex;
gap: 8px;
}
.search-input {
padding: 8px 12px;
border: 1px solid var(--divider-color);
border-radius: 4px;
background: var(--card-background-color, #fff);
color: var(--primary-text-color);
font-size: 14px;
min-width: 200px;
}
.search-input:focus {
outline: none;
border-color: var(--primary-color);
}
/* Checklist preview card (read-only display in task overview) */
.checklist-preview-card {
background: var(--card-background-color, #fff);
border-radius: 8px;
padding: 12px 16px;
border: 1px solid var(--divider-color);
margin-top: 8px;
}
.checklist-preview-header {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
font-weight: 500;
color: var(--secondary-text-color);
margin-bottom: 8px;
}
.checklist-preview-header ha-icon {
--mdc-icon-size: 18px;
}
.checklist-preview-list {
margin: 0;
padding-left: 20px;
color: var(--primary-text-color);
font-size: 14px;
line-height: 1.6;
}
.checklist-preview-list li {
padding: 1px 0;
}
/* Recommendation Card */
.recommendation-card {
background: var(--card-background-color, #fff);
border-radius: 8px;
padding: 16px;
border: 1px solid var(--divider-color);
}
.recommendation-card h4 {
margin: 0 0 12px 0;
font-size: 14px;
}
.interval-comparison {
margin-bottom: 16px;
}
.interval-bar {
margin-bottom: 12px;
}
.interval-label {
font-size: 12px;
margin-bottom: 4px;
display: flex;
align-items: center;
gap: 8px;
}
.interval-visual {
height: 24px;
border-radius: 4px;
transition: width 0.3s;
}
.interval-visual.current {
background: var(--secondary-text-color);
opacity: 0.5;
}
.interval-visual.suggested {
background: var(--primary-color);
}
.confidence-badge {
font-size: 10px;
padding: 2px 6px;
border-radius: 3px;
background: var(--divider-color);
}
.confidence-badge.high {
background: #4caf50;
color: white;
}
.confidence-badge.medium {
background: #ff9800;
color: white;
}
.confidence-badge.low {
background: var(--secondary-text-color);
color: white;
}
.recommendation-actions {
display: flex;
gap: 8px;
}
/* Seasonal Card Compact */
.seasonal-card-compact {
background: var(--card-background-color, #fff);
border-radius: 8px;
padding: 16px;
border: 1px solid var(--divider-color);
}
.seasonal-card-compact h4 {
margin: 0 0 12px 0;
font-size: 14px;
}
.seasonal-mini-chart {
display: flex;
align-items: flex-end;
gap: 4px;
height: 60px;
margin-bottom: 12px;
}
.seasonal-bar {
flex: 1;
border-radius: 2px 2px 0 0;
transition: all 0.2s;
cursor: pointer;
}
.seasonal-bar.low {
background: #2196f3;
}
.seasonal-bar.normal {
background: var(--secondary-text-color);
opacity: 0.5;
}
.seasonal-bar.high {
background: #ff9800;
}
.seasonal-bar.current {
border: 2px solid var(--primary-color);
box-sizing: border-box;
}
.seasonal-legend {
display: flex;
gap: 12px;
font-size: 11px;
}
.legend-item {
display: flex;
align-items: center;
gap: 4px;
}
.legend-item .dot {
width: 8px;
height: 8px;
border-radius: 50%;
}
.legend-item .dot.low {
background: #2196f3;
}
.legend-item .dot.normal {
background: var(--secondary-text-color);
opacity: 0.5;
}
.legend-item .dot.high {
background: #ff9800;
}
/* Task meta card (notes + documentation URL) */
.task-meta-card {
background: var(--card-background-color, #fff);
border: 1px solid var(--divider-color);
border-radius: 12px;
padding: 12px 16px;
margin-bottom: 16px;
display: flex;
flex-direction: column;
gap: 10px;
}
.task-meta-row {
display: flex;
align-items: flex-start;
gap: 8px;
font-size: 14px;
color: var(--primary-text-color);
}
.task-meta-row ha-icon {
--mdc-icon-size: 18px;
color: var(--secondary-text-color);
flex-shrink: 0;
margin-top: 2px;
}
.task-meta-notes {
white-space: pre-wrap;
word-break: break-word;
}
.task-meta-link a {
color: var(--primary-color);
text-decoration: none;
}
.task-meta-link a:hover {
text-decoration: underline;
}
/* ── Responsive: :host([narrow]) (HA sets narrow on mobile/companion) ── */
:host([narrow]) .content {
padding: 0 8px 8px;
}
:host([narrow]) .header {
padding: 8px 12px;
font-size: 14px;
}
:host([narrow]) .kpi-bar {
grid-template-columns: repeat(2, 1fr);
gap: 8px;
margin-bottom: 16px;
}
:host([narrow]) .kpi-card {
padding: 12px 8px;
}
:host([narrow]) .kpi-label {
font-size: 10px;
}
:host([narrow]) .kpi-value {
font-size: 14px;
}
:host([narrow]) .kpi-value-large {
font-size: 18px;
}
:host([narrow]) .two-column-layout {
grid-template-columns: 1fr;
}
:host([narrow]) .tab {
padding: 12px 16px;
font-size: 14px;
}
:host([narrow]) .task-header {
flex-direction: column;
align-items: flex-start;
}
:host([narrow]) .task-header-actions {
width: 100%;
justify-content: flex-start;
}
:host([narrow]) .filter-bar {
flex-wrap: wrap;
}
:host([narrow]) .filter-field {
flex: 1;
min-width: 48%;
}
:host([narrow]) .filter-bar select {
flex: 1;
min-width: 0;
width: 100%;
}
:host([narrow]) .task-table { display: block; }
:host([narrow]) .task-row {
/* Mobile: 4-column grid keeps due-cell + actions at deterministic
X-positions across rows regardless of content (sparkline, bar, %).
Earlier flex-wrap-based layouts let the row wrap unpredictably so
"X days" sometimes sat near the middle, sometimes at the right edge.
Grid template:
[badges auto | task-name 1fr | due-cell 100px | actions auto]
Task-name spans the full top row (own row above), chips span the
full bottom row. */
display: grid;
grid-column: auto;
grid-template-columns: auto minmax(0, 1fr) 100px auto;
grid-template-rows: auto auto auto;
column-gap: 8px;
row-gap: 4px;
padding: 12px;
}
:host([narrow]) .cell.type { display: none; }
:host([narrow]) .cell.task-name {
grid-column: 1 / -1;
grid-row: 1;
min-width: 0;
}
:host([narrow]) .cell-badges {
grid-column: 1;
grid-row: 2;
}
:host([narrow]) .cell.object-name {
grid-column: 2;
grid-row: 2;
min-width: 0;
/* Cap long object names at 2 lines with ellipsis instead of growing
unbounded vertically. The full name is still readable via the panel
object-detail view (one tap on the object). */
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
line-height: 1.2;
}
:host([narrow]) .due-cell {
grid-column: 3;
grid-row: 2;
align-items: flex-end;
min-width: 0;
}
:host([narrow]) .row-actions {
grid-column: 4;
grid-row: 2;
}
:host([narrow]) .task-sub {
grid-column: 1 / -1;
grid-row: 3;
font-size: 11px;
gap: 6px;
justify-content: flex-start;
flex-wrap: wrap;
}
:host([narrow]) .task-sub-empty { display: none; }
:host([narrow]) .mini-sparkline { width: 50px; }
:host([narrow]) .detail-header {
flex-direction: column;
align-items: flex-start;
}
:host([narrow]) .info-grid {
grid-template-columns: 1fr;
}
:host([narrow]) .history-filters-new {
flex-direction: column;
}
:host([narrow]) .search-input {
min-width: 0;
width: 100%;
}
:host([narrow]) .cost-duration-card {
padding: 12px;
}
:host([narrow]) .card-header {
flex-direction: column;
align-items: flex-start;
gap: 8px;
}
:host([narrow]) .toggle-buttons {
width: 100%;
}
:host([narrow]) .toggle-btn {
flex: 1;
padding: 8px;
font-size: 12px;
}
:host([narrow]) .activity-item {
flex-wrap: wrap;
}
:host([narrow]) .activity-date {
min-width: auto;
}
:host([narrow]) .activity-note {
flex-basis: 100%;
white-space: normal;
}
:host([narrow]) .popup-menu {
right: auto;
left: 0;
min-width: 160px;
}
/* Cost/Duration Card with Toggle */
.cost-duration-card {
background: var(--card-background-color, #fff);
border-radius: 8px;
padding: 16px;
border: 1px solid var(--divider-color);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.card-header h3 {
margin: 0;
font-size: 16px;
}
.toggle-buttons {
display: flex;
gap: 4px;
background: var(--divider-color);
border-radius: 4px;
padding: 2px;
}
.toggle-btn {
padding: 6px 12px;
border: none;
background: transparent;
color: var(--primary-text-color);
cursor: pointer;
border-radius: 3px;
font-size: 13px;
transition: all 0.2s;
}
.toggle-btn:hover {
background: rgba(0, 0, 0, 0.05);
}
.toggle-btn.active {
background: var(--primary-color);
color: white;
}
/* ── Responsive: @media fallback (when narrow attr not set) ── */
@media (max-width: 768px) {
.content { padding: 0 8px 8px; }
.header { padding: 8px 12px; font-size: 14px; }
.kpi-bar { grid-template-columns: repeat(2, 1fr); gap: 8px; margin-bottom: 16px; }
.kpi-card { padding: 12px 8px; }
.kpi-label { font-size: 10px; }
.kpi-value { font-size: 14px; }
.kpi-value-large { font-size: 18px; }
.two-column-layout { grid-template-columns: 1fr; }
.tab { padding: 12px 16px; font-size: 14px; }
.task-header { flex-direction: column; align-items: flex-start; }
.task-header-actions { width: 100%; justify-content: flex-start; }
.filter-bar { flex-wrap: wrap; }
.filter-bar select { flex: 1; min-width: 0; }
/* Mirror the :host([narrow]) grid layout for narrow desktop windows */
.task-row {
display: grid;
grid-template-columns: auto minmax(0, 1fr) 100px auto;
grid-template-rows: auto auto auto;
column-gap: 8px;
row-gap: 4px;
padding: 12px;
}
.cell.type { display: none; }
.cell.task-name { grid-column: 1 / -1; grid-row: 1; min-width: 0; }
.cell-badges { grid-column: 1; grid-row: 2; }
.cell.object-name { grid-column: 2; grid-row: 2; min-width: 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; line-height: 1.2; }
.due-cell { grid-column: 3; grid-row: 2; align-items: flex-end; min-width: 0; }
.row-actions { grid-column: 4; grid-row: 2; }
.task-sub { grid-column: 1 / -1; grid-row: 3; font-size: 11px; gap: 6px; justify-content: flex-start; flex-wrap: wrap; }
.task-sub-empty { display: none; }
.mini-sparkline { width: 50px; }
.detail-header { flex-direction: column; align-items: flex-start; }
.info-grid { grid-template-columns: 1fr; }
.history-filters-new { flex-direction: column; }
.search-input { min-width: 0; width: 100%; }
.cost-duration-card { padding: 12px; }
.card-header { flex-direction: column; align-items: flex-start; gap: 8px; }
.toggle-buttons { width: 100%; }
.toggle-btn { flex: 1; padding: 8px; font-size: 12px; }
.activity-item { flex-wrap: wrap; }
.activity-date { min-width: auto; }
.activity-note { flex-basis: 100%; white-space: normal; }
.popup-menu { right: auto; left: 0; min-width: 160px; }
}
/* ha-button handles variant="danger" natively */
.toast {
position: fixed;
bottom: 24px;
left: 50%;
transform: translateX(-50%);
background: var(--error-color, #f44336);
color: #fff;
padding: 12px 24px;
border-radius: 8px;
font-size: 14px;
z-index: 1000;
box-shadow: 0 2px 8px rgba(0,0,0,.3);
animation: toast-in .3s ease;
display: flex;
align-items: center;
gap: 16px;
}
.toast-undo {
font: inherit; font-weight: 600; color: #fff; cursor: pointer;
background: transparent; border: 1px solid rgba(255,255,255,.6);
border-radius: 6px; padding: 4px 12px; text-transform: uppercase; font-size: 12.5px;
}
.toast-undo:hover { background: rgba(255,255,255,.15); }
@keyframes toast-in {
from { opacity: 0; transform: translateX(-50%) translateY(16px); }
to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
`;