---
title: "Case Study III: Retail Performance (KY, OH, PA, 2021–2023)"
author: "Group Members: <ADD NAMES HERE>"
date: "September 16, 2025"
output:
  pdf_document:
    number_sections: true
    toc: true
    toc_depth: 2
  html_document:
    df_print: paged
    toc: true
    toc_depth: 2
---
library(tidyverse)
library(janitor)
library(scales)
library(gt)
library(glue)

0) Reproducible Data Ingest & Cleaning

# ---- Configuration ----
states_of_interest <- c("KY", "OH", "PA")
years_of_interest  <- 2021:2023

# If you have a single combined CSV, set its filename here; leave NULL to auto-read many files.
combined_file <- NULL

# ---- Helper ----
read_one <- function(path) readr::read_csv(path, show_col_types = FALSE) |> clean_names()

# ---- Read data ----
if (!is.null(combined_file) && file.exists(combined_file)) {
  raw <- read_one(combined_file)
} else {
  files <- list.files(pattern = "^(KY|OH|PA)_20.*\\.csv$", full.names = TRUE)
  if (length(files) == 0L) stop("No input files found. Place KY/OH/PA CSVs (e.g., KY_2021.csv) in the working directory.")
  raw <- purrr::map_dfr(files, read_one)
}

# Expected columns (case-insensitive handled by clean_names)
needed <- c("store_id","state","year","sales","customer_count","employees",
            "store_area_sqft","profit_margin","store_type")
stopifnot(all(needed %in% names(raw)))

dat0 <- raw |>
  mutate(state = toupper(state), year = as.integer(year)) |>
  filter(state %in% states_of_interest, year %in% years_of_interest)

# Derived metrics (store-year)
dat <- dat0 |>
  mutate(
    sales_per_employee = if_else(employees > 0, sales / employees, NA_real_),
    sales_per_sqft     = if_else(store_area_sqft > 0, sales / store_area_sqft, NA_real_),
    sales_per_customer = if_else(customer_count > 0, sales / customer_count, NA_real_)
  )

# Quick snapshot
dat |> slice_head(n = 10) |> gt()
store_id state year sales customer_count employees store_area_sqft profit_margin store_type sales_per_employee sales_per_sqft sales_per_customer
1 KY 2021 60127 2064 39 1788 0.18184457 Urban 1541.718 33.628076 29.13130
2 KY 2021 63097 3526 45 2338 0.19847073 Urban 1402.156 26.987596 17.89478
3 KY 2021 192359 1791 41 5591 0.19066358 Rural 4691.683 34.405115 107.40313
4 KY 2021 153471 1239 26 5499 0.06346242 Suburban 5902.731 27.908893 123.86683
5 KY 2021 151949 4984 24 3459 0.24606024 Suburban 6331.208 43.928592 30.48736
6 KY 2021 193611 3492 8 1737 0.15368608 Urban 24201.375 111.462867 55.44416
7 KY 2021 98086 2025 14 1773 0.24574189 Suburban 7006.143 55.322053 48.43753
8 KY 2021 184969 1744 7 8492 0.12997104 Rural 26424.143 21.781559 106.06021
9 KY 2021 52043 1315 35 8152 0.20485211 Suburban 1486.943 6.384078 39.57643
10 KY 2021 130429 3930 45 9042 0.13154801 Suburban 2898.422 14.424795 33.18804

2) Customer Traffic vs. Revenue Conversion

# Regression-based conversion: slope of Sales ~ Customers by state-year
lm_slopes <- dat |>
  nest_by(state, year) |>
  mutate(
    model = list(lm(sales ~ customer_count, data = data)),
    conversion_slope = as.numeric(coef(model)[["customer_count"]])
  ) |>
  ungroup() |>
  select(state, year, conversion_slope)

# Median Sales/Customer as a robust conversion proxy
conv_state_year <- dat |>
  group_by(state, year) |>
  summarize(median_sales_per_customer = median(sales_per_customer, na.rm = TRUE), .groups = "drop") |>
  left_join(lm_slopes, by = c("state","year"))

# High vs Low conversion by comparing each state's median (across years) to global median
conv_class <- conv_state_year |>
  group_by(state) |>
  summarize(
    median_conv = median(median_sales_per_customer, na.rm = TRUE),
    mean_slope  = mean(conversion_slope, na.rm = TRUE),
    .groups = "drop"
  )

global_median <- median(conv_state_year$median_sales_per_customer, na.rm = TRUE)

conv_class <- conv_class |>
  mutate(conversion_class = if_else(median_conv >= global_median, "High-conversion", "Low-conversion")) |>
  arrange(desc(median_conv))

conv_class |>
  mutate(median_conv = dollar(median_conv), mean_slope = dollar(mean_slope)) |>
  gt() |>
  tab_header(title = "Conversion by State (Median Sales/Customer & OLS Slope)") |>
  cols_label(
    state = "State", median_conv = "Median Sales per Customer",
    mean_slope = "OLS Slope (Sales ~ Customers)", conversion_class = "Class"
  )
Conversion by State (Median Sales/Customer & OLS Slope)
State Median Sales per Customer OLS Slope (Sales ~ Customers) Class
OH $49.42 $5.56 High-conversion
KY $41.16 $5.21 High-conversion
PA $34.39 -$11.79 Low-conversion
dat |>
  ggplot(aes(x = customer_count, y = sales)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = "lm", se = FALSE, linewidth = 1) +
  scale_y_continuous(labels = dollar) +
  labs(title = "Store-Level: Customers vs Sales", x = "Customer Count", y = "Sales") +
  facet_wrap(~ state, scales = "free") +
  theme_minimal(base_size = 12)

3) Store Efficiency: Sales/Employee & Sales/SqFt

store_year <- dat |>
  select(store_id, state, year, store_type, sales, profit_margin,
         sales_per_employee, sales_per_sqft)

# Rank within each year
ranked <- store_year |>
  group_by(year) |>
  mutate(
    rank_spe  = dense_rank(desc(sales_per_employee)),
    rank_spsf = dense_rank(desc(sales_per_sqft))
  ) |>
  ungroup()

top_spe <- ranked |>
  group_by(year) |>
  slice_min(rank_spe, n = 10, with_ties = FALSE) |>
  ungroup() |>
  select(year, store_id, state, store_type, sales_per_employee, rank_spe)

top_spsf <- ranked |>
  group_by(year) |>
  slice_min(rank_spsf, n = 10, with_ties = FALSE) |>
  ungroup() |>
  select(year, store_id, state, store_type, sales_per_sqft, rank_spsf)

# Consistency (>=2/3 years)
consistent_top_spe <- top_spe |> count(store_id, sort = TRUE) |> filter(n >= 2) |>
  left_join(distinct(store_year, store_id, state, store_type), by = "store_id")

consistent_top_spsf <- top_spsf |> count(store_id, sort = TRUE) |> filter(n >= 2) |>
  left_join(distinct(store_year, store_id, state, store_type), by = "store_id")

