Select the date range for your cardiologist report:
ClinBridge logs your blood pressure, heart rate, weight, fluid intake, symptoms, medications, meals, and activities — then analyzes the patterns over time so you and your cardiologist have real evidence to work from, not just a single office reading.
Four Advanced Analytics detectors continuously watch for clinically meaningful changes: sustained heart rate shifts, decompensation warning signs, pulse pressure trends, and symptom convergence patterns. Sentinel goes further — it watches for the personal pre-event patterns that came before your own prior clinical events, not population averages. When any tool finds something significant, it tells you what was found and why it matters — in plain language.
ClinBridge is a pattern awareness tool, not a diagnostic device. It does not diagnose, prescribe, or replace your care team. All findings are described as directional — they point toward patterns worth discussing with your cardiologist, never toward a conclusion. The phrase you will see throughout the app: "Math is directional, not definitive."
ClinBridge adapts to you — your conditions, your doctor's targets, your care plan. It needs three things from you first. After that, just start logging. The app will guide you to everything else as your data builds.
Your doctor asked you to track your blood pressure — start there. Log it every time you take a reading using the Log Blood Pressure button on the main screen.
If your doctor also mentioned fluid intake, weight, or symptoms — turn those on in Settings → Tracking Features. Each one adds a button to the main screen.
Everything else can wait. The more you log, the more ClinBridge learns about your patterns — and it will let you know when a new feature is ready to be useful to you.
As your data builds, Sentinel — the status banner on your main screen — will periodically surface one suggestion at a time. Not a list of everything the app can do. Just the one thing that's most useful to you right now, based on what you've already logged. Tap the banner anytime to see it.
Use the full setup guide below to configure everything at once — medications, daily schedule, notifications, and advanced features.
Sentinel is separate from the four detectors and works differently. Instead of watching for population-based thresholds, it watches for your personal pre-event patterns. Every time you pin a clinical event, Sentinel extracts what your data looked like in the 72 hours before it — your Footprint. When your live data resembles a prior Footprint, Sentinel tells you which event it matches and how. Tap 🛡️ Sentinel on the main screen to open it. See the 🛡️ Sentinel tab in this guide for the full explanation.
Analyzes your full HR history to find level shifts — periods where your resting heart rate durably changed to a new baseline — and rapid changes — sudden single-session jumps. Requires 6+ days of HR readings. Use the Today / 7 Days / 30 Days / All Time buttons to narrow the window. A "🔍 Investigate" button on any finding opens Anchor Date Investigation for that exact date.
Monitors five clinical signals simultaneously: weight gain, cardiac output (HR + pulse pressure), symptom frequency, fluid intake patterns, and notes keyword scan. Each signal is scored individually. The composite result ranges from ✅ All Clear → 📋 Early Indicator (1 signal) → ⚠️ Monitor Closely (2+ signals) → 🚨 Contact Cardiologist (multiple red signals). One signal alone is not cause for alarm — the value is in seeing multiple signals converge.
Pulse pressure is systolic minus diastolic BP. Normal range is 40–60 mmHg. A narrowing trend can indicate the heart is working harder to maintain output; a widening trend may indicate arterial stiffness. Many cardiac patients have a chronically reduced PP that is their personal baseline — the detector recognizes this and labels it "Chronically Narrow — Your Stable Baseline" rather than an acute alert. What matters is change from your baseline, not comparison to a textbook number.
Analyzes 30 days of symptom logs across three layers: (1) Intraday clusters — 3+ symptoms within a 4-hour window on the same day; (2) Multi-day escalation — the same symptom worsening in severity across multiple days; (3) Clinical triads — recognized symptom combinations with known cardiac significance (e.g., shortness of breath + fatigue + edema). The 60-day Timeline tab shows where clusters occurred visually.
When any detector finds a significant event (yellow or red), it suggests pinning it. Pinned events are saved permanently — they never roll off with the 90-day data window. Each pin captures the detector's full finding plus all raw log data for that date.
Pinned events appear in three places: the 📌 Pinned Events button in Analytics, the 60-day Timeline as amber markers, and your Doctor's Report as a dedicated section.
After your cardiologist appointment: use "Archive & Clear" to permanently save the current pins and start fresh for the next period. An appointment nudge reminds you automatically.
All four detectors use statistical pattern detection on self-reported data. The math is directional, not definitive. A finding means: "this pattern is present in your data and worth discussing." It does not mean: "something is wrong." Findings can reflect real clinical changes, data entry errors, device variability, or normal day-to-day fluctuation. Your cardiologist provides the clinical interpretation — ClinBridge provides the data and the pattern recognition to make that conversation more productive.
ClinBridge includes built-in safety checks that can block a medication dose before it is logged. These checks run automatically every time you tap Save in Log Medicine.
If a medicine has a condition check set, a blood pressure reading within the last 4 hours is required before the dose can be logged. If no recent reading exists, a block screen appears with a Log BP Now button. After logging BP, return to Log Medicine — your previous selection is automatically restored.
If your current BP or heart rate reading fails a medicine's condition threshold, the dose is blocked. The block screen shows the medicine name, what the condition requires, your actual current reading, and all three vitals against your target ranges. Use the Update Condition button if the threshold needs adjusting, or tap Back to return to Log Medicine.
Each medicine has a minimum time between doses based on its schedule — twice daily means 6 hours minimum, once daily means 12 hours, every 2 days means 48 hours. If your last logged dose was too recent, the block screen shows exactly when you last took it and how long you must wait. Never double dose — if you missed a dose and the next one is close, skip and resume your normal schedule.
When your reading falls between your warn threshold and your block threshold, a caution screen appears. You can still log the dose — but you must acknowledge the risk first. This is designed for situations where the reading is low but not critically so, and your judgment matters. Warn thresholds are set in the Medication Intelligence panel, not in Manage Medicines.
If your most recent pulse pressure (systolic minus diastolic) is below your approved PP warn threshold, a separate caution screen appears before logging certain medications. This is especially relevant for beta blockers and ARBs, which can further narrow PP. Your PP warn threshold and recovery target are set in the Medication Intelligence panel.
If your average HR over the last 3 readings is above your target ceiling (default 80 bpm, or your MIP-approved HR warn threshold), a caution screen appears. A single high reading is not sufficient to trigger this — three consecutive elevated readings are required, which is the clinically appropriate threshold for sustained elevation.
Open Manage Medicines and tap Edit on any medicine. Scroll to the Condition Check section at the bottom. Select the vital to check (Diastolic BP, Systolic BP, or Heart Rate), enter a threshold number, and choose whether to block when the reading is below or above that threshold. The condition note is generated automatically from your settings — no manual text entry needed. For dynamic thresholds derived from your own data, use the Medication Intelligence panel instead.
For medications taken every other day or on a similar pattern, select Every X days (custom) in the frequency dropdown and enter the number of days. Every other day = 2. The minimum interval block uses this number directly — a medicine set to every 2 days requires 48 hours between logged doses.
When you edit a medicine and change its name, ClinBridge asks what changed. Choose Correcting a typo to update all history to the new name. Choose New dose or formulation to keep history under the old name, mark the old medicine as Discontinued today, and start tracking the new name from today. This preserves your before/after history for clinical analysis.
If a red banner appears at the top of the app saying safety checks are disabled, a data integrity problem was detected. This may be caused by a storage error or data edited outside the app.
To restore safety checks: delete any BP readings or medications logged today and re-enter them through the app. Safety checks re-enable automatically on the next save. If the banner keeps appearing, export your backup and contact support at clinbridgeapp@gmail.com.
A threshold that was correct in March may be wrong in August. Your clinical picture shifts — pacemaker adjustments, medication holds, seasonal changes, acute illness. A fixed number baked into the app has no way to know when your baseline has moved. The Medication Intelligence Panel solves this by computing thresholds from your actual recent data and surfacing them for your review.
The panel displays your data across three windows simultaneously:
The panel uses a clinically validated method based on your personal mean and standard deviation:
These numbers are derived from research on home blood pressure monitoring and individual BP variability published in peer-reviewed hypertension literature. A coefficient of variation of approximately 9.9% for systolic BP in home monitoring settings supports using ±1 SD as a meaningful clinical boundary.
The panel suggests — you decide. Nothing changes in the medication safety system until you tap Approve & Activate. You can also override any suggested threshold with your own number. Your personal clinical judgment — informed by your doctor's guidance — always takes precedence over the algorithm.
When you approve a threshold, ClinBridge automatically syncs it into the medicine's condition rules. A block rule is created (or updated) at the block threshold, and a warn rule is created at the warn threshold — so the condition rule engine and the Intelligence Panel are always in agreement. If you have already set a manual rule for the same metric, its threshold is updated in-place while preserving your chosen outcome (block or warn).
Approved PP thresholds sync a warn rule across all active medicines automatically. You can review any synced rule in Manage Medicines and adjust it at any time — manual edits are never overwritten by the MIP.
Pulse pressure (systolic minus diastolic) is tracked separately in the panel. PP is a surrogate for stroke volume — narrow PP suggests the heart is pumping less effectively per beat. The panel lets you set a PP warn threshold and a recovery target, which are used to surface a caution screen before logging medications known to affect PP.
For cardiac patients, a PP consistently below 25 mmHg is associated with reduced cardiac output. The panel tracks your personal PP baseline so your threshold is grounded in your own data, not population norms.
Each medicine can now have up to 4 condition rules. Each rule checks one vital sign (Systolic BP, Diastolic BP, Heart Rate, or Pulse Pressure) against a threshold and either blocks or warns when the reading crosses it.
Rules are set in Manage Medicines — tap any medicine and scroll to the Condition Rules section. The rule builder shows a plain-English preview before saving. Legacy single-condition medicines migrate automatically. Rules created by the Intelligence Panel are labelled MIP-approved with the approval date so you can always tell them apart from rules you wrote manually.
You can tag each medicine with its drug class (Beta Blocker, ARB, SGLT2 Inhibitor, etc.). ClinBridge auto-suggests the class from the medicine name — you confirm or change it. The class is used in the Intelligence Panel to group related medicines and offer to copy condition rules when two medicines share the same class.
Example: if you set up Metoprolol 12.5mg with block rules and later add Metoprolol 25mg (also tagged Beta Blocker), the panel offers one tap to copy the same rules over — then you adjust the thresholds for the new dose.
When you open ClinBridge, the main screen shows sections that each track one part of your health. Each section is called a card. There are nine cards:
Each card shows today's data by default. Tap a tile in Today's Status to open a card. Each card has a 📋 View History button to see up to 90 days of that card's data with search and filter options.
Each card only shows its own data. The BP card shows your blood pressure. The Symptoms card shows your symptoms. But your health doesn't work in separate columns — everything is connected.
Deep Dive shows how consistently you logged each medicine. For the numbers to be accurate, each medicine needs to be set up correctly in your Medicine List.
Deep Dive can only work with data you've logged. A day where you took your medicine but forgot to log it shows as a missed dose. A symptom you didn't log isn't counted.
You don't need to be perfect. Logging BP once a day and medicines daily gives ClinBridge enough to find meaningful patterns. Consistency over weeks matters more than completeness on any single day.
A Pinned Event is a flagged finding from one of ClinBridge's four detectors — captured permanently, along with the full raw data behind it, so it never disappears when your 90-day rolling window advances. It is the difference between "I thought I noticed something" and "here is the exact date, the exact reading, and every data point around it."
Any single detector firing on any single day is background noise. What ClinBridge watches for is convergence — two or more independent detectors flagging the same time window from different directions. When your HR level-shifts and your pulse pressure narrows and your symptom frequency rises in the same week, that combination is clinically meaningful in a way that no individual reading can be.
A single yellow flag: worth watching. Three yellow flags on the same week: worth showing your cardiologist.
Open Pinned Events before your appointment. Each detector-backed pin card now shows a “What to Say at Your Appointment” box with a pre-written sentence generated directly from your detector data. You do not have to figure out how to explain it — just read it aloud exactly as written.
After reading, ask: “Does this line up with anything you’re seeing in my chart? Is it worth investigating further, or is it within normal variation for my condition?”
The sentences in the “What to Say” box are generated entirely from detector data — not from your written notes or your memory. You cannot edit them, and that is by design.
This means the app stands behind every word it generates. If you choose to say something different at your appointment, that is your right — but the documented, data-backed language is always there as your record. A cardiologist reading a timestamped, algorithm-generated sentence weighted by your personal baseline carries more clinical credibility than a patient’s self-description.
A patient using ClinBridge chose to share their experience and gave permission for it to be discussed here. They have a pacemaker and had been logging their heart rate daily for several weeks. The HR Rate Detector identified a durable level shift — a point where the resting heart rate had measurably settled into a new, stable baseline distinctly different from the weeks before it. The change wasn't a single bad reading. It was a sustained pattern across multiple days that the algorithm confirmed as statistically significant.
The pacemaker's remote monitoring system reviewed the same time period during its scheduled download. It did not flag the shift. The clinical team saw nothing requiring follow-up.
The patient brought the Pinned Event to their next cardiology appointment and read it aloud. The cardiologist reviewed the supporting data, confirmed the shift was real, and ordered follow-up testing. The window between device downloads — where most of daily life happens — is exactly the gap that self-logged, multi-stream data is built to fill.
You can now create a pin directly — without needing a detector finding. Tap the ✏️ Add button in the Pinned Events modal header to open the manual pin form.
Manual pins are ideal for: questions you want to raise at your next appointment, observations that don't come from a detector (a symptom pattern you noticed, a concern after a medication change), or anything clinically important you want to preserve and surface at your next visit.
Manual pins appear with a ✏️ Manual Entry label and support all pin features — communication log, question list, status tracking, and inclusion in the Doctor's Report.
On the morning this feature was designed, the builder logged a wake HR of 81 bpm. After 5 minutes of extended-exhale breathing, HR was 67 bpm — a drop of 14 bpm with no medication, no equipment, and no cost. That documented response, in a cardiac patient with a pacemaker, is the entire reason this feature exists.
The Breathing Logger is a pattern awareness tool and data logger. It guides you through a timed breathing session, logs your HR before and after, tracks your personal response over time, and includes that data in your Doctor's Report. It is not a treatment, not a prescription, and not a substitute for your care team. It is a way to capture something real that is otherwise invisible.
How it works physiologically: When you exhale slowly and fully, the vagus nerve — a long nerve running from the brainstem to the heart — sends a parasympathetic signal that tells the sinoatrial node (your heart's natural pacemaker) to slow down. This is called the vagal brake. The longer the exhale relative to the inhale, the stronger this braking effect. This is not a theory — it is the same mechanism used in formal cardiac rehabilitation programs.
Heart rate variability (HRV): HRV is the variation in time between heartbeats. Higher HRV generally means your autonomic nervous system is flexible and responsive — a sign of cardiac resilience. Low HRV is an independent predictor of poor outcomes in heart failure patients. Slow, paced breathing — especially at around 6 breaths per minute (the 5-5 resonance frequency) — has been shown in multiple studies to acutely increase HRV. Some cardiac rehabilitation programs use this technique explicitly.
Sympathetic overdrive in CHF: In heart failure, the sympathetic nervous system is chronically overactivated — the body tries to compensate for reduced cardiac output by raising HR and constricting blood vessels. This compensation is initially helpful but becomes harmful over time. Extended-exhale breathing directly counters sympathetic overdrive by activating the opposing parasympathetic system. This is why the effect can be surprisingly large in cardiac patients.
ClinBridge does not claim this technique treats your condition. The research cited here is the reason the feature was built as a logger — not a prescriber. Your cardiologist interprets what your personal response data means for your health.
The rule behind all three: The exhale must be at least 1.5× to 2× the inhale to activate the vagal brake. Equal breathing (1:1 ratio) produces little parasympathetic effect. The longer and slower the exhale, the stronger the signal to the sinoatrial node.
On the timer: The active session shows a countdown ("4:13 remaining") in large teal text so you always know where you are. The number turns amber in the final 60 seconds. A progress bar tracks overall completion. The cycle counter shows how many complete breath cycles you've done.
This technique is most likely to show a measurable response in people with:
Always confirm with your cardiologist before starting any new self-management practice, particularly if your condition has changed recently.
The rate floor: Your pacemaker is programmed with a lower rate limit — a minimum HR it will not let your heart drop below (commonly 60 bpm). If your resting HR is at or near this floor, the vagal brake has nothing to work against. The pacemaker will maintain its minimum rate regardless of the parasympathetic signal from breathing. A response of 0–3 bpm in this situation is expected and normal — it does not mean the technique is ineffective for you overall.
Rate-responsive pacing: Some pacemakers adjust their rate based on detected activity or minute ventilation (breathing effort). Deep, slow breathing could theoretically interact with a minute-ventilation sensing pacemaker. This is uncommon but worth asking your device clinic about.
What to ask at your next device check: "What is my lower rate limit set to? Does my device use minute ventilation sensing? Is slow paced breathing appropriate given my current programming?"
A reminder that you have a pacemaker is shown on screen during every active session.
Tap 📋 View Session History to see all past sessions and your personal response profile.
The history view is cumulative — it shows all sessions ever logged, not just the current date range.
When you generate a Doctor's Report and breathing sessions exist in the selected date range, a dedicated Breathing Sessions — Vagal Response Log section appears automatically. It includes:
The report explicitly states that all HR values are patient self-reported from manual pulse check or personal device — no clinical device integration. This protects both you and your cardiologist from over-interpreting the data.
This tool is for relaxation and pattern awareness only. It is not a medical treatment and does not replace your care team's guidance. HR values are self-reported — math is directional, not definitive.
Do not use this tool if you are experiencing: chest discomfort, shortness of breath beyond normal breathing effort, dizziness, pre-syncope (feeling faint), or a new arrhythmia. These require medical contact, not a breathing session.
Discuss use of breathing techniques with your cardiologist before starting, particularly if you have a pacemaker, ICD, severe arrhythmia, active decompensation, or have been hospitalized in the last 4 weeks.
Your heart already works harder than most. In hot weather, it must also pump extra blood to your skin to cool your body — on top of whatever activity you're doing. This dual demand can trigger dangerous drops in blood pressure, arrhythmias, or acute decompensation, especially with conditions like heart failure, hypertension, or a pacemaker/ICD.
ClinBridge automatically matches conditions in your profile against a list of cardiac and metabolic conditions known to increase heat risk: Heart Failure, Hypertension, Atrial Fibrillation, Coronary Artery Disease, Pacemaker/ICD, Cardiomyopathy, PAD, Diabetes, CKD, COPD, Obesity. Any custom conditions you've entered are also included.
When your doctor says "50 oz of fluid per day," they're giving you a safe baseline number — typically set for your average conditions. They're usually not accounting for your activity level that day, how many hours you'll be awake, whether it's hot outside, or how well you slept the night before. Your body's actual fluid needs vary with all of these things.
ClinBridge can't tell you whether to exceed your limit. But it can track what happens when you do — and over time, build a pattern that you and your doctor can review together to get you a more personalized recommendation.
1. Each morning, a 45-second check-in prompt appears on your dashboard.
You tap how you feel (Good / Fair / Rough), note any morning symptoms, and answer a few quick questions about yesterday.
2. The questions focus on yesterday's context — were you physically active? Hot outside? Did you exceed your fluid limit? How did you sleep? Did you eat late?
3. After 7+ days of check-ins, the Doctor's Report gains a new section: Lifestyle & Recovery Patterns. This shows whether you felt better or worse the morning after over-limit fluid days, whether activity is a compensating factor, and how poor sleep affects your next-day symptoms.
4. You bring this report to your cardiologist. Instead of asking "can I drink more on busy days?", you show them 60 days of evidence — and they can give you an informed, personalized answer.
ClinBridge records your self-reported data and identifies patterns. It does not recommend specific fluid amounts, tell you whether to exceed your prescribed limit, or replace your care team's guidance. Use the patterns you collect to have a better-informed conversation with your cardiologist — not to make independent medical decisions.
Morning Check-In is on by default. To turn it off: Settings → Features → uncheck "🌅 Morning Check-In & Pattern Tracking." When off, no prompt appears and no data is collected. If you turn it back on, previously collected check-ins are still available and will appear in future reports.
When you open ClinBridge after midnight — whether first thing in the morning or after leaving it running overnight — a blue banner appears at the top of the screen and walks through a short sequence as the app prepares your new day.
One of those steps shows you your real record count: total BP readings, days of history, symptoms logged, medications on file, and appointments saved. This is a live scan — the number you see is the actual count stored on this device right now. When those numbers appear, you know your data is intact, untouched, and exactly where you left it.
You can run the same check manually at any time from the bottom of Settings → 🔒 Privacy & Data Check.
Yes — always export your data before updating. Go to Device Sync & Backup → Export ALL Data and save the file. Then update, then import your data back. This takes about 60 seconds and protects everything you've recorded. The app will show you an update banner and walk you through the steps.
At minimum, before any app update and once a week as a habit. Also back up before clearing your browser cache or before deleting the ClinBridge icon from your Home Screen — both of those actions erase your local data. Go to Device Sync & Backup → Export ALL Data.
After importing, the app reloads automatically. If your data still doesn't appear: close the app completely and reopen it. On any phone or tablet, close the app fully and reopen it. On any desktop or laptop browser, close the tab and open a fresh one at clinbridge.clinic. On iPhone/iPad specifically, swipe up from the bottom and swipe away ClinBridge before reopening. Your .json backup file is safe — you can import it again as many times as needed on any device.
Not automatically — you need to export before updating and import after. This is intentional: ClinBridge never moves your data without you taking a deliberate action. Your health data stays under your control at all times.
ClinBridge has four pattern detectors that analyze your historical data — not just today's readings. The HR Rate Detector finds sustained heart rate shifts and sudden changes. The Decompensation Warning monitors five clinical signs of CHF fluid overload building simultaneously. The Pulse Pressure Detector tracks the gap between your systolic and diastolic readings as a cardiac output indicator. The Symptom Convergence Detector finds clusters, escalations, and clinical patterns across your symptom history. All four are in the Analytics section of the main page.
When a detector finds a significant pattern, it suggests pinning it. A pinned event is permanently saved — it never disappears when your 90-day data window rolls forward. It captures the detector's finding, the event date, and all the raw data (BP readings, symptoms, weight, notes) from that day. Pinned events appear in your Doctor's Report as a dedicated section, in the 60-day Timeline as amber markers, and in the Pinned Events viewer under Analytics. Think of pins as your pre-prepared clinical evidence for your next cardiologist appointment.
After your appointment, open the Pinned Events viewer and tap "Archive & Clear." This permanently saves all current pins to an archive (you can always view them), then clears your active list so the next period starts fresh. ClinBridge will remind you automatically — if you have an upcoming appointment within 14 days, or if you just had one this week, a banner appears on the main page and inside the Pinned Events modal. If no appointment is logged but your oldest pin is 60+ days old, you'll see a gentle nudge to archive and refresh.
It means ClinBridge's detectors can tell you that a pattern exists in your data — but they cannot tell you why it exists or what it means for your specific medical situation. A detected HR level shift is real math — but it could reflect a clinical change, a medication adjustment taking effect, seasonal variation, or something entirely benign. Your cardiologist provides the interpretation. ClinBridge provides the evidence and the pattern recognition to make that conversation richer and more productive than walking in with just a blood pressure number.
ClinBridge keeps 90 days of rolling data on your device. For long-term preservation, export your data as a backup at the end of each quarter — the last day of March, June, September, and December. Save these files somewhere safe (iCloud, Google Drive, email to yourself). A new cardiologist years from now could import your Q3 2026 backup and see your complete cardiac picture from that period. Pinned events in each backup capture the most significant findings for that quarter, pre-annotated for clinical review.
No — ClinBridge findings are not emergency indicators. A red finding means the pattern in your data is statistically significant and worth discussing with your cardiologist promptly — not that you are in immediate danger. If you are experiencing chest pain, severe shortness of breath, sudden dizziness, or other acute symptoms, call 911 or go to an emergency room regardless of what ClinBridge shows. ClinBridge is for pattern tracking over time, not acute symptom assessment.
ClinBridge stores everything — your blood pressure readings, symptoms, medications, weight, fluid logs, notes, and pinned events — exclusively in your browser's local storage on the device you are using right now. There is no server. There is no account. There is no cloud sync. Nothing you enter is ever transmitted anywhere.
Only you — on the device where ClinBridge is installed. If you export your data and share the .json file with someone (a family member, caregiver, or doctor), that person can import and view it. That sharing is entirely under your control and only happens when you initiate it.
If you add ClinBridge to your Home Screen on iPhone or iPad, be aware that the local storage is tied to that browser and device. Removing the icon erases the stored data. Always export a backup before removing the icon or clearing browser data.
ClinBridge was built by a cardiac patient after a hospitalization, motivated by a simple question: why isn't there a tool that tracks all the things my cardiologist actually needs to see — BP trends, symptoms, fluid balance, medication adherence, and pattern detection — in one place, for free, without giving up my health data?
The answer was to build it. The privacy model — all data on-device, no accounts, no servers — is not a limitation. It is a deliberate choice rooted in the belief that your cardiac health data is yours, belongs to no one else, and should never become a product.
ClinBridge includes a built-in Privacy & Data Check you can run whenever you want. Find it at the bottom of Settings — tap 🔒 Run Privacy & Data Check.
When it runs, ClinBridge scans your stored data and shows you the actual count: how many BP readings, how many days of history, how many symptoms logged, medications on file, and appointments saved. You see your real numbers — not a generic reassurance. If those numbers match what you know you've entered, your data is intact and untouched.
The check also confirms what ClinBridge is built to do: your data lives only on this device and is never sent anywhere. That is an architectural fact — there is no server for it to go to.
The same verification runs automatically every morning when ClinBridge resets for your new day, so you see your record count each time you open the app after midnight.
ClinBridge is a personal health tracking tool, not a medical device. It is not FDA-cleared, CE-marked, or certified as a clinical diagnostic system. It does not provide medical advice, diagnosis, or treatment recommendations.
Accuracy statement: All pattern detection is statistical and based on self-reported data. Findings are directional, not definitive — they identify patterns worth discussing with your cardiologist, not conclusions about your medical condition. Results may be affected by data entry errors, device measurement variability, and individual clinical factors the app cannot account for.
Always consult your cardiologist or other qualified healthcare provider before making any changes to your care plan based on information from ClinBridge.
Use the tools below to clear your health data stored on this device. These actions cannot be undone.
Removes only today's BP readings, symptoms, meals, activity, dismissed events, and daily plan. Your settings, medications, procedures, appointments, and all previous days are kept.
Permanently erases everything: all daily readings (every day), settings, medications, procedures, appointments, custom symptoms/activities, analytics notes, and reminders. The app will return to a fresh-install state.
Your data lives only on this device. Back up regularly so you never lose it.
How to back up: Go to Device Sync & Backup → Export ALL Data. Save the .json file to your Files app, iCloud, or email it to yourself.
When a new version is available, the app will show a banner at the top. Follow these steps in order — skipping step 1 risks losing your data.
After importing, the app reloads automatically. If your data still doesn't appear:
This tab tracks bugs that were reported and fixed — things that were broken and are now resolved. Each entry describes the defective behavior, the root cause, and the fix applied.
For new features and capabilities, see the Planned Features tab.
mipApprove() now upserts a block rule at the block threshold and a warn rule at the warn threshold directly into the medicine's conditionRules array. If a rule for that metric already exists, its threshold is updated in-place while preserving the user-set outcome (block or warn). All MIP-synced rules are labelled MIP-approved (date) so they are distinguishable from manually entered rules. MIP-approved PP thresholds now also sync a PP warn rule across all active medicines that do not already have a user-defined PP rule. The conditionNote on each medicine is regenerated after sync so the MIP panel, Manage Medicines, and the log-time safety check all reflect the same state. Help & About updated: the "You Approve Everything" section and the Condition Rules section now accurately describe the auto-sync behavior._mipWarnProceed() set the proceed-flag to true then called saveMedicine(), but saveMedicine() immediately reset the flag to false because the sentinel argument 'warned' was never actually passed. Result: the same warn screen appeared again and again — logging could never complete after any warn acknowledgement. Fixed: _mipWarnProceed() now correctly passes 'warned' to saveMedicine(). Additionally, warn acknowledgement is now tracked per-medicine per save pass using _mipWarnAckedMeds — each medicine in a multi-selection gets its own warn screen shown exactly once, and no warn is silently bypassed when multiple medicines are logged together. Affects all users logging multiple medicines simultaneously with any warn condition active.<div> on one entry, leaving a stale </div> that closed a parent container early. This broke the DOM structure of every section after it — JavaScript’s setHelpSection hide/show calls could not reach the displaced content. Present since v9.10.32. Fixed by inserting the missing wrapper div. All 18 help sections verified balanced by automated div audit before release.tabScrollRight) was position:absolute, z-index:10, spanning full height of the tab bar, always visible (display:flex). On iPhone it permanently covered the first 52px from the right edge of the tab bar, intercepting all touch events on Getting Started, How to Use, and other nearby tabs. Fixed: overlay div set to pointer-events:none so touch passes through to tabs beneath; the arrow span inside gets pointer-events:auto so scrolling still works when the arrow itself is tapped.-webkit-overflow-scrolling:touch, display:none alone does not fully prevent hidden sections from painting. Fixed: visibility:hidden, height:0, overflow:hidden, and zeroed padding/margin added alongside display:none in setHelpSection for non-matching sections.planned-features to render inside known-issues rather than as a sibling section. Fixed: section now correctly placed as a sibling.overflow:hidden on .help-modal-content inside the #aboutModal override — reintroducing the same iOS touch-blocking condition it was trying to fix. Changed to overflow:visible. Also added touch-action:manipulation to both scroll chevron overlay divs which were positioned absolutely above the tab bar and intercepting tap events on iOS even when hidden..modal CSS class sets overflow:hidden on the backdrop element. On iOS Safari, overflow:hidden on a parent intercepts all touch events, preventing child elements from receiving scroll or tap gestures regardless of their own overflow settings. Fixed with a dedicated #aboutModal CSS rule overriding to overflow-y:auto with -webkit-overflow-scrolling:touch. Same property added to .modal-body and .hr-tabs via the #aboutModal rule block. Inline styles on both elements also updated to be consistent.openHelpModal rewrites the tab bar style.cssText via a setTimeout, which wiped out the CSS-applied -webkit-overflow-scrolling:touch rule. Without this property on iOS, touch momentum scrolling was broken — tabs could not be swiped and content could not scroll. Fixed: -webkit-overflow-scrolling:touch!important added to the inline cssText override. Also corrected padding-right to 44px so tabs can scroll past the right chevron overlay.htab-med-intel button was added to the JavaScript tabKeys arrays and the section HTML was created, but the actual <button> element was never inserted into the HTML tab bar. The tab was unreachable by tapping. Fixed: button inserted before the Deep Dive tab.welcome, tab bar scrollLeft is explicitly reset to 0 so the first tabs are always visible on open.CLINBRIDGE_MED_INTEL. Approved thresholds survive data imports and are reloaded automatically.mip_warn (metric in caution zone per MIP thresholds), pp_warn (current pulse pressure below approved PP warn threshold), and hr_warn (average of last 3 HR readings above target ceiling). Each surfaces a distinct amber caution screen — the user must acknowledge before proceeding, but is not hard-blocked. The MIP warn proceed flag resets at the start of each new save attempt._confirmImport() reloaded all other data but never reloaded the savedMeals in-memory array from localStorage. The stale pre-import array remained active, and any subsequent meal save would overwrite localStorage with that stale array, silently erasing meals that were in the backup. Fixed: savedMeals is now explicitly reloaded from localStorage immediately after all other post-import reloads.mbItems was cleared but the mbMealName and mbMealType DOM fields were never reset. Previous session's meal name and type remained visible. Fixed: both fields are now explicitly cleared in the fresh-start branch of openMealBuilder.askThread was set to display:none. The v9.10.160 fix hid the tool panels on reopen but did not restore askThread to visible — leaving Ask blank with no input response. Fixed: openAskPanel now explicitly restores askThread to display:flex alongside resetting the tool panels.grid-template-columns: 1fr 1fr 1fr 1fr), causing the fields to be too narrow to use on a phone screen. Changed to a 2×2 grid (grid-template-columns: 1fr 1fr) so all four fields are legible and tappable.settings.medicineList (active medicines only), then appends any historical medicine names from log entries not already in the list. Discontinued medicines are excluded from the dropdown.conditionMetric (systolic / diastolic / hr / null), conditionThreshold (number or null), conditionDirection (above / below / null). A new “Condition Check” section now appears at the bottom of the Add/Edit medicine screen — select Diastolic, Systolic, or Heart Rate, enter a threshold, and choose whether to block when the reading is below or above that threshold. Selecting None clears all condition fields. Existing medicines without these fields are unaffected.conditionNote (e.g. “Only when diastolic >70” or “Only when systolic >100”) now display an amber warning banner directly under the schedule note in the Log Medicine modal. Previously the condition note only appeared in Manage Medicines, meaning it was invisible at the critical moment of deciding whether to take the medication. Affects Metoprolol, Losartan, and any medicine with a clinical condition attached. Medicines whose conditionNote is simply “As needed” are unaffected since the schedule line already conveys this.hideModal() only closes #modal, tapping the FAB on those screens did nothing while covering their real close button. Fix: _syncFab() now checks whether #modal specifically is open rather than any element with class modal. The FAB now only appears on logging forms and other content rendered inside #modal.grid-column:1/-1 to span the full container width. The pattern already existed on Decompensation Warning, Pulse Pressure Detector, Symptom Convergence, Sentinel, and Pinned Events..hr-stat-card CSS rule contained text-center; — a Tailwind class name accidentally written as a CSS property. It is not valid CSS and was silently ignored, leaving stat card text left-aligned. Fixed to text-align:center;.<s> tags, displaying as struck-through text. On a medical checklist this reads as deleted rather than accomplished. Fix: completed items now display in bold with a ✅ checkmark and green background only — no strikethrough.#helpTabBar was registered without {passive:true}. Non-passive scroll listeners block the browser’s scroll thread and are flagged by Lighthouse. Fix: listener now registered with {passive:true}. The touchstart listener was already correctly marked passive._wzSaveChecklist() which was never defined. Paths B, C, and D correctly called _wzSaveChecklistPath(pathId). Fix: Path A now calls _wzSaveChecklistPath(‘A’) matching the pattern used by all other paths. The confirmation alert (“✓ Checklist saved!”) now appears correctly after tapping Save My Checklist on Path A..audio-alert CSS rule was missing its closing } before @keyframes pulse. The keyframe block was nested inside the unclosed rule, which is invalid CSS. Browsers silently discarded the animation declaration, leaving the alert box static when it should pulse. Fix: closing brace added after animation:pulse 1s ease-in-out infinite; so @keyframes pulse is correctly scoped at the top level.=== FLUID VS NEXT MORNING BP === section added to context. For each day with fluid logged in the window, the first BP reading of date+1 is looked up directly from allBP (already in scope) and output as a verified pair. A system prompt directive instructs the AI to use this table and never construct next-morning pairings from raw data.Date.getDay() was returning the wrong day-of-week value on this device. Fix: replaced Date.getDay() with Tomohiko Sakamoto’s pure-math day-of-week algorithm — computes the weekday directly from the year/month/date components with no reliance on the browser’s Date object timezone behavior.beforeAfterRe pattern inside _parseAskComparison. Queries like “since March 6, how many HR readings were above 80 bpm” were routed to the comparison context builder (which builds a before/after window) instead of the date range parser (which builds the correct open-ended since-March-6 window). The comparison context does not include the HR frequency table, so the AI could not answer threshold queries accurately. Fix: “since” removed from beforeAfterRe so it falls through to Pattern G in _parseAskDateRange as intended.buildAskContext() called getAllHistoricalData() exclusively to load readings. That function applies its own 90-day cutoff check that can differ from the query window set by inWindow() — causing it to return 0 in-period readings for dates that genuinely exist in localStorage (e.g. “7 days ago” correctly resolves to May 5 but getAllHistoricalData() misses those readings). Fix: after getAllHistoricalData() runs, the BP HISTORY section now performs a supplemental direct localStorage scan for every date that passes inWindow() but was not already loaded. This guarantees no readings are skipped regardless of any gap in getAllHistoricalData()’s cutoff logic._parseAskDateRange() identified 7 query types that returned wrong data or fell back to the 14-day default. All 7 are now fixed: N days ago (e.g. “3 days ago”) returns that specific day; last [weekday] (e.g. “last Tuesday”) returns the most recent occurrence; N weeks ago returns the 7-day window from that period; week of [date] returns the full Sunday–Saturday week containing that date; last year returns Jan 1–Dec 31 of the prior year; Q1/Q2/Q3/Q4 and first/second/third/fourth quarter return the correct 3-month window.new RegExp() strings in the comparison parser used single-backslash \s, \d, \w which JavaScript treats as literal characters, not whitespace/digit/word classes. Every comparison query — "February vs March," "before and after March 5," "what changed after March 6" — silently failed and fell through to the date range parser with wrong data. All five regex corrected with proper \\s, \\d, \\w escaping._askSessionDateFrom / _askSessionDateTo) and reused for follow-up questions that don’t specify a new date. Session resets when the panel closes or history is cleared._buildAskComparisonContext() only computed BP, symptoms, and fluid averages. Weight trend, medications logged, activity count, meal count, and note count are now included in both period A and period B stats.stop_reason field is now checked; when it equals max_tokens, a note is appended: “Response was cut off — ask ‘continue’ to see the rest.”AbortController cancels the request after 25 seconds with a clear message explaining the cause and suggesting a narrower date range.from: ‘2000-01-01’, making the AI believe it had 26 years of data. Fix: the pattern now scans localStorage for the actual earliest BP_TRACKER_YYYY-MM-DD key and uses that as the start date.useTo when useFrom was null, falling back to 14 days. Now handles all four combinations correctly: both bounds set, open start (since [date]), open end (before [date]), and no bounds (14-day default).useFrom was null. Now shows accurate label so the AI knows exactly what data it has and can flag period mismatches._parseAskDateRange() matched the month name “April” and consumed the year “2026” via the optional year group, returning April 1–30 instead of April 1. Fix: a new Pattern 4.5 inserted before Pattern 5 matches “Month DD [YYYY]” as a specific single-day window. Only fires when a day number is present alongside the month name; whole-month tokens (month name alone or with year only) still fall through to Pattern 5.buildAskContext() used windowMeals.slice(-20) to limit output. When the window contained many meals (e.g. a full month), slice(-20) returned only the most recent 20 — silently dropping earlier dates. For an April 1 query expanded to all of April, every April 1 meal was cut. Fix: meals are now sorted chronologically and all meals in the window are included (no slice cap), matching the behavior of the BP, symptom, and activity history sections.=== HISTORICAL FLUID ENTRIES === section reads the fluid, bp (f field), and meals (mealFluidOz) arrays from each historical day’s localStorage entry within the query window and lists each entry with date, time, amount, source type, and notes.dailyFluid was unconditionally pushed into the fluid statistics array before the window filter, inflating averages and day counts for date-specific queries (e.g. querying April 1 would show “2 days” of fluid data including May 11). Fix: today is only added to fluid stats when today’s date passes inWindow().touch-action:manipulation to all button CSS classes (body, .btn, .modal-btn, .modal-cancel, .modal-ok, .stat-tile). Eliminates the 300ms iOS WebKit touch delay and intermittent cancelled taps on all interactive elements app-wide.panel-notes, panel-rate) matching all other cards. Both added to CARD_PANEL_MAP with count-based tiles. Med Effectiveness tile always visible — adapts to setup state with educational nudge when medications not yet configured or no tagged readings exist..notes field. All Notes view extended to scan BP, Fluid, and Medicine log entries for notes alongside existing Weight, Symptom, and Activity coverage.closeAnalyticsDashboard() now calls collapseAllAnalyticsPanels() before hiding — next open always starts with a clean collapsed state.scrollIntoView with direct modalContent.scrollTop assignment at 150ms delay. Eliminates intermittent iOS failure where smooth scroll targeted the viewport instead of the modal scroll container.bottom:90px to bottom:24px. _syncFab() rewritten to manage Close FAB + Ask FAB + activity pill without any Today’s Status logic.manageMedicines() modal was fully functional and accessible via the Wizard and a hidden button on the main page, but there was no direct path in Settings. Fix: a dedicated 💊 Medications accordion section added to Settings between Baseline Conditions Registry and Heat & Humidity Advisory, with a single button that opens manageMedicines() directly._confirmImport() wrote all keys to localStorage then called refreshAllDisplays() — but never called loadAppointments(). The appointments[] in-memory array stayed at its pre-restore state, so updateRecentAppointmentWidget() always saw an empty array and showed “No appointments saved yet” even when cardiacAppointments was fully populated in storage. Fix: loadAppointments() added to the post-import refresh block, before refreshAllDisplays().visibilitychange handler has two branches: same-day resume (correctly called loadAppointments()) and date-rollover (did not). On iOS, the PWA JS context is killed overnight — appointments[] resets to [] at declaration. On morning resume, the date has changed so the rollover branch runs, skipping loadAppointments(), and the card renders empty. Fix: loadAppointments() added to the date-rollover branch.setInterval midnight auto-refresh cleared daily arrays and called refreshAllDisplays() but never called loadAppointments(). Fix: loadAppointments() added before refreshAllDisplays() in the midnight handler.appointments = [] but never called updateRecentAppointmentWidget(). The card continued to display the deleted appointment until page reload. Fix: updateRecentAppointmentWidget() called immediately after appointments = [] in the delete-all block.settings.features.meals / d.setup.features.meals. This flag is only ever set by the Getting Started wizard — users who track meals without completing wizard setup never have it. The Meals card itself has no dependency on this flag (it shows by default). Result: the PPH section never rendered and the nudge never fired for any user who did not run the wizard. Fix: both guards replaced with a check on actual meal log count (d.logs.meal.count ≥ 3 for the nudge; data existence check for the Sentinel section). If the user has logged 3+ meals the checks pass — no feature flag dependency.pph_pattern_detected companion card nudge moved from position 21 to position 2 in NUDGE_RULES so it is no longer blocked by behavioral nudges firing first. Also fixed: btnFn was 'openAdvancedAnalytics ? openAdvancedAnalytics() : null' — the function is named openAnalyticsDashboard(); corrected.snapshotSetup() stores d.setup.activeFeatures as an array of enabled feature keys, but never stored d.setup.features as the object the nudge rule was checking. The guard !d.setup.features.meals evaluated undefined.meals and always returned false, silently blocking the nudge regardless of how many PPH events existed. Fix: snapshotSetup() now also writes d.setup.features = features. The nudge guard updated to check d.setup.features.meals first, then fall back to d.setup.activeFeatures.indexOf('meals') !== -1 for existing installs that haven't re-snapshotted yet. The nudge will now fire correctly on the next Sentinel evaluation for users with 3+ PPH events and the average drop guard met.refreshAllDisplays() never called updateRecentAppointmentWidget() — on tab-resume and daily ticks the card went stale without the widget knowing. (2) The same-day path in the visibilitychange iOS resume handler called loadDailyData() but not loadAppointments() — on iOS PWA resume where the JS context was stale, appointments could be [] even though cardiacAppointments was present in localStorage. (3) deleteAppointment() called filterAppointments() to refresh the modal but never called updateRecentAppointmentWidget() — main-page card stayed stale after any delete. (4) updateRecentAppointmentWidget() set display:none when appointments.length === 0, making the card invisible on a fresh session before any data had loaded, which masked the other three bugs. Fix: card now always renders — empty state shows an “➕ Add Appointment” prompt; all three missing call sites added.getAllHistoricalData() was replaced with var passesFilter = true; // TEMPORARILY DISABLED FOR TESTING — bypassing the 90-day data window entirely and loading all historical data on every call regardless of age. This was never reverted before shipping. Additionally, 37 console.log('DEBUG...') and console.log('=====...') statements were left in the same function, flooding the browser console on every analytics call. Both removed: passesFilter restored to (keyDate >= cutoffDate && keyDate <= today); all debug log lines stripped.{bp, weight, symptoms, activities, meals, medicines, notes, procedures} but not breathing. Since breathing sessions are stored as a flat array under a single key (not per-day like BP data), they require a separate read. Fix: clinbridge_breathing_sessions is now read once, filtered to the 90-day window by session date, and returned as breathing: allBreathing. This makes the data available to any future feature that reads the historical bus.buildAskContext() had no breathing section. Questions like “how have my breathing sessions been going?” or “what’s my average HR response?” returned no data. Fix: a new === BREATHING SESSIONS === section added at the end of context, including total session count, average HR response, sessions-with-decrease count, and a per-session line (date, technique, duration, before/after HR, delta, notes) for the 10 most recent sessions.breathing_try_it: fires when app age ≥14 days, 10+ BP readings, 5+ HR readings exist, but no breathing sessions have ever been logged. suppressDays: 30. Action button opens the Breathing Logger directly. breathing_declining_response: fires when 6+ sessions exist and the last 3 sessions average less than 50% of the first 3 sessions’ average HR response (baseline ≥4 bpm required to avoid false fires on weak responders). Prompts clinical discussion about pacemaker rate floor engagement. suppressDays: 14.showMealsHistory() and closeMealsHistory() both used mh.innerHTML = … to rebuild the entire header from scratch, and neither included the 📋 View History button in the rebuilt HTML. Fix: both functions converted to use openCardHistory() / closeCardHistory(), which update only the <span> text and leave all buttons intact. The static header already had a <span> as first child; no HTML changes needed.showWeightHistory() set weightViewMode = 'all' directly without calling claimHistorySlot('weight'), allowing Weight history to open while another card was already showing history. Every other card (BP, Symptoms, Activity, Meals, Medicines) calls claimHistorySlot first and blocks if another card is active. Fix: if(!claimHistorySlot('weight')) return; added as the first line of showWeightHistory().← Back to Today button in Weight history was missing -webkit-tap-highlight-color:transparent and min-height:44px present on every other card’s Back to Today button. Fix: both properties added to match the standard.renderPinSuggestion() always rendered the full suggestion box, then changed individual button states to “✅ Pinned” for already-handled events, but never hid the container when all suggestions were handled. Fix: added an allHandled pre-check at the top of renderPinSuggestion(). If every suggestion in the list returns true from isPinnedEvent() (checking both active and archive), the container is hidden immediately and no box is rendered. Applies to all four pin sections uniformly — no per-detector changes needed.pphEvents ≥ 3, regardless of what the population-level trend looked like. With 4 events out of 160 meal pairs and an average systolic change of −1 mmHg across all pairs, the banner was incorrectly firing on noise. Root cause: the single-threshold guard did not account for the fact that a small number of individually qualifying drops can clear the count threshold while the broader meal→BP relationship is flat or positive. Fix: a second guard added to both generatePPHAnalysis() and the Sentinel pph_pattern_detected nudge — the banner and nudge now require pphEvents ≥ 3 &AND; avgSysDrop ≥ 5 mmHg across all analyzed pairs. The 5 mmHg population-average threshold ensures the overall post-meal BP trend is meaningfully downward before a pattern is declared. The Sentinel nudge received the same calculation inline with its own pair-count and running-sum accumulators, matching the logic exactly.showSymptomsHistory() and closeSymptomsHistory() both used sh.innerHTML = … to rebuild the entire card header from scratch — and neither included the View History button in the rebuilt HTML. All other cards (BP, Weight, Activities, Meals, Medications) use the generic openCardHistory() / closeCardHistory() helpers, which update only the <span> text node and leave every button intact. Fix: both symptom history functions rewritten to use the same generic helpers. The static header HTML was already correctly structured with a <span> as first child; no HTML changes needed.archiveAndClearPins() wrote an empty array to clinbridge_pinned_events and refreshed the modal and badge, but did not clear the four session-scoped detector cache variables (_decompGhostFire, _decompLastPoints, _decompLastActive, _decompCacheTs) or re-render the main-page rate detector. Fix: archiveAndClearPins() now nulls all four cache variables and calls renderRateDetector() before updateAnalyticsBadges(), ensuring the entire UI reflects the empty active-pins state immediately without requiring a page reload.<div> opening tag in the Planned Features section was split mid-attribute (border-ra truncated) with a second complete <div> tag appended on the same line — the same class of corruption test 15n guards against, but in a different form not matched by the existing regex. The browser parsed the two merged tags as one element, leaving an unclosed div inside Planned Features. (2) The "Shipped in v9.10.49 — Clinical Event & Appointment Intelligence" entry in Known Issues was missing its opening <div> wrapper entirely — causing its closing </div> to propagate upward and close a parent container element. This broke the DOM structure of every section that followed: content fell outside the .helpSection elements where JavaScript's setProperty calls could not reach it. No CSS or JS fix could resolve a structural DOM corruption. Fix: inserted the missing <div> wrapper around the orphaned entry; restored the truncated div opening tag to a single well-formed tag. Both sections now have balanced div structure verified by automated audit.hidden attribute removal, hs-visible class — were operating below the decisive level of the CSS cascade. The definitive fix: every section show/hide call now uses el.style.setProperty('display', 'block'/'none', 'important'). An inline style set via setProperty with 'important' priority sits at the absolute top of the CSS cascade — it outranks every author stylesheet rule, every UA stylesheet rule, every inherited style, and every !important in a class rule. No browser on any platform can override it. Applied consistently in all three code paths that control section visibility: setHelpSection, _helpShowAllSections, and helpGoToResult. The third path (helpGoToResult) was missed in all prior fixes and was silently re-introducing a normal inline style.display = 'block' whenever a search result was tapped — leaving a stale inline style that subsequent CSS rules could then fight over.<section> tags carried leftover hidden HTML attributes and style="display:none" inline attributes from all previous fix attempts. On iOS Safari the UA stylesheet and inline style together create a cascade layer that can outrank author !important rules in edge cases. These attributes were a second source of truth competing silently with the CSS. Second: the welcome section had no initial visibility class, so it relied entirely on JavaScript running after page paint to become visible — on slower devices or when the 500ms first-run timer fires, the modal could open to a blank white body. Both gaps fixed: all hidden attributes and style="display:none" inline styles removed from every .helpSection element; the welcome section now carries class="helpSection hs-visible" directly in the HTML so it is visible on first paint before any JavaScript runs. The CSS owns visibility exclusively with no HTML-level overrides competing against it._eventsWidgetCollapsed flag) — the full widget only returns when the user explicitly expands it.getAllHistoricalData() regardless of whether the user has meal tracking enabled. In environments where meal + BP data happened to produce 3+ PPH events, it would fire and suppress other nudge rules (including behavioral milestone cards). Fixed: guard added — d.setup.features.meals must be true before the historical data check runs. Clinically appropriate: PPH nudges should not surface for users who are not tracking meals.pph_pattern_detected fires when 3+ PPH events detected in 30 days. suppressDays: 14.el.style.display to show/hide sections. On iOS Safari, inline styles set by JavaScript participate in the CSS cascade in ways that interact unpredictably with class-based rules — display:none set by JS can be overridden silently by a CSS rule added later, or fail to override an existing inline style set by a prior JS call. The fix eliminates inline style manipulation entirely. Two CSS rules now own visibility exclusively: .helpSection { display:none !important } hides all sections by default; .helpSection.hs-visible { display:block !important } shows the active one. Because .helpSection.hs-visible has higher specificity (0,2,0) than .helpSection (0,1,0), it wins even with both rules carrying !important. setHelpSection and _helpShowAllSections now only call el.classList.toggle('hs-visible', isMatch) — no inline styles, no hidden attribute, no cascade conflict possible on any platform or browser..helpSection { display:block } was competing with the JavaScript section-switching logic — specifically overriding el.style.display = 'none' in browsers where CSS specificity wins over inline style on class-matching elements. The v9.10.64 three-layer fix (adding a .section-hidden { display:none !important } class) added unnecessary complexity. Simplified in v9.10.85: the .helpSection { display:block } rule has been removed entirely. setHelpSection reverted to the clean original approach — el.style.display = isMatch ? 'block' : 'none' plus setAttribute('hidden','') / removeAttribute('hidden'). No competing CSS rule means no override battle on any platform..helpSection { display:block } was overriding the JavaScript el.style.display = 'none' hide instruction on iOS Safari, leaving the Welcome section permanently visible regardless of which tab was tapped. Fixed with a three-layer approach: (1) new CSS class .section-hidden { display:none !important } which outranks the .helpSection class rule, (2) inline style.display = 'none' retained as backup, (3) setAttribute('hidden','') retained as backup. All three point the same direction — no browser on any platform can override them simultaneously.requestAnimationFrame and body.style.scrollBehavior manipulation to reset scroll position on tab switch. On iOS with -webkit-overflow-scrolling:touch, multiple programmatic scrollTop assignments via rAF permanently broke native momentum scroll — touch gestures passed through to the page behind the modal instead of scrolling the modal. Reverted to single synchronous scrollTop = 0. Changed helpModalBody from overflow-y:auto to overflow-y:scroll and added overscroll-behavior:contain to prevent touch bleed-through.setHelpSection iterates a hardcoded tabKeys array to set/clear active tab button states. breathing-logger was added to the tab bar in v9.10.59 but not added to this array — the tab button never cleared when switching away from it. Fixed in both tabKeys arrays. Regression guard test added to Section 15 of the test suite._addAskBubble was calling thread.scrollTop = thread.scrollHeight but askThread is not the scrollable container — helpModalBody is. The scroll did nothing. Fixed: now scrolls helpModalBody to the top of the assistant response bubble so the beginning of the reply is always visible.checkForUpdates() wrote its result to settingsVersionStatus, there was no scroll to bring it into view. Added scrollIntoView({behavior:'smooth',block:'nearest'}) for both the new-version and up-to-date result states.\\n sequences instead of real newlines — rendered as visible text in the modal body. Corrected.overflow:hidden to display:flex;flex-direction:column;max-height:90vh with the scroll area as flex:1 1 auto. (2) Test suite Section 61 added: 25 new tests covering the safety gate, all five prior bug fixes, context advisory DOM elements, override tracking, COPD check, low-response flag math, duplicate declaration checks, and disclaimer placement verification._breathRunContextGate() now calls _silentDecompAnalysis() before reading _decompLastPoints — previously the score could be 20+ minutes stale if the user hadn't triggered a badge refresh, meaning active warning signals could be missed entirely. (2) Duplicate var delta declaration in saveBreathingSession() — second declaration was dead code left from an earlier edit; removed. (3) Unused var now = new Date() in saveBreathingSession() — dead code; removed. (4) Low-response ⚠ flag fired incorrectly on negative deltas — sessions where HR increased were being flagged with the "⚠ <5 bpm" low-response marker alongside the orange ↑ indicator, which was contradictory. Flag now only fires when hrDelta >= 0 && hrDelta < 5 (weak positive response). (5) openBreathingHistory() did not hide breathingBlockView — if the block screen was visible and history was somehow opened, both views could render simultaneously. Fixed. Also removed startTime and pausedAt from breathState (declared but never written or read) and corrected a duplicate display:none in the custom duration row HTML._activityMinimized, _minimizedActivityState, and activityElapsedSeconds are in-memory variables only. When iOS suspends and resumes the JavaScript context, these reset to their initial values. The visibilitychange handler then calls loadDailyData() from localStorage — but the activity state was never written there, so it was unrecoverable. Fix: minimizeActivityLog() now writes the full activity state plus a minimizedAt timestamp to localStorage key CB_ACTIVITY_MINIMIZED. On visibilitychange resume, if _activityMinimized is false but the key exists, the state is restored and elapsed time is recalculated as stored seconds plus seconds elapsed while the app was away. A toast confirms the restore with activity type and elapsed minutes. CB_ACTIVITY_MINIMIZED is cleared on both saveActivity() and cancelActivityLog() so no ghost state persists after the session ends._decompLastPoints) with no freshness check — if the signal fired at load time then cleared, the badge stayed stale indefinitely until the modal was opened. (2) The pin card was rendered purely from live analysis state — no record of the firing event was preserved, so once the signal cleared the pin opportunity was silently lost. Fix: When analyzeDecompensation() scores ≥2 signal points, a session-scoped ghost record (window._decompGhostFire) is written with the active signal labels and today's date key. If the user later opens the modal and the live signal has cleared, _injectDecompPins() detects the ghost record and renders a muted “Earlier Today: signals fired” card with a full pin button — the window stays open for the rest of the day. Ghost expires at midnight via date-key comparison. Separately, updateAnalyticsBadges() now stamps a cache age timestamp (_decompCacheTs); if the cache is >20 minutes old it re-runs _silentDecompAnalysis() before setting the badge, keeping the badge accurate without requiring the modal to be opened.cbTrack() system: ask_panel_opened (each time the Ask panel is opened — measures session frequency), ask_question_submitted with session_q_count parameter (each question sent — counts total volume and questions-per-session depth), and ask_answer_received with session_q_count (each successful answer — measures completion rate vs abandoned questions). A per-session counter _askSessionQuestionCount resets each time the panel opens, enabling average questions per session to be tracked in GA4. This data supports future rate-limit decisions without guessing at real usage patterns.undefined/undefined in the data context sent to Ask, making all BP-related questions unanswerable. Root cause: buildAskContext() was reading r.sys, r.dia, r.hr, and r.time but the BP reading object stores these as r.s, r.d, r.h, and r.t respectively. The same mismatch affected the historical average BP calculation. Also fixed: weight time field (lw.time → lw.t). All BP data, heart rate, and weight timestamps now serialize correctly into Ask context.M array, field m for name, t for time) and up to 20 meals from the last 14 days (from getAllHistoricalData().meals) are now included in context.buildAskContext() revealed that every data type except fluid total and notes had wrong field names. Symptoms used s.name (should be s.symptom) — both today’s and 14-day history. Medications used m.name (should be m.medicine) and a nonexistent m.dose field (replaced with m.time). Pinned Events used p.date, p.doctor, and p.status which do not exist as top-level fields — corrected to p.eventDate, p.commLog.to, and p.commLog.status respectively. Pinned Event p.summary (the detector’s clinical summary text) and question responses (q.response) are now also included in context. All Ask questions involving symptoms (“what symptoms have I had?”), medications (“what did I take today?”), and pinned events (“what do I need to discuss with my doctor?”) now receive accurate data..modal elements for open-state, not the Ask panel. On iPhone PWA, scrolling within the fixed Ask sheet still fires window.scroll, which re-showed the FAB when scrollY > 300px because the Ask panel is not a .modal. Fix: scroll listener now also checks askPanel.style.display, matching the existing _syncFab() logic. Belt-and-suspenders: FAB z-index reduced from 999999 to 999985 (below the Ask backdrop at 999989) so it can never float above the Ask panel regardless of timing.Clinical Event & Appointment Intelligence — 4 New Nudge Rules — Closes the gap between clinical events that happen in the real world and the data ClinBridge needs to stay accurate. New helper function _openSentinelToEventLog() deep-links directly into Sentinel and opens the Clinical Event Log form, scrolling it into view (400ms deferred after render). Four new NUDGE_RULES: (1) pre_appointment_snapshot — fires when a saved appointment is 0–3 days away, no Snapshot saved in 7 days, and 14+ BP readings exist. suppressDays: 3. Action button opens Symptom Convergence → Timeline tab. (2) post_visit_clinical_event — fires when a saved appointment date was 1–4 days ago and no sentinel clinical event has been logged on or after that date. suppressDays: 5. Action button opens Sentinel Clinical Event Log form. (3) hr_shift_no_clinical_event — fires when a pinned HR level shift event (source: hr_detector) exists but no clinical event has been logged within 30 days of the pin date. suppressDays: 14. Action button opens Sentinel Clinical Event Log form. (4) clinical_event_log_unknown — fires when app age ≥30 days, 20+ BP readings, hasConditions, and clinbridge_sentinel_events is empty — the user has never logged any clinical event. suppressDays: 30. Educational nudge, action button opens form. All 4 rules read cardiacAppointments and clinbridge_sentinel_events directly from localStorage via try/catch, matching the existing pattern used by other rules. Gap 4 (reset-baseline reminder after deliberate non-reset) intentionally held — fires too close to a user choice and risks feeling intrusive. Test suite additions required (v12 → Section 52).
Getting Started — “Open Settings Now” button opened Settings hidden behind Help & About — The button called openSettings() directly. openSettings() writes to #modal and makes it visible — but #aboutModal (Help & About) was still displayed on top of it, hiding Settings completely. Fix: button now calls closeHelpModal(); setTimeout(function(){ openSettings(); }, 100); — the identical pattern used by every Settings-opening button inside the wizard (_wzGoSettings()). All other tappable elements in the Getting Started section were audited: wizard navigation stays within #aboutModal and is unaffected. No other buttons had this issue.
Getting Started Tab Rewrite — Progressive Onboarding — The Getting Started tab has been rewritten from a 1,200-word feature manual into a four-section progressive onboarding experience. Section 1: a warm three-step handshake (name, conditions, BP targets) with a direct “Open Settings Now” button. Section 2: plain-language guidance on what to log first — doctor-prescription framing, no feature inventory. Section 3: a short explanation of how Sentinel surfaces one suggestion at a time as data builds, so users understand they don’t need to configure everything upfront. Section 4: the full Setup Wizard repositioned at the bottom under “Already familiar with ClinBridge?” — preserved completely, just no longer the first thing a new user sees. Zero new JavaScript. Zero new logic. Zero conditional paths. The tab is static HTML — testable by eye on any device. Rationale: the behavioral nudge system is now the progressive onboarding engine; the Getting Started tab’s job is to earn trust and get the three critical data points in, then step back.
Behavioral Profile Layer — Accumulated Data Integration — Goal 3 of the v9.10.x behavioral intelligence sprint. Five changes shipped: (1) Streak rules corrected — streak_7_days and streak_30_days now use currentStreak directly instead of the old count/age approximation, which could fire for non-streak loggers. (2) fluid_never_logged nudge — fires when age ≥14 days, 20+ BP readings, hasConditions, and fluid.count = 0. Fluid tracking is a direct decompensation signal; this gap is clinically meaningful for cardiac patients. suppressDays: 21. Action button opens fluid log. (3) pulse_pressure_never_viewed nudge — fires when age ≥14 days, 20+ BP readings, hasConditions, and the Pulse Pressure detector has never been opened. suppressDays: 30. (4) appointment_never_saved nudge — fires when age ≥30 days, hasConditions, and engagement.appointmentsSaved = 0. First rule to use the engagement.* block. Without a saved appointment the Appointment Snapshot workflow is inert. suppressDays: 21. Action button opens appointment modal. (5) Instant-dismiss backoff in evalCard() — if cardsShown ≥ 8 and cardsInstantDismissed / cardsShown ≥ 0.75, nudge evaluation is skipped for that Sentinel session. Unlocks and encouragements still fire. First use of signals.* data in rule logic. Ratio self-corrects naturally as cardsReadAndDismissed grows. Test suite additions required (v12): fluid_never_logged fires/suppresses correctly; pulse_pressure_never_viewed fires/suppresses; appointment_never_saved fires/suppresses; backoff activates at threshold and lifts as ratio improves; streak_7_days uses currentStreak not count; streak_30_days uses currentStreak ≥30.
Baseline Conditions Cross-Reference — Each BP reading card now shows a personal baseline context pill when the reading is within configured thresholds (no red alert) but meaningfully elevated above the user’s personal quiet baseline. The pill appears in amber with the specific deltas: e.g. “↑ Sys +14 · HR +16 vs your baseline”. Thresholds: systolic ≥10 mmHg above baseline, diastolic ≥8 mmHg, HR ≥12 bpm — any one triggers the pill. Requires 14+ qualifying baseline days; never fires alongside a threshold alert. _sentMetrics() extended to return avgSys and avgDia; _sentComputeBaseline() extended to include both in the baseline object. New _getPersonalBaseline() session-cached wrapper computes once per 5 minutes and reuses across all readings in a render — avoids re-scanning 150 days per card. No changes to alert logic or Sentinel engine.
Heat & Humidity Sentinel Integration — The Heat Advisory system is now wired into CB_BEHAVIOR. Three additions to the behavioral schema: heat_advisory screen tracker (records manual advisory checks), heatAdvisoryAutoFired signal counter (increments each time an advisory fires automatically after activity logging), and heatAdvisoryEnabled in the setup snapshot (captured on every Settings save). Two new nudge rules: heat_advisory_conditions_disabled fires when the user has heat-sensitive conditions and 5+ activity logs but Heat Advisory is off — direct action button opens Heat Settings (suppressDays: 14). heat_advisory_feature_unused fires when the advisory is enabled and conditions are present but neither auto nor manual advisories have ever fired — guides the user to start using temperature bands during activity logging (suppressDays: 30). Both rules pass the cry-wolf test: they fire because of a safety behavior gap, not to add trigger volume.
Behavioral Intelligence — Setup Gap Rules + Unified Guidance — Three new companion card nudge rules now fire based on the CB_BEHAVIOR setup snapshot: setup_no_conditions (fires at 3+ days if no conditions set, suppressed 7 days), setup_no_patient_name (fires at 5+ days if name missing, suppressed 14 days), and setup_bp_not_customized (fires when 20+ readings logged and 5+ days old with default BP targets, suppressed 14 days). Each card includes a direct action button that closes Sentinel, opens Settings, and scrolls to the relevant section. The settings_complete encouragement rule now reads d.setup directly instead of calling _checkSettingsGaps() live. The standalone Settings Gap Card in Sentinel (v9.10.35) has been retired — setup guidance is now unified under the companion card system. snapshotSetup() is now called on app init (500ms deferred) so the setup block is populated from day one, not only after the user visits Settings.
Behavioral Intelligence Layer — Schema v2 Redesign — The silent behavioral observer has been redesigned from the ground up. CB_BEHAVIOR now tracks five dimensions: presence (screens and log types used), frequency and recency (with streak tracking and time-of-day distribution per log type), quality (notes attached to logs, context saves), setup completeness (snapshotted on every Settings save — patient name, conditions, daily events, medications, BP target customization), and engagement depth (anchor investigations saved, Doctor’s Reports generated, analytics notes, context notes, appointments, data exports, wizard completion). Signal response tracking records whether companion cards are read before dismissal or instantly dismissed, giving the rule engine a measure of its own effectiveness. 9 new hooks added. Full forward migration from v1 installs with zero data loss. No visible UI changes.
Activity Timer — Background Mode — A timed activity can now be minimized to a persistent blue pill in the bottom-left corner of the screen (mirroring the Today’s Status button on the right). Tapping “↙ Minimize — keep timer running in background” inside the timer display collapses the activity modal, saves all form state (activity type, notes, exertion, temperature band), and continues the timer silently. The blue pill shows the activity icon, name, and live elapsed time. The user can then log BP, check Sentinel, or do anything else in ClinBridge without losing their ride time. Tapping the pill reopens the activity modal with the exact accumulated time, all fields pre-restored, and correct timer button states. If the user taps Log Activity while a background activity is running, a choice prompt appears: Resume & Finish the current activity, or Discard & Start New. The activity pill stays visible even when other modals are open so the user always knows the timer is running. Reminder queue badge moved to bottom:82px to clear both pills. Today’s Status FAB behaviour unchanged.
Sentinel — Fluid Tracking Gap Detection — Sentinel now monitors fluid logging patterns and surfaces a single card when a meaningful gap is detected. Two scenarios are covered: (1) Event deletion drop — when a daily event with a fluid goal is removed from Settings, Sentinel compares today’s fluid total against the 7-day average and, if the gap is significant, shows a card with “Log Fluid Now” and “Restore Event” buttons. (2) Silent fluid day — after 7 PM, if the user has logged fluid on 5 or more of the last 7 days but today’s total is zero, Sentinel surfaces the same card. Both checks are gated to once per 24 hours so the app never nags. The fluid events snapshot is saved every time Settings are saved and on app startup so deletion detection is always current.
Sentinel — Settings Gap Card — Sentinel now checks for high-impact incomplete settings and surfaces a single non-intrusive card at the top of the Sentinel panel. The card identifies up to three gaps in order of clinical importance: patient name missing (affects Doctor’s Report header), no conditions selected (affects symptom matching and detector context), no daily events configured (fluid and BP reminders inactive), and no medications listed (effectiveness tracking inactive). Each gap has one button that closes Sentinel, opens Settings, and scrolls directly to the relevant section. The card has a dismiss button that hides it for 14 days. It never appears more than once every 14 days, and disappears permanently once all gaps are resolved. Does not show until Sentinel has built a baseline (7+ days of data).
Notifications — reminder no longer interrupts mid-log work — When a scheduled event reminder fired while the user was filling in a log form (BP, weight, symptoms, activity), showEventReminder() called showModal() which directly overwrote modalContent.innerHTML, destroying any partially entered data. Fixed: showEventReminder() now detects when the main modal is already open and queues the reminder instead of interrupting. A non-intrusive green badge appears at the bottom of the screen showing the event name with “Show Now” and “Skip” options. The OS chime still plays once. When the user finishes their log and closes the modal, the queued reminder appears automatically. No data is ever lost.
Notifications — advance chime ignored notify=false on Plan My Day events — The advance pre-warning system (checkScheduledAlerts) pushed all dailyPlan events into its fire queue without checking whether the user had turned off notifications. Events with notify: false were chiming early anyway. Fixed: dailyPlan events with both notify: false and sound: false are now skipped.
Notifications — advance chime double-fired after page reload — firedEvents (the advance-reminder tracking object) was stored only in memory. If the app was reloaded or the PWA woke from background after an advance chime had already fired, firedEvents was empty again and the chime re-fired. Fixed: firedEvents is now persisted to localStorage under BP_TRACKER_FIRED_EVENTS and restored on init alongside firedReminders.
Notifications — OS banner could fire after in-app reminder was already dismissed — Plan My Day event IDs were constructed with array index (plan_0_Name) in three different places, with no guarantee the index at scheduling time matched the index at dismissal time. Fixed: all three systems now use a shared _planEventId(evt) helper that builds the ID from name + time instead of index, guaranteeing consistent tags across the full scheduling → fire → dismiss cycle.
Notifications — “Not Now” permanently blocked future permission prompts — promptPWANotificationPermission() wrote the CLINBRIDGE_NOTIF_PROMPTED flag before showing the modal. Tapping “Not Now” left the flag set, permanently blocking the prompt. Fixed: flag now written only when the user taps “Allow Reminders.” A “Re-enable Reminder Prompt” button appears in Settings → OS Notifications for users who previously tapped Not Now.
Sentinel Doctor View — Symptom Frequency now shows actual symptoms — When a cardiologist asks “what were the symptoms?” the Symptom Frequency Doctor View now shows a full list of every symptom logged in the last 7 days, grouped by date, with symptom name, severity score (color-coded), time logged, and any notes. Cardiologist can see not just “3.3 per day” but exactly what was logged, when, and how severe.
Help & About — tab bar scroll chevrons — A tappable ’ › ’ chevron now appears on the right edge of the Help tab bar whenever more tabs are hidden off-screen. Tapping scrolls the bar right by 200px with smooth animation. A ’ ‹ ’ chevron appears on the left when scrolled away from the start. Both chevrons auto-hide when their respective edge is reached. Chevrons use a gradient fade so hidden tabs are visually implied. Large tap targets for senior users. Built for the 14-tab bar where 5–6 tabs are typically off-screen on mobile.
Doctor View — symptom duplicates — getAllHistoricalData() already includes today’s saved symptoms. The Doctor View code was also adding the in-memory S array on top, doubling every symptom logged today. Fixed by removing the S merge — getAllHistoricalData() is the single source of truth.
Sentinel Doctor View — wrong stream shown — doctorLines[i] was mapped to score.streams[i] for stream key lookup, but doctorLines only contains drifting/alarming streams while score.streams contains all streams. Index mismatch caused the first drifting stream to always open HR Daily Spread Doctor View regardless of which sentence was tapped. Fixed: replaced parallel arrays with paired doctorEntries array of {line, key} objects built directly from each stream as it is processed, guaranteeing each sentence button opens the correct stream’s Doctor View.
Doctor View — HR pins still showing ? after repair — _dvBuildHRContent() read only beforeMean/afterMean (level_shift fields), but rapid_change pins store values in from/to fields. Result: all Rapid HR Change pins showed ? even after auto-repair. Fixed to resolve both field names with fallback. Also corrects the section heading (shows “Rapid Heart Rate Change” vs “Heart Rate Level Shift” based on type), and shows “Single session / within one day” instead of blank shift date for rapid changes. Repair key bumped to v2 to force re-run on all existing devices.
Doctor View migration notice — Users upgrading from versions prior to v9.10.25 who have existing pins with empty detectorData now see a one-time blue notice at the top of Pinned Events. The notice explains that existing pins still work for appointment read-aloud, but re-pinning will unlock the full “Tap to Show Your Doctor” data view. Includes a count of affected pins and step-by-step re-pin instructions. Dismissed permanently via “Got it” button stored in localStorage. Notice auto-hides permanently once dismissed and never reappears. Also auto-hides if all pins already have detectorData.
Doctor View — auto-repair of existing pins — On first open of Pinned Events, silently reconstructs detectorData for any existing pins with empty detector data by parsing their summary strings. Covers all four detector types: HR level shift (extracts before/after bpm averages, shift magnitude, direction), HR rapid change (from/to bpm, delta, direction), decompensation (signal names and count), pulse pressure (avgPP, chronic flag, status title), and symptom convergence (symptom names, average severity). Runs once, never again. No user action required — Doctor View data will populate automatically on next open of Pinned Events.
Doctor View — overlay hidden behind Pinned Events modal — Doctor View overlay had z-index:99999, identical to the .modal CSS class. Since Pinned Events modal appears later in DOM order, it won the z-index tie and rendered on top of Doctor View. Fixed: Doctor View z-index raised to 999999, above all modals.
Doctor View — “Symptom detail not available” — handlePinTap() was passing {} as detectorData to pinEvent(), discarding the symptom objects, HR shift values, and signal lists that detectors attached to each suggestion. Fixed: renderPinSuggestion() now stores all suggestion objects in window._pinSuggestionMap keyed by source|eventDate. handlePinTap() retrieves the correct detectorData from that map before saving the pin. All future pins will have full detectorData for Doctor View display.
Doctor View — Read-only data overlay with exact scroll restore — When a cardiologist says “show me,” the patient now taps a full-width “📊 Tap to Show Your Doctor” button (min 56px height, senior-safe tap target) on any sentence in the Sentinel or Pinned Events “What to Say” box. A full-screen read-only overlay opens instantly showing the clinical data behind that specific sentence — HR regime shift with before/after values, decompensation signals, pulse pressure trend, or symptom cluster with severities and timestamps. A large fixed “← Back to ClinBridge” header button (64px, always visible) returns to the exact scroll position. No inputs, no logging, nothing to accidentally tap. Doctor View is completely locked to read-only while open.
closeAbout() instead of closeHelpModal(). The floating Today's Status button did not restore correctly after closing. Fixed.e, E, +, and - as valid browser scientific notation. One global listener now blocks them across all 30+ numeric fields.What is actively in development or on the near-term roadmap. Features are prioritized by clinical value and user feedback.
For bugs that were fixed, see the Known Issues tab. Release history is at the bottom of this tab.
Once enough check-in data exists, a "Your Fluid Response Profile" view in Settings shows your personal pattern in plain language. This becomes the foundation for a productive conversation with your cardiologist about a personalized daily limit.
Barometric pressure drops correlate with PPH episode severity. ClinBridge will detect significant pressure changes and issue a proactive heads-up so you can adjust hydration and activity before symptoms occur.
Optional read-only access for a spouse, adult child, or caregiver to view your dashboard and receive alerts — without being able to edit your data.
Correlate meal logs with post-meal BP readings to identify which foods or meal sizes consistently trigger PPH episodes. Over time, builds a personal map of your dietary BP triggers.
Log sleep quality and duration. Poor sleep is a major driver of next-day BP irregularities and OSA complications. Correlating sleep quality with BP trends gives your doctor a fuller clinical picture.
Full native apps with reliable background notifications, HealthKit / Google Fit integration, Apple Watch complications, and wrist-tap logging. No browser required.
Auto-import heart rate and activity data from Apple Watch, Fitbit, and Garmin — so you are not re-entering data that your devices already captured.
ClinBridge is built by a patient, for patients. If there is something your care plan requires that ClinBridge does not yet do, we want to know. Use the Contact & Feedback section in Settings to send a suggestion directly to the development team.
Food Check. Single-food nutritional awareness tool inside Ask ClinBridge. Access via the 🍴 tools icon in the Ask input bar. Enter food name, preparation method (19 options in 4 clinical groups), portion, and optional label values for Sodium, Potassium, and Phosphorus — each with a mg / %DV toggle. Ask evaluates the food against your logged conditions and medications and returns ✅ Generally fine, ⚠️ Worth watching, or 🚫 High concern with a profile-specific summary. Last-entered values are remembered for quick re-evaluation with changed variables.
Meal Builder. Full-meal nutritional analysis inside Ask ClinBridge. Build complete meals item by item with the same form fields and mg/%DV toggles as Food Check. Running totals for Sodium, Potassium, and Phosphorus update live as items are added. Analyze Meal evaluates the combined load — not individual items. After analysis, a Modify & Re-analyze button returns to the builder with all items intact; Save to Library saves the meal permanently. Individual item correction is done by removing and re-adding the item with corrected values.
Saved Meals Library & Manage Meals. Saved meals are stored in ClinBridge data and included in all backups. Each saved meal records its items, combined nutritional totals, saved date, and last evaluated date. Manage Meals button on the main page (alongside Manage Medicines and Manage Symptoms) opens the library. Each meal card has four actions: ✏️ Edit (opens in builder pre-loaded), 🔄 Re-evaluate (sends to Ask against current conditions/medications), 🚫 Do Not Use (flags with optional note and hides from Log Meal picker), 🗑️ Delete. Saved meals also appear as a picker at the top of the Log Meal modal, organized by type, for fast pre-fill logging.
Ask panel UI restructure. The Ask input bar now has a single 🍴 tools icon that opens a two-option picker (Food Check or Meal Builder). Each tool takes the full panel height with a Back arrow to return to the Ask thread. Eliminates the previous multi-button row that caused scrolling and usability issues on mobile.
Log Medicine — conditional note shown at logging time. Medicines with a clinical condition (e.g. Metoprolol “Only when diastolic >70”, Losartan “Only when systolic >100”) now show an amber warning banner in the Log Medicine modal. Previously the note was only visible in Manage Medicines.
Pinned Events — “What to Say” box showing on Addressed pins — Language engine was checking evt.communications instead of evt.commLog. Fixed to read evt.commLog.status directly. Box now correctly hidden when status is Addressed.
Archived events reappearing as new pin suggestions — isPinnedEvent() now checks both active pins and the archive. An event that has ever been pinned and archived will never surface as a new suggestion again.
Sentinel — “What to Tell Your Doctor” box — When any stream is drifting or alarming, Sentinel now displays a highlighted box at the top of the modal with pre-written plain-language sentences the user can read aloud at their appointment. Box is hidden on All Clear. Orange border for drifting, red for alarming.
Pinned Events — “What to Say at Your Appointment” language engine — Every detector-backed pin card now displays an auto-generated sentence the patient can read aloud to their cardiologist. Language derived from detector data. Box hidden when Addressed, muted when Deferred, fully visible when Unresolved or Follow-up Ordered. Manual pins never get a box.
Help & About tab bar — horizontal scroll layout — Tab bar now scrolls horizontally in a single row. Full content height is always preserved regardless of tab count. Standard mobile UX pattern — swipe the tab bar to reach any section. Scales to any future tab additions without layout impact.
Sentinel documented in Help & About — Dedicated tab covers what Sentinel watches, what a Footprint is, how the Clinical Event Log works, and why personalized pre-event pattern recognition is clinically novel. Modal footer and disclaimer now always visible. Grammar corrected.
Sentinel v2 — Two-tier scoring drives alarms from 14-day recent pattern. Clinical Event Log with baseline reset. Stream cards in plain language with specific action guidance and date ranges.
Sentinel — Personal Pattern Precursor Detector — Watches 3 live data streams (HR daily spread, symptom frequency, pulse pressure) against your personal baseline. Learns from your Footprints — 72-hour pre-event windows extracted from all Pinned Events. Badge turns yellow at 2 drifting streams, red at 3. Pin any match for your Doctor's Report. Built from your real data: 9 Footprints across 45 days.
Sentinel — Personal Pattern Precursor Detector — Watches 3 live data streams (HR daily spread, symptom frequency, pulse pressure) against your personal baseline. Learns from your Footprints — 72-hour pre-event windows extracted from all Pinned Events. Badge turns yellow at 2 drifting streams, red at 3. Pin any match for your Doctor's Report. Built from your real data: 9 Footprints across 45 days.
Pinned Events question UI — three interaction bugs fixed — Add Question now shows the saved question immediately. Mark Asked checkbox now reflects state instantly. Delete (✕) now confirms before removing and always takes effect. All three operations re-render the pin card in place.
Button spacing audit — all main logging modals — Systematic pass through Log BP, Log Fluid, Log Activity, Log Symptom, Log Weight, Log Meal, and Morning Check-In. Minimum 12 px gap enforced between every pair of tappable buttons. Reduces misfire taps for senior users on touchscreens. TestSuite v4 Section 15 (Help & About, 18 new automated tests) released alongside.
Help & About — complete tab overhaul — Sticky tab bar. Larger tap targets. Pinned Events and Heat Advisory tabs added. Pinned Events tab includes full clinical context, doctor workflow, and anonymized case study.
Pinned Events comm layer UI freeze fixed — All 6 operations now in-place with toast. No modal rebuild. Smooth on mobile.
Pinned Events Communication Layer — Log Communication (who, date, response, status) and Add Question per-pin. All data archives with the pin.
All Notes search box fix — Multi-character keywords now work. _filterNotesInPlace() handles live search without destroying the input element.
Help & About documentation catch-up and Already-linked BP card dismiss button.
Recent BP contextual card at Log Activity open. BP Before Activity button in Manual mode. Manual mode info card.
Symptom System Full Overhaul — 70+ synonym mappings, Bulk Rename, clinical context prompt, Manage Symptoms rebuilt in 3 sections.
Tier C Pattern Ripening Nudge and Tier D Urgent Convergence Alert. Glossary Tab. Help & About full rewrite with QR code.
Four detectors live: HR Rate Detector, Decompensation Warning, Pulse Pressure Detector, Symptom Convergence. Pinned Events, 60-day Timeline, Appointment Snapshot, Archive & Clear.
Per-card history isolation. Weight outlier flagging (AHA/ACC thresholds). Weight jump-to-date picker. Critical launch-day regression fix.
Activity Timer Pause/Resume. HR Rate Detector Quick Stats Period Selector. All Notes emoji header fix.
Advanced Analytics analyzes BP readings before and after logged meals. Flags events with ≥15 mmHg systolic drops. For informational tracking only.
Postprandial Hypotension (PPH) is a drop in blood pressure that occurs after eating. "Postprandial" means after a meal; "hypotension" means abnormally low blood pressure.
The clinical definition: A drop of ≥20 mmHg systolic within 2 hours of eating. This is the threshold used by cardiologists and published in clinical guidelines.
Why it matters: PPH is common in older adults and in people with autonomic nervous system conditions, diabetes, Parkinson's disease, and certain cardiac conditions. It can cause dizziness, lightheadedness, falls, and fainting. Many people experience it without realizing meals are the trigger.
When you eat, your body redirects significant blood flow to your digestive tract to absorb nutrients. In a healthy cardiovascular system, compensatory mechanisms — heart rate increase, blood vessel constriction elsewhere — maintain overall blood pressure. In people with autonomic dysfunction or compromised cardiac output, these compensatory responses are slower or weaker, and blood pressure drops before the body can correct it.
Contributing factors include: large meals (more blood required), high-carbohydrate meals (faster digestion, faster demand), alcohol with meals, being dehydrated before eating, and certain medications (especially antihypertensives taken near mealtime).
The Post-Meal BP Patterns panel in Advanced Analytics automatically analyzes your logged data using the clinical standard:
Each meal pair is shown in a table with the pre-meal reading, nadir BP, systolic drop, and how many minutes after eating the nadir occurred. PPH events are marked with ⚑.
Step 1 — Log your meal using the 🍽️ Log Meal button. The timestamp is recorded automatically when you save.
Step 2 — Log BP before eating (within 60 minutes before your meal, while still at rest). This is your baseline. Sitting quietly for 3–5 minutes before taking it gives the most accurate pre-meal reading.
Step 3 — Log BP after eating at roughly 30, 60, and/or 90 minutes post-meal. ClinBridge uses the lowest reading in the 2-hour window — so even one post-meal reading helps, but multiple readings improve accuracy by capturing the true nadir.
Step 4 — Open Advanced Analytics and scroll to Post-Meal BP Patterns. You need at least 3 meals and 5 BP readings in the selected time period before analysis runs.
If you experience any of these within 1–2 hours of eating, log them in ClinBridge immediately and note the meal timing:
Note: PPH can be asymptomatic — a significant drop may occur with no symptoms at all. The only way to know is to measure.
When 3 or more meal pairs are available, your Doctor's Report automatically includes a Post-Meal BP Pattern (PPH) section summarizing the number of PPH events, average post-meal BP change, and (when a pattern is confirmed) a list of the most recent PPH events with dates, meal names, and drop values. This gives your cardiologist documented evidence — not just a complaint of "feeling dizzy after meals."
For informational tracking only. ClinBridge does not diagnose PPH. Discuss any detected pattern with your cardiologist — they can determine clinical relevance, rule out other causes, and advise on management strategies.
Plain-language definitions for every clinical term and app phrase used in ClinBridge. If you see a word in the app and don't know what it means, it's here.
The force your heart uses to push blood through your arteries, measured in millimeters of mercury (mmHg). Expressed as two numbers: systolic (the top number — pressure when your heart beats) over diastolic (the bottom number — pressure when your heart rests between beats). Example: 120/80 mmHg. Normal range for most adults is below 130/80, but your cardiologist will give you a personal target that may differ.
The difference between your systolic and diastolic readings. Example: if your BP is 118/85, your pulse pressure is 33 mmHg. Normal range is 40–60 mmHg. A narrow pulse pressure (below 40) can indicate the heart is working harder to push blood forward — a pattern seen in reduced cardiac output and certain valve conditions. A wide pulse pressure (above 60) may indicate arterial stiffness. Many cardiac patients have a chronically narrow PP that is their personal baseline — what matters is change from that baseline, not comparison to textbook normals.
How many times your heart beats per minute (bpm). Normal resting range is 60–100 bpm. Below 60 is bradycardia (slow heart rate); above 100 is tachycardia (fast heart rate). Patients with pacemakers may have a lower set rate limit — your pacemaker clinic can tell you what range is expected for your device settings.
A heart rate below 60 bpm. In ClinBridge, the HR Rate Detector flags readings below 50 bpm specifically, as this is below the range most pacemakers are programmed to allow. Bradycardia is normal for well-trained athletes and some medication effects (beta-blockers, for example, intentionally slow the heart rate). Context matters — discuss any persistent low readings with your cardiologist or device clinic.
A sustained change in your heart rate baseline — where your resting HR was consistently at one level, then durably shifted to a new level and stayed there. This is different from a single high or low reading. ClinBridge's HR Rate Detector identifies these shifts statistically by comparing before-and-after windows for stability. A level shift is clinically significant because it suggests something changed in your cardiac state — compensation, medication effect, disease progression, or recovery. Your cardiologist will want to know.
A chronic condition where the heart doesn't pump blood as efficiently as it should. "Congestive" refers to fluid backing up into the lungs and body (edema). Heart failure doesn't mean the heart has stopped — it means it's working harder than it should to maintain output. Management focuses on monitoring fluid balance, weight, symptoms, and medication adherence. ClinBridge's Decompensation Warning system is specifically designed to detect early signs of fluid buildup before symptoms become severe.
When a cardiac patient's condition worsens — typically due to fluid overload in CHF — to the point where symptoms become severe and hospitalization may be required. Early decompensation signs include rapid weight gain (fluid retention), worsening shortness of breath, swelling in legs and ankles, fatigue, and reduced activity tolerance. The goal of ClinBridge's Decompensation Warning detector is to surface multiple early signals before they progress to a crisis.
In the Decompensation Warning detector, each of the five clinical signals (weight, cardiac output, symptoms, fluid, notes) can score 0, 1, or 2 points based on severity. Maximum total is 8 points. The detector shows how many points are active and which signals contributed. One point alone is labeled "Early Indicator" — not alarming. Two or more points prompt closer monitoring. Two or more red-level signals prompt contacting your cardiologist.
When multiple symptoms occur together or escalate simultaneously in a pattern that suggests an underlying common cause. In ClinBridge, convergence is detected across three layers: symptoms clustering within a 4-hour window on the same day, the same symptom worsening in severity over multiple days, and recognized clinical symptom triads. The significance is that individual symptoms are often dismissed — but a convergent pattern of multiple symptoms is harder to attribute to chance and more likely to represent a real clinical event.
A recognized combination of three symptoms that together suggest a specific condition or event. ClinBridge recognizes: the CHF Decompensation Triad (shortness of breath + fatigue + swelling/edema — a classic early decompensation pattern); the Arrhythmia Triad (palpitations + dizziness + chest pressure/tightness — may indicate an arrhythmia episode, note timing and duration); and the Systemic Symptom Pattern (nausea + fatigue + reduced appetite — nonspecific, worth noting but not alarming on its own). Triads are worth mentioning to your cardiologist, not reasons to panic.
A drop in blood pressure that occurs after eating. "Postprandial" means after a meal; "hypotension" means low blood pressure. Common in older adults and those with autonomic nervous system conditions. Typically defined as a drop of ≥20 mmHg systolic within 1–2 hours of eating. Symptoms include dizziness, lightheadedness, and fainting. ClinBridge's Post-Meal BP Patterns detector in Advanced Analytics uses the clinical standard — a ≥20 mmHg systolic drop within 2 hours of eating — to identify PPH events and surface patterns for discussion with your care team.
An irregular heart rhythm — the heart beats too fast, too slow, or with an irregular pattern. Common types include atrial fibrillation (AFib), where the upper chambers quiver instead of beating regularly, and various bradycardias and tachycardias. Symptoms can include palpitations (feeling your heart beat irregularly or rapidly), dizziness, shortness of breath, or fatigue. Some arrhythmias are asymptomatic. ClinBridge logs heart rate with each BP reading; rapid changes and low readings are flagged for review.
ClinBridge stores 90 days of daily readings on your device. After 90 days, the oldest day is removed as a new day is added — like a rolling 90-day window. This means data from more than 90 days ago is no longer in the app unless you exported a backup at that time. To preserve data long-term: export quarterly (last day of each quarter is a good practice). Pinned Events and Appointment Snapshots are exceptions — they are stored permanently and never roll off.
A clinically significant finding that you've chosen to permanently preserve. When a detector flags something worth showing your cardiologist, tapping "📌 Pin" saves the finding, the date, and all raw data from that day to a permanent list that never rolls off. Pinned events appear in your Doctor's Report and on the 60-day Timeline. After your cardiologist appointment, use "Archive & Clear" to save all current pins to a permanent archive and start fresh.
Your personal "normal" — the consistent pattern your readings follow when nothing unusual is happening. ClinBridge uses the word "baseline" in two contexts: (1) Your personal BP/HR baseline — the average range your readings cluster around, used as the reference point for detecting changes; and (2) Baseline symptoms in the Morning Check-In — symptoms you experience routinely (such as chronic ankle swelling after a procedure) that are part of your normal state, not new developments. Baseline symptoms are recorded for your doctor but excluded from pattern correlation calculations.
ClinBridge's core accuracy principle. The detectors use real statistical methods on real data — but statistics identify patterns, not causes. A detected HR level shift is mathematically real. Whether it represents disease progression, a medication effect, recovery, or random variation requires clinical judgment that only your cardiologist can provide. ClinBridge points in a direction and gives you the evidence to have a productive conversation — it does not tell you what that pattern means for your specific medical situation.
ClinBridge's design philosophy. Many health apps generate advice or recommendations — telling you what to do. ClinBridge instead verifies patterns across multiple data streams before surfacing a finding. It only escalates when signals converge — when two or more independent data streams agree that something changed. A single reading doesn't trigger an alert. A single signal point doesn't trigger a pin suggestion. This "verification first" approach is designed to prevent false alarms and preserve the credibility of findings that do get surfaced.
Every other cardiac monitoring tool watches for what is happening right now. Sentinel watches for what came before. It is built on a simple but powerful idea: the patterns in your own data in the days before a clinical event are more meaningful than any population-based threshold — because they are yours.
Sentinel watches three data streams around the clock — your HR daily spread, your symptom frequency, and your pulse pressure. It compares each one not to a textbook average, but to your own recent personal pattern. When two or more streams drift above your recent normal at the same time, Sentinel surfaces a pattern match — before symptoms escalate, not after.
Your recent pattern is calculated from your own logged data — the last 14 days, or from a clinical event date if you have logged one. This means Sentinel stays calibrated to where you are in your health journey, not where you were six months ago.
When Sentinel detects that two or more of your streams are drifting above your recent normal, it automatically generates a "What to Tell Your Doctor" box at the top of the Sentinel screen. Each flagged stream gets one plain-language sentence you can read aloud at your appointment.
The language is read-only and auto-generated from your data. Sentinel stands behind every sentence it generates.
Every time you pin a clinical event from one of ClinBridge's detectors, Sentinel automatically extracts what your data looked like in the 3 days before that event and saves it as a Footprint. Over time, Sentinel builds a personal library of your pre-event signatures.
When your current data resembles a prior Footprint, Sentinel tells you specifically — which event it resembles, what your data looked like then, and what your data looks like now. It does not tell you what is going to happen. It tells you that a pattern you have lived through before is appearing again.
Pacemaker adjustments, new medications, procedures, hospitalizations — any clinical change that legitimately shifts your baseline belongs in the Clinical Event Log inside Sentinel. You will find it by opening Sentinel and tapping + Log Clinical Event.
When you mark an event as a baseline reset, Sentinel compares your streams to your data after that event — not before it. This is critical after a pacemaker adjustment, for example: your heart rate pattern may shift significantly as settings take effect, and Sentinel needs to know that the shift is intentional and clinical, not an emerging problem.
The Clinical Event Log is also a permanent record of your care timeline — visible in Sentinel, yours to keep, never transmitted anywhere.
No published cardiac monitoring tool has done this at the individual patient level outside a hospital setting. Academic research on pre-decompensation pattern recognition requires Holter monitors, IRB approvals, and study populations measured over months or years. The results are then averaged across those populations — which means the thresholds apply to the average patient, not to you.
Sentinel does it differently. It uses the data you are already logging every day. It compares you to yourself. Your quiet baseline, your pre-event Footprints, your recent pattern — everything Sentinel knows comes from your own history, not from a population study. That is what makes it personal in a way that published thresholds cannot be.
Sentinel is not a diagnosis. It is not a medical device. A pattern match does not mean something is wrong — it means your data looks similar to a prior period that preceded a clinical event in your own history. That is worth noting. It is not worth panicking about.
Sentinel provides the documented evidence and the pattern recognition. Your cardiologist provides the clinical interpretation. The goal is to walk into your next appointment with something real to show — not a vague feeling that something might be off, but a specific, timestamped pattern match from your own data that your doctor can evaluate.
Ask is a conversational analytical helper built into ClinBridge. It knows every feature of the app and has full awareness of your logged data across all streams — BP, HR, fluid, meals, symptoms, notes, medications, and activities — so you can ask plain questions and get data-driven answers based on what you have actually recorded.
Cross-stream pattern analysis — Ask looks across all your data simultaneously:
About your data — trends, averages, and specific readings:
About how the app works:
Tap the 💬 Ask button on the main screen. A conversation panel opens. Type your question in plain English — no special format required.
Ask reads your entire logged history — BP readings with HR, fluid entries with notes, weight, symptoms with their notes, medications, meals, activities, and standalone notes — and gives you a data-driven answer. Notes attached to any log entry are fully included, so the context you wrote when logging a symptom or a fluid entry is visible to Ask when analyzing patterns.
For pattern questions, Ask examines multiple data streams simultaneously — looking at what was logged before, during, and after events to surface temporal correlations and note text patterns. Findings are always framed as data observations: “The data shows…”, “Of your X readings…”, “Your notes frequently mention…”
Conversation persistence. Your session is saved automatically when you close the panel. When you reopen Ask within 48 hours, a blue banner at the top shows when the session was from and offers a Start Fresh button if you want to begin a new conversation instead. After 48 hours the session clears automatically.
If your question is unclear, Ask will offer you a few clearer versions to tap. You can ask follow-up questions in the same window — the conversation stays connected and builds on previous answers.
When Ask produces a significant data finding — a pattern, a correlation, a before-and-after comparison — a small 📌 Pin this finding button appears below the response.
Tapping it saves the full response as a Pinned Event with today’s date, the raw data context from that day, and the complete text of Ask’s analysis. The pin is immediately available in Pinned Events and appears in your Doctor’s Report — ready to bring to your next appointment.
The button changes to ✅ Pinned to confirm. You decide which findings are worth keeping — pin as many or as few as you choose.
Ask will: observe patterns in your data and report what it finds. “Of your 17 HR readings above 75, 82% occurred between 5:30 PM and 10:30 PM” is a data observation. “Your cough notes mention lying down in 14 entries” is a data observation. Ask is designed to surface these findings clearly and present them in a form you can bring to your cardiologist.
Ask will not: interpret what those patterns mean for your health, suggest a diagnosis, recommend changing medications, or replace your care team. When a finding crosses from data observation into clinical meaning, Ask will say: “That pattern is worth noting — it would make a good Pinned Event for your next appointment.”
The distinction is intentional. Ask gives you the evidence. Your cardiologist gives you the interpretation. Both are necessary. Neither replaces the other.
✅ Ask about correlations. The most powerful questions are cross-stream: “What was happening in the hours before my elevated HR readings?” “Does my fluid intake affect my afternoon BP?” Ask can look across all your data simultaneously.
✅ Ask about your notes text. Every note you wrote when logging a symptom, fluid entry, meal, or activity is available to Ask. “Look at my cough notes and find any repeated words or situations” is a powerful question. Your own observations become searchable patterns.
✅ Ask about a specific date. “Tell me everything logged on April 1 and what happened in the 3 hours before my chest pain entry” pulls the complete picture for that day.
✅ Ask before and after comparisons. If a medication changed, a pacemaker was adjusted, or a procedure happened — ask Ask to compare the weeks before and after. Temporal break points reveal a lot.
✅ Follow up. After an answer, keep asking in the same window. “Are most of those events in the morning?” is a valid follow-up. The conversation stays connected.
✅ Pin what matters. When Ask finds something worth bringing to your doctor, tap Pin This Finding. It lands in Pinned Events and your Doctor’s Report automatically.
✅ Start simple if new. If you are new to Ask, start with “What should I tell my cardiologist about at my next appointment?” to get a feel for what it can surface.
Tap the 🍴 tools icon on the left side of the Ask input bar. A picker opens with two options: 🥦 Food Check and 🍲 Meal Builder. Tap either one to open it. The tool takes over the full panel. Tap ← Back at any time to return to the Ask conversation thread.
Enter a food or product name, how it is prepared, how much you will actually eat, and any label values you have available. All label fields are optional — if you leave them blank, Ask uses its own nutritional knowledge for that food.
Sodium, Potassium, and Phosphorus each have a mg / %DV toggle beneath the field. Some labels show milligrams; others show % Daily Value. Switch the toggle to match what your label shows — Ask converts %DV to mg automatically using FDA Daily Values (Sodium 2,300 mg · Potassium 4,700 mg · Phosphorus 1,250 mg) before evaluating.
The preparation method matters clinically. Boiling and draining removes up to 50% of potassium from vegetables. Canning adds sodium. Drying concentrates all nutrients. The prep method dropdown is organized into four groups — Fresh/Uncooked, Wet heat, Dry heat, and Processed/Preserved — so you can quickly find the right option and Ask can account for how preparation changes the nutritional profile.
Ask evaluates the food against your logged conditions and current medication list. The response begins with one of three indicators: ✅ Generally fine for occasional use, ⚠️ Worth watching, or 🚫 High concern — discuss with your care team, followed by a brief factual summary specific to your profile.
After a Food Check result, tap the 🍴 tools icon again and select Food Check to run another check. Your last-entered values are remembered — the form reopens pre-filled so you can change just the prep method, portion, or any value and resubmit without starting over. Food Check is a nutritional awareness tool, not a dietary prescription. Always discuss dietary restrictions with your cardiologist and renal dietitian.
Meal Builder evaluates the combined nutritional load of an entire meal — not just one food. This matters because a single item may be fine in isolation but the combined sodium, potassium, and phosphorus of a full meal may exceed your safe threshold. Meal Builder is also the right tool for planning before grocery shopping — build the meal you intend to make and check it before you buy.
Building a meal: Give your meal a name and select its type (Breakfast, Lunch, Dinner, Snack, or Meal). Then add items one at a time — enter the food name, prep method, portion, and any label values. Tap + Add to Meal. Running totals for Sodium, Potassium, and Phosphorus update after each item so you can see the cumulative load building in real time.
Analyzing a meal: When all items are added, tap 🔍 Analyze Meal. Ask evaluates the combined totals against your conditions and medications and returns a single verdict for the whole meal with a 3–4 sentence summary. After the analysis, a save/modify bar appears in the conversation thread with two options.
✏️ Modify & Re-analyze: Reopens the builder with all items still loaded. Change a portion size, swap a prep method, remove an item, or add a new one — then tap Analyze again. This is also how you correct an individual item: remove it from the list and add it back with the corrected values.
💾 Save to Library: Saves the meal to your personal Saved Meals Library. A saved meal can be selected directly from the Log Meal screen — tap Log Meal and your saved meals appear at the top, organized by type, so you can pre-fill your log entry in two taps.
You can also save a meal directly from the builder before analyzing it using the 💾 Save button at the bottom of the form. This is useful when you want to save a meal template for future use without running an analysis every time.
Tap the paperclip button (📎) next to the food tool button to attach a PDF or image before sending your question. Use this for hospital discharge summaries, lab reports, specialist letters, or any clinical document you want Ask to read alongside your health data.
Example questions with attachments: "What BP target did my discharge summary specify?" · "Does this lab result explain my HR shift since March?" · "What medications were listed on this clinic note?"
After tapping 📎, a file picker opens. Select your file — a preview strip appears above the input showing the filename with a ✕ to remove it before sending. The blue dot on the 📎 button confirms a file is loaded. When you send your question, the document goes with it.
Ask focuses only on the parts of the document relevant to your specific question — it does not reproduce or summarise the full document. The response combines what it found in the document with your logged ClinBridge data to give you a grounded, contextual answer.
ClinBridge is free, open-source, and built by a cardiac patient for cardiac patients. There is no subscription, no ads, and no paywall — ever. If it helps you manage your health, a small contribution means a lot.
Your support helps cover hosting, development time, and keeps ClinBridge free for every patient who needs it.
💙 Support via PayPal100% optional — your health data stays private regardless
Your data stays private — stored locally on this device only
Pattern awareness tool only. Not a medical treatment. Does not replace your care team. Math is directional, not definitive. If you experience chest discomfort, shortness of breath, or dizziness — contact your cardiologist, do not use this tool.
Track how your medications affect your heart rate over time
Generates a comprehensive medical report for the selected date range — includes BP summary, out-of-range alerts, weight trends, medication adherence, and clinical assessment.
Pick any date to see a focused 20-day window (14 days before → anchor → 5 days after) with all metrics and events aligned on the same timeline.