---
title: "Phase I | Study [STUDY-ID]"          # <-- REPLACE
subtitle: "[SAD/MAD] | [Readout type]"        # <-- REPLACE
author: "Aslane Mortreau · Data & AI Specialist"
date: "[Month Year]"                          # <-- REPLACE
format:
  revealjs:
    theme: [simple, mortreau-slides.scss]
    slide-number: true
    progress: true
    transition: fade
    transition-speed: fast
    code-line-numbers: false
    fig-align: center
    width: 1280
    height: 720
    margin: 0.06
    include-in-header:
      text: |
        <link rel="preconnect" href="https://fonts.googleapis.com"/>
        <link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,600;1,400;1,600&family=DM+Sans:wght@300;400;500&family=DM+Mono:wght@300;400&display=swap" rel="stylesheet"/>
execute:
  echo: false
  warning: false
  message: false
---

```{r setup}
library(dplyr)
library(tidyr)
library(ggplot2)
library(gt)

# ── load_verified() ────────────────────────────────────────────────────────────
# Reads a dataset and verifies its SHA-256 checksum at render time.
# Stops loudly if the file has changed since it was locked.
#
# Supported formats: .sas7bdat, .xpt, .csv, .rds
# To obtain the checksum of a locked file:
#   digest::digest("path/to/file.sas7bdat", algo = "sha256", file = TRUE)

load_verified <- function(path, checksum, label = basename(path)) {
  if (!file.exists(path))
    stop(sprintf("[load_verified] File not found: %s", path))

  actual <- digest::digest(path, algo = "sha256", file = TRUE)
  if (!identical(actual, checksum))
    stop(sprintf(
      "[load_verified] Checksum mismatch for '%s'.\n  Expected: %s\n  Got:      %s\n  Verify lock status before rendering.",
      label, checksum, actual
    ))

  ext <- tolower(tools::file_ext(path))
  ds  <- switch(ext,
    sas7bdat = haven::read_sas(path),
    xpt      = haven::read_xpt(path),
    csv      = readr::read_csv(path, show_col_types = FALSE),
    rds      = readRDS(path),
    stop(sprintf("[load_verified] Unsupported format: .%s", ext))
  )

  message(sprintf("[load_verified] OK  %s  (%s rows)", label, nrow(ds)))
  ds
}

# ── DATA LOADING ───────────────────────────────────────────────────────────────
# Replace each path and checksum with your locked dataset values.
# Run digest::digest("path/to/file", algo="sha256", file=TRUE) once per file
# immediately after locking to obtain the checksum string.

adsl  <- load_verified("data/adsl_locked.sas7bdat",  checksum = "")  # <-- REPLACE checksum
adpc  <- load_verified("data/adpc_locked.sas7bdat",  checksum = "")  # <-- REPLACE checksum
adae  <- load_verified("data/adae_locked.sas7bdat",  checksum = "")  # <-- REPLACE checksum
adnca <- load_verified("data/adnca_locked.sas7bdat", checksum = "")  # <-- REPLACE checksum

# ── STUDY PARAMETERS ──────────────────────────────────────────────────────────
n_per_cohort <- [N_PER_COHORT]                            # <-- REPLACE
cohorts      <- c("[Cohort A label]", "[Cohort B label]") # <-- REPLACE (add/remove as needed)
dose_levels  <- c([DOSE_1], [DOSE_2])                     # <-- REPLACE (mg)
visits_pk    <- c(0, [TIME_POINTS])                       # <-- REPLACE (hours post-dose)
n_total      <- n_per_cohort * length(cohorts)

# ── DERIVED ───────────────────────────────────────────────────────────────────
n_by_cohort <- adsl |> count(COHORT, name = "N")

pk_mean <- adpc |>
  group_by(COHORT, NTIME) |>
  summarise(mean = mean(AVAL), sd = sd(AVAL), .groups = "drop")

# ── PALETTE: blue shades, one per cohort ──────────────────────────────────────
# Keys must match cohort names exactly
cohort_colors <- c(
  "[Cohort A label]" = "#0057B8",  # <-- REPLACE keys
  "[Cohort B label]" = "#5ea8e0"   # <-- add entries for additional cohorts
)

# ── GGPLOT THEME ──────────────────────────────────────────────────────────────
theme_slides <- function() {
  theme_minimal(base_size = 11) +
  theme(
    plot.background   = element_rect(fill = "white", color = NA),
    panel.background  = element_rect(fill = "white", color = NA),
    panel.grid.major  = element_line(color = "#dce4ee", linewidth = 0.4),
    panel.grid.minor  = element_blank(),
    axis.line         = element_line(color = "#3d4a5c", linewidth = 0.4),
    axis.ticks        = element_line(color = "#3d4a5c"),
    axis.text.x       = element_text(color = "#3d4a5c", size = 9, margin = margin(t = 4)),
    axis.text.y       = element_text(color = "#3d4a5c", size = 9, margin = margin(r = 4)),
    axis.title        = element_text(color = "#0b1220", size = 10),
    text              = element_text(color = "#1a2740", family = "sans"),
    legend.background = element_rect(fill = "white", color = NA),
    legend.text       = element_text(color = "#1a2740", size = 10),
    legend.position   = "bottom",
    legend.margin     = margin(t = 2),
    plot.caption      = element_text(color = "orange", size = 8),
    plot.margin       = margin(t = 6, r = 10, b = 10, l = 6),
    strip.text        = element_text(face = "bold", color = "#0b1220")
  )
}

# ── GT HELPER ─────────────────────────────────────────────────────────────────
gt_light <- function(gt_tbl) {
  gt_tbl |>
    tab_options(
      table.background.color            = "transparent",
      table.font.color                  = "#1a2740",
      table.font.size                   = "14px",
      table_body.border.bottom.color    = "#dce4ee",
      table_body.hlines.color           = "#dce4ee",
      column_labels.border.bottom.color = "#0057B8",
      column_labels.border.bottom.width = "2px",
      heading.title.font.size           = "13px",
      heading.border.bottom.color       = "transparent"
    ) |>
    tab_style(
      style     = cell_text(size = px(11), transform = "uppercase",
                            color = "#7a8799", weight = "normal"),
      locations = cells_column_labels()
    ) |>
    tab_style(
      style     = cell_text(size = px(12), color = "#3d4a5c",
                            weight = "normal", style = "italic"),
      locations = cells_title(groups = "title")
    )
}
```