# Underperformers: bottom quartile on BOTH Sales/SqFt and Profit Margin (>=2 years)
thresholds <- store_year |>
  group_by(year) |>
  summarize(
    q25_spsf = quantile(sales_per_sqft, 0.25, na.rm = TRUE),
    q25_pm   = quantile(profit_margin,   0.25, na.rm = TRUE),
    .groups = "drop"
  )

underperf <- store_year |>
  left_join(thresholds, by = "year") |>
  mutate(
    low_spsf = sales_per_sqft <= q25_spsf,
    low_pm   = profit_margin   <= q25_pm,
    under_both = low_spsf & low_pm
  ) |>
  filter(under_both) |>
  count(store_id, sort = TRUE, name = "underperf_years") |>
  filter(underperf_years >= 2) |>
  left_join(distinct(store_year, store_id, state, store_type), by = "store_id")

list(
  "Top-10 Sales/Employee (by year)" = top_spe,
  "Top-10 Sales/SqFt (by year)" = top_spsf,
  "Consistent Top (>=2 yrs) — Sales/Employee" = consistent_top_spe,
  "Consistent Top (>=2 yrs) — Sales/SqFt" = consistent_top_spsf,
  "Consistently Underperform (>=2 yrs) on PM & Sales/SqFt" = underperf
)
## $`Top-10 Sales/Employee (by year)`
## # A tibble: 30 × 6
##     year store_id state store_type sales_per_employee rank_spe
##    <int>    <dbl> <chr> <chr>                   <dbl>    <int>
##  1  2021        8 KY    Rural                  26424.        1
##  2  2021        8 OH    Rural                  26236.        2
##  3  2021        6 KY    Urban                  24201.        3
##  4  2021        6 OH    Urban                  24134.        4
##  5  2021        7 PA    Rural                  17818.        5
##  6  2021        2 PA    Rural                  17326         6
##  7  2021        7 KY    Suburban                7006.        7
##  8  2021        7 OH    Suburban                6970.        8
##  9  2021        1 PA    Suburban                6605.        9
## 10  2021        5 KY    Suburban                6331.       10
## # ℹ 20 more rows
## 
## $`Top-10 Sales/SqFt (by year)`
## # A tibble: 30 × 6
##     year store_id state store_type sales_per_sqft rank_spsf
##    <int>    <dbl> <chr> <chr>               <dbl>     <int>
##  1  2021        6 KY    Urban               111.          1
##  2  2021        6 OH    Urban               111.          2
##  3  2021        1 PA    Suburban             84.6         3
##  4  2021        7 KY    Suburban             55.3         4
##  5  2021        7 OH    Suburban             55.0         5
##  6  2021        9 PA    Urban                46.6         6
##  7  2021        5 KY    Suburban             43.9         7
##  8  2021        5 OH    Suburban             43.9         8
##  9  2021        3 KY    Rural                34.4         9
## 10  2021        3 OH    Rural                34.3        10
## # ℹ 20 more rows
## 
## $`Consistent Top (>=2 yrs) — Sales/Employee`
## # A tibble: 18 × 4
##    store_id     n state store_type
##       <dbl> <int> <chr> <chr>     
##  1        7     8 KY    Suburban  
##  2        7     8 OH    Suburban  
##  3        7     8 PA    Rural     
##  4        6     6 KY    Urban     
##  5        6     6 OH    Urban     
##  6        6     6 PA    Urban     
##  7        8     6 KY    Rural     
##  8        8     6 OH    Rural     
##  9        8     6 PA    Urban     
## 10        1     3 KY    Urban     
## 11        1     3 OH    Urban     
## 12        1     3 PA    Suburban  
## 13        2     3 KY    Urban     
## 14        2     3 OH    Urban     
## 15        2     3 PA    Rural     
## 16        5     3 KY    Suburban  
## 17        5     3 OH    Suburban  
## 18        5     3 PA    Urban     
## 
## $`Consistent Top (>=2 yrs) — Sales/SqFt`
## # A tibble: 18 × 4
##    store_id     n state store_type
##       <dbl> <int> <chr> <chr>     
##  1        5     6 KY    Suburban  
##  2        5     6 OH    Suburban  
##  3        5     6 PA    Urban     
##  4        6     6 KY    Urban     
##  5        6     6 OH    Urban     
##  6        6     6 PA    Urban     
##  7        7     6 KY    Suburban  
##  8        7     6 OH    Suburban  
##  9        7     6 PA    Rural     
## 10        1     5 KY    Urban     
## 11        1     5 OH    Urban     
## 12        1     5 PA    Suburban  
## 13        3     4 KY    Rural     
## 14        3     4 OH    Rural     
## 15        3     4 PA    Urban     
## 16        9     3 KY    Suburban  
## 17        9     3 OH    Suburban  
## 18        9     3 PA    Urban     
## 
## $`Consistently Underperform (>=2 yrs) on PM & Sales/SqFt`
## # A tibble: 3 × 4
##   store_id underperf_years state store_type
##      <dbl>           <int> <chr> <chr>     
## 1       10               6 KY    Suburban  
## 2       10               6 OH    Suburban  
## 3       10               6 PA    Rural
store_year |>
  pivot_longer(c(sales_per_employee, sales_per_sqft), names_to = "metric", values_to = "value") |>
  ggplot(aes(x = value, fill = metric)) +
  geom_histogram(bins = 30, alpha = 0.6, position = "identity") +
  scale_x_continuous(labels = dollar) +
  labs(title = "Store Efficiency Distributions", x = "Value", y = "Count") +
  facet_wrap(~ metric, scales = "free") +
  theme_minimal(base_size = 12) +
  theme(legend.position = "none")

4) Performance by Store Type (Urban, Suburban, Rural)

type_perf <- dat |>
  group_by(state, store_type) |>
  summarize(
    median_sales = median(sales, na.rm = TRUE),
    median_profit_margin = median(profit_margin, na.rm = TRUE),
    .groups = "drop"
  )

type_perf |>
  mutate(
    median_sales = dollar(median_sales),
    median_profit_margin = percent(median_profit_margin, accuracy = 0.1)
  ) |>
  arrange(state, desc(median_sales)) |>
  gt() |>
  tab_header(title = "Performance by Store Type (Median per Store)")
Performance by Store Type (Median per Store)
state store_type median_sales median_profit_margin
KY Urban $60,345 19.7%
KY Rural $179,895 18.7%
KY Suburban $125,452 22.0%
OH Urban $73,661 18.4%
OH Rural $209,904 16.2%
OH Suburban $139,261 20.4%
PA Urban $65,008 20.7%
PA Suburban $201,446 25.5%
PA Rural $125,893 14.6%
dat |>
  group_by(state, store_type, year) |>
  summarize(
    sales_med = median(sales, na.rm = TRUE),
    pm_med    = median(profit_margin, na.rm = TRUE),
    .groups = "drop"
  ) |>
  pivot_longer(c(sales_med, pm_med), names_to = "metric", values_to = "value") |>
  mutate(metric = dplyr::recode(metric,
                                sales_med = "Median Sales",
                                pm_med    = "Median Profit Margin")) |>
  ggplot(aes(x = store_type, y = value, fill = store_type)) +
  geom_col() +
  facet_grid(metric ~ state, scales = "free_y") +
  scale_y_continuous(
    labels = scales::label_number(accuracy = 0.1,
                                  scale_cut = scales::cut_short_scale()),
    breaks = scales::pretty_breaks()
  ) +
  labs(title = "Store-Type Performance by State & Year (Medians)",
       x = "Store Type", y = NULL) +
  theme_minimal(base_size = 12) +
  theme(legend.position = "none")

