2026-09-12 07:35:35 +00:00
|
|
|
|
@import "tailwindcss";
|
|
|
|
|
|
|
Sites: give every site coordinates
`assets` already carried latitude/longitude, but `sites` had nowhere to put a
pin — so there was no way to locate a site. Both fields added, matching the
plant collection's shape so the same map component can plot either.
Coordinates are entered as two plain number fields with an "open in maps" link
to verify the point, rather than a drag-to-pin map: the in-app Leaflet map is
still being worked on, and a coordinate is usually copied off some other map
anyway. Clearing removes the pin rather than leaving half a coordinate, which
would plot in the Gulf of Guinea and read as "located".
Bounds are checked server-side, not just in the form: a point outside South Africa
is refused with the numbers echoed back, because a swapped pair or a dropped
digit is far likelier than a machine abroad. 0,0 is rejected by the same rule.
The sites list marks each row as pinned or "no pin", with a banner counting the
gaps, so an unlocated site is visible without opening it.
While checking this, found that all 44 assets carry the SAME coordinate
(-26.1016, 28.3487) — the Plant Map currently stacks every marker on one pin
while reporting "44 located on the map". Left alone, but worth knowing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-02 14:33:43 +00:00
|
|
|
|
/* Leaflet + marker-cluster must be global stylesheets. Importing them inside
|
|
|
|
|
|
components/PlantMap.tsx works for leaflet.css but the cluster stylesheet gets
|
|
|
|
|
|
dropped, because that component is behind a `next/dynamic` ssr:false boundary
|
|
|
|
|
|
whose CSS is not linked in the initial HTML. Without these, cluster bubbles
|
|
|
|
|
|
land unpositioned and unstyled. */
|
|
|
|
|
|
@import "leaflet/dist/leaflet.css";
|
|
|
|
|
|
@import "leaflet.markercluster/dist/MarkerCluster.css";
|
|
|
|
|
|
|
2026-09-12 07:35:35 +00:00
|
|
|
|
/* Enable dark mode via .dark class on html */
|
|
|
|
|
|
@custom-variant dark (&:where(.dark, .dark *));
|
|
|
|
|
|
|
|
|
|
|
|
/* Coolors palette — stays the same in both modes */
|
|
|
|
|
|
@theme {
|
|
|
|
|
|
--color-sunny: #EDAE49;
|
|
|
|
|
|
--color-brick: #D1495B;
|
|
|
|
|
|
--color-seaweed: #00798C;
|
|
|
|
|
|
--color-casual: #30638E;
|
|
|
|
|
|
--color-indigo: #003D5B;
|
|
|
|
|
|
|
Round 3 (Parts A-B): charts fixes + expenses/overheads cleanup
- A.1: fixed_expenses per month now threaded through to chart bucket
- A.2: null = no data (forecast), 0 = real plotted zero — distinguishable
- A.3: x-axis clipped to last actual month (IncomeAreaChart + IncomeBarChart + MachineLineChart)
- A.4: chart hues as CSS vars (--color-chart-income/fixed/running) — deeper steps of same hues, validated for CVD
- A.5: chart-type toggle (Lines / Cost stack / Profit) + localStorage persistence + dynamic legend
- A.6: profit on charts page comes from computeProfit()
- B.1: deleted /expenses/plant-overheads, /expenses/insurance, /expenses/tracking (all empty); added /expenses/vehicles; ExpenseSectionPage now has an empty state
- B.2: captured R 157,200 Personnel block, R 100,000 Maintenance, R 10,000 Petty Cash; roll-up reconciles to R 675,162.93 (= sum of non-Plant non-Santam rows; workbook grand total R 1,110,486.87 is internally off by R 14,477.56 vs its own rows)
- B.3: seed flags incl<excl, VAT>20%, broken VAT math — does NOT silently correct; 4 anomalies reported on Charl-CCS + Buildsmart
- B.4: noted that workbook Vehicle Costs subtotal skips Santam (app R 9,673.87 is correct; workbook is wrong)
- B.2 reconciliation assertion added to verify-cost-reconciliation.mjs
- Sidebar updated: Vehicles added, Insurance/Tracking/Plant-Overheads removed
2026-09-12 09:24:18 +00:00
|
|
|
|
/* Part A.4: chart hues — deeper steps of the same brand hues, validated for CVD/contrast.
|
|
|
|
|
|
Brand palette (#EDAE49/#00798C/#D1495B) does NOT change; these are read only by chart marks. */
|
|
|
|
|
|
--color-chart-income: #0090A6;
|
|
|
|
|
|
--color-chart-fixed: #BE851F;
|
Charts: a profit line that changes colour, and a Series toggle
Profit was a single always-teal line, so a month that lost money looked
like a month that made a little. It is now drawn per sign: one <Line> per
same-sign run, plus a gradient <Line> across each crossing. Recharts draws
a Line as one <Curve> path, so <Cell> cannot recolour a segment — separate
series are the only way. Every variant is a key on the ONE shared dataset
rather than a sliced `data` prop, because Recharts builds a categorical axis
by concatenating every series' data and a short slice re-adds the month
labels ("Jan … Aug, Jan … Aug"). The tooltip needs a custom `content`
component to fold those per-run keys back into a single profit row.
Two honesty rules: profit stays null in a month with no income figure
(treating it as 0 drew a green dot for a month that was never billed), and
a month with no running-cost row gets a hollow dot, because its profit is
optimistic.
The toolbar's Series button toggles which lines a card draws, remembered in
localStorage. A hidden series takes its legend entry and its Y axis with it,
so there is never an axis for a line that is not drawn, and the last visible
series cannot be switched off.
Palette: Running moves off red to the project's existing brand purple,
because red is now reserved for a loss and a red Running line next to a red
loss segment was unreadable. `--color-chart-loss` and `--color-chart-profit`
are separate tokens on purpose — loss used to read the Running token, so
recolouring Running silently dragged the red with it.
/charts alone now reads profit including running cost, so the card badge,
the profit line and the Profit bars view cannot disagree. Scoped to the
page: lib/profit.ts keeps its workbook default for every other surface.
2026-10-03 07:20:16 +00:00
|
|
|
|
--color-chart-running: #8B5CF6;
|
|
|
|
|
|
/* A month that did not make profit. Its own token so moving the Running line
|
|
|
|
|
|
cannot drag the profit-loss red along with it. */
|
|
|
|
|
|
--color-chart-loss: #C13B4D;
|
|
|
|
|
|
/* Profit-positive. The client's chosen bright green, 2026-10-02 — deliberately
|
|
|
|
|
|
outside the Coolors brand set so the profit line reads as its own series and
|
|
|
|
|
|
not as another teal. */
|
|
|
|
|
|
--color-chart-profit: #7A9E06;
|
Round 3 (Parts A-B): charts fixes + expenses/overheads cleanup
- A.1: fixed_expenses per month now threaded through to chart bucket
- A.2: null = no data (forecast), 0 = real plotted zero — distinguishable
- A.3: x-axis clipped to last actual month (IncomeAreaChart + IncomeBarChart + MachineLineChart)
- A.4: chart hues as CSS vars (--color-chart-income/fixed/running) — deeper steps of same hues, validated for CVD
- A.5: chart-type toggle (Lines / Cost stack / Profit) + localStorage persistence + dynamic legend
- A.6: profit on charts page comes from computeProfit()
- B.1: deleted /expenses/plant-overheads, /expenses/insurance, /expenses/tracking (all empty); added /expenses/vehicles; ExpenseSectionPage now has an empty state
- B.2: captured R 157,200 Personnel block, R 100,000 Maintenance, R 10,000 Petty Cash; roll-up reconciles to R 675,162.93 (= sum of non-Plant non-Santam rows; workbook grand total R 1,110,486.87 is internally off by R 14,477.56 vs its own rows)
- B.3: seed flags incl<excl, VAT>20%, broken VAT math — does NOT silently correct; 4 anomalies reported on Charl-CCS + Buildsmart
- B.4: noted that workbook Vehicle Costs subtotal skips Santam (app R 9,673.87 is correct; workbook is wrong)
- B.2 reconciliation assertion added to verify-cost-reconciliation.mjs
- Sidebar updated: Vehicles added, Insurance/Tracking/Plant-Overheads removed
2026-09-12 09:24:18 +00:00
|
|
|
|
|
2026-09-12 07:35:35 +00:00
|
|
|
|
--color-brand-blue: #30638E;
|
|
|
|
|
|
--color-brand-orange: #EDAE49;
|
|
|
|
|
|
--color-brand-red: #D1495B;
|
|
|
|
|
|
--color-brand-green: #00798C;
|
|
|
|
|
|
--color-brand-purple: #8B5CF6;
|
|
|
|
|
|
--color-brand-cyan: #00798C;
|
|
|
|
|
|
--color-brand-pink: #D1495B;
|
|
|
|
|
|
--color-brand-yellow: #EDAE49;
|
|
|
|
|
|
|
|
|
|
|
|
/* Light theme (default) */
|
|
|
|
|
|
--color-bg: #f5f7fb;
|
|
|
|
|
|
--color-surface: #ffffff;
|
|
|
|
|
|
--color-surface-muted: #f9fafb;
|
|
|
|
|
|
--color-border: #e5e7eb;
|
|
|
|
|
|
--color-border-soft: #f3f4f6;
|
|
|
|
|
|
--color-text: #003D5B;
|
|
|
|
|
|
--color-text-muted: #6b7280;
|
|
|
|
|
|
--color-text-soft: #9ca3af;
|
|
|
|
|
|
--color-row-hover: rgba(0, 0, 0, 0.02);
|
2026-10-02 13:34:19 +00:00
|
|
|
|
|
|
|
|
|
|
/* "Ink" steps — the light-mode colour for text that borrows a brand hue.
|
|
|
|
|
|
The base brand palette above is never used as text on a light surface unless
|
|
|
|
|
|
it clears 4.5:1; these names exist so `text-accent-ink` works in BOTH modes
|
|
|
|
|
|
and only its value changes. See the .dark block for the dark counterparts. */
|
|
|
|
|
|
--color-accent-ink: #30638E;
|
|
|
|
|
|
--color-brick-ink: #D1495B;
|
|
|
|
|
|
--color-indigo-ink: #003D5B;
|
2026-09-12 07:35:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Dark theme overrides */
|
|
|
|
|
|
.dark {
|
2026-10-02 13:34:19 +00:00
|
|
|
|
--color-bg: #0f151b;
|
|
|
|
|
|
--color-surface: #1e2732;
|
|
|
|
|
|
--color-surface-muted: #182029;
|
|
|
|
|
|
--color-border: #303c48;
|
|
|
|
|
|
--color-border-soft: #26313c;
|
|
|
|
|
|
--color-text: #e8eef4;
|
|
|
|
|
|
--color-text-muted: #adb8c2;
|
|
|
|
|
|
--color-text-soft: #87919a;
|
|
|
|
|
|
--color-row-hover: rgba(255, 255, 255, 0.04);
|
|
|
|
|
|
|
|
|
|
|
|
/* Dark "ink" steps. The base brand hues are correct as *fills* but fail WCAG AA
|
|
|
|
|
|
as text on a dark surface (seaweed 3.6:1, casual 2.9:1, brick 3.7:1, indigo 1.6:1).
|
|
|
|
|
|
These are lighter steps of the same hues, reaching 4.8–7.3:1. Text-only —
|
|
|
|
|
|
never a fill — so the @theme brand palette stays untouched. */
|
|
|
|
|
|
--color-accent-ink: #2BB0C4;
|
|
|
|
|
|
--color-brick-ink: #E86E7E;
|
|
|
|
|
|
--color-indigo-ink: #7FA8C9;
|
Round 3 (Parts A-B): charts fixes + expenses/overheads cleanup
- A.1: fixed_expenses per month now threaded through to chart bucket
- A.2: null = no data (forecast), 0 = real plotted zero — distinguishable
- A.3: x-axis clipped to last actual month (IncomeAreaChart + IncomeBarChart + MachineLineChart)
- A.4: chart hues as CSS vars (--color-chart-income/fixed/running) — deeper steps of same hues, validated for CVD
- A.5: chart-type toggle (Lines / Cost stack / Profit) + localStorage persistence + dynamic legend
- A.6: profit on charts page comes from computeProfit()
- B.1: deleted /expenses/plant-overheads, /expenses/insurance, /expenses/tracking (all empty); added /expenses/vehicles; ExpenseSectionPage now has an empty state
- B.2: captured R 157,200 Personnel block, R 100,000 Maintenance, R 10,000 Petty Cash; roll-up reconciles to R 675,162.93 (= sum of non-Plant non-Santam rows; workbook grand total R 1,110,486.87 is internally off by R 14,477.56 vs its own rows)
- B.3: seed flags incl<excl, VAT>20%, broken VAT math — does NOT silently correct; 4 anomalies reported on Charl-CCS + Buildsmart
- B.4: noted that workbook Vehicle Costs subtotal skips Santam (app R 9,673.87 is correct; workbook is wrong)
- B.2 reconciliation assertion added to verify-cost-reconciliation.mjs
- Sidebar updated: Vehicles added, Insurance/Tracking/Plant-Overheads removed
2026-09-12 09:24:18 +00:00
|
|
|
|
|
|
|
|
|
|
/* Part A.4: dark-mode chart hues */
|
|
|
|
|
|
--color-chart-income: #00A6BE;
|
|
|
|
|
|
--color-chart-fixed: #BE851F;
|
Charts: a profit line that changes colour, and a Series toggle
Profit was a single always-teal line, so a month that lost money looked
like a month that made a little. It is now drawn per sign: one <Line> per
same-sign run, plus a gradient <Line> across each crossing. Recharts draws
a Line as one <Curve> path, so <Cell> cannot recolour a segment — separate
series are the only way. Every variant is a key on the ONE shared dataset
rather than a sliced `data` prop, because Recharts builds a categorical axis
by concatenating every series' data and a short slice re-adds the month
labels ("Jan … Aug, Jan … Aug"). The tooltip needs a custom `content`
component to fold those per-run keys back into a single profit row.
Two honesty rules: profit stays null in a month with no income figure
(treating it as 0 drew a green dot for a month that was never billed), and
a month with no running-cost row gets a hollow dot, because its profit is
optimistic.
The toolbar's Series button toggles which lines a card draws, remembered in
localStorage. A hidden series takes its legend entry and its Y axis with it,
so there is never an axis for a line that is not drawn, and the last visible
series cannot be switched off.
Palette: Running moves off red to the project's existing brand purple,
because red is now reserved for a loss and a red Running line next to a red
loss segment was unreadable. `--color-chart-loss` and `--color-chart-profit`
are separate tokens on purpose — loss used to read the Running token, so
recolouring Running silently dragged the red with it.
/charts alone now reads profit including running cost, so the card badge,
the profit line and the Profit bars view cannot disagree. Scoped to the
page: lib/profit.ts keeps its workbook default for every other surface.
2026-10-03 07:20:16 +00:00
|
|
|
|
--color-chart-running: #8B5CF6;
|
|
|
|
|
|
--color-chart-loss: #D94F60;
|
|
|
|
|
|
--color-chart-profit: #7A9E06;
|
2026-09-12 07:35:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
html, body {
|
|
|
|
|
|
background: var(--color-bg);
|
|
|
|
|
|
color: var(--color-text);
|
|
|
|
|
|
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
* { -webkit-font-smoothing: antialiased; }
|
|
|
|
|
|
|
|
|
|
|
|
/* Smooth color transition when toggling themes */
|
|
|
|
|
|
body, .dark body { transition: background-color 0.2s ease, color 0.2s ease; }
|
|
|
|
|
|
|
|
|
|
|
|
.recharts-cartesian-axis-tick text { fill: var(--color-text-soft); font-size: 11px; }
|
Charts: a profit line that changes colour, and a Series toggle
Profit was a single always-teal line, so a month that lost money looked
like a month that made a little. It is now drawn per sign: one <Line> per
same-sign run, plus a gradient <Line> across each crossing. Recharts draws
a Line as one <Curve> path, so <Cell> cannot recolour a segment — separate
series are the only way. Every variant is a key on the ONE shared dataset
rather than a sliced `data` prop, because Recharts builds a categorical axis
by concatenating every series' data and a short slice re-adds the month
labels ("Jan … Aug, Jan … Aug"). The tooltip needs a custom `content`
component to fold those per-run keys back into a single profit row.
Two honesty rules: profit stays null in a month with no income figure
(treating it as 0 drew a green dot for a month that was never billed), and
a month with no running-cost row gets a hollow dot, because its profit is
optimistic.
The toolbar's Series button toggles which lines a card draws, remembered in
localStorage. A hidden series takes its legend entry and its Y axis with it,
so there is never an axis for a line that is not drawn, and the last visible
series cannot be switched off.
Palette: Running moves off red to the project's existing brand purple,
because red is now reserved for a loss and a red Running line next to a red
loss segment was unreadable. `--color-chart-loss` and `--color-chart-profit`
are separate tokens on purpose — loss used to read the Running token, so
recolouring Running silently dragged the red with it.
/charts alone now reads profit including running cost, so the card badge,
the profit line and the Profit bars view cannot disagree. Scoped to the
page: lib/profit.ts keeps its workbook default for every other surface.
2026-10-03 07:20:16 +00:00
|
|
|
|
/* Round 4: no text under 12px on mobile. This CSS rule beats Recharts' tick
|
|
|
|
|
|
fontSize prop, so the bump has to happen here or nowhere. */
|
2026-10-06 02:02:08 +00:00
|
|
|
|
@media (max-width: 1023px) {
|
Charts: a profit line that changes colour, and a Series toggle
Profit was a single always-teal line, so a month that lost money looked
like a month that made a little. It is now drawn per sign: one <Line> per
same-sign run, plus a gradient <Line> across each crossing. Recharts draws
a Line as one <Curve> path, so <Cell> cannot recolour a segment — separate
series are the only way. Every variant is a key on the ONE shared dataset
rather than a sliced `data` prop, because Recharts builds a categorical axis
by concatenating every series' data and a short slice re-adds the month
labels ("Jan … Aug, Jan … Aug"). The tooltip needs a custom `content`
component to fold those per-run keys back into a single profit row.
Two honesty rules: profit stays null in a month with no income figure
(treating it as 0 drew a green dot for a month that was never billed), and
a month with no running-cost row gets a hollow dot, because its profit is
optimistic.
The toolbar's Series button toggles which lines a card draws, remembered in
localStorage. A hidden series takes its legend entry and its Y axis with it,
so there is never an axis for a line that is not drawn, and the last visible
series cannot be switched off.
Palette: Running moves off red to the project's existing brand purple,
because red is now reserved for a loss and a red Running line next to a red
loss segment was unreadable. `--color-chart-loss` and `--color-chart-profit`
are separate tokens on purpose — loss used to read the Running token, so
recolouring Running silently dragged the red with it.
/charts alone now reads profit including running cost, so the card badge,
the profit line and the Profit bars view cannot disagree. Scoped to the
page: lib/profit.ts keeps its workbook default for every other surface.
2026-10-03 07:20:16 +00:00
|
|
|
|
.recharts-cartesian-axis-tick text { font-size: 12px; }
|
2026-10-06 02:02:08 +00:00
|
|
|
|
.text-\[10px\], .text-\[11px\] { font-size: 12px; }
|
|
|
|
|
|
.leaflet-control-zoom a { width: 44px !important; height: 44px !important; line-height: 44px !important; }
|
|
|
|
|
|
.leaflet-control-attribution { font-size: 12px !important; }
|
|
|
|
|
|
.leaflet-control-attribution a, .leaflet-popup-content a {
|
|
|
|
|
|
display: inline-flex; align-items: center; min-width: 44px; min-height: 44px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.leaflet-popup-close-button { width: 44px !important; height: 44px !important; }
|
Charts: a profit line that changes colour, and a Series toggle
Profit was a single always-teal line, so a month that lost money looked
like a month that made a little. It is now drawn per sign: one <Line> per
same-sign run, plus a gradient <Line> across each crossing. Recharts draws
a Line as one <Curve> path, so <Cell> cannot recolour a segment — separate
series are the only way. Every variant is a key on the ONE shared dataset
rather than a sliced `data` prop, because Recharts builds a categorical axis
by concatenating every series' data and a short slice re-adds the month
labels ("Jan … Aug, Jan … Aug"). The tooltip needs a custom `content`
component to fold those per-run keys back into a single profit row.
Two honesty rules: profit stays null in a month with no income figure
(treating it as 0 drew a green dot for a month that was never billed), and
a month with no running-cost row gets a hollow dot, because its profit is
optimistic.
The toolbar's Series button toggles which lines a card draws, remembered in
localStorage. A hidden series takes its legend entry and its Y axis with it,
so there is never an axis for a line that is not drawn, and the last visible
series cannot be switched off.
Palette: Running moves off red to the project's existing brand purple,
because red is now reserved for a loss and a red Running line next to a red
loss segment was unreadable. `--color-chart-loss` and `--color-chart-profit`
are separate tokens on purpose — loss used to read the Running token, so
recolouring Running silently dragged the red with it.
/charts alone now reads profit including running cost, so the card badge,
the profit line and the Profit bars view cannot disagree. Scoped to the
page: lib/profit.ts keeps its workbook default for every other surface.
2026-10-03 07:20:16 +00:00
|
|
|
|
}
|
2026-09-12 07:35:35 +00:00
|
|
|
|
.recharts-cartesian-grid line { stroke: var(--color-border-soft); }
|
|
|
|
|
|
.recharts-default-tooltip {
|
|
|
|
|
|
background: rgba(255,255,255,0.98) !important;
|
|
|
|
|
|
border: 1px solid #e5e7eb !important;
|
|
|
|
|
|
border-radius: 12px !important;
|
|
|
|
|
|
box-shadow: 0 4px 20px rgba(0,0,0,0.08) !important;
|
|
|
|
|
|
font-size: 12px !important;
|
|
|
|
|
|
padding: 8px 12px !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
.recharts-tooltip-label { color: #003D5B !important; font-weight: 600 !important; margin-bottom: 4px !important; }
|
|
|
|
|
|
.recharts-legend-item-text { color: #6b7280 !important; font-size: 12px !important; }
|
|
|
|
|
|
|
|
|
|
|
|
.dark .recharts-default-tooltip {
|
2026-10-02 13:34:19 +00:00
|
|
|
|
background: rgba(30, 39, 50, 0.98) !important;
|
|
|
|
|
|
border: 1px solid #303c48 !important;
|
|
|
|
|
|
color: #e8eef4 !important;
|
2026-09-12 07:35:35 +00:00
|
|
|
|
}
|
2026-10-02 13:34:19 +00:00
|
|
|
|
.dark .recharts-tooltip-label { color: #e8eef4 !important; }
|
|
|
|
|
|
.dark .recharts-legend-item-text { color: #adb8c2 !important; }
|
2026-10-21 04:39:15 +00:00
|
|
|
|
|
|
|
|
|
|
/* Employee clock: generous touch targets, existing Plant palette. */
|
|
|
|
|
|
.plant-clock-page { color: var(--color-text); font-size: 14px; }
|
|
|
|
|
|
.plant-clock-panel { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 16px; }
|
|
|
|
|
|
.plant-clock-eyebrow { font-size: 12px; letter-spacing: .12em; font-weight: 600; color: var(--color-text-muted); }
|
|
|
|
|
|
.plant-clock-button { display: inline-flex; justify-content: center; align-items: center; gap: 8px; min-height: 44px; min-width: 44px; padding: 10px 16px; border-radius: 10px; font-size: 14px; font-weight: 600; cursor: pointer; text-align: center; }
|
|
|
|
|
|
.plant-clock-button:disabled { opacity: .5; cursor: not-allowed; }
|
|
|
|
|
|
.plant-clock-button:focus-visible, .plant-clock-input:focus-visible { outline: 2px solid var(--color-accent-ink); outline-offset: 3px; }
|
|
|
|
|
|
.plant-clock-primary { background: #30638E; color: white; }
|
|
|
|
|
|
.plant-clock-primary:hover:not(:disabled) { background: #003D5B; }
|
|
|
|
|
|
.plant-clock-secondary { border: 1px solid var(--color-border); background: var(--color-surface); color: var(--color-text); }
|
|
|
|
|
|
.plant-clock-secondary:hover:not(:disabled) { background: var(--color-bg); }
|
|
|
|
|
|
.plant-clock-input { display: block; width: 100%; min-width: 0; min-height: 48px; border: 1px solid var(--color-border); border-radius: 10px; padding: 10px 12px; font-size: 16px; background: var(--color-surface); color: var(--color-text); }
|
|
|
|
|
|
.plant-clock-warning { padding: 12px 14px; border-radius: 10px; border: 1px solid #EDAE4980; background: #EDAE4915; font-size: 14px; line-height: 1.6; overflow-wrap: anywhere; }
|
2026-10-22 09:39:18 +00:00
|
|
|
|
.plant-camera { position: relative; overflow: hidden; display: grid; place-items: center; border-radius: 12px; min-height: min(62svh, 520px); background: #003D5B; color: white; }
|
|
|
|
|
|
.plant-clock-banner { display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: 12px; box-shadow: 0 8px 24px rgb(0 0 0 / .25); }
|
2026-10-22 11:55:13 +00:00
|
|
|
|
.plant-camera-compact { min-height: min(34svh, 300px); }
|
2026-10-21 04:39:15 +00:00
|
|
|
|
.plant-scan-frame { display: grid; place-items: center; width: 154px; height: 140px; border: 2px solid #EDAE49; border-radius: 16px; color: #EDAE49; }
|
|
|
|
|
|
.plant-clock-status { display: inline-flex; align-items: center; border-radius: 7px; background: var(--color-bg); color: var(--color-text-muted); padding: 5px 9px; font-size: 12px; font-weight: 600; white-space: nowrap; }
|
|
|
|
|
|
.plant-clock-status-in { background: #00798C15; color: var(--color-accent-ink); }
|