## Study Design

::::: {.grid layout-ncol="2"}
<div>

**Objectives**

- Primary: [PRIMARY OBJECTIVE]        <!-- <-- REPLACE -->
- Secondary: [SECONDARY OBJECTIVES]   <!-- <-- REPLACE -->

**Design**

- [DESIGN DESCRIPTION]                <!-- <-- REPLACE -->
- [N] cohorts x [n] subjects = **[TOTAL] subjects**
- [DOSING REGIMEN]
- [PK SAMPLING SCHEDULE]

</div>

<div>

</br></br></br>

```{r design-table}
tibble(
  Cohort = cohorts,
  Dose   = paste(dose_levels, "mg"),  # <-- adjust format as needed
  N      = n_per_cohort,
  Status = "[Complete / Ongoing]"     # <-- REPLACE
) |>
  gt() |>
  tab_header(title = "Table 1. Study Cohorts and Dose Levels") |>
  gt_light() |>
  cols_label(Cohort = "Cohort", Dose = "Dose", N = "N", Status = "Status")
```

</div>
:::::

::: source-note
Data cut-off: [YYYY-MM-DD] | [Analysis Set] (N=[N])   <!-- <-- REPLACE -->
:::

------------------------------------------------------------------------

## Key Metrics

</br></br></br>

::::::::::::::::::: {.columns style="margin-top: 80px;"}
:::::::::: {.column width="50%"}
::::: metric-card
::: metric-value
`r n_total`
:::

::: metric-label
Subjects enrolled
:::
:::::

:::::: metric-card
::: metric-value
`r round(mean(adnca$t_half), 1)` h
:::

::: metric-label
Mean terminal half-life
:::

::: metric-delta
[Clinical interpretation]   <!-- <-- REPLACE -->
:::
::::::
::::::::::

:::::::::: {.column width="50%"}
::::: metric-card
::: metric-value
`r round(median(adnca$Tmax), 1)` h
:::

::: metric-label
Median Tmax
:::
:::::

:::::: metric-card
::: metric-value
[N_SAE]                     <!-- <-- REPLACE: inline R or hard-coded value -->
:::

::: metric-label
[Safety KPI label]          <!-- <-- REPLACE -->
:::

::: metric-delta
[Clinical interpretation]   <!-- <-- REPLACE -->
:::
::::::
::::::::::
:::::::::::::::::::