5) State Rankings Over Time

state_rank <- dat |>
  group_by(state, year) |>
  summarize(
    total_sales = sum(sales, na.rm = TRUE),
    avg_profit_margin_w = w_avg_profit(profit_margin, sales),
    total_area = sum(store_area_sqft, na.rm = TRUE),
    sales_per_sqft_state = if_else(total_area > 0, total_sales / total_area, NA_real_),
    .groups = "drop"
  ) |>
  group_by(year) |>
  mutate(
    rk_sales = dense_rank(desc(total_sales)),
    rk_pm    = dense_rank(desc(avg_profit_margin_w)),
    rk_spsf  = dense_rank(desc(sales_per_sqft_state))
  ) |>
  ungroup()

# One GT per year
split(state_rank, state_rank$year) |>
  purrr::imap(~ {
    .x |>
      arrange(rk_sales) |>
      mutate(
        total_sales = dollar(total_sales),
        avg_profit_margin_w = percent(avg_profit_margin_w, accuracy = 0.1),
        sales_per_sqft_state = dollar(sales_per_sqft_state)
      ) |>
      select(state, rk_sales, total_sales, rk_pm, avg_profit_margin_w, rk_spsf, sales_per_sqft_state) |>
      gt() |>
      tab_header(title = md(glue("State Rankings — {.y}"))) |>
      cols_label(
        state = "State",
        rk_sales = "Rank: Total Sales",
        total_sales = "Total Sales",
        rk_pm = "Rank: Avg Profit Margin",
        avg_profit_margin_w = "Avg Profit Margin",
        rk_spsf = "Rank: Sales/SqFt",
        sales_per_sqft_state = "Sales/SqFt"
      )
  })
