:root {
    --leaf-green: #6aa84f;
    --sky-blue: #d4e8f5;
    --sun-yellow: #fff9db;
    --dark-green: #355e3b;
    --soft-white: #ffffff;
    --soft-gray: #f5f5f5;
    --text-dark: #333333;
    --text-light: #ffffff;
}

html, body {
    height: 100%;
    margin: 0;
    padding: 0;
    overflow: hidden;
}

/* Scrollbars, dashboard-wide (2026-09-12, Martin's ask: "something like
   a leaf on a vine" instead of the chunky default OS scrollbar) --
   applied once to every element rather than per scrollable container,
   so the mood-breakdown list, the Know Your Plant panel, and anything
   scrollable added later all pick it up automatically. Thin vine-green
   track with a leaf-green thumb; an actual leaf silhouette doesn't hold
   up at an 8px scrollbar width, so this leans on color instead of a
   literal icon to read as "vine," and darkens toward --dark-green on
   hover so it stays out of the way until you're actually using it. */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--leaf-green) rgba(53, 94, 59, 0.2);
}

*::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

*::-webkit-scrollbar-track {
    background: rgba(53, 94, 59, 0.15);
}

*::-webkit-scrollbar-thumb {
    background-color: var(--leaf-green);
    border-radius: 6px;
}

*::-webkit-scrollbar-thumb:hover {
    background-color: var(--dark-green);
}

body {
    font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
    background: none;
    opacity: 0.9;
    color: var(--text-dark);
    padding: 0 1.25rem 1.25rem;
    line-height: 1.6;
    box-sizing: border-box;
    position: relative;
    height: 100vh;
    display: flex;
    flex-direction: column;
}

/* Earth-tone backdrop (2026-09-10) -- replaces the grape-field photo
   with a plain top-to-bottom gradient: sky blue into leaf green into
   topsoil brown into deep earth brown. */
body::before {
    content: "";
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(to bottom, #a8d8e8, #7fa870, #b89968, #4a3728);
    transform-origin: center center;
    z-index: -1;
}

/* Header Styles  Something something*/
header {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 1rem 2rem;
    background: rgba(53, 94, 59, 0.8);
    border-radius: 8px;
    margin-bottom: 2rem;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}

header h1 {
    margin: 0;
    text-align: center;
    color: #fff;
    font-size: 2.5rem;
    text-shadow: 1px 1px 2px rgba(0,0,0,0.3);
}

/* Dashboard Toolbar -- title, active-meter status, time range, meter
   toggles and the Multi Meter View link all live in one compact row
   instead of three stacked full-width sections, so the chart below
   isn't pushed off-screen. Only used on the main dashboard; the shared
   header/.controls/.control-group rules above are untouched and still
   used by multi_meter_view.html. */
.dashboard-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 1.5rem;
    padding: 0.5rem 1.25rem;
    background: rgba(53, 94, 59, 0.85);
    border-radius: 0 0 12px 12px;
    /* 2026-09-10: trimmed from 1rem -- Martin flagged the space above
       the cards as the reason 1-2 devices still need to scroll inside
       .app-scroll-area even with the header/footer locked. */
    margin-bottom: 0.5rem;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
    flex: 0 0 auto;
}

.toolbar-brand h1 {
    margin: 0;
    color: #fff;
    font-size: 1.5rem;
    white-space: nowrap;
    text-shadow: 1px 1px 2px rgba(0,0,0,0.3);
}

.toolbar-status {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    color: var(--text-light);
    white-space: nowrap;
}

.toolbar-status .status-label {
    font-size: 0.85rem;
    opacity: 0.85;
}

.toolbar-field {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--text-light);
    white-space: nowrap;
}

.toolbar-field select {
    margin-top: 0;
    width: auto;
    padding: 0.35rem 0.6rem;
}

/* Segmented Celsius/Fahrenheit toggle in the toolbar */
.unit-toggle {
    display: flex;
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid rgba(255, 255, 255, 0.3);
}

.unit-toggle button {
    padding: 0.35rem 0.7rem;
    border: none;
    border-radius: 0;
    background-color: transparent;
    color: var(--text-light);
    font-weight: 600;
    font-size: 0.85rem;
    cursor: pointer;
    transition: background-color 0.2s ease;
}

.unit-toggle button.active {
    background-color: var(--leaf-green);
}

.unit-toggle button:not(.active):hover {
    background-color: rgba(255, 255, 255, 0.15);
}

/* App-shell region, between the fixed header and fixed footer (2026-09-10
   originally, 2026-09-12 update: Martin's ask -- this used to be its own
   scroll area so header/footer stayed pinned while it scrolled on its
   own. He'd rather nothing on the dashboard scroll at all, since a
   stray wheel/trackpad nudge could quietly move pinned info out of
   view -- "look tackier" and feel accidental. So this no longer
   scrolls; if a screen ever has more meter cards/charts than fit
   vertically, the extra content is clipped rather than reachable by
   scrolling. That's an intentional trade-off, not an oversight. */
.app-scroll-area {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
}

/* "At a Glance" stat cards -- one per active meter, sits between the
   toolbar and the chart grid. */
.glance-section {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    width: 100%;
    padding: 0.5rem 1rem 0;
    box-sizing: border-box;
    /* 2026-09-10: trimmed from 1rem, same space-above-the-cards pass
       as .dashboard-toolbar above. */
    margin-bottom: 0.5rem;
}

.glance-card {
    position: relative;
    background: linear-gradient(145deg, var(--dark-green), #2e4b33);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 14px;
    padding: 0.5rem 1rem;
    min-width: 150px;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}

/* Quick Glance tiles (2026-09-10) are individually pinned/removable, so
   each one gets its own small close button -- unlike the old hardcoded
   temp-per-meter cards, which had nothing to remove. */
.glance-card-remove {
    position: absolute;
    top: 0.15rem;
    right: 0.3rem;
    border: none;
    background: transparent;
    color: var(--text-light);
    opacity: 0.4;
    font-size: 0.9rem;
    line-height: 1;
    cursor: pointer;
    padding: 0.1rem 0.2rem;
    transition: opacity 0.15s ease;
}

.glance-card-remove:hover {
    opacity: 1;
}

.glance-card .glance-meter-name {
    font-size: 0.8rem;
    color: var(--leaf-green);
    font-weight: bold;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.glance-card .glance-metric-row {
    display: flex;
    align-items: baseline;
    gap: 0.3rem;
    margin-top: 0.25rem;
}

.glance-card .glance-value {
    font-size: 2rem;
    font-weight: bold;
    color: var(--text-light);
    line-height: 1;
}

.glance-card .glance-unit {
    font-size: 1.1rem;
    color: var(--text-light);
    opacity: 0.8;
}

.glance-card .glance-metric-label {
    font-size: 0.75rem;
    color: var(--text-light);
    opacity: 0.7;
    margin-top: 0.15rem;
}

nav {
    display: flex;
}

.meter-toggles-nav {
    align-items: center;
    margin-left: auto;
}

.nav-button {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 1.2rem;
    border: none;
    border-radius: 8px;
    background-color: var(--leaf-green);
    color: white;
    font-weight: bold;
    font-size: 1rem;
    cursor: pointer;
    transition: background-color 0.2s ease, transform 0.1s ease;
    text-decoration: none;
}

.nav-button:hover {
    background-color: var(--dark-green);
    transform: scale(1.05);
}

.nav-button:active {
    transform: scale(0.95);
}

.nav-button span {
    display: inline-block;
}

.nav-button.compare::before {
    content: "📊";
    font-size: 1.2rem;
}

.nav-button.back::before {
    content: "⬅";
    font-size: 1.2rem;
}

.nav-button.claim {
    background-color: #d98c1f;
}

.nav-button.claim:hover {
    background-color: #b9750f;
}

.nav-button.claim::before {
    content: "🔑";
    font-size: 1.2rem;
}

.toolbar-account {
    position: relative;
    margin-left: 0.75rem;
    padding-left: 0.75rem;
    border-left: 1px solid rgba(255, 255, 255, 0.2);
    color: var(--text-light);
}

.toolbar-account-toggle {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    border: none;
    background: transparent;
    color: var(--text-light);
    cursor: pointer;
    padding: 0.2rem 0.3rem;
    border-radius: 8px;
    transition: background-color 0.15s ease;
}

.toolbar-account-toggle:hover,
.toolbar-account-toggle[aria-expanded="true"] {
    background: rgba(255, 255, 255, 0.08);
}

.toolbar-account-caret {
    font-size: 0.7rem;
    opacity: 0.7;
}

.toolbar-avatar {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    object-fit: cover;
}

.toolbar-username {
    font-weight: 600;
    font-size: 0.9rem;
}

.toolbar-role-badge {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding: 0.15rem 0.5rem;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.15);
}

.toolbar-role-badge.toolbar-role-admin {
    background: #ff8c42;
    color: #2e1a00;
}

.toolbar-account-menu {
    position: absolute;
    top: calc(100% + 0.4rem);
    right: 0;
    min-width: 140px;
    background: var(--dark-green);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 8px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
    padding: 0.35rem;
    z-index: 20;
}

.toolbar-account-menu-item {
    display: block;
    padding: 0.5rem 0.7rem;
    border-radius: 6px;
    color: var(--text-light);
    text-decoration: none;
    font-size: 0.9rem;
}

.toolbar-account-menu-item:hover {
    background: rgba(255, 255, 255, 0.1);
}

.nav-button.toolbar-logout,
.nav-button.toolbar-login {
    padding: 0.4rem 0.9rem;
    font-size: 0.85rem;
}

.controls {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 1rem;
    padding: 1.5rem;
    background: var(--dark-green);
    border-radius: 16px;
    box-shadow: 0 4px 10px rgba(0,0,0,0.05);
    margin-bottom: 2rem;
    color: var(--text-light);
}

.control-group {
    background-color: var(--dark-green);
    border: 1px solid #e0e0e0;
    border-radius: 12px;
    padding: 1rem;
}

.control-group legend {
    font-weight: bold;
    margin-bottom: 0.5rem;
    color: var(--leaf-green);
    font-size: 1.1rem;
}

.control-group label {
    margin: 0.5rem 0;
    font-size: 0.95rem;
    color: var(--text-light);
}

/* Context Menu and Submenu Styles */
.context-menu {
    position: absolute;
    background: var(--dark-green);
    border: none;
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
    z-index: 1000;
    padding: 0.5rem 0;
    min-width: 200px;
}

.context-menu-item {
    padding: 0.5rem 1.2rem;
    cursor: pointer;
    color: var(--text-light);
    font-weight: 500;
    transition: background-color 0.2s ease;
}

.context-menu-item:hover {
    background-color: var(--leaf-green);
}

.has-submenu {
    position: relative;
}

.context-submenu {
    display: none;
    position: absolute;
    left: 100%;
    top: 0;
    background: var(--dark-green);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
    padding: 0.5rem 0;
    z-index: 1001;
    min-width: 150px;
}

.has-submenu:hover .context-submenu {
    display: block;
}

.context-submenu-item {
    padding: 0.5rem 1.2rem;
    cursor: pointer;
    color: var(--text-light);
    font-weight: 500;
    transition: background-color 0.2s ease;
}

.context-submenu-item:hover {
    background-color: var(--leaf-green);
}

input[type="checkbox"],
input[type="radio"] {
    accent-color: var(--leaf-green);
}

select, input[type="datetime-local"] {
    padding: 0.4rem;
    border-radius: 6px;
    border: 1px solid #e0e0e0;
    margin-top: 0.3rem;
    width: 100%;
    background-color: var(--soft-white);
    color: var(--text-dark);
}

.action-buttons {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 0.8rem;
    margin-top: 1rem;
}

button {
    padding: 0.6rem 1rem;
    border: none;
    border-radius: 8px;
    background-color: var(--leaf-green);
    color: white;
    font-weight: bold;
    transition: background-color 0.2s ease;
    cursor: pointer;
}

button:hover {
    background-color: var(--dark-green);
}

.toggle-button {
    padding: 0.5rem 1rem;
    background-color: var(--leaf-green);
    border: none;
    border-radius: 8px;
    color: white;
    font-weight: 500;
    cursor: pointer;
    transition: background-color 0.2s ease-in-out, opacity 0.2s ease-in-out;
}

.toggle-button:hover {
    background-color: var(--dark-green);
}

.toggle-button.active {
    background-color: var(--leaf-green);
    opacity: 1;
}

.toggle-button:not(.active) {
    background-color: #e0e7ff;
    color: var(--text-dark);
    opacity: 0.7;
}

.toggle-button:not(.active):hover {
    background-color: #c7d2fe;
}

.random-meters-container {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 1rem;
    margin-bottom: 2rem;
}

.summary-card {
    background-color: #f9fafb;
    padding: 1rem;
    border-radius: 1rem;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    text-align: center;
    margin-bottom: 1.5rem;
    font-size: 1.25rem;
    font-weight: bold;
}

.charts-container {
    display: flex;
    flex-direction: column;
    width: 100%;
    box-sizing: border-box;
    padding: 0 1rem;
    gap: 1rem;
}

.meter-toggles {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    color: var(--text-light);
    flex: 1 1 auto;
    min-width: 160px;
}

/* CHARTS */
.chart-container {
    width: 100%;
    background: var(--dark-green);
    padding: 1rem;
    border-radius: 16px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
    min-height: 400px;
    display: flex;
    justify-content: center;
    align-items: center;
}

.chart-wrapper {
    flex: 1;
    width: 100%;
    height: 60vh;
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    background: var(--dark-green);
    border-radius: 12px;
}

.chart-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(500px, 650px));
    justify-content: center;
    gap: 2rem;
    width: 100%;
    padding: 0 1rem;
    box-sizing: border-box;
}

