* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--bg: #121212;
--surface: #1e1e1e;
--primary: #bb86fc;
--on-bg: #e0e0e0;
--on-surface: #ffffff;
--positive: #cf6679;
--negative: #03dac6;
--muted: #888;
--border: #333;
--radius: 8px;
--safe-area-top: env(safe-area-inset-top, 0px);
--safe-area-bottom: env(safe-area-inset-bottom, 0px);
}
html, body {
height: 100%;
}
body {
font-family: system-ui, -apple-system, sans-serif;
background: var(--bg);
color: var(--on-bg);
font-size: 16px;
line-height: 1.4;
overflow-x: hidden;
-webkit-tap-highlight-color: transparent;
}
#app {
max-width: 600px;
margin: 0 auto;
height: 100%;
display: flex;
flex-direction: column;
}
@media (min-width: 768px) {
#app { max-width: 100%; padding: 0 24px; }
.summary-row { gap: 12px; padding: 14px 16px; }
.gps-map { height: 450px; }
.sd-map { height: 400px; }
.modal { max-width: 100%; }
.sd-row { gap: 16px; }
.sd-val { font-size: 22px; }
.products-screen, .settings-screen { max-width: 700px; margin: 0 auto; }
.log-section { max-width: 700px; margin: 0 auto; }
.day-header, .summary-row, .micro-strip { max-width: 700px; margin-left: auto; margin-right: auto; }
}
/* Header / date navigation */
.day-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
padding-top: calc(12px + var(--safe-area-top));
background: var(--surface);
border-bottom: 1px solid var(--border);
position: sticky;
top: 0;
z-index: 10;
}
.day-header button {
background: none;
border: none;
color: var(--primary);
font-size: 24px;
padding: 8px;
cursor: pointer;
border-radius: var(--radius);
}
.day-header button:active {
background: rgba(187, 134, 252, 0.15);
}
.day-header .date-text {
font-size: 18px;
font-weight: 500;
color: var(--on-surface);
}
/* Weight display */
.weight-row {
padding: 8px 16px;
background: var(--surface);
border-bottom: 1px solid var(--border);
font-size: 14px;
color: var(--muted);
}
.weight-row span {
color: var(--on-surface);
font-weight: 500;
}
/* Entry list */
.entries {
flex: 1;
overflow-y: auto;
padding: 8px 0;
}
.entry-item {
display: grid;
grid-template-columns: 50px 1fr 70px;
align-items: center;
padding: 10px 16px;
border-bottom: 1px solid var(--border);
}
.entry-item:active {
background: rgba(255, 255, 255, 0.05);
}
.entry-time {
font-size: 13px;
color: var(--muted);
}
.entry-desc {
font-size: 15px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.entry-kcal {
text-align: right;
font-size: 14px;
font-weight: 500;
}
.entry-kcal.intake {
color: var(--positive);
}
.entry-kcal.expenditure {
color: var(--negative);
}
/* Balance summary */
.balance-bar {
display: flex;
justify-content: space-around;
padding: 12px 16px;
background: var(--surface);
border-top: 1px solid var(--border);
font-size: 14px;
}
.balance-bar .label {
color: var(--muted);
font-size: 12px;
}
.balance-bar .value {
font-size: 18px;
font-weight: 600;
}
.balance-bar .value.deficit {
color: var(--negative);
}
.balance-bar .value.surplus {
color: var(--positive);
}
/* FAB (add button) */
.fab {
position: fixed;
bottom: 80px;
right: 24px;
width: 56px;
height: 56px;
border-radius: 50%;
background: var(--primary);
color: #000;
border: none;
font-size: 28px;
font-weight: 300;
cursor: pointer;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
display: flex;
align-items: center;
justify-content: center;
}
.fab:active {
transform: scale(0.95);
}
/* Bottom nav — see .nav-btn below for button styles */
/* Modal / add entry overlay */
.modal-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.7);
z-index: 100;
display: flex;
align-items: flex-end;
justify-content: center;
}
.modal-sheet {
background: var(--surface);
width: 100%;
max-width: 480px;
border-radius: 16px 16px 0 0;
padding: 20px 16px;
max-height: 85vh;
overflow-y: auto;
}
.modal-sheet h2 {
font-size: 18px;
margin-bottom: 16px;
color: var(--on-surface);
}
/* Form elements */
.form-group {
position: relative;
margin-bottom: 14px;
}
.form-group label {
display: block;
font-size: 13px;
color: var(--muted);
margin-bottom: 4px;
}
.form-group input,
.form-group select,
.form-group textarea {
width: 100%;
padding: 10px 12px;
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--on-surface);
font-size: 16px;
font-family: inherit;
color-scheme: dark;
-webkit-appearance: none;
appearance: none;
}
/* Toggle switch: a checkbox styled as a sliding on/off switch. Overrides the
full-width .form-group input rule above (which otherwise stretches a checkbox
into an empty box). Apply class="toggle" to . */
.form-group input[type="checkbox"].toggle {
width: 46px;
height: 26px;
flex: 0 0 auto;
padding: 0;
border-radius: 13px;
background: var(--bg);
border: 1px solid var(--border);
position: relative;
cursor: pointer;
transition: background 0.15s, border-color 0.15s;
}
.form-group input[type="checkbox"].toggle::after {
content: "";
position: absolute;
top: 50%;
left: 3px;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--muted);
transform: translateY(-50%);
transition: left 0.15s, background 0.15s;
}
.form-group input[type="checkbox"].toggle:checked {
background: var(--primary);
border-color: var(--primary);
}
.form-group input[type="checkbox"].toggle:checked::after {
left: 23px;
background: #fff;
}
select {
background: var(--bg);
color: var(--on-surface);
color-scheme: dark;
}
.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
outline: none;
border-color: var(--primary);
}
.type-chips {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.type-chip {
padding: 6px 14px;
border-radius: 20px;
border: 1px solid var(--border);
background: none;
color: var(--on-bg);
font-size: 14px;
cursor: pointer;
}
.type-chip.selected {
background: var(--primary);
color: #000;
border-color: var(--primary);
}
.btn-row {
display: flex;
gap: 12px;
margin-top: 16px;
}
.btn {
flex: 1;
padding: 12px;
border-radius: var(--radius);
border: none;
font-size: 16px;
font-family: inherit;
cursor: pointer;
}
.btn-primary {
background: var(--primary);
color: #000;
font-weight: 600;
}
.btn-secondary {
background: var(--border);
color: var(--on-bg);
}
/* Setup screen */
.setup-screen {
padding: 24px 16px;
display: flex;
flex-direction: column;
gap: 20px;
min-height: 100vh;
justify-content: center;
}
.setup-screen h1 {
font-size: 24px;
color: var(--on-surface);
text-align: center;
}
.setup-screen p {
color: var(--muted);
text-align: center;
font-size: 14px;
}
/* Kcal preview */
.kcal-preview {
padding: 10px 12px;
background: rgba(187, 134, 252, 0.1);
border-radius: var(--radius);
text-align: center;
font-size: 18px;
font-weight: 500;
color: var(--primary);
}
/* Empty state */
.empty-state {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
color: var(--muted);
font-size: 15px;
padding: 40px;
text-align: center;
}
/* Screen layout */
.bottom-nav {
order: 2;
display: flex;
background: var(--surface);
border-top: 1px solid var(--border);
position: sticky;
bottom: 0;
}
.screen-content {
order: 1;
flex: 1;
overflow-y: auto;
padding-bottom: 8px;
}
/* Gap-fill preview panel (track detail): floats above the bottom, dismissible. */
.gap-panel {
position: fixed;
left: 8px;
right: 8px;
bottom: calc(16px + var(--safe-area-bottom));
background: var(--surface);
color: var(--on-bg);
border: 1px solid var(--border);
border-radius: 10px;
padding: 10px 12px;
z-index: 100000;
box-shadow: 0 2px 14px rgba(0,0,0,0.55);
display: flex;
flex-direction: column;
gap: 8px;
font-size: 14px;
}
.gap-panel-hint { color: var(--muted); font-size: 12px; }
.gap-panel-btns { display: flex; gap: 8px; }
.gap-panel-btns button { flex: 1; padding: 8px 12px; }
.nav-btn {
flex: 1;
background: none;
border: none;
color: var(--muted);
font-size: 12px;
padding: 14px 4px;
padding-bottom: calc(14px + var(--safe-area-bottom));
cursor: pointer;
font-family: inherit;
text-align: center;
-webkit-tap-highlight-color: rgba(187,134,252,0.15);
}
.nav-btn:active {
background: rgba(187,134,252,0.1);
}
.nav-btn.active {
color: var(--primary);
font-weight: 600;
border-top: 2px solid var(--primary);
}
/* Day navigation */
.day-header h2 {
font-size: 15px;
font-weight: 500;
text-align: center;
}
.day-nav {
background: none;
border: none;
color: var(--primary);
font-size: 20px;
padding: 4px 10px;
cursor: pointer;
}
/* Summary cards */
.summary-row {
display: flex;
gap: 8px;
padding: 10px 12px;
background: var(--surface);
border-bottom: 1px solid var(--border);
}
.summary-card {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
padding: 6px 4px;
border-radius: var(--radius);
background: var(--bg);
}
.summary-val {
font-size: 18px;
font-weight: 700;
}
.summary-lbl {
font-size: 10px;
color: var(--muted);
text-align: center;
}
.summary-card.surplus .summary-val { color: #cf6679; }
.summary-card.deficit .summary-val { color: #03dac6; }
.summary-card.balanced .summary-val { color: var(--on-bg); }
/* Log sections */
.log-section {
padding: 0 0 4px;
border-bottom: 1px solid var(--border);
}
.section-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 14px 4px;
}
.section-header h3 {
font-size: 13px;
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.add-btn {
background: none;
border: 0.5px solid var(--border);
border-radius: 6px;
color: var(--primary);
font-size: 22px;
line-height: 1;
cursor: pointer;
padding: 4px 10px;
min-width: 40px;
min-height: 36px;
display: flex;
align-items: center;
justify-content: center;
}
.log-list {
list-style: none;
padding: 0;
margin: 0;
}
.log-item {
display: flex;
align-items: center;
gap: 8px;
padding: 7px 14px;
border-top: 1px solid rgba(255,255,255,0.04);
}
.log-time {
font-size: 12px;
color: var(--muted);
min-width: 38px;
}
.log-desc {
flex: 1;
font-size: 14px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.log-desc small {
color: var(--muted);
margin-left: 4px;
font-size: 11px;
}
.log-kcal {
font-size: 13px;
color: var(--muted);
min-width: 52px;
text-align: right;
}
.log-empty {
padding: 6px 14px;
font-size: 13px;
color: var(--muted);
font-style: italic;
}
.del-btn {
background: none;
border: none;
color: #555;
font-size: 14px;
cursor: pointer;
padding: 2px 4px;
flex-shrink: 0;
}
.del-btn:active { color: #cf6679; }
.food-edit-item { cursor: pointer; }
.food-edit-item:active { background: rgba(255,255,255,0.05); }
.food-edit-item .log-desc { white-space: normal; }
/* Sleep info */
.sleep-info {
padding: 6px 14px 8px;
display: flex;
flex-direction: column;
gap: 2px;
}
.sleep-line {
font-size: 13px;
color: var(--on-bg);
}
/* Modal */
.modal-overlay {
position: fixed;
inset: 0;
background: var(--bg);
z-index: 500;
display: flex;
align-items: stretch;
justify-content: center;
}
.modal {
background: var(--surface);
width: 100%;
border-radius: 0;
padding: 0;
height: 100%;
padding-top: var(--safe-area-top);
padding-bottom: var(--safe-area-bottom);
display: flex;
flex-direction: column;
}
.modal-header {
display: flex;
align-items: center;
padding: 12px 16px;
border-bottom: 1px solid var(--border);
flex-shrink: 0;
}
.modal-back {
background: none;
border: none;
color: var(--primary);
font-size: 20px;
padding: 4px 8px 4px 0;
cursor: pointer;
}
.modal-body {
flex: 1;
overflow-y: auto;
padding: 16px 16px 8px;
}
.modal h3 {
font-size: 17px;
margin-bottom: 16px;
}
.modal-btns {
display: flex;
gap: 10px;
padding: 12px 16px;
border-top: 1px solid var(--border);
flex-shrink: 0;
}
/* In-app confirm / prompt dialog — centered card over a dimmed backdrop,
above full-screen modals (z-index 500) and fullscreen maps (9999). */
.confirm-overlay {
background: rgba(0, 0, 0, 0.6);
align-items: center;
padding: 0 24px;
z-index: 10000;
}
.confirm-box {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 20px 18px 16px;
width: 100%;
max-width: 340px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}
.confirm-msg {
font-size: 15px;
line-height: 1.4;
margin-bottom: 16px;
color: var(--on-bg);
}
.confirm-input {
width: 100%;
padding: 10px;
margin-bottom: 16px;
background: var(--bg);
border: 1px solid var(--border);
border-radius: 4px;
color: var(--on-bg);
font-size: 15px;
}
.confirm-btns {
display: flex;
gap: 10px;
}
.confirm-btns button {
flex: 1;
}
.btn-primary, .btn-secondary {
flex: 1;
padding: 12px;
border-radius: var(--radius);
border: none;
font-size: 16px;
font-family: inherit;
cursor: pointer;
}
.btn-primary {
background: var(--primary);
color: #000;
font-weight: 600;
}
.btn-secondary {
background: var(--border);
color: var(--on-bg);
}
.full-width { width: 100%; }
/* HR-only workout (зарядка) recording screen: big heart rate, timer, kcal, no map. */
.workout-screen { padding: 24px 16px; display: flex; flex-direction: column; align-items: center; gap: 8px; }
.wk-hr-big { font-size: 92px; font-weight: 700; line-height: 1; color: var(--primary); }
.wk-hr-lbl { color: var(--muted); margin-top: -4px; }
.wk-stats { display: flex; gap: 18px; margin: 14px 0; flex-wrap: wrap; justify-content: center; }
.wk-stat { display: flex; flex-direction: column; align-items: center; min-width: 64px; }
.wk-val { font-size: 22px; font-weight: 600; }
.wk-lbl { font-size: 12px; color: var(--muted); }
.wk-status { color: var(--muted); font-size: 13px; text-align: center; min-height: 18px; margin-bottom: 6px; }
.workout-screen .btn-primary, .workout-screen .btn-secondary { margin-top: 8px; width: 100%; }
/* HR on/off toggle on the record screen (replaces the wind button): grey = off, coloured = on. */
.rec-hr-toggle { color: #888; display: inline-flex; align-items: center; justify-content: center; gap: 4px;
/* Strap battery as a background fill, bottom-up, 0-100% (--bat), coloured by level (--bat-color). */
background-image: linear-gradient(to top, var(--bat-color, transparent) var(--bat, 0%), transparent var(--bat, 0%)); }
.rec-hr-toggle svg { display: block; }
.rec-hr-toggle.active { color: #fff; } /* HR on = white icon + bpm (over the battery fill) */
.rec-hr-num { font-size: 15px; font-weight: 700; min-width: 0; }
.rec-hr-num:empty { display: none; }
/* Progress fill for long-running action buttons: the background fills left-to-right by
--pct (0-100%, set from JS). The label stays on top and readable; the unfilled part keeps
the button's own background. Used by recompute / elevation-refine / roads-rebuild. */
.btn-progress {
background-image: linear-gradient(90deg, var(--primary) var(--pct, 0%), rgba(0,0,0,0) var(--pct, 0%));
transition: background-image 0.15s linear;
}
/* Products screen */
.products-screen, .stub-screen, .settings-screen {
padding: 16px;
padding-top: calc(16px + var(--safe-area-top));
}
.settings-section {
margin-bottom: 16px;
background: var(--surface);
border-radius: var(--radius);
overflow: hidden;
}
.settings-section-title {
font-size: 11px;
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.5px;
padding: 8px 14px 4px;
}
.settings-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 14px;
border-bottom: 1px solid var(--border);
cursor: pointer;
}
.settings-item:last-child { border-bottom: none; }
.settings-item:active { background: rgba(255,255,255,0.03); }
.settings-item-title {
font-size: 15px;
color: var(--on-surface);
}
.settings-item-desc {
font-size: 12px;
color: var(--muted);
margin-top: 2px;
}
.settings-arrow {
font-size: 20px;
color: var(--muted);
}
.settings-toggle {
width: 44px;
height: 24px;
border-radius: 12px;
border: none;
background: var(--border);
position: relative;
cursor: pointer;
flex-shrink: 0;
transition: background 0.2s;
}
.settings-toggle::after {
content: "";
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--on-bg);
transition: transform 0.2s;
}
.settings-toggle.on {
background: var(--primary);
}
.settings-toggle.on::after {
transform: translateX(20px);
}
.products-screen h2, .stub-screen h2, .settings-screen h2 {
font-size: 20px;
margin-bottom: 16px;
}
.stub-note {
color: var(--muted);
font-size: 14px;
margin-top: 8px;
}
.search-input {
width: 100%;
padding: 10px 14px;
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--on-surface);
font-size: 16px;
font-family: inherit;
margin-bottom: 8px;
}
.search-input:focus {
outline: none;
border-color: var(--primary);
}
/* Product count & hint */
.prod-count {
font-size: 12px;
color: var(--muted);
padding: 0 0 8px;
}
.prod-hint {
color: var(--muted);
font-size: 14px;
font-style: italic;
padding: 20px 0;
text-align: center;
}
.prod-list {
display: flex;
flex-direction: column;
gap: 6px;
max-height: calc(100vh - 209px - var(--safe-area-top) - var(--safe-area-bottom));
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.prod-list .prod-card {
flex-shrink: 0;
}
/* Product card — collapsed */
.prod-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
transition: border-color 0.15s;
}
.prod-card.open {
border-color: var(--primary);
}
.prod-card-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 12px;
cursor: pointer;
gap: 8px;
}
.prod-card-header:active {
background: rgba(255,255,255,0.03);
}
.prod-card-name {
flex: 1;
font-size: 14px;
line-height: 1.3;
}
.prod-brand {
display: inline;
color: var(--muted);
font-size: 12px;
margin-left: 4px;
}
.prod-weight {
display: inline;
color: var(--muted);
font-size: 11px;
margin-left: 4px;
}
.prod-card-kcal {
font-size: 13px;
color: var(--muted);
white-space: nowrap;
flex-shrink: 0;
}
/* Product card — expanded */
.prod-details {
padding: 0 12px 12px;
border-top: 1px solid var(--border);
}
.prod-macros {
display: flex;
gap: 4px;
padding: 10px 0 8px;
}
.macro {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
padding: 6px 4px;
background: var(--bg);
border-radius: var(--radius);
}
.macro-val {
font-size: 15px;
font-weight: 600;
color: var(--on-surface);
}
.macro-lbl {
font-size: 10px;
color: var(--muted);
margin-top: 2px;
}
.prod-composition {
font-size: 12px;
color: var(--muted);
line-height: 1.4;
margin-bottom: 10px;
max-height: 80px;
overflow-y: auto;
}
.prod-add-btn {
width: 100%;
padding: 10px;
font-size: 14px;
}
/* Modal product search */
.search-dropdown {
position: absolute;
left: 0;
right: 0;
z-index: 100;
max-height: 60vh;
overflow-y: auto;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
box-shadow: 0 4px 16px rgba(0,0,0,0.5);
-webkit-overflow-scrolling: touch;
}
.search-dropdown .sd-item,
.search-dropdown .modal-prod-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 12px;
cursor: pointer;
border-bottom: 1px solid var(--border);
font-size: 14px;
}
.search-dropdown .sd-item:active,
.search-dropdown .modal-prod-item:active {
background: rgba(255,255,255,0.05);
}
.sd-item-kcal {
color: var(--muted);
font-size: 13px;
white-space: nowrap;
margin-left: 8px;
}
.search-dropdown .prod-card {
border: none;
border-bottom: 1px solid var(--border);
border-radius: 0;
background: transparent;
}
.modal-search-results {
position: absolute;
left: 0;
right: 0;
z-index: 100;
max-height: 50vh;
overflow-y: auto;
margin-top: 2px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
box-shadow: 0 4px 16px rgba(0,0,0,0.5);
-webkit-overflow-scrolling: touch;
}
.modal-prod-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 10px;
border-bottom: 1px solid var(--border);
cursor: pointer;
font-size: 13px;
gap: 8px;
}
.modal-prod-item:active {
background: rgba(187, 134, 252, 0.1);
}
.modal-selected {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 10px;
margin-bottom: 10px;
background: rgba(187, 134, 252, 0.12);
border-radius: var(--radius);
font-size: 14px;
color: var(--primary);
cursor: pointer;
}
.modal-selected:active {
background: rgba(187, 134, 252, 0.2);
}
/* Micronutrient strip on Today */
.micro-strip {
display: flex;
gap: 6px;
padding: 8px 12px;
overflow-x: auto;
flex-shrink: 0;
scrollbar-width: none;
}
.micro-strip::-webkit-scrollbar { display: none; }
.micro-chip {
display: inline-block;
padding: 3px 8px;
border-radius: 12px;
font-size: 11px;
font-weight: 600;
flex-shrink: 0;
}
.micro-low { background: rgba(207,102,121,0.2); color: #cf6679; }
.micro-mid { background: rgba(255,183,77,0.2); color: #ffb74d; }
.micro-ok { background: rgba(3,218,198,0.2); color: #03dac6; }
/* GPS screen */
.gps-screen {
display: flex;
flex-direction: column;
height: 100%;
}
.gps-map {
height: 250px;
width: 100%;
background: #1a1a1a;
flex-shrink: 0;
z-index: 1;
}
/* Floating recording bar */
.rec-floating-bar {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
padding-top: calc(8px + var(--safe-area-top));
background: rgba(187, 134, 252, 0.15);
border-bottom: 1px solid var(--primary);
cursor: pointer;
order: 0;
}
.rec-bar-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: #f44336;
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
}
#rec-bar-text {
font-size: 13px;
color: var(--primary);
font-weight: 500;
}
/* Recording screen */
.rec-screen {
display: flex;
flex-direction: column;
height: 100%;
}
.rec-panel {
flex-shrink: 0;
}
.draw-screen {
display: flex;
flex-direction: column;
height: 100%;
}
.draw-map {
flex: 1;
min-height: 200px;
}
/* Route editor bottom bar: compact hint on top, buttons in a row, cancel below. */
.re-bottom {
display: flex;
flex-direction: column;
gap: 6px;
padding: 6px 12px;
padding-bottom: calc(6px + var(--safe-area-bottom));
background: var(--surface);
border-top: 1px solid var(--border);
}
.re-hint {
font-size: 11px;
line-height: 1.25;
color: var(--muted);
text-align: center;
}
.re-btns {
display: flex;
gap: 8px;
}
.re-btns button {
flex: 1;
padding: 9px 6px;
font-size: 13px;
}
.re-cancel {
color: #cf6679;
padding: 6px;
font-size: 13px;
}
/* Invisible fat hit target for route legs — clickable despite zero opacity. */
.re-hit { pointer-events: stroke; }
/* Share image ("Похвастаться") preview modal. */
.share-modal {
position: fixed;
inset: 0;
z-index: 100000;
background: rgba(0,0,0,0.88);
display: flex;
align-items: center;
justify-content: center;
padding: 16px;
padding-top: calc(16px + var(--safe-area-top));
padding-bottom: calc(16px + var(--safe-area-bottom));
}
.share-box {
display: flex;
flex-direction: column;
gap: 10px;
align-items: center;
max-width: 100%;
max-height: 100%;
}
.share-preview {
max-width: 100%;
max-height: 54vh;
object-fit: contain;
border-radius: 10px;
/* checkerboard so a transparent PNG reads as transparent */
background-image:
linear-gradient(45deg, #3a3a3a 25%, transparent 25%, transparent 75%, #3a3a3a 75%),
linear-gradient(45deg, #3a3a3a 25%, #262626 25%, #262626 75%, #3a3a3a 75%);
background-size: 24px 24px;
background-position: 0 0, 12px 12px;
}
.share-toggle, .share-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.share-toggle button, .share-actions button { padding: 9px 14px; }
.share-fields {
display: flex; flex-wrap: wrap; gap: 6px 12px; justify-content: center;
max-width: 520px;
}
.share-field {
display: inline-flex; align-items: center; gap: 5px;
font-size: 13px; color: #ddd; white-space: nowrap; cursor: pointer;
}
.share-field input { width: 16px; height: 16px; flex: none; }
.rec-map-wrap {
flex: 1;
min-height: 200px;
position: relative;
}
.rec-map {
position: absolute;
inset: 0;
}
.rec-map-btn {
position: absolute;
z-index: 1000;
width: 32px;
height: 32px;
border-radius: 4px;
border: 1px solid var(--border);
background: rgba(30, 30, 30, 0.8);
color: var(--on-bg);
font-size: 14px;
font-weight: 700;
cursor: pointer;
}
.rec-map-btn.active {
background: rgba(255, 255, 255, 0.5);
color: #1a1a1a;
border-color: rgba(255, 255, 255, 0.6);
}
.rec-rotate-btn { right: 8px; bottom: 48px; font-size: 18px; transition: transform 0.15s; }
.rec-freeze-btn { right: 8px; bottom: 86px; }
.rec-roads-toggle { right: 8px; bottom: 124px; }
.rec-mode-btn { right: 8px; bottom: 162px; font-size: 11px; }
.rec-route-toggle { right: 8px; bottom: 200px; }
.rec-dark-toggle { right: 8px; bottom: 238px; }
.rec-follow-btn { right: 8px; bottom: 276px; font-size: 18px; }
/* nogo (⛔) and reroute (↪) had no position class — they piled at the map's top-left over the
zoom controls. Give them slots in the right-hand stack. */
.rec-nogo-btn { right: 8px; bottom: 314px; }
.rec-reroute-btn { right: 8px; bottom: 352px; }
/* Left-hand group (bottom-left), opposite the right control stack: SMS + live toggle. */
.rec-sms-btn { left: 8px; bottom: 48px; font-size: 11px; }
.rec-live-btn { left: 8px; bottom: 86px; font-size: 10px; }
.rec-share-btn { left: 8px; bottom: 124px; font-size: 11px; }
/* Route editor: danger indicator (fords / rough tracks the route passes). */
.re-danger { color: #ff7043; font-size: 13px; font-weight: 600; min-height: 16px; margin: 2px 0; text-align: center; }
/* Dark map: invert ONLY the tile layer (track, route, puck keep their colours).
User-tuned filter on OSM standard tiles. Applies to every Leaflet map. */
body.dark-map .leaflet-tile-pane { filter: invert(1) hue-rotate(180deg) brightness(1.5); }
/* Roads overlay was tuned for LIGHT tiles, so on inverted (dark) tiles it blended in.
Give the roads pane the SAME filter as the tiles so road colours shift identically and
stay contrasting. Roads live in `roadsPane` (record screen SVG + roads screen canvas). */
body.dark-map .leaflet-roadsPane { filter: invert(1) hue-rotate(180deg) brightness(1.5); }
/* Darken the map backdrop too, else the light Leaflet container (#ddd) flashes bright
between/behind tiles while zooming or where a tile is missing. */
body.dark-map .leaflet-container { background: #1b1f24; }
/* POI overlay: circular contrasting icon badges (readable on light & dark tiles). */
.poi-badge-wrap { background: none; border: none; }
.poi-badge {
width: 26px; height: 26px; line-height: 22px; text-align: center; font-size: 15px;
background: #fff; border: 2px solid #222; border-radius: 50%;
box-shadow: 0 1px 3px rgba(0,0,0,.5);
}
body.dark-map .poi-badge { background: #111; border-color: #eee; }
.poi-panel {
margin-top: 4px; max-height: 55vh; overflow: auto; min-width: 150px;
background: var(--surface); border: 1px solid var(--border); border-radius: 6px;
padding: 6px 8px; box-shadow: 0 2px 8px rgba(0,0,0,.45);
}
.poi-row { display: block; font-size: 13px; color: var(--on-bg); padding: 2px 0; cursor: pointer; white-space: nowrap; }
.poi-head { font-weight: 600; border-bottom: 1px solid var(--border); margin-bottom: 4px; padding-bottom: 4px; }
.poi-btn.active { background: rgba(255,255,255,0.5); color: #1a1a1a; }
#re-brouter.active { background: #4caf50; color: #fff; }
/* Always-on compass needle: red half = North, grey = South. Rotates to point to real north.
Top-RIGHT (zoom controls are top-left), below the status-bar safe area. */
/* Position/direction puck (SVG divIcon) — no default leaflet-div-icon box. */
.rec-puck { background: none; border: none; pointer-events: none; }
.rec-puck svg { display: block; overflow: visible; }
.rec-compass {
position: absolute; top: calc(8px + var(--safe-area-top, 0px)); right: 8px; z-index: 1001;
width: 40px; height: 40px; border-radius: 50%;
background: rgba(20,20,20,0.8); border: 1px solid var(--border);
cursor: pointer;
}
/* Keep Leaflet zoom controls below the status bar on the recording map. */
/* The top strip (.rec-topbar) now sits above the map and already backs the status bar, so the
map no longer draws under the status bar — no backdrop strip, and controls start at the map top. */
.rec-map-wrap .leaflet-top { margin-top: 0; }
.rec-screen.rot-90 .rec-map-wrap::before,
.rec-screen.rot-270 .rec-map-wrap::before { display: none; }
.rec-compass-arrow { position: absolute; inset: 0; transition: transform 0.12s linear; }
.rec-compass-arrow::before {
content: "N"; position: absolute; top: 1px; left: 50%; transform: translateX(-50%);
color: #f44336; font: 700 11px sans-serif;
}
.rec-compass-arrow::after {
content: ""; position: absolute; left: 50%; top: 14px; bottom: 6px; width: 3px; margin-left: -1.5px;
background: linear-gradient(to bottom, #f44336 0 55%, #9e9e9e 55% 100%);
border-radius: 2px;
}
.gps-placeholder {
position: absolute;
inset: 0;
z-index: 1000;
background: url('../img/gps-placeholder.png') center/cover;
display: flex;
align-items: center;
justify-content: center;
}
.gps-placeholder-text {
background: rgba(0,0,0,0.7);
color: var(--on-bg);
padding: 12px 24px;
border-radius: 8px;
font-size: 18px;
}
/* Manual screen rotation (rotate button). 90/270 = landscape (swap dims, panel to side).
180 is intentionally not used — it would flip the panel text upside down.
Map compensates via setBearing(heading - rotOffset). */
.rec-screen.rot-90,
.rec-screen.rot-270 {
position: fixed;
width: 100vh;
height: 100vw;
top: calc((100vh - 100vw) / 2);
left: calc((100vw - 100vh) / 2);
z-index: 9999;
flex-direction: row;
}
.rec-screen.rot-90 { transform: rotate(90deg); }
.rec-screen.rot-270 { transform: rotate(270deg); }
.rec-screen.rot-90 .rec-map-wrap,
.rec-screen.rot-270 .rec-map-wrap { min-height: 0; }
.rec-screen.rot-90 .rec-panel,
.rec-screen.rot-270 .rec-panel {
width: 200px;
flex-shrink: 0;
display: flex;
flex-direction: column;
justify-content: space-evenly;
border-left: 1px solid var(--border);
}
.rec-screen.rot-90 .rec-stats,
.rec-screen.rot-270 .rec-stats {
flex-direction: column;
border-top: none;
padding: 8px;
gap: 2px;
}
.rec-screen.rot-90 .rec-bottom .rec-status,
.rec-screen.rot-270 .rec-bottom .rec-status { display: none; }
.rec-screen.rot-90 .rec-hr-row,
.rec-screen.rot-270 .rec-hr-row { display: none; }
.rec-stats {
display: flex;
justify-content: space-around;
padding: 12px 8px;
background: var(--surface);
border-top: 1px solid var(--border);
}
.rec-stat {
display: flex;
flex-direction: column;
align-items: center;
}
.rec-val {
font-size: 27px;
font-weight: 700;
color: var(--on-surface);
}
/* Top strip (external info): training time (left), temperature (centre), clock (right).
Same big digits as the bottom stats (.rec-val). */
.rec-topbar {
display: flex; justify-content: space-between; align-items: baseline;
padding: 4px 16px; padding-top: calc(4px + var(--safe-area-top));
background: var(--surface);
}
.rec-topbar .rec-top { font-size: 27px; font-weight: 700; color: var(--on-surface); }
.rec-topbar .rec-top-mid { color: var(--on-surface); }
.rec-lbl {
font-size: 10px;
color: var(--muted);
text-transform: uppercase;
}
.rec-hr-row { display:flex; align-items:baseline; justify-content:center; gap:8px; padding:6px 8px; background:var(--surface); border-top:1px solid var(--border); }
.rec-hr-val { font-size:42px; font-weight:700; }
.rec-hr-unit { font-size:14px; color:var(--muted); }
.rec-hr-extra { font-size:14px; color:var(--muted); margin-left:12px; }
.hr-zone-green { color:#81c784; }
.hr-zone-yellow { color:#ffb74d; }
.hr-zone-orange { color:#ff8a65; }
.hr-zone-red { color:#ef5350; }
.rec-bottom {
display: flex;
align-items: stretch;
gap: 8px;
padding: 6px 8px;
padding-bottom: calc(6px + var(--safe-area-bottom));
background: var(--surface);
}
/* All three controls (HR toggle, pause, stop) share the width equally — no clustering right.
border-box + one padding so the different per-button paddings don't make them unequal. */
.rec-bottom > button { flex: 1 1 0; box-sizing: border-box; min-width: 0; padding: 12px 8px; }
.gps-header {
padding: 10px 12px;
padding-top: calc(10px + var(--safe-area-top));
background: var(--surface);
border-bottom: 1px solid var(--border);
}
.gps-btns {
display: flex;
gap: 8px;
align-items: center;
}
.gps-type-sel {
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--on-bg);
padding: 8px 10px;
font-size: 14px;
font-family: inherit;
color-scheme: dark;
}
.gps-type-sel option {
background: var(--surface);
color: var(--on-bg);
}
.gps-rec {
flex: 1;
padding: 10px;
font-size: 16px;
}
.gps-rec.recording {
background: #cf6679;
}
.gps-menu-wrap {
position: relative;
}
.gps-menu-btn {
background: var(--border);
border: none;
color: var(--on-bg);
font-size: 20px;
padding: 8px 12px;
border-radius: var(--radius);
cursor: pointer;
line-height: 1;
}
.gps-menu {
position: absolute;
right: 0;
top: 100%;
margin-top: 4px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
z-index: 50;
min-width: 200px;
box-shadow: 0 4px 12px rgba(0,0,0,0.4);
}
.gps-menu.hidden { display: none; }
.gps-menu-item {
padding: 10px 14px;
font-size: 14px;
cursor: pointer;
white-space: nowrap;
}
.gps-menu-item:active {
background: rgba(187, 134, 252, 0.1);
}
/* Session detail */
.sd-section {
margin-bottom: 16px;
}
.sd-title {
font-size: 13px;
color: var(--primary);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 8px;
font-weight: 600;
}
/* Collapsible section (native ): header stays visible, body folds away
so the action buttons below aren't buried under a long segment list. */
.sd-acc-title {
cursor: pointer;
list-style: none;
display: flex;
align-items: center;
gap: 8px;
user-select: none;
padding: 6px 0;
}
.sd-acc-title::-webkit-details-marker { display: none; }
.sd-acc-title::before {
content: "\25B8"; /* ▸ */
display: inline-block;
transition: transform 0.15s;
font-size: 11px;
}
.sd-accordion[open] .sd-acc-title::before { transform: rotate(90deg); }
.sd-acc-count {
background: var(--border);
color: var(--on-bg);
border-radius: 10px;
padding: 1px 8px;
font-size: 11px;
font-weight: 600;
}
/* Repeat / interval analysis table + verdict */
.repeats-head { font-size: 12px; color: var(--on-bg); opacity: 0.8; margin-bottom: 8px; }
.repeats-tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
.repeats-tbl th, .repeats-tbl td { padding: 5px 6px; text-align: right; border-bottom: 1px solid var(--border); }
.repeats-tbl th:first-child, .repeats-tbl td:first-child { text-align: left; }
.repeats-tbl th { color: var(--primary); font-weight: 600; }
.repeats-verdict { margin-top: 10px; padding: 10px; border-radius: var(--radius); text-align: center; line-height: 1.4; }
.repeats-verdict .rv-num { font-size: 22px; font-weight: 700; }
.repeats-verdict.ok { background: rgba(46, 160, 67, 0.18); color: #4caf50; }
.repeats-verdict.warn { background: rgba(255, 179, 0, 0.16); color: #ffb300; }
.repeats-verdict.bad { background: rgba(207, 102, 121, 0.18); color: #cf6679; }
.sd-row {
display: flex;
gap: 8px;
margin-bottom: 6px;
}
.sd-stat {
flex: 1;
display: flex;
flex-direction: column;
}
.sd-val {
font-size: 18px;
font-weight: 700;
color: var(--on-surface);
}
.sd-lbl {
font-size: 11px;
color: var(--muted);
text-transform: uppercase;
}
.sd-map {
height: 200px;
border-radius: var(--radius);
overflow: hidden;
cursor: pointer;
touch-action: pan-y pinch-zoom;
}
.sd-map-full {
position: fixed !important;
inset: 0 !important;
height: 100vh !important;
width: 100vw !important;
max-width: none !important;
z-index: 9999;
border-radius: 0;
}
.sd-map-full .leaflet-top {
top: var(--safe-area-top) !important;
}
.sd-map-full .leaflet-bottom {
bottom: var(--safe-area-bottom) !important;
}
.sd-map-fs-btn {
position: relative;
z-index: 10000;
}
.sd-map-fs-btn {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--on-bg);
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 18px;
box-shadow: 0 2px 6px rgba(0,0,0,0.3);
}
.sd-map-fs-btn.active {
background: rgba(255, 255, 255, 0.5);
color: #1a1a1a;
border-color: rgba(255, 255, 255, 0.6);
}
.sd-smooth-panel {
position: fixed;
z-index: 10001;
left: 8px;
bottom: 8px;
width: 210px;
background: rgba(20, 20, 20, 0.93);
color: #eee;
font-size: 12px;
padding: 8px 10px;
border-radius: 6px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
}
.sd-smooth-panel label { display: block; margin: 6px 0 2px; }
.sd-smooth-panel input[type=range] { width: 100%; }
.sd-smooth-panel .sm-stat { margin: 4px 0; color: #9be89b; }
.zoom-display {
background: rgba(0,0,0,0.6);
color: #fff;
font-size: 13px;
font-weight: 700;
padding: 2px 6px;
border-radius: 4px;
}
.chart-wrap {
position: relative;
cursor: pointer;
height: 200px;
width: 100%;
}
/* Block touch on canvas when chart is minimized — lets page scroll normally.
Clicks on the .chart-wrap div still work (pointer-events: auto on parent). */
.chart-wrap:not(.chart-full) canvas {
pointer-events: none;
}
.chart-full {
position: fixed;
left: 0;
top: var(--safe-area-top);
z-index: 9999;
background: var(--bg);
width: 100vw;
height: calc(100vh - var(--safe-area-top) - var(--safe-area-bottom));
}
.chart-close-btn {
position: absolute;
top: calc(12px + var(--safe-area-top));
right: calc(12px + var(--safe-area-right, 0px));
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--on-bg);
font-size: 18px;
cursor: pointer;
z-index: 10000;
}
.point-popup .leaflet-popup-content-wrapper {
background: var(--surface);
color: var(--on-bg);
font-size: 12px;
border-radius: 6px;
padding: 4px 8px;
}
.point-popup .leaflet-popup-tip {
background: var(--surface);
}
.gps-download-status {
text-align: center;
font-size: 12px;
color: var(--primary);
padding: 6px 0;
}
.gps-sessions {
flex: 1;
overflow-y: auto;
padding: 8px 12px;
}
.gps-sessions h3 {
font-size: 13px;
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 8px;
}
.gps-session-item {
padding: 10px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
margin-bottom: 6px;
cursor: pointer;
}
.gps-session-item:active {
border-color: var(--primary);
}
.gps-session-item.selected {
border-color: var(--primary);
background: color-mix(in srgb, var(--primary) 20%, var(--surface));
box-shadow: inset 0 0 0 1px var(--primary);
}
/* Floating action bar for multi-select merge (sits above the bottom tab bar) */
.gps-sel-bar {
position: fixed;
left: 0; right: 0;
bottom: calc(56px + var(--safe-area-bottom));
z-index: 90;
display: flex;
align-items: center;
gap: 10px;
padding: 10px 16px;
background: var(--surface);
border-top: 1px solid var(--border);
box-shadow: 0 -2px 8px rgba(0,0,0,0.3);
}
.gps-sel-bar[hidden] { display: none; }
/* "Split here" button inside a point popup — visible only when the map is in split mode */
.split-here {
display: inline-block;
margin-top: 6px;
padding: 4px 10px;
background: #ff9800;
color: #000;
border: none;
border-radius: 4px;
font-size: 12px;
font-weight: 600;
cursor: pointer;
}
#sd-map:not(.split-mode) .split-here { display: none; }
.gps-sel-bar #gps-sel-count { flex: 1; font-size: 14px; }
.gps-sel-bar button { padding: 8px 14px; }
.gps-session-head {
display: flex;
justify-content: space-between;
font-size: 13px;
margin-bottom: 4px;
}
.gps-session-type {
color: var(--primary);
font-size: 12px;
}
.gps-session-stats {
font-size: 12px;
color: var(--muted);
}
.supp-summary {
padding: 0 12px 8px;
font-size: 11px;
color: var(--muted);
line-height: 1.3;
}
/* Supplement pick list (in modal) */
.supp-pick-list {
display: flex;
flex-direction: column;
gap: 4px;
max-height: 200px;
overflow-y: auto;
}
.supp-pick-item {
padding: 8px 10px;
border: 1px solid var(--border);
border-radius: var(--radius);
cursor: pointer;
font-size: 14px;
}
.supp-pick-item.selected {
border-color: var(--primary);
background: rgba(187, 134, 252, 0.12);
color: var(--primary);
}
.supp-pick-item:active {
background: rgba(187, 134, 252, 0.08);
}
.supp-pick-divider {
padding: 6px 10px 2px;
font-size: 11px;
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.5px;
}
/* Micronutrient grid in supplement edit modal */
.micro-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px 12px;
}
.micro-field label {
font-size: 11px;
}
.micro-field input {
padding: 6px 8px;
font-size: 14px;
}
/* Per-food-item nutrient line */
.src-badge {
display: inline-block;
font-size: 10px;
padding: 1px 5px;
border-radius: 3px;
vertical-align: middle;
margin-left: 4px;
font-weight: 600;
}
.src-magnit { background: rgba(229, 57, 53, 0.25); color: #ef5350; }
.src-5ka { background: rgba(129, 199, 132, 0.2); color: #a5d6a7; }
.src-kdv { background: rgba(255, 167, 38, 0.25); color: #ffb74d; }
.src-ion { background: rgba(158, 158, 158, 0.2); color: #9e9e9e; }
.src-manual { background: rgba(255, 235, 59, 0.2); color: #fff176; }
.src-chzn { background: rgba(66, 165, 245, 0.22); color: #64b5f6; }
.food-nutrients {
font-size: 11px;
color: var(--muted);
margin-top: 2px;
white-space: normal;
}
/* Daily nutrient totals strip — chips sorted by deficiency */
.nutrient-strip {
display: flex;
flex-wrap: wrap;
gap: 6px;
padding: 8px 14px;
cursor: pointer;
}
/* Collapsed: single scrollable row */
.nutrient-strip.nutrient-collapsed {
flex-wrap: nowrap;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
}
.nutrient-strip.nutrient-collapsed::-webkit-scrollbar { display: none; }
.nut-item {
font-size: 12px;
padding: 3px 8px;
border-radius: 12px;
background: var(--surface);
border: 1px solid var(--border);
}
.nut-low { color: #f44336; border-color: #f44336; }
.nut-mid { color: #ffb74d; border-color: #ffb74d; }
.nut-ok { color: #81c784; border-color: #81c784; }
/* Recipe components */
/* Guessed nutrients indicator — slight tint on food items with estimated micronutrients */
.log-item.guessed {
background: rgba(187, 134, 252, 0.2);
}
.seed-progress {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 60vh;
gap: 12px;
padding: 0 32px;
}
.seed-label {
color: var(--on-bg);
font-size: 16px;
}
.seed-bar {
width: 100%;
max-width: 300px;
height: 8px;
background: var(--surface);
border-radius: 4px;
overflow: hidden;
}
.seed-bar-fill {
height: 100%;
width: 30%;
background: var(--primary);
border-radius: 4px;
animation: seed-slide 1.2s ease-in-out infinite;
}
@keyframes seed-slide {
0% { margin-left: 0%; }
50% { margin-left: 70%; }
100% { margin-left: 0%; }
}
/* When progress is known, switch to determinate mode */
.seed-bar-fill.determinate {
animation: none;
margin-left: 0;
transition: width 0.3s;
}
.drink-bar-wrap { padding: 6px 14px; display: flex; align-items: center; gap: 8px; }
.drink-label { font-size: 12px; color: var(--muted); white-space: nowrap; }
.drink-bar { flex: 1; height: 6px; background: var(--surface); border-radius: 3px; overflow: hidden; }
.drink-bar-fill { height: 100%; border-radius: 3px; transition: width 0.3s; }
.drink-bar-fill.low { background: #cf6679; }
.drink-bar-fill.mid { background: #ffb74d; }
.drink-bar-fill.ok { background: #81c784; }
.seed-count {
color: var(--muted);
font-size: 13px;
}
.sub-tabs {
display: flex;
gap: 0;
margin-bottom: 12px;
border-bottom: 1px solid var(--border);
}
.sub-tab {
flex: 1;
background: none;
border: none;
color: var(--muted);
font-size: 14px;
padding: 8px 0;
cursor: pointer;
border-bottom: 2px solid transparent;
}
.sub-tab.active {
color: var(--primary);
border-bottom-color: var(--primary);
}
.recipe-macros-hint {
padding: 2px 12px 8px;
font-size: 12px;
color: var(--muted);
}
.recipe-ing-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 0;
border-bottom: 1px solid rgba(255,255,255,0.04);
}
.recipe-ing-info {
flex: 1;
display: flex;
align-items: baseline;
gap: 8px;
overflow: hidden;
}
.recipe-ing-name {
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.recipe-ing-weight {
font-size: 12px;
color: var(--muted);
flex-shrink: 0;
}
.recipe-ing-cm {
font-size: 11px;
color: var(--primary);
flex-shrink: 0;
}
.recipe-totals {
padding: 10px 0;
font-size: 15px;
font-weight: 600;
color: var(--primary);
text-align: center;
}
/* Unit chips (alternative food units) */
.unit-chips {
display: flex;
gap: 6px;
overflow-x: auto;
padding: 4px 0;
margin-bottom: 8px;
}
.unit-chip {
padding: 4px 12px;
border-radius: 16px;
font-size: 13px;
border: 1px solid var(--border);
background: transparent;
color: var(--on-bg);
cursor: pointer;
white-space: nowrap;
font-family: inherit;
}
.unit-chip.selected {
background: var(--primary);
color: #000;
border-color: var(--primary);
}
/* Stats charts */
.stats-chart-block {
margin-bottom: 16px;
padding: 0 14px;
}
.stats-period {
display: flex;
gap: 4px;
}
/* Loading */
.loading {
text-align: center;
padding: 40px;
color: var(--muted);
}
/* Climb segments (session detail) */
.climb-segments {
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
}
.segment-item {
display: flex;
gap: 8px;
padding: 8px;
border-bottom: 1px solid var(--border);
align-items: center;
}
.segment-item:last-child {
border-bottom: none;
}
.segment-item.climb .seg-icon {
color: #f44336;
font-weight: 700;
}
.segment-item.descent .seg-icon {
color: #4caf50;
font-weight: 700;
}
.segment-item.flat .seg-icon {
color: var(--muted);
}
.seg-icon {
width: 20px;
text-align: center;
font-size: 16px;
}
.seg-info {
flex: 1;
font-size: 13px;
}
.seg-stats {
font-size: 12px;
color: var(--muted);
white-space: nowrap;
}
/* Bike maintenance list */
.maint-item {
display: flex;
align-items: center;
padding: 8px;
border-bottom: 1px solid var(--border);
gap: 8px;
}
.maint-item:last-child {
border-bottom: none;
}
.maint-overdue {
background: rgba(244, 67, 54, 0.08);
}
.maint-info {
flex: 1;
font-size: 13px;
display: flex;
gap: 6px;
flex-wrap: wrap;
align-items: center;
}
.maint-date {
color: var(--muted);
font-size: 12px;
min-width: 40px;
}
.maint-desc {
font-weight: 500;
}
.maint-km {
font-size: 12px;
color: var(--muted);
}
.maint-warn {
color: #f44336;
font-weight: 700;
}
.maint-del {
background: none;
border: none;
color: var(--muted);
font-size: 18px;
cursor: pointer;
padding: 4px 8px;
font-family: inherit;
}
.maint-del:active {
color: #f44336;
}
/* Compare session list */
.compare-list {
max-height: 60vh;
overflow-y: auto;
}
.compare-item {
padding: 12px;
border: 1px solid var(--border);
border-radius: var(--radius);
margin-bottom: 8px;
cursor: pointer;
}
.compare-item:active {
border-color: var(--primary);
background: rgba(187, 134, 252, 0.05);
}
/* 7-day balance trend (IDEA 6) */
.balance-trend {
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
padding: 6px 12px;
background: var(--surface);
border-bottom: 1px solid var(--border);
min-height: 0;
}
.balance-trend:empty {
display: none;
}
.balance-trend-label {
font-size: 12px;
color: var(--muted);
}
.balance-trend-val {
font-size: 14px;
font-weight: 700;
}
.trend-deficit {
color: #03dac6;
}
.trend-surplus {
color: #cf6679;
}
/* Goal markers (IDEA 2) */
.goal-markers-list {
display: flex;
flex-direction: column;
gap: 6px;
max-height: 50vh;
overflow-y: auto;
}
.goal-marker-card {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 12px;
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--radius);
}
.goal-marker-info {
flex: 1;
}
.goal-marker-name {
font-size: 14px;
font-weight: 600;
color: var(--on-surface);
}
.goal-marker-coords {
font-size: 11px;
color: var(--muted);
margin-top: 2px;
}
.goal-marker-notes {
font-size: 12px;
color: var(--muted);
margin-top: 2px;
font-style: italic;
}
/* Goal marker map (add marker modal) */
.gm-map-wrap {
margin-top: 8px;
}
.gm-map {
height: 250px;
border-radius: var(--radius);
overflow: hidden;
}
.gm-coords {
font-size: 12px;
color: var(--muted);
margin-top: 4px;
text-align: center;
}
/* Goal markers in session detail */
.goal-marker-item {
padding: 8px 0;
border-bottom: 1px solid rgba(255,255,255,0.04);
}
.goal-marker-item:last-child {
border-bottom: none;
}
.goal-marker-dist {
font-size: 12px;
color: var(--muted);
margin-top: 2px;
}
.goal-bar-wrap {
height: 6px;
background: var(--border);
border-radius: 3px;
margin-top: 6px;
overflow: hidden;
}
.goal-bar-fill {
height: 100%;
background: var(--primary);
border-radius: 3px;
transition: width 0.3s;
}
.goal-progress {
font-size: 11px;
color: var(--muted);
margin-top: 4px;
display: block;
}
.goal-better {
color: #03dac6;
}
.goal-worse {
color: #cf6679;
}
/* Food cost of workout (IDEA 8) */
.food-cost {
padding: 4px 0;
}
.food-cost-total {
font-size: 16px;
font-weight: 700;
color: var(--on-surface);
margin-bottom: 6px;
}
.food-cost-items {
display: flex;
flex-direction: column;
gap: 2px;
}
.food-cost-line {
font-size: 14px;
color: var(--on-bg);
padding: 2px 0;
}
.food-cost-or {
font-size: 12px;
color: var(--muted);
font-style: italic;
padding: 0 0 0 8px;
}