Which daily habit affects your lifespan more?
Interactive quiz comparing chronic lifestyle factors measured in microlives — 30 minutes of life expectancy per day.
#| '!! shinylive warning !!': |
#| shinylive does not work in self-contained HTML documents.
#| Please set `embed-resources: false` in your metadata.
#| standalone: true
#| viewerHeight: 1200
library(shiny)
library(bslib)
# ---- Quiz data loaded from separate file (## file: directive) ----
# Data is pre-computed from micromort::chronic_quiz_pairs(difficulty = ..., seed = 42)
# Combined easy/medium/hard tiers.
#
# WHY SEPARATE FILE: Shinylive's JS preloader cannot parse CSV embedded in
# R string literals (commas/quotes break the parser). The ## file: directive
# puts the CSV in a virtual file that R reads normally.
#
# PIPELINE TRACKED: vig_chronic_csv_check target verifies this data matches
# the canonical output of chronic_quiz_pairs().
quiz_pool <- read.csv("chronic_pairs.csv", stringsAsFactors = FALSE)
# ---- format_activity_name helper ----
format_activity_name <- function(name) {
formatted <- sub("\\s*\\(", "<br>(", name)
HTML(formatted)
}
# ---- CSS ----
quiz_css <- "
.quiz-title {
white-space: nowrap;
font-size: clamp(1rem, 2.5vw, 1.5rem);
}
.quiz-btn {
min-height: 180px;
width: 100%;
white-space: normal;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 8px;
padding: 16px 12px;
font-size: 1rem;
border: 2px solid #dee2e6;
border-radius: 8px;
background-color: #2b3e50;
color: #ffffff;
transition: border-color 0.3s, background-color 0.1s;
user-select: text;
-webkit-user-select: text;
}
.quiz-btn:hover { border-color: #2c7be5; background-color: #1a2a3a; color: #ffffff; }
.quiz-btn .activity-name { font-weight: 600; font-size: 1.1rem; line-height: 1.3; }
.quiz-btn .badge { font-size: 0.75em; }
.quiz-btn-correct {
border: 3px solid #198754 !important;
background-color: #d1e7dd !important;
color: #0f5132 !important;
}
.quiz-btn-wrong {
border: 3px solid #dc3545 !important;
background-color: #f8d7da !important;
color: #842029 !important;
}
.quiz-btn-neutral {
border: 3px solid #6c757d !important;
background-color: #e9ecef !important;
color: #495057 !important;
}
.quiz-btn .help-icon { font-size: 0.8rem; color: #adb5bd; cursor: help; margin-left: 4px; }
.quiz-btn .help-link { font-size: 0.7rem; color: #8bb9fe; text-decoration: none; }
.quiz-btn .help-link:hover { text-decoration: underline; }
.explanation-panel { background-color: #f8f9fa; border: 1px solid #dee2e6; border-radius: 8px; padding: 12px 16px; font-size: 0.9rem; }
.gap-3 { gap: 1rem; }
.option-btn-group { display: flex; gap: 8px; flex-wrap: wrap; }
.option-btn {
padding: 8px 18px; border: 2px solid #dee2e6; border-radius: 8px;
background-color: #2b3e50; color: #ffffff; font-size: 1rem;
cursor: pointer; transition: border-color 0.3s, background-color 0.1s;
text-align: center; min-width: 60px;
}
.option-btn:hover { border-color: #2c7be5; background-color: #1a2a3a; }
.option-btn.selected { border-color: #2c7be5; background-color: #2c7be5; color: #fff; }
.option-row { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.option-label { font-weight: 600; white-space: nowrap; min-width: 140px; }
.detail-scroll { overflow-x: auto; width: 100%; }
.detail-table { white-space: nowrap; width: auto; min-width: 100%; }
.detail-table th, .detail-table td { padding: 6px 10px; }
#submit_btn:disabled { opacity: 0.6; cursor: not-allowed; }
"
# ---- Leaderboard (reuses acute quiz Google Form + Sheet) ----
chronic_leaderboard_js <- "
var FORM_URL = 'https://docs.google.com/forms/d/e/1FAIpQLSc1HX5kPVO6G982zOxH2BLv1FWexiITPnbjfWMN3a1M9yDtvw/formResponse';
var SHEET_URL = 'https://docs.google.com/spreadsheets/d/17HLtIdV3r55dIh06cSaWT8kFXzNrkR-Fu2ZJkjszG8k/gviz/tq?tqx=out:json';
var scoreSubmitted = false;
function resetLeaderboard() {
scoreSubmitted = false;
var btn = document.getElementById('submit_btn');
if (btn) { btn.disabled = false; btn.textContent = 'Submit Score'; btn.className = 'btn btn-warning btn-lg'; }
var el = document.getElementById('percentile_text');
if (el) el.textContent = '';
}
function submitScore(score, total, difficulty, nQuestions) {
if (scoreSubmitted) return;
var btn = document.getElementById('submit_btn');
if (btn) {
btn.disabled = true;
btn.textContent = 'Submitting...';
btn.className = 'btn btn-secondary btn-lg';
}
var data = new URLSearchParams();
data.append('entry.335579146', score);
data.append('entry.2122920576', total);
data.append('entry.621716914', new Date().toISOString());
data.append('entry.268026248', 'chronic');
data.append('entry.232879816', difficulty || '');
data.append('entry.2010782223', nQuestions || '');
fetch(FORM_URL, {method: 'POST', mode: 'no-cors', body: data}).then(function() {
scoreSubmitted = true;
if (btn) {
btn.textContent = 'Submitted!';
btn.className = 'btn btn-success btn-lg';
}
getPercentile(score, total, difficulty, nQuestions);
}).catch(function() {
scoreSubmitted = true;
if (btn) {
btn.textContent = 'Score saved locally';
btn.className = 'btn btn-info btn-lg';
}
});
}
var STATS_URL = 'https://johngavin.github.io/micromort/api/quiz_stats.json';
function interpolatePercentile(scorePct, group) {
var p = group.percentiles;
var s = group.scores_pct;
for (var i = s.length - 1; i >= 0; i--) {
if (scorePct >= s[i]) return p[i];
}
return 0;
}
function getPercentile(score, total, difficulty, nQuestions) {
var pct = score / total * 100;
fetch(STATS_URL).then(function(r) {
if (!r.ok) throw new Error('stats unavailable');
return r.json();
}).then(function(stats) {
var data = stats.chronic;
var overallPct = interpolatePercentile(pct, data.overall);
var msg = 'You scored better than ' + overallPct + '% of all chronic quiz players';
var configKey = (difficulty || 'mixed') + '_' + (nQuestions || 10);
var sub = data.by_config[configKey];
if (sub && sub.n >= 10) {
var subPct = interpolatePercentile(pct, sub);
msg += ' (' + subPct + '% of ' + difficulty + '/' + nQuestions + 'Q players)';
}
msg += '! (' + data.overall.n + ' submissions)';
var el = document.getElementById('percentile_text');
if (el) el.textContent = msg;
}).catch(function(err) {
console.log('Stats JSON fetch failed:', err, '— trying live Sheet');
getPercentileLive(score, total);
});
}
function getPercentileLive(score, total) {
var el = document.getElementById('percentile_text');
if (el) el.textContent = 'Loading rankings...';
fetch(SHEET_URL).then(function(r) { return r.text(); }).then(function(text) {
var json = JSON.parse(text.replace(/.*google.visualization.Query.setResponse\\(/, '').replace(/\\);$/, ''));
var rows = json.table.rows;
var pct = score / total * 100;
var below = 0;
var chronicCount = 0;
for (var i = 0; i < rows.length; i++) {
var s = rows[i].c[0] ? rows[i].c[0].v : 0;
var t = rows[i].c[1] ? rows[i].c[1].v : 10;
var qt = rows[i].c[3] ? rows[i].c[3].v : 'acute';
if (qt !== 'chronic') continue;
chronicCount++;
if ((s / t * 100) < pct) below++;
}
var percentile = chronicCount > 0 ? Math.round(below / chronicCount * 100) : 50;
if (el) el.textContent = 'You scored better than ' + percentile + '% of chronic quiz players! (' + chronicCount + ' submissions)';
}).catch(function(err2) {
console.log('Live Sheet fetch also failed:', err2);
if (el) el.textContent = 'Score submitted! Rankings unavailable right now.';
});
}
"
# ---- Fun result phrases ----
chronic_result_phrase <- function(pct) {
phrases <- list(
list(min = 95, phrase = "Longevity expert!",
fact = "A microlife equals 30 minutes of life expectancy.",
link = "https://en.wikipedia.org/wiki/Microlife"),
list(min = 90, phrase = "You think in microlives!",
fact = "David Spiegelhalter introduced microlives to communicate chronic risk.",
link = "https://en.wikipedia.org/wiki/Microlife"),
list(min = 80, phrase = "Impressive health literacy!",
fact = "Most people underestimate the effect of everyday habits on lifespan.",
link = "https://en.wikipedia.org/wiki/Health_literacy"),
list(min = 70, phrase = "Better than average!",
fact = "Exercise is one of the most effective longevity interventions known.",
link = "https://en.wikipedia.org/wiki/Exercise#Health_effects"),
list(min = 60, phrase = "Getting there!",
fact = "Gains from healthy habits can partially offset losses from unhealthy ones.",
link = "https://en.wikipedia.org/wiki/Healthy_diet"),
list(min = 50, phrase = "About average!",
fact = "Many chronic risk factors interact, making individual effects hard to estimate.",
link = "https://en.wikipedia.org/wiki/Risk_factor"),
list(min = 30, phrase = "Surprises everywhere!",
fact = "Small daily habits compound over years into large effects on life expectancy.",
link = "https://en.wikipedia.org/wiki/Life_expectancy"),
list(min = -1, phrase = "Room to learn!",
fact = "Understanding risk helps you make better decisions about your health.",
link = "https://en.wikipedia.org/wiki/Risk_communication")
)
for (p in phrases) {
if (pct >= p$min) return(p)
}
phrases[[length(phrases)]]
}
# ---- Encouragement lines ----
chronic_encouragement_lines <- function() {
c(
"30 minutes of life expectancy per microlife. Choose wisely.",
"Your daily habits are quietly writing your life story.",
"Think you know which choices matter most? Prove it.",
"Every day is a longevity experiment. How's yours going?",
"Side effects may include sudden urge to eat more vegetables.",
"Some habits give you time. Others take it away.",
"Spoiler: your lifestyle choices matter more than you think.",
"Statistically, this quiz will be good for you. Probably."
)
}
# ---- Helper: microlife label ----
ml_label <- function(ml, direction) {
sign_char <- if (direction == "gain") "+" else "\u2212"
color <- if (direction == "gain") "#198754" else "#dc3545"
sprintf('<span style="color: %s; font-weight: bold;">%s%s ml/day</span>',
color, sign_char, abs(ml))
}
# ---- Instructions page ----
instructions_ui <- function() {
encouragement <- sample(chronic_encouragement_lines(), 1L)
tagList(
card(
card_body(
tags$ul(class = "mb-1",
tags$li("Each question shows ", tags$b(tags$em("two daily habits or risk factors")), "."),
tags$li("Tap the one with the ", tags$b(tags$em("bigger effect")),
" on your lifespan (regardless of direction)."),
tags$li("Some habits ", tags$b(tags$em("gain")), " time (",
span(class = "badge bg-success", "+"), "), others ",
tags$b(tags$em("cost")), " time (",
span(class = "badge bg-danger", "\u2212"), ")."),
tags$li("You can ", tags$b(tags$em("skip")), " questions or go ",
tags$b(tags$em("back")), "."),
tags$li("A ", tags$b(tags$em("microlife")),
" = 30 minutes of life expectancy.", br(),
span(style = "padding-left: 1em;",
"Smoking 20/day costs 10 microlives: like aging 29 hours every 24."))
),
div(class = "mb-1", style = "padding-left: 1.5em;", tags$em(encouragement)),
div(class = "option-row",
span(class = "option-label", "Difficulty:"),
div(class = "option-btn-group", id = "grp_diff",
actionButton("diff_easy", "Easy", class = "option-btn",
onclick = "selectInGroup('grp_diff', this)"),
actionButton("diff_medium", "Medium", class = "option-btn",
onclick = "selectInGroup('grp_diff', this)"),
actionButton("diff_hard", "Hard", class = "option-btn",
onclick = "selectInGroup('grp_diff', this)"),
actionButton("diff_mixed", "Mixed", class = "option-btn selected",
onclick = "selectInGroup('grp_diff', this)"))
),
div(class = "option-row",
span(class = "option-label", "Questions:"),
div(class = "option-btn-group", id = "grp_nq",
actionButton("nq_5", "5", class = "option-btn selected",
onclick = "selectInGroup('grp_nq', this)"),
actionButton("nq_10", "10", class = "option-btn",
onclick = "selectInGroup('grp_nq', this)"))
),
div(class = "text-center mt-3",
actionButton("start_quiz", "Start Quiz", class = "btn-primary btn-lg"))
)
)
)
}
# ---- Question page ----
question_ui <- function(state) {
q <- state$current_q
n <- state$n_questions
pair <- state$pairs[q, ]
ord <- state$display_order[[q]]
revealed <- state$revealed[q]
answer <- state$answers[q]
correct_answer <- pair$answer
left_side <- ord[1]
right_side <- ord[2]
left_factor <- pair[[paste0("factor_", left_side)]]
left_category <- pair[[paste0("category_", left_side)]]
left_ml <- pair[[paste0("microlives_", left_side)]]
left_dir <- pair[[paste0("direction_", left_side)]]
left_days <- pair[[paste0("annual_days_", left_side)]]
left_desc <- pair[[paste0("description_", left_side)]]
left_help <- pair[[paste0("help_url_", left_side)]]
right_factor <- pair[[paste0("factor_", right_side)]]
right_category <- pair[[paste0("category_", right_side)]]
right_ml <- pair[[paste0("microlives_", right_side)]]
right_dir <- pair[[paste0("direction_", right_side)]]
right_days <- pair[[paste0("annual_days_", right_side)]]
right_desc <- pair[[paste0("description_", right_side)]]
right_help <- pair[[paste0("help_url_", right_side)]]
left_class <- "btn quiz-btn"
right_class <- "btn quiz-btn"
left_extra <- ""
right_extra <- ""
if (revealed) {
left_bigger <- abs(left_ml) > abs(right_ml)
right_bigger <- abs(right_ml) > abs(left_ml)
if (!is.na(answer)) {
chose_left <- answer == left_side
chose_right <- answer == right_side
} else {
chose_left <- FALSE
chose_right <- FALSE
}
if (left_bigger) {
left_class <- paste(left_class, "quiz-btn-correct")
right_class <- paste(right_class, if (chose_right) "quiz-btn-wrong" else "quiz-btn-neutral")
} else if (right_bigger) {
right_class <- paste(right_class, "quiz-btn-correct")
left_class <- paste(left_class, if (chose_left) "quiz-btn-wrong" else "quiz-btn-neutral")
} else {
left_class <- paste(left_class, "quiz-btn-correct")
right_class <- paste(right_class, "quiz-btn-correct")
}
left_extra <- ml_label(left_ml, left_dir)
right_extra <- ml_label(right_ml, right_dir)
}
make_btn_content <- function(factor_name, category, direction, ml_text,
description = NULL, help_url = NULL) {
dir_badge <- if (direction == "gain") {
span(class = "badge bg-success", "GAIN")
} else {
span(class = "badge bg-danger", "LOSS")
}
name_el <- span(class = "activity-name", format_activity_name(factor_name))
if (!is.null(description) && nzchar(description)) {
name_el <- tagList(name_el,
tooltip(span(class = "help-icon", "\u24d8"), description))
}
parts <- list(name_el,
div(span(class = "badge bg-secondary me-1", category), dir_badge))
if (nzchar(ml_text)) {
parts <- c(parts, list(strong(HTML(ml_text), style = "font-size: 1.2rem;")))
}
if (!is.null(help_url) && nzchar(help_url)) {
parts <- c(parts, list(tags$a(class = "help-link", href = help_url,
target = "_blank", onclick = "event.stopPropagation();", "Learn more \u2192")))
}
parts
}
result_text <- NULL
explanation_panel <- NULL
if (revealed) {
user_correct <- !is.na(answer) && answer == correct_answer
result_text <- if (user_correct) {
div(class = "alert alert-success text-center mt-2 py-2", strong("Correct!"))
} else {
bigger <- pair[[paste0("factor_", correct_answer)]]
div(class = "alert alert-danger text-center mt-2 py-2",
if (is.na(answer)) "Skipped! " else tagList(strong("Incorrect! ")),
sprintf("%s has a bigger effect.", bigger))
}
ratio_text <- sprintf("%.1f", pair$ratio)
bigger_side <- pair$answer
smaller_side <- if (bigger_side == "a") "b" else "a"
bigger_ml <- pair[[paste0("microlives_", bigger_side)]]
smaller_ml <- pair[[paste0("microlives_", smaller_side)]]
bigger_days <- pair[[paste0("annual_days_", bigger_side)]]
smaller_days <- pair[[paste0("annual_days_", smaller_side)]]
bigger_dir <- pair[[paste0("direction_", bigger_side)]]
smaller_dir <- pair[[paste0("direction_", smaller_side)]]
explanation_panel <- card(
class = "explanation-panel mt-2",
card_body(
tags$p(strong(pair[[paste0("factor_", bigger_side)]]),
sprintf(" %s %s microlives/day (%.1f days/year): ",
if (bigger_dir == "gain") "gains" else "costs",
abs(bigger_ml), abs(bigger_days)),
pair[[paste0("description_", bigger_side)]]),
tags$p(strong(pair[[paste0("factor_", smaller_side)]]),
sprintf(" %s %s microlives/day (%.1f days/year): ",
if (smaller_dir == "gain") "gains" else "costs",
abs(smaller_ml), abs(smaller_days)),
pair[[paste0("description_", smaller_side)]]),
tags$p(sprintf("%s has a %sx larger effect on lifespan than %s.",
pair[[paste0("factor_", bigger_side)]], ratio_text,
pair[[paste0("factor_", smaller_side)]])),
tags$p(class = "text-muted mb-0",
sprintf("1 microlife = 30 min. Over a year, %s microlives/day = %.1f days.",
abs(bigger_ml), abs(bigger_days)))
)
)
}
# Global score
all_qs <- seq_len(n)
answered_so_far <- sum(!is.na(state$answers[all_qs]) & state$revealed[all_qs])
correct_so_far <- sum(vapply(all_qs, function(i) {
!is.na(state$answers[i]) && state$answers[i] == state$pairs$answer[i]
}, logical(1)))
tally_text <- sprintf("Score: %d/%d correct", correct_so_far, answered_so_far)
nav_ui <- div(
class = "d-flex justify-content-between align-items-center mb-3",
actionButton("prev_q", "\u2190 Back", class = "btn-secondary"),
span(class = "text-muted",
if ("difficulty" %in% names(pair) && !is.na(pair$difficulty)) {
diff_colors <- c(easy = "success", medium = "warning", hard = "danger")
span(class = paste0("badge bg-", diff_colors[pair$difficulty], " me-2"),
pair$difficulty)
},
sprintf("%d of %d", q, n),
" \u00b7 ", tags$small(tally_text)),
actionButton("next_q", if (q == n) "Finish" else "Next \u2192", class = "btn-primary")
)
tagList(
nav_ui,
div(class = "row align-items-center",
div(class = "col-5",
if (!revealed) {
actionButton("choose_left",
tagList(make_btn_content(left_factor, left_category, left_dir,
left_extra, left_desc, left_help)),
class = left_class)
} else {
div(class = left_class,
make_btn_content(left_factor, left_category, left_dir,
left_extra, left_desc, left_help))
}),
div(class = "col-2 text-center", h3("VS", class = "text-muted mb-0")),
div(class = "col-5",
if (!revealed) {
actionButton("choose_right",
tagList(make_btn_content(right_factor, right_category, right_dir,
right_extra, right_desc, right_help)),
class = right_class)
} else {
div(class = right_class,
make_btn_content(right_factor, right_category, right_dir,
right_extra, right_desc, right_help))
})
),
result_text,
explanation_panel
)
}
# ---- Results summary page ----
results_summary_ui <- function(state) {
pairs <- state$pairs
answers <- state$answers
n <- state$n_questions
correct <- vapply(seq_len(n), function(i) {
!is.na(answers[i]) && answers[i] == pairs$answer[i]
}, logical(1))
score <- sum(correct)
pct <- score / n * 100
baseline <- n / 2
result_info <- chronic_result_phrase(pct)
tagList(
h2("Results", class = "text-center mb-4"),
div(class = "row mb-4",
div(class = "col-6",
div(class = "card text-white bg-primary mb-3",
div(class = "card-body text-center",
tags$small("Your Score"), h2(sprintf("%d / %d", score, n), class = "mb-0")))),
div(class = "col-6",
div(class = "card text-white bg-secondary mb-3",
div(class = "card-body text-center",
tags$small("Random Guessing"), h2(sprintf("~%.1f / %d", baseline, n), class = "mb-0"))))
),
div(class = "text-center mb-4",
h3(result_info$phrase),
tags$em(result_info$fact), br(),
tags$a(href = result_info$link, target = "_blank", "Learn more \u2192")),
div(class = "d-flex justify-content-center gap-3",
tags$button(id = "submit_btn", class = "btn btn-warning btn-lg",
onclick = sprintf("submitScore(%d, %d, '%s', %d)", score, n,
state$sel_difficulty, state$sel_nq), "Submit Score"),
tags$button(id = "share_btn", class = "btn btn-success btn-lg",
onclick = sprintf(paste0(
"var pEl=document.getElementById('percentile_text');",
"var pLine=pEl&&pEl.textContent?'\\n'+pEl.textContent+'\\n':'\\n';",
"var text='\\u23f3 Microlife Quiz: I scored %d/%d!'+pLine+",
"'Which daily habit affects your lifespan more?\\n",
"Can you beat my score? \\u23f3\\n",
"https://johngavin.github.io/micromort/articles/chronic_quiz_shinylive.html';",
"navigator.clipboard.writeText(text).then(function(){",
"var btn=document.getElementById('share_btn');",
"btn.textContent='Copied!';",
"setTimeout(function(){btn.textContent='Share';},2000);",
"});"), score, n),
"Share"),
actionButton("view_details", "View Details", class = "btn-outline-primary btn-lg"),
actionButton("try_again", "Try Again", class = "btn-primary btn-lg",
onclick = "resetLeaderboard()")
),
div(class = "text-center mt-2",
tags$small(id = "percentile_text", class = "text-muted"),
tags$br(),
tags$small(class = "text-muted", "Scores are anonymous. No personal data is collected."))
)
}
# ---- Results detail page ----
results_detail_ui <- function(state) {
pairs <- state$pairs
answers <- state$answers
n <- state$n_questions
detail_rows <- lapply(seq_len(n), function(i) {
user_ans <- if (is.na(answers[i])) "Skipped"
else if (answers[i] == "a") pairs$factor_a[i] else pairs$factor_b[i]
correct_ans <- if (pairs$answer[i] == "a") pairs$factor_a[i] else pairs$factor_b[i]
result <- if (is.na(answers[i])) "\u2014"
else if (answers[i] == pairs$answer[i]) "\u2713" else "\u2717"
dir_a <- if (pairs$direction_a[i] == "gain") "+" else "\u2212"
dir_b <- if (pairs$direction_b[i] == "gain") "+" else "\u2212"
link_a <- if (!is.na(pairs$help_url_a[i]) && nzchar(pairs$help_url_a[i]))
tags$a(href = pairs$help_url_a[i], target = "_blank", pairs$factor_a[i])
else pairs$factor_a[i]
link_b <- if (!is.na(pairs$help_url_b[i]) && nzchar(pairs$help_url_b[i]))
tags$a(href = pairs$help_url_b[i], target = "_blank", pairs$factor_b[i])
else pairs$factor_b[i]
tags$tr(tags$td(i), tags$td(link_a),
tags$td(sprintf("%s%s", dir_a, abs(pairs$microlives_a[i]))),
tags$td(link_b),
tags$td(sprintf("%s%s", dir_b, abs(pairs$microlives_b[i]))),
tags$td(user_ans), tags$td(correct_ans), tags$td(result))
})
tagList(
div(class = "d-flex justify-content-between align-items-center mb-4",
actionButton("back_to_summary", "\u2190 Back to Results", class = "btn-secondary"),
h3("Your quiz details", class = "mb-0"),
actionButton("try_again_detail", "Try Again", class = "btn-primary",
onclick = "resetLeaderboard()")),
div(class = "detail-scroll",
tags$table(class = "table table-striped table-hover detail-table",
tags$thead(tags$tr(tags$th("Q"), tags$th("Factor A"), tags$th("ml/day A"),
tags$th("Factor B"), tags$th("ml/day B"),
tags$th("Your Answer"), tags$th("Correct"), tags$th("Result"))),
tags$tbody(detail_rows)))
)
}
# ---- App ----
ui <- page_fluid(
theme = bs_theme(bootswatch = "flatly", version = 5),
tags$head(
tags$style(HTML(quiz_css)),
tags$script(HTML(chronic_leaderboard_js)),
tags$script(HTML("
function selectInGroup(groupId, clicked) {
var grp = document.getElementById(groupId);
if (!grp) return;
var btns = grp.querySelectorAll('.option-btn');
for (var i = 0; i < btns.length; i++) {
btns[i].classList.remove('selected');
}
clicked.classList.add('selected');
}
"))
),
div(class = "container-fluid",
style = "max-width: 100%; padding: 20px;",
uiOutput("main_ui"))
)
server <- function(input, output, session) {
state <- reactiveValues(
phase = "instructions", n_questions = 5L, current_q = 1L,
pairs = NULL, answers = NULL, display_order = NULL, revealed = NULL,
sel_difficulty = "mixed", sel_nq = 5L,
seen_pairs = character())
# Difficulty button handlers
observeEvent(input$diff_easy, { state$sel_difficulty <- "easy" })
observeEvent(input$diff_medium, { state$sel_difficulty <- "medium" })
observeEvent(input$diff_hard, { state$sel_difficulty <- "hard" })
observeEvent(input$diff_mixed, { state$sel_difficulty <- "mixed" })
# N questions button handlers
observeEvent(input$nq_5, { state$sel_nq <- 5L })
observeEvent(input$nq_10, { state$sel_nq <- 10L })
observeEvent(input$start_quiz, {
n <- state$sel_nq
diff <- state$sel_difficulty
pool <- if (!is.null(diff) && diff != "mixed") {
quiz_pool[quiz_pool$difficulty == diff, ]
} else {
quiz_pool
}
# Exclude pairs seen in previous rounds
pair_keys <- paste(pmin(pool$factor_a, pool$factor_b),
pmax(pool$factor_a, pool$factor_b), sep = "|||")
unseen <- !(pair_keys %in% state$seen_pairs)
if (sum(unseen) >= n) {
pool <- pool[unseen, ]
}
# If not enough unseen pairs, reset history
if (nrow(pool) < n) {
state$seen_pairs <- character()
pool <- if (!is.null(diff) && diff != "mixed") {
quiz_pool[quiz_pool$difficulty == diff, ]
} else {
quiz_pool
}
}
n <- min(n, nrow(pool))
state$n_questions <- n
selected <- pool[sample(nrow(pool), n), ]
# Record these pairs as seen
new_keys <- paste(pmin(selected$factor_a, selected$factor_b),
pmax(selected$factor_a, selected$factor_b), sep = "|||")
state$seen_pairs <- c(state$seen_pairs, new_keys)
state$pairs <- selected
state$answers <- rep(NA_character_, n)
state$display_order <- lapply(seq_len(n), function(i) sample(c("a", "b")))
state$revealed <- rep(FALSE, n)
state$current_q <- 1L
state$phase <- "question"
})
observeEvent(input$choose_left, {
q <- state$current_q
state$answers[q] <- state$display_order[[q]][1]
state$revealed[q] <- TRUE
})
observeEvent(input$choose_right, {
q <- state$current_q
state$answers[q] <- state$display_order[[q]][2]
state$revealed[q] <- TRUE
})
observeEvent(input$next_q, {
if (state$current_q < state$n_questions) state$current_q <- state$current_q + 1L
else state$phase <- "results_summary"
})
observeEvent(input$prev_q, {
if (state$current_q > 1L) state$current_q <- state$current_q - 1L
else state$phase <- "instructions"
})
observeEvent(input$view_details, { state$phase <- "results_detail" })
observeEvent(input$back_to_summary, { state$phase <- "results_summary" })
observeEvent(input$try_again, { state$phase <- "instructions" })
observeEvent(input$try_again_detail, { state$phase <- "instructions" })
output$main_ui <- renderUI({
switch(state$phase,
instructions = instructions_ui(),
question = question_ui(state),
results_summary = results_summary_ui(state),
results_detail = results_detail_ui(state))
})
}
shinyApp(ui, server)
## file: chronic_pairs.csv
## type: text
"factor_b","factor_a","microlives_a","direction_a","category_a","annual_days_a","microlives_b","direction_b","category_b","annual_days_b","ratio","difficulty","answer","description_a","help_url_a","description_b","help_url_b"
"150 min weekly exercise","Smoking 20 cigarettes",-10,"loss","Smoking",-76,3,"gain","Exercise",22.8,3.33333333333333,"easy","a","A pack-a-day habit accelerates aging so that each day lived costs 29 hours of life expectancy. The single largest modifiable mortality risk.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Meeting WHO physical activity guidelines reduces cardiovascular, cancer, and all-cause mortality substantially.","https://www.who.int/news-room/fact-sheets/detail/physical-activity"
"5 servings fruit/veg","Smoking 2 cigarettes",-1,"loss","Smoking",-7.6,4,"gain","Diet",30.4,4,"easy","b","Even light smoking (2 cigarettes/day) carries measurable cardiovascular and cancer risk. Each cigarette costs roughly 15 minutes of life.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Daily fruit and vegetable intake reduces cardiovascular disease, cancer, and all-cause mortality. Largest benefit from 5+ servings.","https://en.wikipedia.org/wiki/Five_A_Day"
"5 servings fruit/veg","Being 5 kg overweight",-1,"loss","Weight",-7.6,4,"gain","Diet",30.4,4,"easy","b","Each 5 kg above optimum BMI increases risk of type 2 diabetes, cardiovascular disease, and several cancers.","https://en.wikipedia.org/wiki/Obesity#Effects_on_health","Daily fruit and vegetable intake reduces cardiovascular disease, cancer, and all-cause mortality. Largest benefit from 5+ servings.","https://en.wikipedia.org/wiki/Five_A_Day"
"5 servings fruit/veg","2nd-3rd alcoholic drink",-1,"loss","Alcohol",-7.6,4,"gain","Diet",30.4,4,"easy","b","After the first drink's potential protective effect, the second and third drinks increase liver disease and accident risk.","https://en.wikipedia.org/wiki/Alcohol_and_health","Daily fruit and vegetable intake reduces cardiovascular disease, cancer, and all-cause mortality. Largest benefit from 5+ servings.","https://en.wikipedia.org/wiki/Five_A_Day"
"Being 15 kg overweight","Smoking 20 cigarettes",-10,"loss","Smoking",-76,-3,"loss","Weight",-22.8,3.33333333333333,"easy","a","A pack-a-day habit accelerates aging so that each day lived costs 29 hours of life expectancy. The single largest modifiable mortality risk.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Significant obesity (BMI ~30+) with substantially elevated risks of heart disease, stroke, and cancer.","https://en.wikipedia.org/wiki/Obesity#Effects_on_health"
"Being female (vs male)","Processed meat (1 portion/day)",-1,"loss","Diet",-7.6,4,"gain","Demographics",30.4,4,"easy","b","Bacon, sausages, ham, etc. classified as Group 1 carcinogens by IARC. Strongest evidence for colorectal cancer.","https://www.who.int/news-room/questions-and-answers/item/cancer-carcinogenicity-of-the-consumption-of-red-meat-and-processed-meat","Female sex advantage: longer telomeres, oestrogen cardioprotection, and lower risk-taking behaviour.","https://en.wikipedia.org/wiki/Life_expectancy#Sex_differences"
"Being female (vs male)","Low fiber diet",-1,"loss","Diet",-7.6,4,"gain","Demographics",30.4,4,"easy","b","Less than 25 g fiber daily increases colorectal cancer risk and is associated with higher cardiovascular mortality.","https://en.wikipedia.org/wiki/Dietary_fiber#Health_effects","Female sex advantage: longer telomeres, oestrogen cardioprotection, and lower risk-taking behaviour.","https://en.wikipedia.org/wiki/Life_expectancy#Sex_differences"
"Being female (vs male)","Red meat (1 portion/day)",-1,"loss","Diet",-7.6,4,"gain","Demographics",30.4,4,"easy","b","Daily red meat consumption is associated with increased colorectal cancer and cardiovascular disease risk.","https://www.who.int/news-room/questions-and-answers/item/cancer-carcinogenicity-of-the-consumption-of-red-meat-and-processed-meat","Female sex advantage: longer telomeres, oestrogen cardioprotection, and lower risk-taking behaviour.","https://en.wikipedia.org/wiki/Life_expectancy#Sex_differences"
"Being male (vs female)","2nd-3rd alcoholic drink",-1,"loss","Alcohol",-7.6,-4,"loss","Demographics",-30.4,4,"easy","b","After the first drink's potential protective effect, the second and third drinks increase liver disease and accident risk.","https://en.wikipedia.org/wiki/Alcohol_and_health","Males have 4-5 year shorter life expectancy than females in most populations, driven by biology and behaviour.","https://en.wikipedia.org/wiki/Life_expectancy#Sex_differences"
"Being male (vs female)","Smoking 2 cigarettes",-1,"loss","Smoking",-7.6,-4,"loss","Demographics",-30.4,4,"easy","b","Even light smoking (2 cigarettes/day) carries measurable cardiovascular and cancer risk. Each cigarette costs roughly 15 minutes of life.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Males have 4-5 year shorter life expectancy than females in most populations, driven by biology and behaviour.","https://en.wikipedia.org/wiki/Life_expectancy#Sex_differences"
"Being male (vs female)","Being 5 kg overweight",-1,"loss","Weight",-7.6,-4,"loss","Demographics",-30.4,4,"easy","b","Each 5 kg above optimum BMI increases risk of type 2 diabetes, cardiovascular disease, and several cancers.","https://en.wikipedia.org/wiki/Obesity#Effects_on_health","Males have 4-5 year shorter life expectancy than females in most populations, driven by biology and behaviour.","https://en.wikipedia.org/wiki/Life_expectancy#Sex_differences"
"Low fiber diet","Smoking 10 cigarettes",-5,"loss","Smoking",-38,-1,"loss","Diet",-7.6,5,"easy","a","Half-a-pack daily. Dose-response is roughly linear: half the cigarettes, half the microlife cost.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Less than 25 g fiber daily increases colorectal cancer risk and is associated with higher cardiovascular mortality.","https://en.wikipedia.org/wiki/Dietary_fiber#Health_effects"
"Processed meat (1 portion/day)","Smoking 10 cigarettes",-5,"loss","Smoking",-38,-1,"loss","Diet",-7.6,5,"easy","a","Half-a-pack daily. Dose-response is roughly linear: half the cigarettes, half the microlife cost.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Bacon, sausages, ham, etc. classified as Group 1 carcinogens by IARC. Strongest evidence for colorectal cancer.","https://www.who.int/news-room/questions-and-answers/item/cancer-carcinogenicity-of-the-consumption-of-red-meat-and-processed-meat"
"Red meat (1 portion/day)","Smoking 10 cigarettes",-5,"loss","Smoking",-38,-1,"loss","Diet",-7.6,5,"easy","a","Half-a-pack daily. Dose-response is roughly linear: half the cigarettes, half the microlife cost.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Daily red meat consumption is associated with increased colorectal cancer and cardiovascular disease risk.","https://www.who.int/news-room/questions-and-answers/item/cancer-carcinogenicity-of-the-consumption-of-red-meat-and-processed-meat"
"Type 2 diabetes (poorly controlled)","Smoking 20 cigarettes",-10,"loss","Smoking",-76,-3,"loss","Cardiovascular",-22.8,3.33333333333333,"easy","a","A pack-a-day habit accelerates aging so that each day lived costs 29 hours of life expectancy. The single largest modifiable mortality risk.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","HbA1c > 8% dramatically increases risk of cardiovascular disease, neuropathy, retinopathy, and kidney failure.","https://en.wikipedia.org/wiki/Type_2_diabetes"
"Untreated hypertension","2nd-3rd alcoholic drink",-1,"loss","Alcohol",-7.6,-4,"loss","Cardiovascular",-30.4,4,"easy","b","After the first drink's potential protective effect, the second and third drinks increase liver disease and accident risk.","https://en.wikipedia.org/wiki/Alcohol_and_health","Systolic BP > 140 mmHg left untreated is the leading modifiable risk factor for stroke, heart attack, and kidney disease.","https://en.wikipedia.org/wiki/Hypertension"
"Untreated hypertension","Smoking 2 cigarettes",-1,"loss","Smoking",-7.6,-4,"loss","Cardiovascular",-30.4,4,"easy","b","Even light smoking (2 cigarettes/day) carries measurable cardiovascular and cancer risk. Each cigarette costs roughly 15 minutes of life.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Systolic BP > 140 mmHg left untreated is the leading modifiable risk factor for stroke, heart attack, and kidney disease.","https://en.wikipedia.org/wiki/Hypertension"
"Untreated hypertension","Being 5 kg overweight",-1,"loss","Weight",-7.6,-4,"loss","Cardiovascular",-30.4,4,"easy","b","Each 5 kg above optimum BMI increases risk of type 2 diabetes, cardiovascular disease, and several cancers.","https://en.wikipedia.org/wiki/Obesity#Effects_on_health","Systolic BP > 140 mmHg left untreated is the leading modifiable risk factor for stroke, heart attack, and kidney disease.","https://en.wikipedia.org/wiki/Hypertension"
"150 min weekly exercise","Smoking 2 cigarettes",-1,"loss","Smoking",-7.6,3,"gain","Exercise",22.8,3,"medium","b","Even light smoking (2 cigarettes/day) carries measurable cardiovascular and cancer risk. Each cigarette costs roughly 15 minutes of life.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Meeting WHO physical activity guidelines reduces cardiovascular, cancer, and all-cause mortality substantially.","https://www.who.int/news-room/fact-sheets/detail/physical-activity"
"150 min weekly exercise","2nd-3rd alcoholic drink",-1,"loss","Alcohol",-7.6,3,"gain","Exercise",22.8,3,"medium","b","After the first drink's potential protective effect, the second and third drinks increase liver disease and accident risk.","https://en.wikipedia.org/wiki/Alcohol_and_health","Meeting WHO physical activity guidelines reduces cardiovascular, cancer, and all-cause mortality substantially.","https://www.who.int/news-room/fact-sheets/detail/physical-activity"
"150 min weekly exercise","Being 5 kg overweight",-1,"loss","Weight",-7.6,3,"gain","Exercise",22.8,3,"medium","b","Each 5 kg above optimum BMI increases risk of type 2 diabetes, cardiovascular disease, and several cancers.","https://en.wikipedia.org/wiki/Obesity#Effects_on_health","Meeting WHO physical activity guidelines reduces cardiovascular, cancer, and all-cause mortality substantially.","https://www.who.int/news-room/fact-sheets/detail/physical-activity"
"2nd-3rd alcoholic drink","Being 15 kg overweight",-3,"loss","Weight",-22.8,-1,"loss","Alcohol",-7.6,3,"medium","a","Significant obesity (BMI ~30+) with substantially elevated risks of heart disease, stroke, and cancer.","https://en.wikipedia.org/wiki/Obesity#Effects_on_health","After the first drink's potential protective effect, the second and third drinks increase liver disease and accident risk.","https://en.wikipedia.org/wiki/Alcohol_and_health"
"4th-5th alcoholic drink","Smoking 10 cigarettes",-5,"loss","Smoking",-38,-2,"loss","Alcohol",-15.2,2.5,"medium","a","Half-a-pack daily. Dose-response is roughly linear: half the cigarettes, half the microlife cost.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Heavy daily drinking (4-5 drinks) dramatically increases liver cirrhosis, cancer, and cardiovascular mortality.","https://en.wikipedia.org/wiki/Alcohol_and_health"
"5 servings fruit/veg","Smoking 20 cigarettes",-10,"loss","Smoking",-76,4,"gain","Diet",30.4,2.5,"medium","a","A pack-a-day habit accelerates aging so that each day lived costs 29 hours of life expectancy. The single largest modifiable mortality risk.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Daily fruit and vegetable intake reduces cardiovascular disease, cancer, and all-cause mortality. Largest benefit from 5+ servings.","https://en.wikipedia.org/wiki/Five_A_Day"
"Being 10 kg overweight","Smoking 10 cigarettes",-5,"loss","Smoking",-38,-2,"loss","Weight",-15.2,2.5,"medium","a","Half-a-pack daily. Dose-response is roughly linear: half the cigarettes, half the microlife cost.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Cumulative metabolic and cardiovascular burden of moderate obesity (BMI ~28-30).","https://en.wikipedia.org/wiki/Obesity#Effects_on_health"
"Being 15 kg overweight","Smoking 2 cigarettes",-1,"loss","Smoking",-7.6,-3,"loss","Weight",-22.8,3,"medium","b","Even light smoking (2 cigarettes/day) carries measurable cardiovascular and cancer risk. Each cigarette costs roughly 15 minutes of life.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Significant obesity (BMI ~30+) with substantially elevated risks of heart disease, stroke, and cancer.","https://en.wikipedia.org/wiki/Obesity#Effects_on_health"
"Being male (vs female)","Smoking 20 cigarettes",-10,"loss","Smoking",-76,-4,"loss","Demographics",-30.4,2.5,"medium","a","A pack-a-day habit accelerates aging so that each day lived costs 29 hours of life expectancy. The single largest modifiable mortality risk.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Males have 4-5 year shorter life expectancy than females in most populations, driven by biology and behaviour.","https://en.wikipedia.org/wiki/Life_expectancy#Sex_differences"
"Red meat (1 portion/day)","Being 15 kg overweight",-3,"loss","Weight",-22.8,-1,"loss","Diet",-7.6,3,"medium","a","Significant obesity (BMI ~30+) with substantially elevated risks of heart disease, stroke, and cancer.","https://en.wikipedia.org/wiki/Obesity#Effects_on_health","Daily red meat consumption is associated with increased colorectal cancer and cardiovascular disease risk.","https://www.who.int/news-room/questions-and-answers/item/cancer-carcinogenicity-of-the-consumption-of-red-meat-and-processed-meat"
"Sitting 8+ hours/day","Smoking 10 cigarettes",-5,"loss","Smoking",-38,-2,"loss","Sedentary",-15.2,2.5,"medium","a","Half-a-pack daily. Dose-response is roughly linear: half the cigarettes, half the microlife cost.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Full-day desk work without breaks substantially increases cardiovascular disease, diabetes, and all-cause mortality risk.","https://en.wikipedia.org/wiki/Sedentary_lifestyle"
"Type 2 diabetes (poorly controlled)","2nd-3rd alcoholic drink",-1,"loss","Alcohol",-7.6,-3,"loss","Cardiovascular",-22.8,3,"medium","b","After the first drink's potential protective effect, the second and third drinks increase liver disease and accident risk.","https://en.wikipedia.org/wiki/Alcohol_and_health","HbA1c > 8% dramatically increases risk of cardiovascular disease, neuropathy, retinopathy, and kidney failure.","https://en.wikipedia.org/wiki/Type_2_diabetes"
"Type 2 diabetes (poorly controlled)","Smoking 2 cigarettes",-1,"loss","Smoking",-7.6,-3,"loss","Cardiovascular",-22.8,3,"medium","b","Even light smoking (2 cigarettes/day) carries measurable cardiovascular and cancer risk. Each cigarette costs roughly 15 minutes of life.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","HbA1c > 8% dramatically increases risk of cardiovascular disease, neuropathy, retinopathy, and kidney failure.","https://en.wikipedia.org/wiki/Type_2_diabetes"
"Type 2 diabetes (poorly controlled)","Being 5 kg overweight",-1,"loss","Weight",-7.6,-3,"loss","Cardiovascular",-22.8,3,"medium","b","Each 5 kg above optimum BMI increases risk of type 2 diabetes, cardiovascular disease, and several cancers.","https://en.wikipedia.org/wiki/Obesity#Effects_on_health","HbA1c > 8% dramatically increases risk of cardiovascular disease, neuropathy, retinopathy, and kidney failure.","https://en.wikipedia.org/wiki/Type_2_diabetes"
"Untreated hypertension","Smoking 20 cigarettes",-10,"loss","Smoking",-76,-4,"loss","Cardiovascular",-30.4,2.5,"medium","a","A pack-a-day habit accelerates aging so that each day lived costs 29 hours of life expectancy. The single largest modifiable mortality risk.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Systolic BP > 140 mmHg left untreated is the leading modifiable risk factor for stroke, heart attack, and kidney disease.","https://en.wikipedia.org/wiki/Hypertension"
"150 min weekly exercise","4th-5th alcoholic drink",-2,"loss","Alcohol",-15.2,3,"gain","Exercise",22.8,1.5,"hard","b","Heavy daily drinking (4-5 drinks) dramatically increases liver cirrhosis, cancer, and cardiovascular mortality.","https://en.wikipedia.org/wiki/Alcohol_and_health","Meeting WHO physical activity guidelines reduces cardiovascular, cancer, and all-cause mortality substantially.","https://www.who.int/news-room/fact-sheets/detail/physical-activity"
"150 min weekly exercise","Sitting 8+ hours/day",-2,"loss","Sedentary",-15.2,3,"gain","Exercise",22.8,1.5,"hard","b","Full-day desk work without breaks substantially increases cardiovascular disease, diabetes, and all-cause mortality risk.","https://en.wikipedia.org/wiki/Sedentary_lifestyle","Meeting WHO physical activity guidelines reduces cardiovascular, cancer, and all-cause mortality substantially.","https://www.who.int/news-room/fact-sheets/detail/physical-activity"
"150 min weekly exercise","Being 10 kg overweight",-2,"loss","Weight",-15.2,3,"gain","Exercise",22.8,1.5,"hard","b","Cumulative metabolic and cardiovascular burden of moderate obesity (BMI ~28-30).","https://en.wikipedia.org/wiki/Obesity#Effects_on_health","Meeting WHO physical activity guidelines reduces cardiovascular, cancer, and all-cause mortality substantially.","https://www.who.int/news-room/fact-sheets/detail/physical-activity"
"20 min moderate exercise","2nd-3rd alcoholic drink",-1,"loss","Alcohol",-7.6,2,"gain","Exercise",15.2,2,"hard","b","After the first drink's potential protective effect, the second and third drinks increase liver disease and accident risk.","https://en.wikipedia.org/wiki/Alcohol_and_health","Daily brisk walking or equivalent moderate activity reduces all-cause mortality by ~30%. The single most effective lifestyle intervention.","https://www.who.int/news-room/fact-sheets/detail/physical-activity"
"20 min moderate exercise","Being 5 kg overweight",-1,"loss","Weight",-7.6,2,"gain","Exercise",15.2,2,"hard","b","Each 5 kg above optimum BMI increases risk of type 2 diabetes, cardiovascular disease, and several cancers.","https://en.wikipedia.org/wiki/Obesity#Effects_on_health","Daily brisk walking or equivalent moderate activity reduces all-cause mortality by ~30%. The single most effective lifestyle intervention.","https://www.who.int/news-room/fact-sheets/detail/physical-activity"
"20 min moderate exercise","Red meat (1 portion/day)",-1,"loss","Diet",-7.6,2,"gain","Exercise",15.2,2,"hard","b","Daily red meat consumption is associated with increased colorectal cancer and cardiovascular disease risk.","https://www.who.int/news-room/questions-and-answers/item/cancer-carcinogenicity-of-the-consumption-of-red-meat-and-processed-meat","Daily brisk walking or equivalent moderate activity reduces all-cause mortality by ~30%. The single most effective lifestyle intervention.","https://www.who.int/news-room/fact-sheets/detail/physical-activity"
"4th-5th alcoholic drink","Being 15 kg overweight",-3,"loss","Weight",-22.8,-2,"loss","Alcohol",-15.2,1.5,"hard","a","Significant obesity (BMI ~30+) with substantially elevated risks of heart disease, stroke, and cancer.","https://en.wikipedia.org/wiki/Obesity#Effects_on_health","Heavy daily drinking (4-5 drinks) dramatically increases liver cirrhosis, cancer, and cardiovascular mortality.","https://en.wikipedia.org/wiki/Alcohol_and_health"
"Being 10 kg overweight","Smoking 2 cigarettes",-1,"loss","Smoking",-7.6,-2,"loss","Weight",-15.2,2,"hard","b","Even light smoking (2 cigarettes/day) carries measurable cardiovascular and cancer risk. Each cigarette costs roughly 15 minutes of life.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Cumulative metabolic and cardiovascular burden of moderate obesity (BMI ~28-30).","https://en.wikipedia.org/wiki/Obesity#Effects_on_health"
"Blood pressure control","Red meat (1 portion/day)",-1,"loss","Diet",-7.6,2,"gain","Medical",15.2,2,"hard","b","Daily red meat consumption is associated with increased colorectal cancer and cardiovascular disease risk.","https://www.who.int/news-room/questions-and-answers/item/cancer-carcinogenicity-of-the-consumption-of-red-meat-and-processed-meat","Achieving target BP < 130/80 mmHg through medication and lifestyle reduces stroke risk by 35-40%.","https://en.wikipedia.org/wiki/Antihypertensive_drug"
"Blood pressure control","Processed meat (1 portion/day)",-1,"loss","Diet",-7.6,2,"gain","Medical",15.2,2,"hard","b","Bacon, sausages, ham, etc. classified as Group 1 carcinogens by IARC. Strongest evidence for colorectal cancer.","https://www.who.int/news-room/questions-and-answers/item/cancer-carcinogenicity-of-the-consumption-of-red-meat-and-processed-meat","Achieving target BP < 130/80 mmHg through medication and lifestyle reduces stroke risk by 35-40%.","https://en.wikipedia.org/wiki/Antihypertensive_drug"
"Blood pressure control","Low fiber diet",-1,"loss","Diet",-7.6,2,"gain","Medical",15.2,2,"hard","b","Less than 25 g fiber daily increases colorectal cancer risk and is associated with higher cardiovascular mortality.","https://en.wikipedia.org/wiki/Dietary_fiber#Health_effects","Achieving target BP < 130/80 mmHg through medication and lifestyle reduces stroke risk by 35-40%.","https://en.wikipedia.org/wiki/Antihypertensive_drug"
"Family history of heart disease","Smoking 2 cigarettes",-1,"loss","Smoking",-7.6,-2,"loss","Cardiovascular",-15.2,2,"hard","b","Even light smoking (2 cigarettes/day) carries measurable cardiovascular and cancer risk. Each cigarette costs roughly 15 minutes of life.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","First-degree relative with CVD before age 55 roughly doubles your own cardiovascular risk.","https://en.wikipedia.org/wiki/Cardiovascular_disease#Risk_factors"
"Family history of heart disease","Being 5 kg overweight",-1,"loss","Weight",-7.6,-2,"loss","Cardiovascular",-15.2,2,"hard","b","Each 5 kg above optimum BMI increases risk of type 2 diabetes, cardiovascular disease, and several cancers.","https://en.wikipedia.org/wiki/Obesity#Effects_on_health","First-degree relative with CVD before age 55 roughly doubles your own cardiovascular risk.","https://en.wikipedia.org/wiki/Cardiovascular_disease#Risk_factors"
"Family history of heart disease","2nd-3rd alcoholic drink",-1,"loss","Alcohol",-7.6,-2,"loss","Cardiovascular",-15.2,2,"hard","b","After the first drink's potential protective effect, the second and third drinks increase liver disease and accident risk.","https://en.wikipedia.org/wiki/Alcohol_and_health","First-degree relative with CVD before age 55 roughly doubles your own cardiovascular risk.","https://en.wikipedia.org/wiki/Cardiovascular_disease#Risk_factors"
"High fiber diet","2 hours TV watching",-1,"loss","Sedentary",-7.6,2,"gain","Diet",15.2,2,"hard","b","Prolonged sedentary behaviour (sitting/lying) increases cardiovascular mortality independent of exercise. TV time is a proxy for total sitting.","https://en.wikipedia.org/wiki/Sedentary_lifestyle","25 g+ fiber daily from whole grains, fruit, and vegetables reduces colorectal cancer, cardiovascular disease, and type 2 diabetes.","https://en.wikipedia.org/wiki/Dietary_fiber#Health_effects"
"High fiber diet","2nd-3rd alcoholic drink",-1,"loss","Alcohol",-7.6,2,"gain","Diet",15.2,2,"hard","b","After the first drink's potential protective effect, the second and third drinks increase liver disease and accident risk.","https://en.wikipedia.org/wiki/Alcohol_and_health","25 g+ fiber daily from whole grains, fruit, and vegetables reduces colorectal cancer, cardiovascular disease, and type 2 diabetes.","https://en.wikipedia.org/wiki/Dietary_fiber#Health_effects"
"High fiber diet","Living with a smoker",-1,"loss","Environment",-7.6,2,"gain","Diet",15.2,2,"hard","b","Second-hand smoke exposure increases lung cancer risk by 20-30% and heart disease risk by 25-30%.","https://en.wikipedia.org/wiki/Passive_smoking","25 g+ fiber daily from whole grains, fruit, and vegetables reduces colorectal cancer, cardiovascular disease, and type 2 diabetes.","https://en.wikipedia.org/wiki/Dietary_fiber#Health_effects"
"High LDL cholesterol (untreated)","Being 5 kg overweight",-1,"loss","Weight",-7.6,-2,"loss","Cardiovascular",-15.2,2,"hard","b","Each 5 kg above optimum BMI increases risk of type 2 diabetes, cardiovascular disease, and several cancers.","https://en.wikipedia.org/wiki/Obesity#Effects_on_health","LDL > 160 mg/dL without statin therapy accelerates atherosclerosis and coronary heart disease.","https://en.wikipedia.org/wiki/Low-density_lipoprotein#Role_in_disease"
"High LDL cholesterol (untreated)","Smoking 2 cigarettes",-1,"loss","Smoking",-7.6,-2,"loss","Cardiovascular",-15.2,2,"hard","b","Even light smoking (2 cigarettes/day) carries measurable cardiovascular and cancer risk. Each cigarette costs roughly 15 minutes of life.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","LDL > 160 mg/dL without statin therapy accelerates atherosclerosis and coronary heart disease.","https://en.wikipedia.org/wiki/Low-density_lipoprotein#Role_in_disease"
"High LDL cholesterol (untreated)","Being 15 kg overweight",-3,"loss","Weight",-22.8,-2,"loss","Cardiovascular",-15.2,1.5,"hard","a","Significant obesity (BMI ~30+) with substantially elevated risks of heart disease, stroke, and cancer.","https://en.wikipedia.org/wiki/Obesity#Effects_on_health","LDL > 160 mg/dL without statin therapy accelerates atherosclerosis and coronary heart disease.","https://en.wikipedia.org/wiki/Low-density_lipoprotein#Role_in_disease"
"Mediterranean diet","2 hours TV watching",-1,"loss","Sedentary",-7.6,2,"gain","Diet",15.2,2,"hard","b","Prolonged sedentary behaviour (sitting/lying) increases cardiovascular mortality independent of exercise. TV time is a proxy for total sitting.","https://en.wikipedia.org/wiki/Sedentary_lifestyle","Rich in olive oil, fish, vegetables, and whole grains. Proven to reduce cardiovascular events and cancer incidence.","https://en.wikipedia.org/wiki/Mediterranean_diet"
"Mediterranean diet","Living with a smoker",-1,"loss","Environment",-7.6,2,"gain","Diet",15.2,2,"hard","b","Second-hand smoke exposure increases lung cancer risk by 20-30% and heart disease risk by 25-30%.","https://en.wikipedia.org/wiki/Passive_smoking","Rich in olive oil, fish, vegetables, and whole grains. Proven to reduce cardiovascular events and cancer incidence.","https://en.wikipedia.org/wiki/Mediterranean_diet"
"Mediterranean diet","Air pollution (high)",-1,"loss","Environment",-7.6,2,"gain","Diet",15.2,2,"hard","b","Living in a highly polluted urban area (PM2.5 > 25 ug/m3) causes chronic respiratory and cardiovascular damage.","https://en.wikipedia.org/wiki/Air_pollution#Health_effects","Rich in olive oil, fish, vegetables, and whole grains. Proven to reduce cardiovascular events and cancer incidence.","https://en.wikipedia.org/wiki/Mediterranean_diet"
"Sitting 8+ hours/day","Being 15 kg overweight",-3,"loss","Weight",-22.8,-2,"loss","Sedentary",-15.2,1.5,"hard","a","Significant obesity (BMI ~30+) with substantially elevated risks of heart disease, stroke, and cancer.","https://en.wikipedia.org/wiki/Obesity#Effects_on_health","Full-day desk work without breaks substantially increases cardiovascular disease, diabetes, and all-cause mortality risk.","https://en.wikipedia.org/wiki/Sedentary_lifestyle"
"Smoking 10 cigarettes","Smoking 20 cigarettes",-10,"loss","Smoking",-76,-5,"loss","Smoking",-38,2,"hard","a","A pack-a-day habit accelerates aging so that each day lived costs 29 hours of life expectancy. The single largest modifiable mortality risk.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco","Half-a-pack daily. Dose-response is roughly linear: half the cigarettes, half the microlife cost.","https://en.wikipedia.org/wiki/Health_effects_of_tobacco"
"Type 2 diabetes (poorly controlled)","Being 10 kg overweight",-2,"loss","Weight",-15.2,-3,"loss","Cardiovascular",-22.8,1.5,"hard","b","Cumulative metabolic and cardiovascular burden of moderate obesity (BMI ~28-30).","https://en.wikipedia.org/wiki/Obesity#Effects_on_health","HbA1c > 8% dramatically increases risk of cardiovascular disease, neuropathy, retinopathy, and kidney failure.","https://en.wikipedia.org/wiki/Type_2_diabetes"
"Type 2 diabetes (poorly controlled)","Sitting 8+ hours/day",-2,"loss","Sedentary",-15.2,-3,"loss","Cardiovascular",-22.8,1.5,"hard","b","Full-day desk work without breaks substantially increases cardiovascular disease, diabetes, and all-cause mortality risk.","https://en.wikipedia.org/wiki/Sedentary_lifestyle","HbA1c > 8% dramatically increases risk of cardiovascular disease, neuropathy, retinopathy, and kidney failure.","https://en.wikipedia.org/wiki/Type_2_diabetes"
"Type 2 diabetes (poorly controlled)","4th-5th alcoholic drink",-2,"loss","Alcohol",-15.2,-3,"loss","Cardiovascular",-22.8,1.5,"hard","b","Heavy daily drinking (4-5 drinks) dramatically increases liver cirrhosis, cancer, and cardiovascular mortality.","https://en.wikipedia.org/wiki/Alcohol_and_health","HbA1c > 8% dramatically increases risk of cardiovascular disease, neuropathy, retinopathy, and kidney failure.","https://en.wikipedia.org/wiki/Type_2_diabetes"