/* --- Master-detail dashboard layout: a 3-column collapsible meter rail
   sitting beside a single focus panel, replacing the old always-all-
   visible grid. Higher specificity (#tab-contents.chart-grid) so this
   wins over the base .chart-grid rule and its responsive breakpoints
   below without having to touch either.
   No horizontal padding of its own (2026-09-10) -- body already carries
   1.25rem on each side, and dashboard-layout/.charts-container/
   .chart-grid were each separately adding another 1rem on top of that,
   stacking to as much as 4.25rem of dead space on some paths. That
   stacked padding was also eating into the width 2 focused cards need
   to sit side-by-side -- trimming it back to one layer (body's) buys
   back real room instead of just looking tidier. --- */
.dashboard-layout {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: 1rem;
    width: 100%;
    box-sizing: border-box;
}

.dashboard-layout .charts-container {
    flex: 1 1 auto;
    min-width: 0;
    width: auto;
    padding-left: 0;
    padding-right: 0;
}

/* The rail itself just lays out its columns in a row and sticks with the
   viewport while the charts below scroll -- the columns are the visual
   unit, not the rail. */
.meter-rail {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    flex: 0 0 auto;
    gap: 0.6rem;
    position: sticky;
    top: 1rem;
    align-self: flex-start;
}

/* One column (Staff Picks / My Top 10 +1 / All Devices). Columns are
   reordered in JS on every render -- see renderMeterRail() in
   index.html -- so only the visual treatment lives here, not the order.
   flex-basis (not just width) is set so collapse/expand animates the
   column's share of the row, not just its content box. */
.meter-column {
    display: flex;
    flex-direction: column;
    flex: 0 0 122px;
    width: 122px;
    box-sizing: border-box;
    background: rgba(0, 0, 0, 0.15);
    border-radius: 12px;
    padding: 0.5rem;
    gap: 0.4rem;
    transition: flex-basis 0.15s ease, width 0.15s ease, padding 0.15s ease;
}

/* Collapsed columns always sort to the rightmost position (see
   renderMeterRail()) and shrink to a thin strip so they stay out of the
   way of whichever columns -- and the focused cards beyond them -- are
   still expanded. */
.meter-column.is-collapsed {
    flex-basis: 40px;
    width: 40px;
    padding: 0.5rem 0.25rem;
}

.meter-column-header {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 0.4rem;
    width: 100%;
    background: none;
    border: none;
    color: inherit;
    font: inherit;
    text-align: left;
    padding: 0.1rem 0.1rem 0.4rem;
    margin: 0;
    cursor: pointer;
}

.meter-column.is-collapsed .meter-column-header {
    flex-direction: column;
    padding: 0.1rem 0 0.3rem;
}