## $`2021`
## <div id="foufhbxvgn" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
##   <style>#foufhbxvgn table {
##   font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
##   -webkit-font-smoothing: antialiased;
##   -moz-osx-font-smoothing: grayscale;
## }
## 
## #foufhbxvgn thead, #foufhbxvgn tbody, #foufhbxvgn tfoot, #foufhbxvgn tr, #foufhbxvgn td, #foufhbxvgn th {
##   border-style: none;
## }
## 
## #foufhbxvgn p {
##   margin: 0;
##   padding: 0;
## }
## 
## #foufhbxvgn .gt_table {
##   display: table;
##   border-collapse: collapse;
##   line-height: normal;
##   margin-left: auto;
##   margin-right: auto;
##   color: #333333;
##   font-size: 16px;
##   font-weight: normal;
##   font-style: normal;
##   background-color: #FFFFFF;
##   width: auto;
##   border-top-style: solid;
##   border-top-width: 2px;
##   border-top-color: #A8A8A8;
##   border-right-style: none;
##   border-right-width: 2px;
##   border-right-color: #D3D3D3;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #A8A8A8;
##   border-left-style: none;
##   border-left-width: 2px;
##   border-left-color: #D3D3D3;
## }
## 
## #foufhbxvgn .gt_caption {
##   padding-top: 4px;
##   padding-bottom: 4px;
## }
## 
## #foufhbxvgn .gt_title {
##   color: #333333;
##   font-size: 125%;
##   font-weight: initial;
##   padding-top: 4px;
##   padding-bottom: 4px;
##   padding-left: 5px;
##   padding-right: 5px;
##   border-bottom-color: #FFFFFF;
##   border-bottom-width: 0;
## }
## 
## #foufhbxvgn .gt_subtitle {
##   color: #333333;
##   font-size: 85%;
##   font-weight: initial;
##   padding-top: 3px;
##   padding-bottom: 5px;
##   padding-left: 5px;
##   padding-right: 5px;
##   border-top-color: #FFFFFF;
##   border-top-width: 0;
## }
## 
## #foufhbxvgn .gt_heading {
##   background-color: #FFFFFF;
##   text-align: center;
##   border-bottom-color: #FFFFFF;
##   border-left-style: none;
##   border-left-width: 1px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 1px;
##   border-right-color: #D3D3D3;
## }
## 
## #foufhbxvgn .gt_bottom_border {
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
## }
## 
## #foufhbxvgn .gt_col_headings {
##   border-top-style: solid;
##   border-top-width: 2px;
##   border-top-color: #D3D3D3;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   border-left-style: none;
##   border-left-width: 1px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 1px;
##   border-right-color: #D3D3D3;
## }
## 
## #foufhbxvgn .gt_col_heading {
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: normal;
##   text-transform: inherit;
##   border-left-style: none;
##   border-left-width: 1px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 1px;
##   border-right-color: #D3D3D3;
##   vertical-align: bottom;
##   padding-top: 5px;
##   padding-bottom: 6px;
##   padding-left: 5px;
##   padding-right: 5px;
##   overflow-x: hidden;
## }
## 
## #foufhbxvgn .gt_column_spanner_outer {
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: normal;
##   text-transform: inherit;
##   padding-top: 0;
##   padding-bottom: 0;
##   padding-left: 4px;
##   padding-right: 4px;
## }
## 
## #foufhbxvgn .gt_column_spanner_outer:first-child {
##   padding-left: 0;
## }
## 
## #foufhbxvgn .gt_column_spanner_outer:last-child {
##   padding-right: 0;
## }
## 
## #foufhbxvgn .gt_column_spanner {
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   vertical-align: bottom;
##   padding-top: 5px;
##   padding-bottom: 5px;
##   overflow-x: hidden;
##   display: inline-block;
##   width: 100%;
## }
## 
## #foufhbxvgn .gt_spanner_row {
##   border-bottom-style: hidden;
## }
## 
## #foufhbxvgn .gt_group_heading {
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: initial;
##   text-transform: inherit;
##   border-top-style: solid;
##   border-top-width: 2px;
##   border-top-color: #D3D3D3;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   border-left-style: none;
##   border-left-width: 1px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 1px;
##   border-right-color: #D3D3D3;
##   vertical-align: middle;
##   text-align: left;
## }
## 
## #foufhbxvgn .gt_empty_group_heading {
##   padding: 0.5px;
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: initial;
##   border-top-style: solid;
##   border-top-width: 2px;
##   border-top-color: #D3D3D3;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   vertical-align: middle;
## }
## 
## #foufhbxvgn .gt_from_md > :first-child {
##   margin-top: 0;
## }
## 
## #foufhbxvgn .gt_from_md > :last-child {
##   margin-bottom: 0;
## }
## 
## #foufhbxvgn .gt_row {
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
##   margin: 10px;
##   border-top-style: solid;
##   border-top-width: 1px;
##   border-top-color: #D3D3D3;
##   border-left-style: none;
##   border-left-width: 1px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 1px;
##   border-right-color: #D3D3D3;
##   vertical-align: middle;
##   overflow-x: hidden;
## }
## 
## #foufhbxvgn .gt_stub {
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: initial;
##   text-transform: inherit;
##   border-right-style: solid;
##   border-right-width: 2px;
##   border-right-color: #D3D3D3;
##   padding-left: 5px;
##   padding-right: 5px;
## }
## 
## #foufhbxvgn .gt_stub_row_group {
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: initial;
##   text-transform: inherit;
##   border-right-style: solid;
##   border-right-width: 2px;
##   border-right-color: #D3D3D3;
##   padding-left: 5px;
##   padding-right: 5px;
##   vertical-align: top;
## }
## 
## #foufhbxvgn .gt_row_group_first td {
##   border-top-width: 2px;
## }
## 
## #foufhbxvgn .gt_row_group_first th {
##   border-top-width: 2px;
## }
## 
## #foufhbxvgn .gt_summary_row {
##   color: #333333;
##   background-color: #FFFFFF;
##   text-transform: inherit;
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
## }
## 
## #foufhbxvgn .gt_first_summary_row {
##   border-top-style: solid;
##   border-top-color: #D3D3D3;
## }
## 
## #foufhbxvgn .gt_first_summary_row.thick {
##   border-top-width: 2px;
## }
## 
## #foufhbxvgn .gt_last_summary_row {
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
## }
## 
## #foufhbxvgn .gt_grand_summary_row {
##   color: #333333;
##   background-color: #FFFFFF;
##   text-transform: inherit;
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
## }
## 
## #foufhbxvgn .gt_first_grand_summary_row {
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
##   border-top-style: double;
##   border-top-width: 6px;
##   border-top-color: #D3D3D3;
## }
## 
## #foufhbxvgn .gt_last_grand_summary_row_top {
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
##   border-bottom-style: double;
##   border-bottom-width: 6px;
##   border-bottom-color: #D3D3D3;
## }
## 
## #foufhbxvgn .gt_striped {
##   background-color: rgba(128, 128, 128, 0.05);
## }
## 
## #foufhbxvgn .gt_table_body {
##   border-top-style: solid;
##   border-top-width: 2px;
##   border-top-color: #D3D3D3;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
## }
## 
## #foufhbxvgn .gt_footnotes {
##   color: #333333;
##   background-color: #FFFFFF;
##   border-bottom-style: none;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   border-left-style: none;
##   border-left-width: 2px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 2px;
##   border-right-color: #D3D3D3;
## }
## 
## #foufhbxvgn .gt_footnote {
##   margin: 0px;
##   font-size: 90%;
##   padding-top: 4px;
##   padding-bottom: 4px;
##   padding-left: 5px;
##   padding-right: 5px;
## }
## 
## #foufhbxvgn .gt_sourcenotes {
##   color: #333333;
##   background-color: #FFFFFF;
##   border-bottom-style: none;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   border-left-style: none;
##   border-left-width: 2px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 2px;
##   border-right-color: #D3D3D3;
## }
## 
## #foufhbxvgn .gt_sourcenote {
##   font-size: 90%;
##   padding-top: 4px;
##   padding-bottom: 4px;
##   padding-left: 5px;
##   padding-right: 5px;
## }
## 
## #foufhbxvgn .gt_left {
##   text-align: left;
## }
## 
## #foufhbxvgn .gt_center {
##   text-align: center;
## }
## 
## #foufhbxvgn .gt_right {
##   text-align: right;
##   font-variant-numeric: tabular-nums;
## }
## 
## #foufhbxvgn .gt_font_normal {
##   font-weight: normal;
## }
## 
## #foufhbxvgn .gt_font_bold {
##   font-weight: bold;
## }
## 
## #foufhbxvgn .gt_font_italic {
##   font-style: italic;
## }
## 
## #foufhbxvgn .gt_super {
##   font-size: 65%;
## }
## 
## #foufhbxvgn .gt_footnote_marks {
##   font-size: 75%;
##   vertical-align: 0.4em;
##   position: initial;
## }
## 
## #foufhbxvgn .gt_asterisk {
##   font-size: 100%;
##   vertical-align: 0;
## }
## 
## #foufhbxvgn .gt_indent_1 {
##   text-indent: 5px;
## }
## 
## #foufhbxvgn .gt_indent_2 {
##   text-indent: 10px;
## }
## 
## #foufhbxvgn .gt_indent_3 {
##   text-indent: 15px;
## }
## 
## #foufhbxvgn .gt_indent_4 {
##   text-indent: 20px;
## }
## 
## #foufhbxvgn .gt_indent_5 {
##   text-indent: 25px;
## }
## 
## #foufhbxvgn .katex-display {
##   display: inline-flex !important;
##   margin-bottom: 0.75em !important;
## }
## 
## #foufhbxvgn div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
##   height: 0px !important;
## }
## </style>
##   <table class="gt_table" data-quarto-disable-processing="false" data-quarto-bootstrap="false">
##   <thead>
##     <tr class="gt_heading">
##       <td colspan="7" class="gt_heading gt_title gt_font_normal gt_bottom_border" style><span class='gt_from_md'>State Rankings — 2021</span></td>
##     </tr>
##     
##     <tr class="gt_col_headings">
##       <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="state">State</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="rk_sales">Rank: Total Sales</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="total_sales">Total Sales</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="rk_pm">Rank: Avg Profit Margin</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="avg_profit_margin_w">Avg Profit Margin</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="rk_spsf">Rank: Sales/SqFt</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="sales_per_sqft_state">Sales/SqFt</th>
##     </tr>
##   </thead>
##   <tbody class="gt_table_body">
##     <tr><td headers="state" class="gt_row gt_left">KY</td>
## <td headers="rk_sales" class="gt_row gt_right">1</td>
## <td headers="total_sales" class="gt_row gt_right">$1,280,141</td>
## <td headers="rk_pm" class="gt_row gt_right">2</td>
## <td headers="avg_profit_margin_w" class="gt_row gt_right">16.6%</td>
## <td headers="rk_spsf" class="gt_row gt_right">1</td>
## <td headers="sales_per_sqft_state" class="gt_row gt_right">$26.74</td></tr>
##     <tr><td headers="state" class="gt_row gt_left">OH</td>
## <td headers="rk_sales" class="gt_row gt_right">2</td>
## <td headers="total_sales" class="gt_row gt_right">$1,266,415</td>
## <td headers="rk_pm" class="gt_row gt_right">3</td>
## <td headers="avg_profit_margin_w" class="gt_row gt_right">16.2%</td>
## <td headers="rk_spsf" class="gt_row gt_right">2</td>
## <td headers="sales_per_sqft_state" class="gt_row gt_right">$26.45</td></tr>
##     <tr><td headers="state" class="gt_row gt_left">PA</td>
## <td headers="rk_sales" class="gt_row gt_right">3</td>
## <td headers="total_sales" class="gt_row gt_right">$1,168,255</td>
## <td headers="rk_pm" class="gt_row gt_right">1</td>
## <td headers="avg_profit_margin_w" class="gt_row gt_right">16.9%</td>
## <td headers="rk_spsf" class="gt_row gt_right">3</td>
## <td headers="sales_per_sqft_state" class="gt_row gt_right">$23.90</td></tr>
##   </tbody>
##   
##   
## </table>
## </div>
## 
## $`2022`
## <div id="nsgwsbmzlq" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
##   <style>#nsgwsbmzlq table {
##   font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
##   -webkit-font-smoothing: antialiased;
##   -moz-osx-font-smoothing: grayscale;
## }
## 
## #nsgwsbmzlq thead, #nsgwsbmzlq tbody, #nsgwsbmzlq tfoot, #nsgwsbmzlq tr, #nsgwsbmzlq td, #nsgwsbmzlq th {
##   border-style: none;
## }
## 
## #nsgwsbmzlq p {
##   margin: 0;
##   padding: 0;
## }
## 
## #nsgwsbmzlq .gt_table {
##   display: table;
##   border-collapse: collapse;
##   line-height: normal;
##   margin-left: auto;
##   margin-right: auto;
##   color: #333333;
##   font-size: 16px;
##   font-weight: normal;
##   font-style: normal;
##   background-color: #FFFFFF;
##   width: auto;
##   border-top-style: solid;
##   border-top-width: 2px;
##   border-top-color: #A8A8A8;
##   border-right-style: none;
##   border-right-width: 2px;
##   border-right-color: #D3D3D3;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #A8A8A8;
##   border-left-style: none;
##   border-left-width: 2px;
##   border-left-color: #D3D3D3;
## }
## 
## #nsgwsbmzlq .gt_caption {
##   padding-top: 4px;
##   padding-bottom: 4px;
## }
## 
## #nsgwsbmzlq .gt_title {
##   color: #333333;
##   font-size: 125%;
##   font-weight: initial;
##   padding-top: 4px;
##   padding-bottom: 4px;
##   padding-left: 5px;
##   padding-right: 5px;
##   border-bottom-color: #FFFFFF;
##   border-bottom-width: 0;
## }
## 
## #nsgwsbmzlq .gt_subtitle {
##   color: #333333;
##   font-size: 85%;
##   font-weight: initial;
##   padding-top: 3px;
##   padding-bottom: 5px;
##   padding-left: 5px;
##   padding-right: 5px;
##   border-top-color: #FFFFFF;
##   border-top-width: 0;
## }
## 
## #nsgwsbmzlq .gt_heading {
##   background-color: #FFFFFF;
##   text-align: center;
##   border-bottom-color: #FFFFFF;
##   border-left-style: none;
##   border-left-width: 1px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 1px;
##   border-right-color: #D3D3D3;
## }
## 
## #nsgwsbmzlq .gt_bottom_border {
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
## }
## 
## #nsgwsbmzlq .gt_col_headings {
##   border-top-style: solid;
##   border-top-width: 2px;
##   border-top-color: #D3D3D3;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   border-left-style: none;
##   border-left-width: 1px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 1px;
##   border-right-color: #D3D3D3;
## }
## 
## #nsgwsbmzlq .gt_col_heading {
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: normal;
##   text-transform: inherit;
##   border-left-style: none;
##   border-left-width: 1px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 1px;
##   border-right-color: #D3D3D3;
##   vertical-align: bottom;
##   padding-top: 5px;
##   padding-bottom: 6px;
##   padding-left: 5px;
##   padding-right: 5px;
##   overflow-x: hidden;
## }
## 
## #nsgwsbmzlq .gt_column_spanner_outer {
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: normal;
##   text-transform: inherit;
##   padding-top: 0;
##   padding-bottom: 0;
##   padding-left: 4px;
##   padding-right: 4px;
## }
## 
## #nsgwsbmzlq .gt_column_spanner_outer:first-child {
##   padding-left: 0;
## }
## 
## #nsgwsbmzlq .gt_column_spanner_outer:last-child {
##   padding-right: 0;
## }
## 
## #nsgwsbmzlq .gt_column_spanner {
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   vertical-align: bottom;
##   padding-top: 5px;
##   padding-bottom: 5px;
##   overflow-x: hidden;
##   display: inline-block;
##   width: 100%;
## }
## 
## #nsgwsbmzlq .gt_spanner_row {
##   border-bottom-style: hidden;
## }
## 
## #nsgwsbmzlq .gt_group_heading {
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: initial;
##   text-transform: inherit;
##   border-top-style: solid;
##   border-top-width: 2px;
##   border-top-color: #D3D3D3;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   border-left-style: none;
##   border-left-width: 1px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 1px;
##   border-right-color: #D3D3D3;
##   vertical-align: middle;
##   text-align: left;
## }
## 
## #nsgwsbmzlq .gt_empty_group_heading {
##   padding: 0.5px;
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: initial;
##   border-top-style: solid;
##   border-top-width: 2px;
##   border-top-color: #D3D3D3;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   vertical-align: middle;
## }
## 
## #nsgwsbmzlq .gt_from_md > :first-child {
##   margin-top: 0;
## }
## 
## #nsgwsbmzlq .gt_from_md > :last-child {
##   margin-bottom: 0;
## }
## 
## #nsgwsbmzlq .gt_row {
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
##   margin: 10px;
##   border-top-style: solid;
##   border-top-width: 1px;
##   border-top-color: #D3D3D3;
##   border-left-style: none;
##   border-left-width: 1px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 1px;
##   border-right-color: #D3D3D3;
##   vertical-align: middle;
##   overflow-x: hidden;
## }
## 
## #nsgwsbmzlq .gt_stub {
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: initial;
##   text-transform: inherit;
##   border-right-style: solid;
##   border-right-width: 2px;
##   border-right-color: #D3D3D3;
##   padding-left: 5px;
##   padding-right: 5px;
## }
## 
## #nsgwsbmzlq .gt_stub_row_group {
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: initial;
##   text-transform: inherit;
##   border-right-style: solid;
##   border-right-width: 2px;
##   border-right-color: #D3D3D3;
##   padding-left: 5px;
##   padding-right: 5px;
##   vertical-align: top;
## }
## 
## #nsgwsbmzlq .gt_row_group_first td {
##   border-top-width: 2px;
## }
## 
## #nsgwsbmzlq .gt_row_group_first th {
##   border-top-width: 2px;
## }
## 
## #nsgwsbmzlq .gt_summary_row {
##   color: #333333;
##   background-color: #FFFFFF;
##   text-transform: inherit;
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
## }
## 
## #nsgwsbmzlq .gt_first_summary_row {
##   border-top-style: solid;
##   border-top-color: #D3D3D3;
## }
## 
## #nsgwsbmzlq .gt_first_summary_row.thick {
##   border-top-width: 2px;
## }
## 
## #nsgwsbmzlq .gt_last_summary_row {
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
## }
## 
## #nsgwsbmzlq .gt_grand_summary_row {
##   color: #333333;
##   background-color: #FFFFFF;
##   text-transform: inherit;
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
## }
## 
## #nsgwsbmzlq .gt_first_grand_summary_row {
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
##   border-top-style: double;
##   border-top-width: 6px;
##   border-top-color: #D3D3D3;
## }
## 
## #nsgwsbmzlq .gt_last_grand_summary_row_top {
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
##   border-bottom-style: double;
##   border-bottom-width: 6px;
##   border-bottom-color: #D3D3D3;
## }
## 
## #nsgwsbmzlq .gt_striped {
##   background-color: rgba(128, 128, 128, 0.05);
## }
## 
## #nsgwsbmzlq .gt_table_body {
##   border-top-style: solid;
##   border-top-width: 2px;
##   border-top-color: #D3D3D3;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
## }
## 
## #nsgwsbmzlq .gt_footnotes {
##   color: #333333;
##   background-color: #FFFFFF;
##   border-bottom-style: none;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   border-left-style: none;
##   border-left-width: 2px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 2px;
##   border-right-color: #D3D3D3;
## }
## 
## #nsgwsbmzlq .gt_footnote {
##   margin: 0px;
##   font-size: 90%;
##   padding-top: 4px;
##   padding-bottom: 4px;
##   padding-left: 5px;
##   padding-right: 5px;
## }
## 
## #nsgwsbmzlq .gt_sourcenotes {
##   color: #333333;
##   background-color: #FFFFFF;
##   border-bottom-style: none;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   border-left-style: none;
##   border-left-width: 2px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 2px;
##   border-right-color: #D3D3D3;
## }
## 
## #nsgwsbmzlq .gt_sourcenote {
##   font-size: 90%;
##   padding-top: 4px;
##   padding-bottom: 4px;
##   padding-left: 5px;
##   padding-right: 5px;
## }
## 
## #nsgwsbmzlq .gt_left {
##   text-align: left;
## }
## 
## #nsgwsbmzlq .gt_center {
##   text-align: center;
## }
## 
## #nsgwsbmzlq .gt_right {
##   text-align: right;
##   font-variant-numeric: tabular-nums;
## }
## 
## #nsgwsbmzlq .gt_font_normal {
##   font-weight: normal;
## }
## 
## #nsgwsbmzlq .gt_font_bold {
##   font-weight: bold;
## }
## 
## #nsgwsbmzlq .gt_font_italic {
##   font-style: italic;
## }
## 
## #nsgwsbmzlq .gt_super {
##   font-size: 65%;
## }
## 
## #nsgwsbmzlq .gt_footnote_marks {
##   font-size: 75%;
##   vertical-align: 0.4em;
##   position: initial;
## }
## 
## #nsgwsbmzlq .gt_asterisk {
##   font-size: 100%;
##   vertical-align: 0;
## }
## 
## #nsgwsbmzlq .gt_indent_1 {
##   text-indent: 5px;
## }
## 
## #nsgwsbmzlq .gt_indent_2 {
##   text-indent: 10px;
## }
## 
## #nsgwsbmzlq .gt_indent_3 {
##   text-indent: 15px;
## }
## 
## #nsgwsbmzlq .gt_indent_4 {
##   text-indent: 20px;
## }
## 
## #nsgwsbmzlq .gt_indent_5 {
##   text-indent: 25px;
## }
## 
## #nsgwsbmzlq .katex-display {
##   display: inline-flex !important;
##   margin-bottom: 0.75em !important;
## }
## 
## #nsgwsbmzlq div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
##   height: 0px !important;
## }
## </style>
##   <table class="gt_table" data-quarto-disable-processing="false" data-quarto-bootstrap="false">
##   <thead>
##     <tr class="gt_heading">
##       <td colspan="7" class="gt_heading gt_title gt_font_normal gt_bottom_border" style><span class='gt_from_md'>State Rankings — 2022</span></td>
##     </tr>
##     
##     <tr class="gt_col_headings">
##       <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="state">State</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="rk_sales">Rank: Total Sales</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="total_sales">Total Sales</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="rk_pm">Rank: Avg Profit Margin</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="avg_profit_margin_w">Avg Profit Margin</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="rk_spsf">Rank: Sales/SqFt</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="sales_per_sqft_state">Sales/SqFt</th>
##     </tr>
##   </thead>
##   <tbody class="gt_table_body">
##     <tr><td headers="state" class="gt_row gt_left">OH</td>
## <td headers="rk_sales" class="gt_row gt_right">1</td>
## <td headers="total_sales" class="gt_row gt_right">$1,416,733</td>
## <td headers="rk_pm" class="gt_row gt_right">3</td>
## <td headers="avg_profit_margin_w" class="gt_row gt_right">17.1%</td>
## <td headers="rk_spsf" class="gt_row gt_right">1</td>
## <td headers="sales_per_sqft_state" class="gt_row gt_right">$29.59</td></tr>
##     <tr><td headers="state" class="gt_row gt_left">PA</td>
## <td headers="rk_sales" class="gt_row gt_right">2</td>
## <td headers="total_sales" class="gt_row gt_right">$1,270,717</td>
## <td headers="rk_pm" class="gt_row gt_right">2</td>
## <td headers="avg_profit_margin_w" class="gt_row gt_right">17.9%</td>
## <td headers="rk_spsf" class="gt_row gt_right">2</td>
## <td headers="sales_per_sqft_state" class="gt_row gt_right">$26.00</td></tr>
##     <tr><td headers="state" class="gt_row gt_left">KY</td>
## <td headers="rk_sales" class="gt_row gt_right">3</td>
## <td headers="total_sales" class="gt_row gt_right">$1,226,768</td>
## <td headers="rk_pm" class="gt_row gt_right">1</td>
## <td headers="avg_profit_margin_w" class="gt_row gt_right">18.4%</td>
## <td headers="rk_spsf" class="gt_row gt_right">3</td>
## <td headers="sales_per_sqft_state" class="gt_row gt_right">$25.63</td></tr>
##   </tbody>
##   
##   
## </table>
## </div>
## 
## $`2023`
## <div id="gzoqsfisni" style="padding-left:0px;padding-right:0px;padding-top:10px;padding-bottom:10px;overflow-x:auto;overflow-y:auto;width:auto;height:auto;">
##   <style>#gzoqsfisni table {
##   font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
##   -webkit-font-smoothing: antialiased;
##   -moz-osx-font-smoothing: grayscale;
## }
## 
## #gzoqsfisni thead, #gzoqsfisni tbody, #gzoqsfisni tfoot, #gzoqsfisni tr, #gzoqsfisni td, #gzoqsfisni th {
##   border-style: none;
## }
## 
## #gzoqsfisni p {
##   margin: 0;
##   padding: 0;
## }
## 
## #gzoqsfisni .gt_table {
##   display: table;
##   border-collapse: collapse;
##   line-height: normal;
##   margin-left: auto;
##   margin-right: auto;
##   color: #333333;
##   font-size: 16px;
##   font-weight: normal;
##   font-style: normal;
##   background-color: #FFFFFF;
##   width: auto;
##   border-top-style: solid;
##   border-top-width: 2px;
##   border-top-color: #A8A8A8;
##   border-right-style: none;
##   border-right-width: 2px;
##   border-right-color: #D3D3D3;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #A8A8A8;
##   border-left-style: none;
##   border-left-width: 2px;
##   border-left-color: #D3D3D3;
## }
## 
## #gzoqsfisni .gt_caption {
##   padding-top: 4px;
##   padding-bottom: 4px;
## }
## 
## #gzoqsfisni .gt_title {
##   color: #333333;
##   font-size: 125%;
##   font-weight: initial;
##   padding-top: 4px;
##   padding-bottom: 4px;
##   padding-left: 5px;
##   padding-right: 5px;
##   border-bottom-color: #FFFFFF;
##   border-bottom-width: 0;
## }
## 
## #gzoqsfisni .gt_subtitle {
##   color: #333333;
##   font-size: 85%;
##   font-weight: initial;
##   padding-top: 3px;
##   padding-bottom: 5px;
##   padding-left: 5px;
##   padding-right: 5px;
##   border-top-color: #FFFFFF;
##   border-top-width: 0;
## }
## 
## #gzoqsfisni .gt_heading {
##   background-color: #FFFFFF;
##   text-align: center;
##   border-bottom-color: #FFFFFF;
##   border-left-style: none;
##   border-left-width: 1px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 1px;
##   border-right-color: #D3D3D3;
## }
## 
## #gzoqsfisni .gt_bottom_border {
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
## }
## 
## #gzoqsfisni .gt_col_headings {
##   border-top-style: solid;
##   border-top-width: 2px;
##   border-top-color: #D3D3D3;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   border-left-style: none;
##   border-left-width: 1px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 1px;
##   border-right-color: #D3D3D3;
## }
## 
## #gzoqsfisni .gt_col_heading {
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: normal;
##   text-transform: inherit;
##   border-left-style: none;
##   border-left-width: 1px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 1px;
##   border-right-color: #D3D3D3;
##   vertical-align: bottom;
##   padding-top: 5px;
##   padding-bottom: 6px;
##   padding-left: 5px;
##   padding-right: 5px;
##   overflow-x: hidden;
## }
## 
## #gzoqsfisni .gt_column_spanner_outer {
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: normal;
##   text-transform: inherit;
##   padding-top: 0;
##   padding-bottom: 0;
##   padding-left: 4px;
##   padding-right: 4px;
## }
## 
## #gzoqsfisni .gt_column_spanner_outer:first-child {
##   padding-left: 0;
## }
## 
## #gzoqsfisni .gt_column_spanner_outer:last-child {
##   padding-right: 0;
## }
## 
## #gzoqsfisni .gt_column_spanner {
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   vertical-align: bottom;
##   padding-top: 5px;
##   padding-bottom: 5px;
##   overflow-x: hidden;
##   display: inline-block;
##   width: 100%;
## }
## 
## #gzoqsfisni .gt_spanner_row {
##   border-bottom-style: hidden;
## }
## 
## #gzoqsfisni .gt_group_heading {
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: initial;
##   text-transform: inherit;
##   border-top-style: solid;
##   border-top-width: 2px;
##   border-top-color: #D3D3D3;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   border-left-style: none;
##   border-left-width: 1px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 1px;
##   border-right-color: #D3D3D3;
##   vertical-align: middle;
##   text-align: left;
## }
## 
## #gzoqsfisni .gt_empty_group_heading {
##   padding: 0.5px;
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: initial;
##   border-top-style: solid;
##   border-top-width: 2px;
##   border-top-color: #D3D3D3;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   vertical-align: middle;
## }
## 
## #gzoqsfisni .gt_from_md > :first-child {
##   margin-top: 0;
## }
## 
## #gzoqsfisni .gt_from_md > :last-child {
##   margin-bottom: 0;
## }
## 
## #gzoqsfisni .gt_row {
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
##   margin: 10px;
##   border-top-style: solid;
##   border-top-width: 1px;
##   border-top-color: #D3D3D3;
##   border-left-style: none;
##   border-left-width: 1px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 1px;
##   border-right-color: #D3D3D3;
##   vertical-align: middle;
##   overflow-x: hidden;
## }
## 
## #gzoqsfisni .gt_stub {
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: initial;
##   text-transform: inherit;
##   border-right-style: solid;
##   border-right-width: 2px;
##   border-right-color: #D3D3D3;
##   padding-left: 5px;
##   padding-right: 5px;
## }
## 
## #gzoqsfisni .gt_stub_row_group {
##   color: #333333;
##   background-color: #FFFFFF;
##   font-size: 100%;
##   font-weight: initial;
##   text-transform: inherit;
##   border-right-style: solid;
##   border-right-width: 2px;
##   border-right-color: #D3D3D3;
##   padding-left: 5px;
##   padding-right: 5px;
##   vertical-align: top;
## }
## 
## #gzoqsfisni .gt_row_group_first td {
##   border-top-width: 2px;
## }
## 
## #gzoqsfisni .gt_row_group_first th {
##   border-top-width: 2px;
## }
## 
## #gzoqsfisni .gt_summary_row {
##   color: #333333;
##   background-color: #FFFFFF;
##   text-transform: inherit;
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
## }
## 
## #gzoqsfisni .gt_first_summary_row {
##   border-top-style: solid;
##   border-top-color: #D3D3D3;
## }
## 
## #gzoqsfisni .gt_first_summary_row.thick {
##   border-top-width: 2px;
## }
## 
## #gzoqsfisni .gt_last_summary_row {
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
## }
## 
## #gzoqsfisni .gt_grand_summary_row {
##   color: #333333;
##   background-color: #FFFFFF;
##   text-transform: inherit;
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
## }
## 
## #gzoqsfisni .gt_first_grand_summary_row {
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
##   border-top-style: double;
##   border-top-width: 6px;
##   border-top-color: #D3D3D3;
## }
## 
## #gzoqsfisni .gt_last_grand_summary_row_top {
##   padding-top: 8px;
##   padding-bottom: 8px;
##   padding-left: 5px;
##   padding-right: 5px;
##   border-bottom-style: double;
##   border-bottom-width: 6px;
##   border-bottom-color: #D3D3D3;
## }
## 
## #gzoqsfisni .gt_striped {
##   background-color: rgba(128, 128, 128, 0.05);
## }
## 
## #gzoqsfisni .gt_table_body {
##   border-top-style: solid;
##   border-top-width: 2px;
##   border-top-color: #D3D3D3;
##   border-bottom-style: solid;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
## }
## 
## #gzoqsfisni .gt_footnotes {
##   color: #333333;
##   background-color: #FFFFFF;
##   border-bottom-style: none;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   border-left-style: none;
##   border-left-width: 2px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 2px;
##   border-right-color: #D3D3D3;
## }
## 
## #gzoqsfisni .gt_footnote {
##   margin: 0px;
##   font-size: 90%;
##   padding-top: 4px;
##   padding-bottom: 4px;
##   padding-left: 5px;
##   padding-right: 5px;
## }
## 
## #gzoqsfisni .gt_sourcenotes {
##   color: #333333;
##   background-color: #FFFFFF;
##   border-bottom-style: none;
##   border-bottom-width: 2px;
##   border-bottom-color: #D3D3D3;
##   border-left-style: none;
##   border-left-width: 2px;
##   border-left-color: #D3D3D3;
##   border-right-style: none;
##   border-right-width: 2px;
##   border-right-color: #D3D3D3;
## }
## 
## #gzoqsfisni .gt_sourcenote {
##   font-size: 90%;
##   padding-top: 4px;
##   padding-bottom: 4px;
##   padding-left: 5px;
##   padding-right: 5px;
## }
## 
## #gzoqsfisni .gt_left {
##   text-align: left;
## }
## 
## #gzoqsfisni .gt_center {
##   text-align: center;
## }
## 
## #gzoqsfisni .gt_right {
##   text-align: right;
##   font-variant-numeric: tabular-nums;
## }
## 
## #gzoqsfisni .gt_font_normal {
##   font-weight: normal;
## }
## 
## #gzoqsfisni .gt_font_bold {
##   font-weight: bold;
## }
## 
## #gzoqsfisni .gt_font_italic {
##   font-style: italic;
## }
## 
## #gzoqsfisni .gt_super {
##   font-size: 65%;
## }
## 
## #gzoqsfisni .gt_footnote_marks {
##   font-size: 75%;
##   vertical-align: 0.4em;
##   position: initial;
## }
## 
## #gzoqsfisni .gt_asterisk {
##   font-size: 100%;
##   vertical-align: 0;
## }
## 
## #gzoqsfisni .gt_indent_1 {
##   text-indent: 5px;
## }
## 
## #gzoqsfisni .gt_indent_2 {
##   text-indent: 10px;
## }
## 
## #gzoqsfisni .gt_indent_3 {
##   text-indent: 15px;
## }
## 
## #gzoqsfisni .gt_indent_4 {
##   text-indent: 20px;
## }
## 
## #gzoqsfisni .gt_indent_5 {
##   text-indent: 25px;
## }
## 
## #gzoqsfisni .katex-display {
##   display: inline-flex !important;
##   margin-bottom: 0.75em !important;
## }
## 
## #gzoqsfisni div.Reactable > div.rt-table > div.rt-thead > div.rt-tr.rt-tr-group-header > div.rt-th-group:after {
##   height: 0px !important;
## }
## </style>
##   <table class="gt_table" data-quarto-disable-processing="false" data-quarto-bootstrap="false">
##   <thead>
##     <tr class="gt_heading">
##       <td colspan="7" class="gt_heading gt_title gt_font_normal gt_bottom_border" style><span class='gt_from_md'>State Rankings — 2023</span></td>
##     </tr>
##     
##     <tr class="gt_col_headings">
##       <th class="gt_col_heading gt_columns_bottom_border gt_left" rowspan="1" colspan="1" scope="col" id="state">State</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="rk_sales">Rank: Total Sales</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="total_sales">Total Sales</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="rk_pm">Rank: Avg Profit Margin</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="avg_profit_margin_w">Avg Profit Margin</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="rk_spsf">Rank: Sales/SqFt</th>
##       <th class="gt_col_heading gt_columns_bottom_border gt_right" rowspan="1" colspan="1" scope="col" id="sales_per_sqft_state">Sales/SqFt</th>
##     </tr>
##   </thead>
##   <tbody class="gt_table_body">
##     <tr><td headers="state" class="gt_row gt_left">OH</td>
## <td headers="rk_sales" class="gt_row gt_right">1</td>
## <td headers="total_sales" class="gt_row gt_right">$1,596,196</td>
## <td headers="rk_pm" class="gt_row gt_right">3</td>
## <td headers="avg_profit_margin_w" class="gt_row gt_right">17.9%</td>
## <td headers="rk_spsf" class="gt_row gt_right">1</td>
## <td headers="sales_per_sqft_state" class="gt_row gt_right">$33.34</td></tr>
##     <tr><td headers="state" class="gt_row gt_left">PA</td>
## <td headers="rk_sales" class="gt_row gt_right">2</td>
## <td headers="total_sales" class="gt_row gt_right">$1,415,636</td>
## <td headers="rk_pm" class="gt_row gt_right">2</td>
## <td headers="avg_profit_margin_w" class="gt_row gt_right">19.0%</td>
## <td headers="rk_spsf" class="gt_row gt_right">2</td>
## <td headers="sales_per_sqft_state" class="gt_row gt_right">$28.96</td></tr>
##     <tr><td headers="state" class="gt_row gt_left">KY</td>
## <td headers="rk_sales" class="gt_row gt_right">3</td>
## <td headers="total_sales" class="gt_row gt_right">$1,175,403</td>
## <td headers="rk_pm" class="gt_row gt_right">1</td>
## <td headers="avg_profit_margin_w" class="gt_row gt_right">20.8%</td>
## <td headers="rk_spsf" class="gt_row gt_right">3</td>
## <td headers="sales_per_sqft_state" class="gt_row gt_right">$24.55</td></tr>
##   </tbody>
##   
##   
## </table>
## </div>