------------------------------------------------------------------------

## Pharmacokinetics {.section-divider}

::: {style="text-align: center;"}
NCA · Concentration-Time · Dose Proportionality
:::

------------------------------------------------------------------------

## PK Profiles: Linear Scale

</br></br>

```{r pk-linear, fig.height=3.6, fig.width=10, fig.cap="Figure 1. Mean Plasma Concentration-Time Profile (Linear Scale). Mean ± SD. PK Analysis Set (N=[N])."}
# <-- REPLACE N in fig.cap above
ggplot(pk_mean, aes(x = NTIME, y = mean,
                    color = COHORT, fill = COHORT, group = COHORT)) +
  geom_ribbon(aes(ymin = pmax(0, mean - sd), ymax = mean + sd),
              alpha = 0.12, color = NA) +
  geom_line(linewidth = 0.9) +
  geom_point(size = 2) +
  scale_color_manual(values = cohort_colors) +
  scale_fill_manual(values  = cohort_colors) +
  scale_x_continuous(
    breaks = visits_pk,                                  # <-- adjust if breaks too dense
    expand = expansion(mult = c(0.03, 0.03))
  ) +
  scale_y_continuous(expand = expansion(mult = c(0.05, 0.1))) +
  labs(
    x       = "Time post-dose (h)",
    y       = "Plasma concentration (ng/mL)",  # <-- adjust unit
    color   = NULL, fill = NULL,
    caption = "Mean +/- SD | [Data source]"    # <-- REPLACE
  ) +
  theme_slides() +
  coord_cartesian(clip = "off")
```

------------------------------------------------------------------------

## PK Profiles: Semi-Log Scale

</br></br>

```{r pk-log, fig.height=3.6, fig.width=10, fig.cap="Figure 2. Mean Plasma Concentration-Time Profile (Semi-Logarithmic Scale). PK Analysis Set (N=[N])."}
# <-- REPLACE N in fig.cap above
ggplot(pk_mean |> filter(NTIME > 0),
       aes(x = NTIME, y = mean, color = COHORT, group = COHORT)) +
  geom_line(linewidth = 0.9) +
  geom_point(size = 2) +
  scale_color_manual(values = cohort_colors) +
  scale_y_log10(expand = expansion(mult = c(0.05, 0.1))) +
  scale_x_continuous(
    breaks = visits_pk[visits_pk > 0],
    expand = expansion(mult = c(0.03, 0.03))
  ) +
  labs(
    x       = "Time post-dose (h)",
    y       = "Plasma concentration (ng/mL, log scale)",
    color   = NULL,
    caption = "Semi-log scale | Terminal phase linearity"
  ) +
  theme_slides() +
  coord_cartesian(clip = "off")
```

------------------------------------------------------------------------

## NCA Parameters

::::: {style="margin-top: 60px;"}
</br></br>

```{r nca-table}
# Adjust summarise() to match your NCA output (add/remove parameters as needed)
adnca |>
  group_by(COHORT) |>
  summarise(
    N       = n(),
    Cmax    = sprintf("%.1f (%.1f)", mean(Cmax),    sd(Cmax)),
    Tmax    = sprintf("%.1f [%.1f, %.1f]", median(Tmax), min(Tmax), max(Tmax)),
    AUClast = sprintf("%.0f (%.0f)",  mean(AUClast), sd(AUClast)),
    `t1/2`  = sprintf("%.1f (%.1f)", mean(t_half),  sd(t_half)),
    .groups = "drop"
  ) |>
  gt() |>
  tab_header(title = "Table 2. Non-Compartmental Pharmacokinetic Parameters") |>
  gt_light() |>
  tab_footnote("[Units] | Mean (SD) except Tmax: Median [Min, Max]") |>  # <-- REPLACE units
  tab_style(
    style     = cell_text(color = "#7a8799", size = px(10)),
    locations = cells_footnotes()
  ) |>
  cols_label(COHORT = "Cohort")
```

:::: c-box
::: c-title
Dose proportionality
:::

<p>[Describe observed dose-proportionality and reference SAP pre-specification.]</p>  <!-- <-- REPLACE -->
::::
:::::

------------------------------------------------------------------------

## Safety {.section-divider}

::: {style="text-align: center;"}
TEAEs · Severity · Laboratory Findings
:::

------------------------------------------------------------------------

## Adverse Events Overview

::::::::: columns
::: {.column width="60%"}
</br></br></br>