.meter-column-title {
    font-size: 0.85rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.75;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.meter-column.is-collapsed .meter-column-title {
    writing-mode: vertical-rl;
    text-orientation: mixed;
    white-space: nowrap;
    overflow: visible;
    text-overflow: clip;
}

.meter-column-count {
    flex: 0 0 auto;
    font-size: 0.75rem;
    opacity: 0.55;
}

.meter-column-toggle {
    flex: 0 0 auto;
    font-size: 0.7rem;
    opacity: 0.6;
}

.meter-column-body {
    gap: 0.6rem;
    max-height: 70vh;
    overflow-y: auto;
    scrollbar-width: none;
    -ms-overflow-style: none;
}

.meter-column-body:not([hidden]) {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.meter-column-body::-webkit-scrollbar {
    display: none;
}

.meter-column-empty {
    font-size: 0.8rem;
    opacity: 0.6;
    padding: 0.3rem 0;
    text-align: center;
}

/* Mobile-only segmented control replacing the 3-column rail below 768px
   (2026-09-14, Riley's brainstorm fix) -- visual language matches
   .unit-toggle (the Celsius/Fahrenheit toggle) on purpose, so it reads as
   the same kind of control rather than a new pattern. Hidden here;
   switched on inside the @media (max-width: 768px) block below along
   with the column show/hide rules it drives. */
.meter-rail-tabs {
    display: none;
}

.meter-rail-tab {
    padding: 0.4rem 0.5rem;
    border: none;
    background-color: transparent;
    color: var(--text-light);
    font-weight: 600;
    font-size: 0.78rem;
    cursor: pointer;
    transition: background-color 0.2s ease;
    white-space: nowrap;
}

.meter-rail-tab.active {
    background-color: var(--leaf-green);
}

.meter-rail-tab:not(.active):hover {
    background-color: rgba(255, 255, 255, 0.15);
}

.meter-rail-tab-count {
    opacity: 0.7;
    font-size: 0.7rem;
    margin-left: 0.1rem;
}

.meter-tile {
    position: relative;
    flex-shrink: 0;
    width: 78px;
    height: 78px;
    border-radius: 13px;
    border: 2px solid transparent;
    background: linear-gradient(145deg, var(--dark-green), #2e4b33);
    cursor: pointer;
    padding: 0;
    overflow: visible;
    transition: border-color 0.15s ease, transform 0.1s ease;
}

.meter-tile:hover {
    transform: scale(1.03);
}

.meter-tile.active {
    border-color: var(--leaf-green);
}

.meter-tile-photo {
    width: 100%;
    height: 100%;
    border-radius: 11px;
    background-size: cover;
    background-position: center;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.45rem;
    color: var(--text-light);
    box-sizing: border-box;
    border-bottom: 3px solid transparent;
}

.meter-tile.mood-Happy .meter-tile-photo { border-bottom-color: #78dc96; }
.meter-tile.mood-Meh .meter-tile-photo   { border-bottom-color: #f5d76e; }
.meter-tile.mood-Sad .meter-tile-photo   { border-bottom-color: #ff9a5c; }
.meter-tile.mood-Dead .meter-tile-photo  { border-bottom-color: #999999; }

.meter-tile-badge {
    position: absolute;
    top: -5px;
    right: -5px;
    min-width: 1.1rem;
    height: 1.1rem;
    padding: 0 0.25rem;
    border-radius: 999px;
    background: var(--leaf-green);
    color: #fff;
    font-size: 0.6rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
}

.meter-tile-badge-favorite {
    background: #f5c518;
    color: #3a2e00;
}

/* Up to two meters can be focused at once (see toggleFocus() in
   index.html). Columns have a comfortable, capped width (not 1fr) so a
   focused card doesn't stretch edge-to-edge. Centered again (2026-09-10)
   now that the meter rail is a side column next to this grid rather than
   a full-width row sitting above it, so there's no dead gap to close by
   left-aligning. */
#tab-contents.chart-grid {
    grid-template-columns: repeat(auto-fit, minmax(460px, 620px));
    justify-content: center;
}

.chart-grid .tab-content {
    width: 100%;
    background: linear-gradient(145deg, var(--dark-green), #2e4b33);
    padding: 1.5rem;
    border-radius: 20px;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    position: relative;
    border: 1px solid rgba(255, 255, 255, 0.1);
    margin: 0;
    /* Updated: Ensure the container stretches to fit children */
    flex-wrap: wrap; /* Allow wrapping if needed */
    min-height: 400px; /* Ensure enough height for content */
}

.chart-grid.multiple-charts .tab-content {
    width: 100%;
}

.tab-content.first-chart.full-row {
    grid-column: 1 / -1;
}

.tab-content:not(.first-chart) {
    grid-column: auto;
}

/* Updated: Ensure info-content and chart-wrapper fit within tab-content */
.tab-content .info-content {
    flex: 0 0 30%; /* Take 30% of the width */
    min-width: 300px; /* Prevent shrinking too much */
    margin-right: 1rem; /* Keep spacing consistent */
}

/* Only the first-loaded meter's tab-content ever gets info-content
   filled in (see isFirstChart in renderCharts()); every other meter's
   copy is left empty. Without this, that empty div still claimed its
   30% flex-basis + 300px min-width, leaving a big blank column next to
   a squeezed chart -- the "chart is small, info card is huge" bug. */
.tab-content .info-content:empty {
    display: none;
    flex: 0;
    min-width: 0;
    margin-right: 0;
}

.tab-content .chart-wrapper {
    flex: 1; /* Take the remaining space */
    min-width: 280px; /* Ensure chart has enough space, but still shrink to fit side-by-side with another focused meter */
    background: transparent; /* Avoid nested background conflicts */
}

canvas {
    width: 100% !important;
    height: 100% !important;
    border-radius: 12px 12px 0 0;
    background: transparent;
}

.chart-container canvas,
.chart-wrapper canvas {
    background: transparent !important;
}

.chart-container text,
.chart-wrapper text,
.chart-container .chartjs-legend text,
.chart-wrapper .chartjs-legend text,
.chart-container .chartjs-title,
.chart-wrapper .chartjs-title,
.chart-container .chartjs-legend-text,
.chart-wrapper .chartjs-legend-text,
.chart-container .chartjs-axis-label,
.chart-wrapper .chartjs-axis-label,
.chart-container .chartjs-tick,
.chart-wrapper .chartjs-tick {
    fill: var(--soft-white) !important;
    color: var(--soft-white) !important;
}

.chart-container .chartjs-grid-line,
.chart-wrapper .chartjs-grid-line {
    border-color: rgba(255, 255, 255, 0.2) !important;
}

/* INFO */
.info-section {
    display: none;
}

.info-button {
    position: absolute;
    top: 1rem;
    right: 1rem;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background-color: var(--leaf-green);
    color: white;
    font-weight: bold;
    font-size: 1rem;
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.2s ease, transform 0.1s ease;
}

.info-button:hover {
    background-color: var(--dark-green);
    transform: scale(1.1);
}

.info-button:active {
    transform: scale(0.9);
}

.info-content {
    display: none;
    width: 300px;
    background: var(--dark-green);
    color: var(--text-light);
    padding: 1rem;
    border-radius: 8px;
    font-size: 0.9rem;
    line-height: 1.4;
    margin-right: 1rem;
    flex-shrink: 0;
}

.info-content.visible {
    display: block;
}

.info-content h4 {
    margin: 0 0 0.5rem 0;
    font-size: 1.1rem;
    color: var(--leaf-green);
}

.info-content ul {
    margin: 0;
    padding: 0 0 0 1rem;
}

.info-content li {
    margin-bottom: 0.5rem;
}

.info-content strong {
    color: var(--leaf-green);
}

.info-content .more-info {
    margin-top: 0.5rem;
    text-align: center;
}

.info-content .more-info a {
    color: var(--leaf-green);
    text-decoration: none;
    font-weight: bold;
}

.info-content .more-info a:hover {
    text-decoration: underline;
}

/* AVERAGES */
.averages-section {
    display: flex;
    font-size: 0.9rem;
    color: var(--text-light);
    justify-content: center;
    padding: 0.5rem 1rem;
    border-bottom-left-radius: 12px;
    border-bottom-right-radius: 12px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

.avg-label {
    font-weight: bold;
    color: var(--leaf-green);
}

.avg-ppfd {
    color: hsl(0, 70%, 50%);
}

.avg-lum {
    color: hsl(60, 70%, 50%);
}

.avg-lux {
    color: hsl(120, 70%, 50%);
}

.avg-gas {
    color: hsl(180, 70%, 50%);
}

.avg-temp {
    color: hsl(240, 70%, 50%);
}

.avg-humidity {
    color: hsl(300, 70%, 50%);
}

.avg-pressure {
    color: hsl(360, 70%, 50%);
}

.avg-ppfd sup {
    font-size: 0.7em;
    vertical-align: super;
}

/* Legend */
.legend-tooltip {
    position: fixed;
    background: var(--dark-green);
    color: var(--text-light);
    padding: 0.5rem;
    border-radius: 4px;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
    z-index: 1000;
    font-size: 0.85rem;
    max-width: 200px;
    display: none;
}

.legend-tooltip a.tooltip-link {
    color: var(--leaf-green);
    text-decoration: none;
    font-weight: bold;
    display: block;
    margin-top: 0.3rem;
}

.legend-tooltip a.tooltip-link:hover {
    text-decoration: underline;
}

/* Light Source Popup Styles */
.light-source-popup {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 2000;
}

.light-source-popup-content {
    background: var(--dark-green);
    padding: 2rem;
    border-radius: 12px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
    max-width: 90%;
    max-height: 80vh;
    overflow-y: auto;
    color: var(--text-light);
}

.light-source-popup-content h3 {
    margin: 0 0 1rem 0;
    color: var(--leaf-green);
    font-size: 1.5rem;
}

.light-source-table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 1rem;
}

.light-source-table th,
.light-source-table td {
    padding: 0.75rem;
    text-align: left;
    border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}

.light-source-table th {
    background: var(--leaf-green);
    color: var(--text-light);
    font-weight: bold;
}

.light-source-table td {
    color: var(--text-light);
}

.light-source-table tr:hover {
    background: rgba(255, 255, 255, 0.1);
}

.select-light-source-btn {
    padding: 0.5rem 1rem;
    background: var(--leaf-green);
    color: var(--text-light);
    border: none;
    border-radius: 8px;
    cursor: pointer;
    transition: background-color 0.2s ease;
}

.select-light-source-btn:hover {
    background: var(--dark-green);
}

.close-popup-btn {
    display: block;
    margin: 1rem auto 0;
    padding: 0.5rem 2rem;
    background: var(--leaf-green);
    color: var(--text-light);
    border: none;
    border-radius: 8px;
    cursor: pointer;
    transition: background-color 0.2s ease;
}

.close-popup-btn:hover {
    background: var(--dark-green);
}


    /* Add styles for soil moisture category indicator */
    .soil-moisture-status {
      display: inline-block;
      margin-left: 5px;
      padding: 2px 6px;
      border-radius: 4px;
      font-size: 0.9em;
      color: #fff;
    }
    .soil-moisture-status.Dry {
      background-color: #ff6347; /* Tomato red for Dry */
    }
    .soil-moisture-status.Moist {
      background-color: #32cd32; /* Lime green for Moist */
    }
    .soil-moisture-status.Wet {
      background-color: #4682b4; /* Steel blue for Wet */
    }
	
	
 /* Styles for the serial output modal */
    .serial-modal {
      display: none;
      position: fixed;
      z-index: 1000;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      background-color: rgba(0, 0, 0, 0.5);
      justify-content: center;
      align-items: center;
    }

    .serial-modal-content {
      background-color: #1e1e1e;
      padding: 20px;
      border-radius: 8px;
      width: 80%;
      max-width: 600px;
      max-height: 80%;
      display: flex;
      flex-direction: column;
      color: #ffffff;
      position: relative;
    }

    .serial-output {
      background-color: #2e2e2e;
      padding: 10px;
      border-radius: 4px;
      height: 300px;
      overflow-y: auto;
      font-family: monospace;
      font-size: 14px;
      white-space: pre-wrap;
      margin-bottom: 10px;
    }

    .serial-modal-content h3 {
      margin: 0 0 10px 0;
    }

    .close-serial-btn,
    .clear-serial-btn {
      padding: 8px 16px;
      margin: 5px;
      border: none;
      border-radius: 4px;
      cursor: pointer;
      font-size: 14px;
    }

    .close-serial-btn {
      background-color: #ff5555;
      color: #ffffff;
    }

    .clear-serial-btn {
      background-color: #555555;
      color: #ffffff;
    }
	
/***************************
      PLANT FLIP-CARD
***************************/
/* .plant-card is now the actual grid item .chart-grid tiles; .tab-content
   (the chart, unchanged) lives nested inside .plant-card-back. Front and
   back are stacked in the same CSS Grid cell (grid-area) so the card's
   height always follows whichever face is taller, without needing a fixed
   height or JS measurement. */
.plant-card {
    position: relative;
    width: 100%;
    perspective: 1800px;
    display: grid;
    grid-template-areas: "face";
}

.plant-card.first-chart.full-row {
    grid-column: 1 / -1;
}

.plant-card-front,
.plant-card-back {
    grid-area: face;
    width: 100%;
    min-width: 0;
    backface-visibility: hidden;
    transition: transform 0.6s ease;
}

.plant-card-back {
    transform: rotateY(180deg);
}

.plant-card.flipped .plant-card-front {
    transform: rotateY(180deg);
}

.plant-card.flipped .plant-card-back {
    transform: rotateY(0deg);
}

.plant-flip-btn {
    position: absolute;
    top: 1rem;
    left: 1rem;
    z-index: 2;
    padding: 0.35rem 0.75rem;
    border: none;
    border-radius: 20px;
    background-color: var(--leaf-green);
    color: #fff;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.2s ease, transform 0.1s ease;
}

.plant-flip-btn:hover {
    background-color: var(--dark-green);
    transform: scale(1.05);
}

.plant-card-front {
    position: relative;
    background: linear-gradient(145deg, var(--dark-green), #2e4b33);
    border-radius: 20px;
    padding: 1.5rem;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.1);
    box-sizing: border-box;
    min-height: 400px;
    display: flex;
    flex-direction: column;
    align-items: center;
    color: var(--text-light);
}

/* Two-column card body (2026-09-10): photo + happiness + mood beside the
   identity/stats/watering column instead of stacked below it, so the
   card's total height is roughly the taller of the two columns rather
   than the sum of everything -- the main lever for getting a whole card
   to fit on screen without zooming out. Falls back to a single stacked
   column at narrow widths (below). */
.plant-card-body {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: 1.25rem;
    width: 100%;
    margin-top: 1rem;
}

.plant-card-visual {
    flex: 0 0 160px;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.plant-card-details {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
    text-align: left;
}

@media (max-width: 600px) {
    .plant-card-body {
        flex-direction: column;
        align-items: center;
    }

    .plant-card-details {
        align-items: center;
        text-align: center;
    }
}

.plant-front-loading,
.plant-front-error {
    margin: auto;
    color: var(--text-light);
    opacity: 0.8;
    font-size: 0.95rem;
}

.plant-photo-wrap {
    width: 100%;
    display: flex;
    justify-content: center;
    margin-top: 0.75rem;
}

.plant-photo-wrap-clickable {
    cursor: pointer;
}

.plant-photo-wrap-clickable:hover .plant-photo {
    filter: brightness(1.1);
    transform: scale(1.03);
    transition: filter 0.15s ease, transform 0.15s ease;
}

.plant-photo {
    width: 160px;
    height: 160px;
    object-fit: cover;
    border-radius: 16px;
    border: 1px solid rgba(255, 255, 255, 0.15);
    background: rgba(255, 255, 255, 0.05);
}

.plant-photo-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 4rem;
    line-height: 1;
}

.plant-happiness-score {
    position: relative;
    margin-top: 0.6rem;
    font-size: 1.5rem;
    font-weight: 800;
    line-height: 1;
}

.plant-mood-badge {
    margin-top: 0.5rem;
    display: flex;
    align-items: center;
    gap: 0.4rem;
    background: rgba(255, 255, 255, 0.08);
    padding: 0.3rem 0.8rem;
    border-radius: 20px;
}

.plant-mood-emoji {
    font-size: 1.2rem;
}

.plant-mood-label {
    font-weight: 600;
    font-size: 0.9rem;
}

.plant-mood-score {
    font-size: 0.8rem;
    opacity: 0.75;
    margin-left: 0.1rem;
}

.plant-collapsible {
    margin-top: 0.5rem;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.plant-collapsible-toggle {
    border: none;
    background: transparent;
    color: var(--text-light);
    opacity: 0.7;
    font-size: 0.8rem;
    cursor: pointer;
    padding: 0.2rem 0.4rem;
    transition: opacity 0.15s ease;
}

.plant-collapsible-toggle:hover {
    opacity: 1;
}

.plant-collapsible-caret {
    display: inline-block;
    transition: transform 0.15s ease;
}

.plant-collapsible-toggle.is-expanded .plant-collapsible-caret {
    transform: rotate(90deg);
}

.plant-needs-readout {
    margin-top: 0.4rem;
    width: 100%;
    gap: 0.3rem;
}

.plant-needs-readout:not([hidden]) {
    display: flex;
    flex-direction: column;
}

.plant-mood-breakdown {
    margin-top: 0.4rem;
    width: 100%;
    gap: 0.3rem;
    /* Scrollable (2026-09-12, Martin's ask): this now sits in the narrow
       160px visual column, expanded by default, and VPD can add a second
       or third simultaneous factor alongside soil/light/temp -- capping
       the height and scrolling keeps a plant with several debuffs from
       pushing Log Watering/the photo out of a short viewport instead of
       just growing forever. */
    max-height: 160px;
    overflow-y: auto;
    padding-right: 0.2rem;
    box-sizing: border-box;
}

.plant-mood-breakdown:not([hidden]) {
    display: flex;
    flex-direction: column;
}

.plant-mood-factor {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.8rem;
    background: rgba(255, 99, 71, 0.14);
    border-left: 3px solid #ff6347;
    padding: 0.3rem 0.6rem;
    border-radius: 4px;
}

.plant-mood-factor-penalty {
    font-weight: 700;
    color: #ff9a86;
    min-width: 2.5rem;
    flex-shrink: 0;
}

.plant-mood-factor-label {
    opacity: 0.9;
}

.plant-identity {
    margin-top: 0.75rem;
    text-align: center;
    display: flex;
    flex-direction: column;
}

.plant-name {
    font-size: 1.2rem;
    font-weight: 700;
}

.plant-species {
    font-size: 0.85rem;
    opacity: 0.75;
    font-style: italic;
}

.plant-identity-edit-btn {
    margin-top: 0.4rem;
    align-self: center;
    border: none;
    background: transparent;
    color: var(--text-light);
    opacity: 0.6;
    font-size: 0.75rem;
    cursor: pointer;
    padding: 0.15rem 0.4rem;
    transition: opacity 0.15s ease;
}

.plant-identity-edit-btn:hover {
    opacity: 1;
}

.plant-identity-input {
    width: 100%;
    max-width: 260px;
    margin: 0.25rem auto 0;
    padding: 0.35rem 0.6rem;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.3);
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-light);
    font-size: 0.9rem;
    text-align: center;
    box-sizing: border-box;
}

.plant-identity-input:focus {
    outline: none;
    border-color: var(--leaf-green);
    background: rgba(255, 255, 255, 0.14);
}

/* Device name header (promoted 2026-09-10 -- was a small owner-only row
   below the plant identity; is now the card's primary title, shown to
   every viewer, since device identity is the one naming concept that
   actually belongs at the top level. Deliberately separate from
   .plant-identity above: that block renames the PLANT (plantables.name),
   this one renames the DEVICE (metering_device.device_name), two
   different concepts that used to be conflated by treating gnode_uuid
   itself as if it were a human-editable name. */
.device-name-header {
    margin-top: 2.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    font-size: 1.3rem;
    font-weight: 700;
    text-align: center;
}

.device-name-value {
    font-weight: 700;
}

.plant-species-inline {
    font-weight: 400;
    font-style: italic;
    opacity: 0.75;
    font-size: 0.85em;
}

/* Owner byline (2026-09-11, Martin's call: "this is meant to be a social
   platform") -- sits between the name/species header and the online
   indicator, so every card (Staff Picks, All Devices, a compare panel)
   shows whose plant it is at a glance, not just the ones you own. */
.plant-owner-byline {
    margin-top: 0.1rem;
    text-align: center;
    font-size: 0.8rem;
    opacity: 0.7;
}

.plant-owner-username {
    font-weight: 600;
}

/* "Online indicator" (2026-09-10) -- a freshness read on when this gnode
   last reported in, not a strict binary online/offline. Sits right under
   the name/species header. */
.device-status-row {
    margin-top: 0.15rem;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    font-size: 0.75rem;
    opacity: 0.75;
}

.device-status-dot {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    flex-shrink: 0;
}

.device-status-dot.device-status-fresh { background: #6aeb8c; box-shadow: 0 0 4px rgba(106, 235, 140, 0.7); }
.device-status-dot.device-status-stale { background: #f5d76e; }
.device-status-dot.device-status-old   { background: #ff6347; }
.device-status-dot.device-status-unknown { background: #999999; }

.card-edit-btn {
    border: none;
    background: transparent;
    color: var(--text-light);
    opacity: 0.6;
    font-size: 0.85rem;
    cursor: pointer;
    padding: 0.1rem 0.4rem;
    transition: opacity 0.15s ease;
}

.card-edit-btn:hover {
    opacity: 1;
}

/* Overlay, not inline (2026-09-12, Martin's flag: the inline panel used
   to sit between the reporting-status row and the Chart/Plant-Needs
   content, pushing the whole card taller and burying the stats behind a
   long form). .plant-card-front is the positioned ancestor (see its own
   position: relative) this covers -- opening Edit now floats a clean
   card-shaped panel on top of the front face instead of growing it, and
   closing it (panel.hidden, still toggled the same way in JS) just
   removes the overlay with nothing left behind to collapse back down.
   overflow-y auto is a safety net for when the form (device name +
   species picker + species + visibility + 3 profile selects) is taller
   than whatever the card's current content height happens to be. */
.plant-edit-panel {
    position: absolute;
    inset: 0;
    z-index: 10;
    margin: 0;
    padding: 1.25rem;
    border-radius: 20px;
    background: linear-gradient(160deg, rgba(20, 32, 20, 0.98), rgba(15, 22, 14, 0.98));
    border: 1px solid rgba(255, 255, 255, 0.18);
    box-shadow: 0 14px 34px rgba(0, 0, 0, 0.5);
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

/* Without this, the panel shows even while JS sets the hidden ATTRIBUTE
   (2026-09-12 regression, Martin's flag -- "tiles are blacked out"): the
   browser's own default stylesheet hides [hidden] elements via display:
   none, but that rule and .plant-edit-panel's own display: flex above
   are equal specificity, and this stylesheet loads after the browser's
   default one -- so the flex declaration silently won and the panel
   rendered open at all times, not just when toggled. A bare [hidden]
   can't out-specificity a class selector; pairing it with the class
   (.plant-edit-panel[hidden]) can and does. */
.plant-edit-panel[hidden] {
    display: none;
}

/* Close "X" (2026-09-14, Martin's mom's feedback via iPad testing): the
   panel already had sticky Save/Cancel pinned to the bottom (see
   .plant-identity-edit-actions below), but nothing at the top -- on a
   long form (species picker expanded, etc.) that meant scrolling all the
   way down just to back out. This mirrors .photo-gallery-close's/
   .claim-code-close's look (top-right circular X) but uses position:
   sticky instead of absolute, since it's the first item in
   .plant-edit-panel's own flex column and that panel is the scrolling
   container -- sticky top here plus align-self: flex-end keeps it
   pinned in the top-right corner even while the form scrolls underneath
   it, giving a second, always-visible way to close alongside Cancel. */
.plant-edit-panel-close {
    position: sticky;
    top: -1.25rem;
    align-self: flex-end;
    margin: -1.25rem -1.25rem -0.35rem 0;
    width: 32px;
    height: 32px;
    min-height: 32px;
    flex: 0 0 auto;
    border-radius: 50%;
    border: none;
    background: rgba(255, 255, 255, 0.1);
    color: var(--text-light);
    font-size: 1.3rem;
    line-height: 1;
    cursor: pointer;
    z-index: 11;
}

.plant-edit-panel-close:hover {
    background: rgba(255, 255, 255, 0.2);
}

.device-name-input {
    max-width: 220px;
    padding: 0.3rem 0.6rem;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.3);
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-light);
    font-size: 1.1rem;
    text-align: center;
    box-sizing: border-box;
}

.device-name-input:focus {
    outline: none;
    border-color: var(--leaf-green);
    background: rgba(255, 255, 255, 0.14);
}

/* Species-aware mood scoring dropdowns (Track D, 2026-09-09): each select
   reuses .plant-identity-input for sizing, this just adds the small
   caption label above it and a little vertical rhythm between the three. */
.plant-identity-profile-label {
    display: block;
    margin-top: 0.4rem;
    font-size: 0.7rem;
    opacity: 0.75;
    color: var(--text-light);
}

/* Dark-mode contrast fix (2026-09-11, Martin's flag; broadened
   2026-09-12 after Visibility and the watering-unit dropdown showed the
   same unreadable white-on-white popup): without an explicit
   color-scheme, the browser guesses at the OPEN dropdown list's colors
   independently of the closed control's translucent background above --
   on a dark-mode browser/OS that guess can land on a light popup panel
   behind light text, which is unreadable. Declaring color-scheme +
   explicit, opaque colors on every <select> (not just the species-aware
   profile dropdowns) stops the guess and matches the app's own
   dark-green theme everywhere, including selects added later. */
select {
    color-scheme: dark;
    background-color: var(--dark-green);
    color: var(--text-light);
}

select option {
    background-color: var(--dark-green);
    color: var(--text-light);
}

.plant-identity-profile-select {
    margin-top: 0.15rem;
}

.plant-identity-edit-actions {
    /* Sticky (2026-09-12): .plant-edit-panel is a fixed-bounds overlay
       now (see its own comment) that scrolls internally when the form is
       taller than the card -- without this, Save/Cancel could end up
       below the fold on a shorter card with nothing telling you to
       scroll for them. Pinning them to the bottom of the scroll area
       keeps them reachable regardless of form length. */
    position: sticky;
    bottom: -1.25rem;
    margin: 0.5rem -1.25rem -1.25rem;
    padding: 0.6rem 1.25rem calc(0.6rem + 1.25rem);
    background: linear-gradient(180deg, transparent, rgba(12, 18, 11, 0.92) 35%);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.plant-identity-save-btn,
.plant-identity-cancel-btn {
    padding: 0.3rem 0.8rem;
    border-radius: 999px;
    border: none;
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
}

.plant-identity-save-btn {
    background-color: var(--leaf-green);
    color: #fff;
}

.plant-identity-save-btn:hover {
    background-color: var(--dark-green);
}

.plant-identity-cancel-btn {
    background: rgba(255, 255, 255, 0.1);
    color: var(--text-light);
}

.plant-identity-cancel-btn:hover {
    background: rgba(255, 255, 255, 0.18);
}

.plant-identity-edit-status {
    width: 100%;
    text-align: center;
    font-size: 0.75rem;
    opacity: 0.85;
    color: #ffb4a6;
}

/* Curated species picker (2026-09-12, Track B / Onboarding Phase 1 item
   1) -- a small combobox sitting above the existing plain Species text
   box + profile dropdowns in the plant-identity edit panel. Purely a
   quick-fill affordance: .species-picker-input reuses .plant-identity-
   input's sizing/look, this just adds the floating suggestion list and
   the reference-only humidity/notes readout beneath it.

   Fixed 2026-09-12 (Martin's flag -- "impossible to see"): the caption
   ("Quick-pick a species") used to be a <label> WRAPPING this whole div,
   and .plant-identity-profile-label carries opacity: 0.75 for dimming
   small caption text. Opacity on an ancestor flattens its entire
   subtree into one translucent layer at render time -- so the dropdown
   below inherited that 75% translucency wholesale, on top of never
   establishing its own stacking context (position: relative with no
   z-index doesn't), which let it paint BEHIND the Species/Visibility
   fields below it despite z-index: 5. Two fixes: the caption is now a
   plain sibling .species-picker-caption span (not a wrapping label), so
   its opacity never touches this div; and this div gets its own
   explicit z-index so the dropdown's z-index actually has a local
   stacking context to win in, instead of relying on how it happens to
   flatten into some ancestor's. */
.species-picker {
    position: relative;
    z-index: 2;
    display: block;
    width: 100%;
}

.species-picker-suggestions {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    top: calc(100% + 2px);
    z-index: 5;
    width: 100%;
    max-width: 260px;
    max-height: 220px;
    overflow-y: auto;
    margin: 0;
    padding: 0.25rem 0;
    list-style: none;
    background: var(--dark-green);
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: 8px;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);
    text-align: left;
}

.species-picker-suggestion {
    padding: 0.35rem 0.7rem;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    gap: 0.05rem;
}

.species-picker-suggestion:hover,
.species-picker-suggestion.is-active {
    background: var(--leaf-green);
}

.species-picker-suggestion-name {
    font-size: 0.85rem;
    color: var(--text-light);
}

.species-picker-suggestion-sci {
    font-size: 0.7rem;
    font-style: italic;
    opacity: 0.75;
    color: var(--text-light);
}

.species-picker-disclaimer {
    margin: 0.35rem auto 0;
    max-width: 260px;
    font-size: 0.68rem;
    font-style: italic;
    line-height: 1.4;
    opacity: 0.75;
    color: var(--text-light);
    text-align: center;
}

.species-picker-detail {
    margin: 0.35rem auto 0;
    max-width: 260px;
    padding: 0.4rem 0.6rem;
    border-radius: 8px;
    background: rgba(106, 168, 79, 0.15);
    border: 1px solid rgba(106, 168, 79, 0.35);
    font-size: 0.72rem;
    line-height: 1.4;
    color: var(--text-light);
    text-align: center;
}

.species-picker-note-tag {
    opacity: 0.75;
    font-style: italic;
}

/* Display-only (2026-09-10): moved to the visual/left column, centered
   above the photo, actual toggling lives in the Edit panel so it can't
   be flipped by an accidental click. */
.plant-visibility-indicator {
    margin-bottom: 0.5rem;
    align-self: center;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.3rem 0.8rem;
    border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, 0.3);
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-light);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.02em;
}

.plant-visibility-indicator.plant-visibility-public {
    border-color: rgba(120, 220, 150, 0.6);
    background: rgba(120, 220, 150, 0.15);
}

.plant-visibility-indicator.plant-visibility-private {
    border-color: rgba(255, 255, 255, 0.25);
    background: rgba(0, 0, 0, 0.15);
}

.plant-photo-frame {
    position: relative;
    width: 160px;
    height: 160px;
}

.plant-photo-frame .plant-photo {
    margin: 0;
}

.plant-photo-icon-btn {
    position: absolute;
    top: 6px;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    border: none;
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    font-size: 1.1rem;
    font-weight: 700;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background 0.15s ease, transform 0.1s ease;
    z-index: 3;
}

.plant-photo-icon-btn:hover {
    transform: scale(1.1);
}

.plant-photo-icon-btn:disabled {
    opacity: 0.6;
    cursor: default;
    transform: none;
}

.plant-favorite-icon {
    right: 6px;
}

.plant-favorite-icon.is-favorite {
    background: rgba(245, 197, 24, 0.9);
    color: #3a2e00;
}

.plant-top10-icon {
    left: 6px;
    font-size: 1.4rem;
}

.plant-top10-icon.is-top10 {
    background: rgba(120, 220, 150, 0.9);
    color: #123018;
}

/* Photo-upload icon (2026-09-10): bottom-center of the photo frame,
   opens .plant-upload-panel below the photo instead of a form that used
   to sit permanently at the bottom of the whole card. */
.plant-upload-icon {
    top: auto;
    bottom: 6px;
    left: 50%;
    transform: translateX(-50%);
    font-size: 1rem;
}

.plant-upload-icon:hover {
    transform: translateX(-50%) scale(1.1);
}

.plant-upload-panel {
    margin-top: 0.6rem;
    width: 100%;
    box-sizing: border-box;
    padding: 0.6rem;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.12);
}

.plant-stats {
    margin-top: 1.25rem;
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.75rem;
}

.plant-stat {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    background: rgba(255, 255, 255, 0.06);
    border-radius: 10px;
    padding: 0.5rem 0.9rem;
    min-width: 70px;
}

.plant-stat-label {
    font-size: 0.75rem;
    opacity: 0.7;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.plant-stat-value {
    font-size: 1rem;
    font-weight: 600;
    margin-top: 0.15rem;
}

/* Plant Needs rows (2026-09-10, per Martin's whiteboard sketch + typed
   example): each axis gets its own accentuated treatment instead of one
   generic small-text status line -- Light shows a big value/target
   ratio, Watering shows a 3-tier Dry/Moist/Wet spectrum with the current
   tier picked out, Temperature shows the big reading plus a small
   colored Too Cold/Ideal/Too Hot tag. All three still lead with the
   profile's target label (e.g. "Partial Sun"), matching Martin's own
   example. */
.plant-needs-row {
    position: relative;
    width: 100%;
    background: rgba(255, 255, 255, 0.06);
    border-radius: 12px;
    padding: 0.6rem 0.9rem;
    box-sizing: border-box;
    text-align: center;
}

.plant-needs-row-label {
    font-size: 0.75rem;
    opacity: 0.7;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.plant-needs-target {
    font-size: 0.85rem;
    font-weight: 600;
    margin-top: 0.1rem;
}

/* Light: big "value / target" ratio, unit underneath in small text. */
.plant-needs-ratio {
    margin-top: 0.3rem;
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: 0.35rem;
}

.plant-needs-ratio-value {
    font-size: 1.6rem;
    font-weight: 800;
    line-height: 1;
}

.plant-needs-ratio-sep {
    font-size: 1.1rem;
    opacity: 0.5;
}

.plant-needs-ratio-target {
    font-size: 1.1rem;
    opacity: 0.65;
    font-weight: 600;
}

.plant-needs-ratio-unit {
    margin-top: 0.15rem;
    font-size: 0.7rem;
    opacity: 0.6;
}

/* Watering: Dry / Moist / Wet spectrum, current tier picked out bold +
   colored, the other two dimmed rather than dropped entirely -- keeps
   the full picture visible while still drawing the eye to "here". */
.plant-needs-spectrum {
    margin-top: 0.35rem;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    font-size: 1rem;
}

.plant-needs-spectrum-option {
    opacity: 0.35;
    font-weight: 600;
    transition: opacity 0.15s ease, transform 0.15s ease;
}

.plant-needs-spectrum-sep {
    opacity: 0.3;
    font-size: 0.8rem;
}

.plant-needs-spectrum-option.is-current {
    opacity: 1;
    font-size: 1.25rem;
    font-weight: 800;
}

.plant-needs-spectrum-option.dry.is-current   { color: #e0a458; }
.plant-needs-spectrum-option.moist.is-current { color: #6aeb8c; }
.plant-needs-spectrum-option.wet.is-current   { color: #6ab7e0; }

/* Temperature: big reading, small colored Too Cold/Ideal/Too Hot tag. */
.plant-needs-temp-value {
    margin-top: 0.3rem;
    font-size: 1.6rem;
    font-weight: 800;
    line-height: 1;
}

.plant-needs-temp-unit {
    font-size: 1rem;
    font-weight: 600;
    opacity: 0.7;
    margin-left: 0.1rem;
}

.plant-needs-temp-tag {
    display: inline-block;
    margin-top: 0.3rem;
    padding: 0.15rem 0.6rem;
    border-radius: 999px;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

/* Temperature + Humidity combined row (2026-09-12, Martin's ask): the two
   used to be separate full-width .plant-needs-row cards, which pushed the
   rest of the card below the fold once Humidity/VPD shipped. Same row,
   split into two columns instead -- .plant-needs-combo-half reuses the
   .plant-needs-temp-value/-unit/-tag styles above unchanged, just wrapped
   narrower. Each half gets its own `position: relative` so its Quick
   Glance pin button (`position: absolute`, see .quick-glance-tag-btn)
   anchors to that half's corner rather than both buttons overlapping in
   the shared row's single top-right corner. */
.plant-needs-row-combo {
    text-align: center;
}

.plant-needs-combo-cols {
    display: flex;
    align-items: stretch;
    justify-content: center;
    gap: 0.75rem;
    margin-top: 0.2rem;
}

.plant-needs-combo-half {
    position: relative;
    flex: 1 1 0;
    min-width: 0;
}

.plant-needs-combo-half-label {
    font-size: 0.7rem;
    opacity: 0.6;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.plant-needs-combo-divider {
    width: 1px;
    align-self: stretch;
    background: rgba(255, 255, 255, 0.12);
}

.plant-needs-temp-tag-cold  { background: rgba(106, 183, 224, 0.2); color: #6ab7e0; }
.plant-needs-temp-tag-ideal { background: rgba(106, 235, 140, 0.2); color: #6aeb8c; }
.plant-needs-temp-tag-hot   { background: rgba(255, 99, 71, 0.2); color: #ff9a86; }

/* Stat info bubble (2026-09-12, Martin's ask): a small hover/tap "what
   does this mean" explainer, starting on VPD/Humidity. Two independent
   reveal mechanisms stacked on the same element -- :hover/:focus-within
   for desktop (free, no JS), plus a JS-toggled .is-open class for touch
   devices, which never fire :hover. That's also why this uses a
   visibility toggle instead of the `hidden` attribute every other
   collapsible on the card uses: `[hidden]` is display:none and would
   block the pure CSS hover path entirely. (Originally opacity-based too;
   dropped opacity from the transition after the first version could get
   caught mid-fade looking translucent -- see the bubble rule below.)
   text-transform/letter-spacing are reset to `none`/`normal` here since
   this is nested inside .plant-needs-combo-half-label, which uppercases
   its text -- the (i) glyph and the explanation prose shouldn't be. */
.stat-info {
    position: relative;
    z-index: 5;
    display: inline-flex;
    align-items: center;
    margin-left: 0.25rem;
    text-transform: none;
}

.stat-info-btn {
    width: 15px;
    height: 15px;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.18);
    color: inherit;
    font-size: 0.62rem;
    font-weight: 700;
    font-style: italic;
    line-height: 1;
    letter-spacing: normal;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    opacity: 0.8;
    transition: opacity 0.15s ease, background-color 0.15s ease;
}

.stat-info-btn:hover,
.stat-info-btn:focus-visible {
    opacity: 1;
    background: rgba(255, 255, 255, 0.32);
}

.stat-info-bubble {
    position: absolute;
    top: calc(100% + 0.4rem);
    left: 50%;
    transform: translateX(-50%) translateY(-4px);
    width: 300px;
    max-width: min(300px, 88vw);
    /* Solid, opaque background (2026-09-12, Martin's ask -- the previous
       version read as translucent/see-through against the card content
       behind it and was too cramped to read comfortably). A hex color
       with no alpha channel, not a shared CSS variable, so there's no
       ambiguity about where any transparency could be sneaking in --
       paired with the much higher z-index and the opacity-free
       visibility toggle below to close off every angle that could have
       caused the see-through look. */
    background-color: #12241a;
    border: 1px solid rgba(255, 255, 255, 0.16);
    color: var(--text-light);
    padding: 0.75rem 0.9rem;
    border-radius: 8px;
    font-size: 0.82rem;
    font-weight: 400;
    text-align: left;
    text-transform: none;
    letter-spacing: normal;
    line-height: 1.5;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.55);
    /* Well above anything else in this card's own stacking context (the
       card's tiles/rows top out around z-index 2-3) so it can never be
       painted under a sibling again regardless of exactly which ancestor
       ends up owning the local stacking context. */
    z-index: 999;
    /* Visibility-only toggle, no opacity transition -- opacity was
       animatable, so a screenshot (or just unlucky timing) could catch
       the bubble mid-fade and look partially see-through even though its
       resting state was fully solid. This is a hard on/off with a small
       slide, nothing in between. */
    visibility: hidden;
    pointer-events: none;
    transition: transform 0.12s ease, visibility 0s linear 0.12s;
}

.stat-info:hover .stat-info-bubble,
.stat-info:focus-within .stat-info-bubble,
.stat-info-bubble.is-open {
    visibility: visible;
    pointer-events: auto;
    transform: translateX(-50%) translateY(0);
    /* No delay on the way in -- only the way out (base rule above) waits
       for the slide-out to finish before actually hiding. */
    transition: transform 0.12s ease, visibility 0s linear 0s;
}

.stat-info-bubble strong {
    color: var(--leaf-green);
}

/* "Know Your Plant" panel (2026-09-12, Martin's ask): an in-page
   slide-out drawer on the right edge of the screen -- mirrors the
   Claude Desktop app's left sidebar, flipped to the right per Martin's
   whiteboard sketch. Deliberately a drawer over the existing page, not
   a separate route, so opening/closing it never reloads the dashboard
   or drops any card state. "Values section only" this round -- "How to
   Make Your Plants Happy" and "Tip of the Day" are sketched in the
   markup's comments for later, not styled/built yet.

   Background (2026-09-12, Martin's follow-up ask): a vertical gradient
   "representing the life within a forest" -- dappled canopy light at
   the top, down through two leaf greens, into near-black forest-floor
   humus at the bottom. Same top-to-bottom banded-gradient idea as the
   page's own earth-tone body::before backdrop, but themed as the
   inside of a forest rather than a cross-section of sky-to-soil. */
.kyp-panel {
    position: fixed;
    top: 0;
    right: 0;
    width: 340px;
    max-width: 90vw;
    height: 100vh;
    background: linear-gradient(to bottom, #d9e8a3, var(--leaf-green), var(--dark-green), #1c1710);
    color: var(--text-light);
    box-shadow: -4px 0 24px rgba(0, 0, 0, 0.45);
    display: flex;
    flex-direction: column;
    transform: translateX(100%);
    transition: transform 0.25s ease;
    z-index: 2500;
    /* (2026-09-12, bugfix) Without this, a flex child that refuses to
       shrink below its content height (see .kyp-panel-body's min-height
       note below) could quietly poke out past this panel's own 100vh
       box. Since the panel is position:fixed, that overflowing sliver
       was extending past the bottom of the viewport -- and Chromium
       still counts a fixed element's overflow toward the PAGE's own
       scrollable area even with html/body's overflow:hidden, which is
       what was letting the whole dashboard scroll and hide the pinned
       cards at top. Clipping it here closes off that path regardless of
       whether the flex fix below is ever bypassed by future content. */
    overflow: hidden;
}

.kyp-panel.is-open {
    transform: translateX(0);
}

.kyp-panel-header {
    display: flex;
    align-items: center;
    padding: 1rem 1.25rem;
    background: rgba(0, 0, 0, 0.18);
    border-bottom: 1px solid rgba(255, 255, 255, 0.15);
    flex: 0 0 auto;
}

.kyp-panel-header h3 {
    margin: 0;
    font-size: 1.1rem;
    color: var(--text-light);
}

/* Close "X" (2026-09-14, Martin's mom's feedback): the panel could only
   be closed by clicking the edge tab again or pressing Escape, neither
   obvious from inside the panel itself. margin-left: auto pushes it to
   the right end of the header row (which is just display: flex,
   align-items: center -- no justify-content needed), matching the panel
   title's height */
.kyp-panel-close {
    margin-left: auto;
    width: 28px;
    height: 28px;
    min-height: 28px;
    flex: 0 0 auto;
    border-radius: 50%;
    border: none;
    background: rgba(255, 255, 255, 0.12);
    color: var(--text-light);
    font-size: 1.2rem;
    line-height: 1;
    padding: 0;
    cursor: pointer;
}

.kyp-panel-close:hover {
    background: rgba(255, 255, 255, 0.25);
}

.kyp-panel-body {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 1rem 1.25rem 1.5rem;
    /* (2026-09-12, bugfix) Flex items default to min-height: auto, which
       lets a tall child ignore its flex container's fixed height and
       grow to fit its content instead of shrinking to the space left
       after the header -- so this list's own overflow-y:auto never
       actually kicked in, and the excess just spilled out past the
       panel (see the whole-page-scroll bug this caused, noted on
       .kyp-panel's overflow rule above). This is the standard fix for
       "overflow-y: auto doesn't work" inside a flex column. */
    min-height: 0;
}

.kyp-section h4 {
    margin: 0 0 0.6rem;
    font-size: 0.95rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: rgba(255, 255, 255, 0.85);
}

/* Accuracy/expectation-setting note (2026-09-15, Track B Phase 1 item 5) --
   styled like .kyp-credit-text (italic, muted) so it reads as a caveat
   rather than a list item, but with a left accent bar since this one is a
   warning-adjacent framing note rather than a simple credit line. */
.kyp-accuracy-note {
    margin: 0 0 0.8rem;
    padding: 0.5rem 0.7rem;
    border-left: 3px solid rgba(255, 249, 219, 0.4);
    background: rgba(0, 0, 0, 0.15);
    border-radius: 0 6px 6px 0;
    font-size: 0.78rem;
    font-style: italic;
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.85);
}

.kyp-values-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.kyp-values-list li {
    padding: 0.6rem 0.1rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
    font-size: 0.85rem;
    line-height: 1.5;
    border-radius: 4px;
    transition: background-color 0.4s ease, box-shadow 0.4s ease;
}

.kyp-values-list li:last-child {
    border-bottom: none;
}

.kyp-values-list li strong {
    display: block;
    margin-bottom: 0.15rem;
    color: var(--sun-yellow);
}

/* Flash-then-settle highlight (2026-09-12, Martin's ask): landing on an
   entry via a "?" click briefly calls it out for ~2s, then the flash
   clears on its own -- the entry itself stays put, nothing collapses or
   scrolls again. Timed and removed in JS (openKypPanel()); this class
   only supplies the look. */
.kyp-highlight {
    background-color: rgba(255, 249, 219, 0.22);
    box-shadow: 0 0 0 1px rgba(255, 249, 219, 0.5) inset;
}

/* Credit "plaque" (2026-09-12, Martin's ask): sits above the Values
   list, not at the bottom -- a person being credited belongs up front,
   not as an afterthought link. Also, per Martin's own observation,
   having this here pushes the Values heading further down the panel's
   gradient, past the lightest (hardest-to-read-against-white-text)
   canopy band right at the top.

   2026-09-12 follow-up: given its own solid card instead of a plain
   line of text, specifically so IT ALSO reads clearly against that
   same light canopy band -- a dark, opaque background plus an inset
   highlight along the top edge (the "engraved plaque" cue) gives it
   contrast that doesn't depend on which part of the gradient it lands
   on, the way plain text sitting directly on the gradient did. */
.kyp-credit {
    margin: 0 0 1.25rem;
    padding: 1.1rem 1rem 1.2rem;
    text-align: center;
    background: rgba(20, 26, 16, 0.6);
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: 10px;
    box-shadow: 0 3px 10px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.15);
}

.kyp-credit-icon {
    display: block;
    font-size: 1.75rem;
    line-height: 1;
    margin-bottom: 0.4rem;
}

.kyp-credit-name {
    display: block;
    font-size: 1.2rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: var(--sun-yellow);
    text-decoration: none;
}

.kyp-credit-name:hover,
.kyp-credit-name:focus-visible {
    text-decoration: underline;
}

.kyp-credit-role {
    display: block;
    margin-top: 0.2rem;
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: rgba(255, 255, 255, 0.75);
}

.kyp-credit-text {
    margin: 0.7rem 0 0;
    font-size: 0.78rem;
    font-style: italic;
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.85);
}

/* 2026-09-12, Martin's ask: the Apogee PAR/FAR sensor support link
   (his own material) lives inside his plaque now, styled as a small
   distinct call-to-action rather than blending into the italic
   attribution line above it. */
.kyp-credit-link {
    margin: 0.6rem 0 0;
}

.kyp-credit-link a {
    display: inline-block;
    font-size: 0.78rem;
    font-weight: 600;
    font-style: normal;
    color: var(--sun-yellow);
    border-bottom: 1px solid rgba(255, 249, 219, 0.4);
    padding-bottom: 0.1rem;
}

.kyp-credit-link a:hover,
.kyp-credit-link a:focus-visible {
    border-bottom-color: var(--sun-yellow);
}

/* Persistent edge tab (2026-09-12, Martin's ask): always visible on the
   right edge of the screen, whether or not the panel is open, so there
   is always a way in beyond the contextual "?" icons -- and the only
   way to close the panel again (2026-09-12 follow-up: no separate X
   button in the header anymore; this same tab does both jobs). When
   closed it sits flush against the right edge of the screen; when open
   (JS adds .is-open and sets its own `right` offset to the open panel's
   actual width) it slides left along with the panel so it stays right
   on the seam, still clickable to collapse it again. `right` is
   transitioned here in CSS but its target value is set inline by JS
   since the panel's width varies (90vw cap, full-width under 480px). */
.kyp-edge-tab {
    position: fixed;
    top: 50%;
    right: 0;
    transform: translateY(-50%);
    z-index: 2400;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.35rem;
    background: var(--dark-green);
    color: var(--text-light);
    border: none;
    border-radius: 8px 0 0 8px;
    padding: 0.9rem 0.4rem;
    cursor: pointer;
    box-shadow: -2px 0 10px rgba(0, 0, 0, 0.35);
    transition: background-color 0.15s ease, padding-right 0.15s ease, right 0.25s ease;
}

.kyp-edge-tab.is-open {
    background: var(--leaf-green);
}

.kyp-edge-tab:hover,
.kyp-edge-tab:focus-visible {
    background: var(--leaf-green);
    padding-right: 0.6rem;
}

.kyp-edge-tab-icon {
    font-size: 1.1rem;
    line-height: 1;
}

.kyp-edge-tab-label {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}

@media (max-width: 480px) {
    .kyp-panel {
        width: 100vw;
        max-width: 100vw;
    }
}

.quick-glance-tag-btn {
    position: absolute;
    top: 0.2rem;
    right: 0.3rem;
    border: none;
    background: transparent;
    font-size: 0.7rem;
    line-height: 1;
    opacity: 0.35;
    cursor: pointer;
    padding: 0.1rem;
    transition: opacity 0.15s ease, transform 0.1s ease;
}

.quick-glance-tag-btn:hover {
    opacity: 0.85;
    transform: scale(1.15);
}

.quick-glance-tag-btn.is-tagged {
    opacity: 1;
}

.plant-upload-form {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    justify-content: center;
}

.plant-upload-form input[type="file"] {
    color: var(--text-light);
    font-size: 0.8rem;
    max-width: 160px;
}

.plant-upload-form select {
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-light);
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 6px;
    padding: 0.25rem 0.4rem;
    font-size: 0.8rem;
}

.plant-upload-form button[type="submit"] {
    padding: 0.35rem 0.75rem;
    border: none;
    border-radius: 20px;
    background-color: var(--leaf-green);
    color: #fff;
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
}

.plant-upload-form button[type="submit"]:hover {
    background-color: var(--dark-green);
}

.plant-upload-form button[type="submit"]:disabled {
    opacity: 0.6;
    cursor: default;
}

.plant-upload-status {
    width: 100%;
    text-align: center;
    font-size: 0.8rem;
    opacity: 0.85;
    min-height: 1em;
}

/* Watering tracking (2026-09-09) */
.plant-watering-trigger {
    margin-top: 0.25rem;
    padding: 0.35rem 0.75rem;
    border: none;
    border-radius: 20px;
    background-color: rgba(56, 189, 248, 0.18);
    color: #7dd3fc;
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.15s ease;
}

.plant-watering-trigger:hover {
    background-color: rgba(56, 189, 248, 0.3);
}

.plant-watering-panel {
    margin-top: 0.4rem;
    width: 100%;
    box-sizing: border-box;
    padding: 0.6rem;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.12);
}

.plant-watering-form {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    justify-content: flex-start;
}

.plant-watering-form-label {
    font-size: 0.8rem;
    opacity: 0.85;
}

.plant-watering-form input[type="number"] {
    width: 70px;
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-light);
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 6px;
    padding: 0.25rem 0.4rem;
    font-size: 0.8rem;
}

.plant-watering-form select {
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-light);
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 6px;
    padding: 0.25rem 0.4rem;
    font-size: 0.8rem;
}

.plant-watering-form button[type="submit"] {
    padding: 0.35rem 0.75rem;
    border: none;
    border-radius: 20px;
    background-color: #38bdf8;
    color: #06202b;
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
}

.plant-watering-form button[type="submit"]:hover {
    background-color: #7dd3fc;
}

.plant-watering-status {
    width: 100%;
    text-align: center;
    font-size: 0.8rem;
    opacity: 0.85;
    min-height: 1em;
}

.watering-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.8rem;
    color: var(--text-light);
    opacity: 0.85;
    cursor: pointer;
    margin-left: 0.75rem;
    user-select: none;
}

.watering-toggle input[type="checkbox"] {
    cursor: pointer;
}

/* PHOTO TIMELINE LIGHTBOX */
.photo-gallery-modal {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 2000;
    background: rgba(0, 0, 0, 0.8);
    align-items: center;
    justify-content: center;
    padding: 2rem;
    box-sizing: border-box;
}

.photo-gallery-modal[hidden] {
    display: none !important;
}

.photo-gallery-content {
    position: relative;
    background: linear-gradient(145deg, var(--dark-green), #2e4b33);
    border-radius: 16px;
    border: 1px solid rgba(255, 255, 255, 0.15);
    padding: 1.5rem;
    max-width: 700px;
    width: 100%;
    max-height: 90vh;
    display: flex;
    flex-direction: column;
    box-sizing: border-box;
}

.photo-gallery-close {
    position: absolute;
    top: 0.75rem;
    right: 0.75rem;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: none;
    background: rgba(255, 255, 255, 0.1);
    color: var(--text-light);
    font-size: 1.3rem;
    line-height: 1;
    cursor: pointer;
}

.photo-gallery-close:hover {
    background: rgba(255, 255, 255, 0.2);
}

/* CLAIM CODE MODAL -- manual-entry twin of the QR-scan claim flow */
.claim-code-modal {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 2000;
    background: rgba(0, 0, 0, 0.8);
    align-items: center;
    justify-content: center;
    padding: 2rem;
    box-sizing: border-box;
}

.claim-code-modal[hidden] {
    display: none !important;
}

.claim-code-content {
    position: relative;
    background: linear-gradient(145deg, var(--dark-green), #2e4b33);
    border-radius: 16px;
    border: 1px solid rgba(255, 255, 255, 0.15);
    padding: 1.75rem;
    max-width: 360px;
    width: 100%;
    box-sizing: border-box;
    color: var(--text-light);
}

.claim-code-content h3 {
    margin: 0 2rem 0.5rem 0;
}

.claim-code-close {
    position: absolute;
    top: 0.75rem;
    right: 0.75rem;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: none;
    background: rgba(255, 255, 255, 0.1);
    color: var(--text-light);
    font-size: 1.3rem;
    line-height: 1;
    cursor: pointer;
}

.claim-code-close:hover {
    background: rgba(255, 255, 255, 0.2);
}

.claim-code-hint {
    font-size: 0.85rem;
    opacity: 0.85;
    margin: 0 0 1rem 0;
}

#claim-code-form {
    display: flex;
    gap: 0.5rem;
}

.claim-code-input {
    flex: 1;
    min-width: 0;
    padding: 0.6rem 0.75rem;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.25);
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-light);
    font-size: 1.3rem;
    letter-spacing: 0.05em;
    text-align: center;
}

.claim-code-submit {
    padding: 0.6rem 1rem;
    border: none;
    border-radius: 8px;
    background-color: var(--leaf-green);
    color: white;
    font-weight: bold;
    cursor: pointer;
}

.claim-code-submit:hover {
    background-color: var(--dark-green);
}

.claim-code-status {
    margin-top: 0.75rem;
    font-size: 0.85rem;
    min-height: 1.1em;
}

.photo-gallery-title {
    margin: 0 2.5rem 1rem 0;
    color: var(--text-light);
    font-size: 1.2rem;
}

.photo-gallery-main {
    display: flex;
    flex-direction: column;
    align-items: center;
    min-height: 0;
    flex: 1;
}

.photo-gallery-main-img {
    max-width: 100%;
    max-height: 50vh;
    object-fit: contain;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.05);
}

.photo-gallery-caption {
    margin-top: 0.75rem;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.6rem;
    color: var(--text-light);
    font-size: 0.85rem;
    text-align: center;
}

.photo-gallery-date {
    opacity: 0.85;
}

.photo-gallery-stage {
    background: rgba(255, 255, 255, 0.1);
    padding: 0.1rem 0.6rem;
    border-radius: 12px;
    font-weight: 600;
}

.photo-gallery-notes {
    opacity: 0.75;
    font-style: italic;
}

.photo-gallery-delete {
    margin-top: 0.75rem;
    border: none;
    border-radius: 8px;
    padding: 0.4rem 0.9rem;
    background: rgba(220, 53, 69, 0.15);
    color: #ff8a94;
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
}

.photo-gallery-delete:hover {
    background: rgba(220, 53, 69, 0.28);
}

.photo-gallery-delete:disabled {
    opacity: 0.5;
    cursor: default;
}

.photo-gallery-filmstrip {
    margin-top: 1rem;
    display: flex;
    gap: 0.5rem;
    overflow-x: auto;
    padding: 0.25rem;
    flex-shrink: 0;
}

.photo-gallery-thumb {
    width: 64px;
    height: 64px;
    object-fit: cover;
    border-radius: 8px;
    cursor: pointer;
    opacity: 0.6;
    border: 2px solid transparent;
    flex-shrink: 0;
    transition: opacity 0.15s ease, border-color 0.15s ease;
}

.photo-gallery-thumb:hover {
    opacity: 0.9;
}

.photo-gallery-thumb.active {
    opacity: 1;
    border-color: var(--leaf-green);
}

/***************************
          MEDIA
***************************/
@media (min-width: 2560px) {
    .chart-grid {
        grid-template-columns: repeat(auto-fit, minmax(700px, 800px)); /* Updated: Wider columns for better spacing */
        gap: 5rem; /* Updated: More breathing room */
        justify-content: center;
    }

    .chart-grid .tab-content {
        max-width: 800px; /* Updated: Allow more space for content */
        flex-direction: row; /* Ensure side-by-side layout */
    }


    /* Added: Prevent info-content from stretching too wide */
    .info-content {
        max-width: 400px;
    }

    /* Added: Cap chart width for readability */
    .chart-wrapper {
        max-width: 1600px;
    }
}

@media (min-width: 1600px) {
    .chart-grid {
        grid-template-columns: repeat(auto-fit, minmax(600px, 650px));
        gap: 4rem;
        justify-content: center;
    }

    .chart-grid .tab-content {
        max-width: 650px;
    }

}

@media (max-width: 1000px) {
    .chart-grid {
        grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
        justify-content: center;
    }

    /* Below this width there isn't room for 3 side columns plus a card,
       so the rail drops back to a horizontal strip above the cards
       (columns keep their own collapse state, they just lay out in a
       row instead of sitting sticky beside the grid). */
    .dashboard-layout {
        flex-direction: column;
    }

    .meter-rail {
        flex-direction: row;
        flex-wrap: wrap;
        position: static;
        width: 100%;
    }

    .meter-column {
        flex: 1 1 122px;
    }

    .meter-column.is-collapsed {
        flex: 0 0 40px;
    }

    .tab-content {
        flex-direction: column;
    }

    .tab-content.first-chart.full-row {
        grid-column: 1 / -1;
    }

    .plant-card.first-chart.full-row {
        grid-column: 1 / -1;
    }

    .info-content {
        width: 100%;
        margin-right: 0;
        margin-bottom: 1rem;
    }

    .chart-wrapper {
        height: 50vh;
    }

    canvas {
        height: 100% !important;
    }

    .averages-section {
        font-size: 0.8rem;
        gap: 0.5rem;
        padding: 0.4rem 0.8rem;
    }


    .meter-toggles-nav {
        align-self: flex-end;
        padding: 0;
    }
}

@media (max-width: 768px) {
    .charts-container,
    .chart-grid {
        grid-template-columns: 1fr;
        width: 95%;
        padding: 0 0.5rem;
    }

    .chart-grid .tab-content,
    .chart-container {
        width: 100%;
    }

    .chart-grid.multiple-charts .tab-content {
        grid-column: auto;
        width: 100%;
    }

    .controls {
        grid-template-columns: 1fr;
    }

    .context-submenu {
        left: auto;
        right: 100%;
        top: 0;
    }

    .chart-wrapper {
        height: 45vh;
    }


    .meter-toggles-nav {
        align-self: flex-end;
        padding: 0;
    }

    /* Mobile rail fix, round 2 (2026-09-14, Riley's brainstorm after
       Martin's mom's iPad testing showed round 1 still too tall): round 1
       (a single horizontally-scrollable row, still below) kept the strip
       from wrapping onto multiple rows, but each collapsed column's
       height still scaled with its rotated label's text length -- "MY TOP
       10 +1" turned sideways needs real room. Round 2 replaces the whole
       3-column pattern on mobile with the segmented control above
       (#meter-rail-tabs): exactly one group shows at a time, at a fixed
       height independent of any label, full width, normal (non-rotated)
       tiles. Round 1's rules stay as the fallback layout for the row
       itself (now holding just the one visible column). */
    .meter-rail-tabs {
        display: flex;
        border-radius: 8px;
        overflow: hidden;
        border: 1px solid rgba(255, 255, 255, 0.3);
        width: 100%;
        margin-bottom: 0.5rem;
    }

    .meter-rail-tab {
        flex: 1 1 0;
        text-align: center;
    }

    .meter-rail {
        flex-wrap: nowrap;
        overflow-x: auto;
        overflow-y: hidden;
        -webkit-overflow-scrolling: touch;
        padding-bottom: 0.35rem;
    }

    .meter-column {
        display: none;
    }

    .meter-column.is-mobile-active {
        display: flex;
        flex: 1 1 auto;
        width: 100%;
        max-height: none;
    }

    /* The tab bar already shows the title + count, so the column's own
       (possibly vertical-rl, if desktop had it collapsed) header would
       be redundant chrome at best and the exact problem we're fixing at
       worst -- hide it outright on mobile. */
    .meter-column.is-mobile-active .meter-column-header {
        display: none;
    }

    /* buildMeterColumn() sets the native `hidden` attribute on a
       collapsed section's body -- that's a desktop-only concept (see
       mobileActiveSection in index.html), so override it here whenever
       this is the mobile-selected column regardless of its desktop
       collapse state. Author rules win over the UA [hidden] rule at
       equal origin, no !important needed. */
    .meter-column.is-mobile-active .meter-column-body[hidden] {
        display: flex;
    }

    .meter-column.is-mobile-active .meter-column-body {
        max-height: 45vh;
        overflow-y: auto;
    }

    /* Header compaction (2026-09-14, Riley + Dani, round 2 of the mobile
       feedback -- the rail fix above landed but the header itself was
       still taking up roughly a third to a half of the screen before any
       plant data appeared). .dashboard-toolbar is a wrapping flex row;
       at phone width there isn't room for brand + Active Meters + Time
       Range + Temp Units + the nav buttons side by side, so each one was
       dropping to its own full-width row. The single biggest offender
       was the nav row: "Multi Meter View" and "Register Device" wrapped
       their labels onto 2-3 lines each at this width, so that one row
       alone was roughly as tall as the rest of the header combined.
       Fix: `order` regroups the toolbar's existing children into 3 tight
       rows (brand; Active Meters + Time Range + Temp Units together;
       nav buttons) instead of 5, and the nav buttons drop to icon-only
       on mobile -- the emoji was already there as a leading icon via
       ::before, so it becomes the whole button instead of adding new
       markup. Labels aren't deleted, just visually hidden, so screen
       readers still get them (see aria-label added on the buttons/link
       themselves in index.html, since a hidden span no longer
       contributes to the accessible name). */
    .dashboard-toolbar {
        padding: 0.4rem 0.75rem;
        gap: 0.3rem 0.6rem;
    }

    .toolbar-brand {
        order: 1;
    }

    .toolbar-brand h1 {
        font-size: 1.15rem;
    }

    .toolbar-status {
        order: 2;
        font-size: 0.8rem;
    }

    .toolbar-field {
        order: 2;
        font-size: 0.8rem;
        gap: 0.3rem;
    }

    .toolbar-field label,
    .toolbar-field > span:first-child {
        font-size: 0.8rem;
    }

    .toolbar-field select {
        max-width: 128px;
        padding: 0.25rem 0.4rem;
        font-size: 0.78rem;
    }

    .unit-toggle button {
        padding: 0.3rem 0.5rem;
        font-size: 0.78rem;
    }

    .meter-toggles-nav {
        order: 3;
        flex-basis: 100%;
        justify-content: space-between;
        margin-left: 0;
        padding-top: 0.1rem;
    }

    .nav-button {
        padding: 0.4rem 0.55rem;
        gap: 0;
    }

    /* Text hidden, not removed -- aria-label on the element itself (see
       index.html) keeps it announced to screen readers. */
    .nav-button span {
        display: none;
    }

    .nav-button.compare::before,
    .nav-button.back::before,
    .nav-button.claim::before {
        font-size: 1.3rem;
    }

    .toolbar-account-toggle {
        padding: 0.3rem 0.4rem;
        gap: 0.3rem;
    }

    .toolbar-username,
    .toolbar-role-badge {
        display: none;
    }
}

@media (max-width: 400px) {
    body {
        padding: 0.5rem;
    }

    .header {
        flex-direction: column;
        gap: 1rem;
        padding: 0.5rem;
    }

    header h1 {
        font-size: 1.8rem;
    }

    .charts-container,
    .chart-grid {
        width: 95%;
        padding: 0 0.25rem;
    }

    .chart-wrapper {
        height: 40vh;
    }

    .averages-section {
        font-size: 0.75rem;
        flex-wrap: wrap;
    }

    .control-group label {
        font-size: 0.9rem;
    }


    .meter-toggles-nav {
        align-self: flex-end;
        padding: 0;
    }
}

/* Copyright/version footer (2026-09-10) -- click to fetch and reveal
   the Docker image's GIT_COMMIT/BUILD_TIME (see /version in app.py),
   mirroring the firmware's own build_info.h version check so Martin can
   confirm the dashboard he's looking at matches what he expects to be
   live. */
.app-footer {
    flex: 0 0 auto;
    margin-top: 0;
    padding: 0.5rem 1.5rem;
    text-align: right;
    font-size: 0.75rem;
    color: #f2e8d5;
}

.app-footer-copyright {
    border: none;
    background: transparent;
    padding: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
    text-decoration: underline dotted;
}

.app-footer-copyright:hover {
    opacity: 0.8;
}

.app-footer-learn-more {
    color: inherit;
    text-decoration: underline dotted;
}

.app-footer-learn-more:hover {
    opacity: 0.8;
}

.app-version-detail {
    margin-top: 0.25rem;
    font-family: "Courier New", monospace;
    color: #f2e8d5;
}