Conclusions

best_by_year <- state_rank |>
  group_by(year) |>
  summarize(
    sales_winner = state[which.min(rk_sales)],
    pm_winner    = state[which.min(rk_pm)],
    spsf_winner  = state[which.min(rk_spsf)]
  )

conv_summary <- conv_class |>
  arrange(desc(median_conv)) |>
  mutate(median_conv = dollar(median_conv))

cat("### Executive Summary\n")
## ### Executive Summary
cat("- Over 2021–2023, ", growth_tbl$state[which.max(growth_tbl$cagr)], " shows the strongest sales growth (CAGR).\n", sep = "")
## - Over 2021–2023, OH shows the strongest sales growth (CAGR).
cat("- Profit margins tended to move in the *",
    ifelse(mean(growth_tbl$pm_slope, na.rm = TRUE) >= 0, "same/upward", "different/downward"),
    "* direction as sales overall, with state-level exceptions.\n", sep = "")
## - Profit margins tended to move in the *same/upward* direction as sales overall, with state-level exceptions.
cat("- Conversion leaders (median sales/customer): ",
    paste0(conv_summary$state, " (", conv_summary$median_conv, ")", collapse = "; "), ".\n")
## - Conversion leaders (median sales/customer):  OH ($49.42); KY ($41.16); PA ($34.39) .
cat("- Efficiency: See Top-10 tables for Sales/Employee & Sales/SqFt (consistency noted).\n")
## - Efficiency: See Top-10 tables for Sales/Employee & Sales/SqFt (consistency noted).
if (nrow(underperf) > 0) {
  cat("- Attention: Some stores consistently underperform on both Profit Margin and Sales/SqFt (≥2 years). Prioritize diagnostics.\n")
} else {
  cat("- No stores consistently underperform on both Profit Margin and Sales/SqFt across multiple years.\n")
}
## - Attention: Some stores consistently underperform on both Profit Margin and Sales/SqFt (≥2 years). Prioritize diagnostics.
cat("- Rankings: Winners by metric each year:\n")
## - Rankings: Winners by metric each year:
print(best_by_year)
## # A tibble: 3 × 4
##    year sales_winner pm_winner spsf_winner
##   <int> <chr>        <chr>     <chr>      
## 1  2021 KY           PA        KY         
## 2  2022 OH           KY        OH         
## 3  2023 OH           KY        OH

Tip: If you don’t have a LaTeX engine installed, knit to HTML first (or install TinyTeX via tinytex::install_tinytex()).