```{r ae-table}
adae |>
  filter(TRTEMFL == "Y") |>
  left_join(n_by_cohort, by = "COHORT") |>
  group_by(COHORT, N) |>
  summarise(
    `Any TEAE` = sprintf("%d (%.0f%%)", n_distinct(USUBJID),
                         100 * n_distinct(USUBJID) / first(N)),
    Mild       = sprintf("%d", sum(AESEV == "MILD")),
    Moderate   = sprintf("%d", sum(AESEV == "MODERATE")),
    Serious    = sprintf("%d", sum(AESER == "Y")),
    .groups = "drop"
  ) |>
  select(-N) |>
  gt() |>
  tab_header(title = "Table 3. Overview of Treatment-Emergent Adverse Events") |>
  gt_light() |>
  cols_label(COHORT = "Cohort")
```
:::

::::::: {.column width="40%"}
**Key observations**

::: fragment
- [Key safety observation 1]   <!-- <-- REPLACE -->
:::

::: fragment
- [Key safety observation 2]   <!-- <-- REPLACE -->
:::

::: fragment
- [Key safety observation 3]   <!-- <-- REPLACE -->
:::
:::::::
:::::::::

::: source-note
Source: [Dataset name] | TEAE: [definition]   <!-- <-- REPLACE -->
:::

------------------------------------------------------------------------

## TEAEs by System Organ Class

</br></br>

```{r ae-soc}
adae |>
  filter(TRTEMFL == "Y") |>
  left_join(n_by_cohort, by = "COHORT") |>
  group_by(AESOC, AEDECOD, COHORT, N) |>
  summarise(n = n_distinct(USUBJID), .groups = "drop") |>
  mutate(cell = sprintf("%d (%.0f%%)", n, 100 * n / N)) |>
  select(AESOC, AEDECOD, COHORT, cell) |>
  pivot_wider(names_from = COHORT, values_from = cell, values_fill = "0") |>
  arrange(AESOC, AEDECOD) |>
  gt(groupname_col = "AESOC") |>
  tab_header(title = "Table 4. Treatment-Emergent Adverse Events by System Organ Class and Preferred Term") |>
  tab_style(
    style     = list(cell_fill(color = "#e8f1fb"),
                     cell_text(weight = "bold", color = "#0057B8")),
    locations = cells_row_groups()
  ) |>
  gt_light() |>
  cols_label(AEDECOD = "Preferred Term")
```

------------------------------------------------------------------------

## Conclusions {.section-divider}

::: {style="text-align: center;"}
Safety · PK · Next Steps
:::

------------------------------------------------------------------------

## Key Findings

:::::::::::: columns
::::: {.column width="50%"}
**Safety** [[Label]]{.tag}   <!-- <-- REPLACE: e.g. Favourable -->

::: {.fragment .fade-in-then-semi-out}
- [Safety finding 1]         <!-- <-- REPLACE -->
- [Safety finding 2]
- [Safety finding 3]
:::

**PK** [[Label]]{.tag}       <!-- <-- REPLACE: e.g. On target -->

::: {.fragment .fade-in-then-semi-out}
- [PK finding 1]             <!-- <-- REPLACE -->
- Median Tmax `r round(median(adnca$Tmax), 1)` h, mean t1/2 `r round(mean(adnca$t_half), 1)` h
- [Clinical implication]
:::
:::::

::::: {.column width="50%"}
**Recommendation**

</br></br>

::: fragment

:::: c-box
::: c-title
Next step
:::

<p>[Recommend next action based on data.]</p>   <!-- <-- REPLACE -->
::::

::::: fragment
:::: c-box-warn
::: c-title
Monitor
:::

<p>[Specify parameters requiring continued monitoring.]</p>   <!-- <-- REPLACE -->
::::
:::::

::::::::::::

:::

------------------------------------------------------------------------

## Reproducibility

</br></br></br>

``` r
quarto render slides-template.qmd --no-cache

# Datasets: loaded via load_verified() with SHA-256 checksum verification
# Key packages: dplyr, ggplot2, gt
```

:::: c-box
::: c-title
Audit trail
:::

<p>All datasets loaded via <code>load_verified()</code>, which checks SHA-256 checksums against locked ADaM references at render time. Every number in this deck traces to a versioned dataset and a specific code commit.</p>
::::

::: source-note
Generated: `r Sys.time()` | Rendered by: `r Sys.info()[["user"]]`
:::
