/* ── Tipografía y layout ───────────────────────────────────────────────── */
body { font-family: 'Inter', 'Segoe UI', sans-serif; color: #1a1a2e; }
h1, h2, h3 { font-weight: 600; }
h2 { border-bottom: 2px solid #e9ecef; padding-bottom: .4rem; margin-top: 2.5rem; }

/* ── KPI Cards ───────────────────────────────────────────────────────────── */
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fill,minmax(160px,1fr)); gap: 14px; margin-bottom: 2rem; }
.kpi-card { background:#fff; border:1px solid #e9ecef; border-radius:10px; padding:16px 18px; box-shadow:0 1px 4px rgba(0,0,0,.06); }
.kpi-card .label { font-size:.72rem; text-transform:uppercase; letter-spacing:.06em; color:#868e96; margin-bottom:4px; }
.kpi-card .value { font-size:1.55rem; font-weight:700; color:#2E4057; line-height:1.1; }
.kpi-card .delta { font-size:.75rem; color:#868e96; margin-top:3px; }
.kpi-card.accent { border-left:4px solid #2E4057; }
.kpi-card.accent2 { border-left:4px solid #048A81; }

/* ── Callout-style insight ───────────────────────────────────────────────── */
.insight { background:#f8f9fa; border-left:4px solid #2E4057; border-radius:0 8px 8px 0; padding:12px 16px; margin:1.2rem 0; font-size:.9rem; }
.insight strong { color:#2E4057; }

/* ── Section divider ─────────────────────────────────────────────────────── */
.section-intro { color:#495057; font-size:.95rem; margin-bottom:1.2rem; }

1. Resumen ejecutivo

Unidades vendidas
160
Benchmark: 551
Facturacion total
$1944.7M
MXN <U+2014> cierres firmados + en aprobaci<U+00F3>n
Ticket promedio
$12,154,624
Benchmark: $10,762,085
Pct_Recompra
23.1%
Benchmark: 23.4%
Mediana precio/m<U+00B2>
$67,632
Benchmark: $68,194
Vendedores activos
23
Or<U+00ED>genes distintos
10
resumen_proy <- foco |>
  group_by(Proyecto = Project_OS) |>
  summarise(
    Unidades    = n(),
    Facturacion = sum(Purchase.price, na.rm=TRUE),
    `Ticket_prom` = mean(Purchase.price, na.rm=TRUE),
    `Precio_m2 med.` = median(precio_m2, na.rm=TRUE),
    `Pct_Recompra` = mean(es_recompra, na.rm=TRUE),
    `Vendedores` = n_distinct(Seller.full.name),
    .groups="drop"
  ) |>
  arrange(desc(Facturacion)) |>
  mutate(
    Facturacion    = MXN(Facturacion),
    `Ticket_prom` = MXN(`Ticket_prom`),
    `Precio_m2 med.` = MXN(`Precio_m2 med.`),
    `Pct_Recompra`   = PCT(`Pct_Recompra`)
  )

DT::datatable(resumen_proy,
  options = list(dom='t', pageLength=10, ordering=FALSE),
  rownames = FALSE, class="compact stripe hover"
)

Tabla 1 — KPIs por proyecto foco

top_proy <- foco |> count(Project_OS, wt=Purchase.price) |> slice_max(n,n=1) |> pull(Project_OS)
top_fact <- foco |> filter(Project_OS==top_proy) |> summarise(s=sum(Purchase.price)) |> pull(s)
top_pct  <- top_fact / kpi$facturacion

Oficinas Pininfarina concentra el 44.7% de la facturación total del universo foco ($870,218,786 MXN), seguido de Silenzio y Nativ T1. Los seis proyectos suman $1,944,739,819 MXN en 160 unidades desde 2022.


2. Evolución temporal

Serie histórica mensual desde el primer cierre registrado. Los picos y valles permiten identificar campañas de venta, lanzamientos y estacionalidad.

2.1 Volumen y facturación mensual

mensual <- foco |>
  group_by(mes) |>
  summarise(
    n_uds    = n(),
    fact     = sum(Purchase.price, na.rm=TRUE),
    .groups  = "drop"
  ) |>
  arrange(mes) |>
  mutate(fact_cum = cumsum(fact))

# Detectar pico
pico <- mensual |> slice_max(n_uds, n=1, with_ties=FALSE)

fig_ev <- plot_ly(mensual, x = ~mes) |>
  add_bars(y = ~n_uds, name = "Unidades",
           marker = list(color = "#2E4057", opacity=.85),
           hovertemplate = "<b>%{x|%b %Y}</b><br>Unidades: %{y}<extra></extra>") |>
  add_lines(y = ~fact/1e6, name = "Facturacion (M MXN)",
            yaxis = "y2", line=list(color="#048A81", width=2.5),
            hovertemplate = "<b>%{x|%b %Y}</b><br>Facturacion: $%{y:.1f}M<extra></extra>") |>
  add_annotations(
    x = pico$mes, y = pico$n_uds + .8, text = paste0("🏆 Pico:<br>", pico$n_uds, " uds"),
    font=list(size=11, color="#2E4057"), showarrow=TRUE, arrowhead=1, arrowcolor="#2E4057",
    ay=-40, bgcolor="white", bordercolor="#2E4057", borderpad=4
  ) |>
  layout(
    yaxis  = list(title="Unidades", side="left", showgrid=TRUE, gridcolor="#f0f0f0"),
    yaxis2 = list(title="Facturacion (M MXN)", overlaying="y", side="right", showgrid=FALSE),
    legend = list(orientation="h", x=0, y=1.12),
    hovermode = "x unified",
    plot_bgcolor = "white", paper_bgcolor = "white",
    margin = list(t=30, r=60)
  )
fig_ev

2.2 Facturación mensual por proyecto

mensual_proy <- foco |>
  group_by(mes, Project_OS) |>
  summarise(fact = sum(Purchase.price, na.rm=TRUE), .groups="drop")

fig_proy <- plot_ly()
for (p in FOCUS_PROJECTS) {
  d <- mensual_proy |> filter(Project_OS == p)
  fig_proy <- fig_proy |>
    add_bars(data=d, x=~mes, y=~fact/1e6, name=p,
             marker=list(color=pal_proyectos[p]),
             hovertemplate=paste0("<b>",p,"</b><br>%{x|%b %Y}<br>$%{y:.1f}M MXN<extra></extra>"))
}
fig_proy <- fig_proy |>
  layout(
    barmode = "stack",
    xaxis   = list(title=""),
    yaxis   = list(title="Facturacion (M MXN)", gridcolor="#f0f0f0"),
    legend  = list(orientation="h", x=0, y=1.1),
    plot_bgcolor="white", paper_bgcolor="white",
    hovermode="x unified"
  )
fig_proy

2.3 Origen comercial en el tiempo

mensual_origen <- foco |>
  group_by(mes, grupo_agg) |>
  summarise(n=n(), fact=sum(Purchase.price, na.rm=TRUE), .groups="drop")

fig_oa <- plot_ly(mensual_origen, x=~mes, y=~fact/1e6, color=~grupo_agg,
                  colors = pal_grupo, type="bar",
                  hovertemplate="%{x|%b %Y}<br>$%{y:.1f}M<extra>%{fullData.name}</extra>") |>
  layout(barmode="stack",
         xaxis=list(title=""),
         yaxis=list(title="Facturacion (M MXN)", gridcolor="#f0f0f0"),
         legend=list(orientation="h",x=0,y=1.1),
         plot_bgcolor="white", paper_bgcolor="white",
         hovermode="x unified")
fig_oa
ult6 <- foco |>
  filter(mes >= max(mes, na.rm=TRUE) %m-% months(6)) |>
  count(grupo_agg, wt=Purchase.price) |>
  mutate(pct=n/sum(n))

gbr_rec <- ult6 |> filter(grupo_agg=="GBR") |> pull(pct)
gbr_hist <- mean(foco$grupo_agg=="GBR")

En los últimos 6 meses, GBR representa el 11.5% de la facturación vs 44.4% histórico. <U+0001F4C9> Producci<U+00F3>n directa sigue siendo el motor principal.


3. Orígenes de venta

Analizamos quién trae los clientes: ventas directas del equipo, embajadores o canales externos (GBR). El origen explica el costo de adquisición y la predictibilidad del flujo.

3.1 Mix por facturación

mix_origen <- foco |>
  group_by(Origin_OS, grupo_origen, grupo_agg) |>
  summarise(
    n_uds = n(),
    fact  = sum(Purchase.price, na.rm=TRUE),
    .groups = "drop"
  ) |>
  arrange(desc(fact)) |>
  mutate(
    pct_fact = fact / sum(fact),
    Origin_display = ifelse(nchar(Origin_OS)==0, "Sin origen", Origin_OS)
  )

col_fn <- function(o) { v <- pal_origen[o]; if(is.na(v)) "#ADB5BD" else v }

fig_mix <- plot_ly(mix_origen,
  x = ~reorder(Origin_display, fact), y = ~fact/1e6,
  type="bar", orientation="v",
  marker = list(color = sapply(mix_origen$Origin_display, col_fn)),
  text = ~paste0(round(pct_fact*100,1), "%"),
  textposition = "outside",
  hovertemplate = "<b>%{x}</b><br>Facturacion: $%{y:.1f}M MXN<br>%{text} del total<extra></extra>"
) |>
  layout(
    xaxis = list(title=""),
    yaxis = list(title="Facturacion (M MXN)", gridcolor="#f0f0f0"),
    plot_bgcolor="white", paper_bgcolor="white",
    showlegend=FALSE
  )
fig_mix

3.2 Directo + Prod. Directa vs GBR por proyecto

cross <- foco |>
  group_by(Project_OS, grupo_agg) |>
  summarise(fact=sum(Purchase.price, na.rm=TRUE), .groups="drop") |>
  group_by(Project_OS) |>
  mutate(pct=fact/sum(fact)) |>
  ungroup()

fig_cross <- plot_ly(cross, x=~grupo_agg, y=~Project_OS, z=~round(pct*100,1),
  type="heatmap",
  colorscale=list(c(0,"#EDF2FB"), c(1,"#2E4057")),
  text=~paste0(round(pct*100,1),"%\n$",round(fact/1e6,1),"M"),
  hovertemplate="<b>%{y}</b><br>%{x}<br>%{text}<extra></extra>",
  showscale=TRUE
) |>
  layout(
    xaxis=list(title=""),
    yaxis=list(title=""),
    plot_bgcolor="white", paper_bgcolor="white"
  )
fig_cross

3.3 Tabla de orígenes × proyecto

tabla_ox <- foco |>
  group_by(Origen=Origin_OS, Proyecto=Project_OS) |>
  summarise(Uds=n(), Facturacion=sum(Purchase.price, na.rm=TRUE), .groups="drop") |>
  mutate(
    Grupo = grupo_origen_fn(Origen),
    `Pct_total` = PCT(Facturacion / kpi$facturacion),
    Facturacion = MXN(Facturacion)
  ) |>
  arrange(Proyecto, desc(Uds))

DT::datatable(tabla_ox,
  filter="top",
  options=list(pageLength=15, dom="ftip",
               columnDefs=list(list(className="dt-right", targets=c(2,3)))),
  rownames=FALSE, class="compact stripe hover"
)

4. Recompra

El 23.1% de las unidades en proyectos foco son recompras (clientes que ya compraron antes). Esto es -0.3 pp por debajo del benchmark del portafolio.

4.1 Tasa de recompra por proyecto

rc_proy <- foco |>
  group_by(Project_OS) |>
  summarise(
    n_total    = n(),
    n_recompra = sum(es_recompra),
    tasa       = mean(es_recompra),
    .groups    = "drop"
  ) |>
  arrange(desc(tasa))

fig_rc <- plot_ly(rc_proy,
  x=~tasa*100, y=~reorder(Project_OS, tasa),
  type="bar", orientation="h",
  marker=list(color=sapply(rc_proy$Project_OS, function(p) pal_proyectos[p])),
  text=~paste0(round(tasa*100,1),"% (", n_recompra,"/",n_total," uds)"),
  textposition="outside",
  hovertemplate="<b>%{y}</b><br>%{text}<extra></extra>"
) |>
  add_segments(x=kpi$b_recompra*100, xend=kpi$b_recompra*100,
               y=0.4, yend=nrow(rc_proy)+0.6, line=list(color="grey50", dash="dot"),
               showlegend=TRUE, name=paste0("Benchmark (",PCT(kpi$b_recompra),")")) |>
  layout(
    xaxis=list(title="% recompra", ticksuffix="%", gridcolor="#f0f0f0"),
    yaxis=list(title=""),
    plot_bgcolor="white", paper_bgcolor="white",
    legend=list(x=0.6, y=0.05)
  )
fig_rc
## Warning: Can't display both discrete & non-discrete data on same axis
## A marker object has been specified, but markers is not in the mode
## Adding markers to the mode...

4.2 Ticket: recompra vs primera vez

ticket_rc <- foco |>
  group_by(`Tipo_cliente`=ifelse(es_recompra,"Recompra","Primera vez")) |>
  summarise(
    Unidades    = n(),
    `Ticket_prom` = mean(Purchase.price, na.rm=TRUE),
    `Ticket mediana` = median(Purchase.price, na.rm=TRUE),
    .groups="drop"
  )

fig_trc <- plot_ly(ticket_rc,
  x=~`Tipo_cliente`, y=~`Ticket_prom`/1e6,
  type="bar",
  marker=list(color=c("#2E4057","#048A81")),
  text=~paste0(MXN(`Ticket_prom`),"\nn=",Unidades),
  textposition="outside",
  hovertemplate="<b>%{x}</b><br>Ticket prom: $%{y:.2f}M MXN<extra></extra>"
) |>
  layout(
    yaxis=list(title="Ticket promedio (M MXN)", gridcolor="#f0f0f0"),
    xaxis=list(title=""),
    plot_bgcolor="white", paper_bgcolor="white", showlegend=FALSE
  )
fig_trc

4.3 Clientes con más de una compra

clientes_rc <- foco |>
  group_by(`Cliente`=Client.full.name) |>
  summarise(
    `N_Compras`  = n(),
    Proyectos    = paste(sort(unique(Project_OS)), collapse=", "),
    `Facturacion total` = sum(Purchase.price, na.rm=TRUE),
    .groups="drop"
  ) |>
  filter(`N_Compras` > 1) |>
  arrange(desc(`Facturacion total`)) |>
  mutate(`Facturacion total` = MXN(`Facturacion total`))

DT::datatable(clientes_rc,
  options=list(pageLength=10, dom="ftp"),
  rownames=FALSE, class="compact stripe hover"
)

5. Precio y metraje

Comparamos la distribución de precio por m² entre proyectos para entender posicionamiento de producto. Un precio/m² más alto puede reflejar acabados premium, ubicación o escasez de inventario.

5.1 Distribución precio/m² por proyecto (boxplot)

foco_pm2 <- foco |> filter(!is.na(precio_m2), precio_m2 > 0, precio_m2 < 300000)

fig_box <- plot_ly(foco_pm2, x=~precio_m2, y=~Project_OS,
  type="box", color=~Project_OS, colors=pal_proyectos,
  boxmean=TRUE, jitter=0.3, pointpos=0,
  hovertemplate="<b>%{y}</b><br>$%{x:,.0f}/m²<extra></extra>"
) |>
  add_segments(
    x=kpi$b_pm2, xend=kpi$b_pm2,
    y=0.4, yend=length(FOCUS_PROJECTS)+0.6,
    line=list(color="grey50", dash="dot"),
    name=paste0("Benchmark (",MXN(kpi$b_pm2),"/m²)"),
    showlegend=TRUE, inherit=FALSE
  ) |>
  layout(
    xaxis=list(title="Precio_m2 (MXN)", tickformat="$,.0f", gridcolor="#f0f0f0"),
    yaxis=list(title=""),
    showlegend=TRUE, legend=list(x=0.7, y=0.05),
    plot_bgcolor="white", paper_bgcolor="white"
  )
fig_box
## Warning: Can't display both discrete & non-discrete data on same axis

5.2 Tamaño vs precio (scatter)

fig_sc <- plot_ly(foco_pm2,
  x=~m2, y=~Purchase.price/1e6,
  color=~Project_OS, colors=pal_proyectos,
  type="scatter", mode="markers",
  size=~Purchase.price, sizes=c(6,30),
  text=~paste0(Project_OS,"<br>",round(m2,0)," m²<br>",MXN(Purchase.price),"<br>",MXN(precio_m2),"/m²"),
  hovertemplate="%{text}<extra></extra>",
  marker=list(opacity=0.75, line=list(width=0.5, color="white"))
) |>
  layout(
    xaxis=list(title="Superficie (m²)", gridcolor="#f0f0f0"),
    yaxis=list(title="Precio de venta (M MXN)", gridcolor="#f0f0f0"),
    legend=list(orientation="h", x=0, y=1.1),
    plot_bgcolor="white", paper_bgcolor="white"
  )
fig_sc
## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

5.3 Evolución precio/m² mediano por proyecto

pm2_evol <- foco_pm2 |>
  group_by(mes, Project_OS) |>
  summarise(med_pm2=median(precio_m2, na.rm=TRUE), .groups="drop")

fig_pm2 <- plot_ly()
for (p in FOCUS_PROJECTS) {
  d <- pm2_evol |> filter(Project_OS==p)
  if (nrow(d) > 1) {
    fig_pm2 <- fig_pm2 |>
      add_lines(data=d, x=~mes, y=~med_pm2, name=p,
                line=list(color=pal_proyectos[p], width=2),
                hovertemplate=paste0("<b>",p,"</b><br>%{x|%b %Y}<br>$%{y:,.0f}/m²<extra></extra>"))
  }
}
fig_pm2 <- fig_pm2 |>
  layout(
    xaxis=list(title=""),
    yaxis=list(title="Precio_m2 mediano (MXN)", tickformat="$,.0f", gridcolor="#f0f0f0"),
    legend=list(orientation="h", x=0, y=1.1),
    plot_bgcolor="white", paper_bgcolor="white",
    hovermode="x unified"
  )
fig_pm2

6. Vendedores

Entender quién vende y por qué canal es crítico para replicar el éxito. La concentración en pocos vendedores es un riesgo operativo; el HHI cuantifica eso.

6.1 Top vendedores por facturación

top_vend <- foco |>
  group_by(Vendedor=Seller.full.name) |>
  summarise(
    Unidades    = n(),
    Facturacion = sum(Purchase.price, na.rm=TRUE),
    `Ticket_prom` = mean(Purchase.price, na.rm=TRUE),
    `Origen_principal` = names(sort(table(Origin_OS), decreasing=TRUE))[1],
    `Proyectos`  = paste(sort(unique(Project_OS)), collapse=", "),
    .groups="drop"
  ) |>
  filter(Vendedor != "Sin vendedor") |>
  arrange(desc(Facturacion)) |>
  head(15) |>
  mutate(
    `Pct_total` = PCT(Facturacion / kpi$facturacion),
    Facturacion   = MXN(Facturacion),
    `Ticket_prom`= MXN(`Ticket_prom`)
  )

DT::datatable(top_vend,
  options=list(pageLength=15, dom="t", ordering=FALSE),
  rownames=FALSE, class="compact stripe hover"
)

6.2 Heatmap: vendedor × proyecto

top10_v <- foco |>
  group_by(Seller.full.name) |>
  summarise(f=sum(Purchase.price, na.rm=TRUE)) |>
  filter(Seller.full.name!="Sin vendedor") |>
  slice_max(f, n=10) |>
  pull(Seller.full.name)

hm_data <- foco |>
  filter(Seller.full.name %in% top10_v) |>
  group_by(Vendedor=Seller.full.name, Proyecto=Project_OS) |>
  summarise(fact=sum(Purchase.price, na.rm=TRUE), n=n(), .groups="drop")

fig_hm <- plot_ly(hm_data,
  x=~Proyecto, y=~Vendedor, z=~round(fact/1e6,1),
  type="heatmap",
  colorscale=list(c(0,"#EDF2FB"), c(0.5,"#7EC8E3"), c(1,"#2E4057")),
  text=~paste0("$",round(fact/1e6,1),"M\n",n," uds"),
  hovertemplate="<b>%{y}</b><br>%{x}<br>%{text}<extra></extra>",
  showscale=TRUE
) |>
  layout(
    xaxis=list(title="", tickangle=-20),
    yaxis=list(title=""),
    plot_bgcolor="white", paper_bgcolor="white"
  )
fig_hm

6.3 Concentración (índice HHI)

shares <- foco |>
  group_by(Seller.full.name) |>
  summarise(f=sum(Purchase.price, na.rm=TRUE)) |>
  filter(Seller.full.name!="Sin vendedor") |>
  mutate(s=f/sum(f))

hhi <- sum(shares$s^2)
top1_share <- max(shares$s)
top1_name  <- shares$Seller.full.name[which.max(shares$s)]
top3_share <- sum(sort(shares$s, decreasing=TRUE)[1:3])

fig_lorenz <- plot_ly() |>
  add_lines(
    x=c(0, cumsum(sort(shares$s))/sum(shares$s)),
    y=c(0, cumsum(sort(shares$f))/sum(shares$f)),
    name="Curva de Lorenz", line=list(color="#2E4057", width=2.5)
  ) |>
  add_lines(x=c(0,1), y=c(0,1), name="Igualdad perfecta",
            line=list(color="#ADB5BD", dash="dot")) |>
  layout(
    xaxis=list(title="Fracción acumulada de vendedores", tickformat=".0%"),
    yaxis=list(title="Fracción acumulada de facturación", tickformat=".0%"),
    legend=list(x=0.05, y=0.95),
    plot_bgcolor="white", paper_bgcolor="white",
    annotations=list(x=0.65, y=0.2,
      text=paste0("HHI = ", round(hhi,3),
                  "<br>Top 1: ", PCT(top1_share),
                  " (", top1_name, ")",
                  "<br>Top 3: ", PCT(top3_share)),
      showarrow=FALSE, bgcolor="white",
      bordercolor="#dee2e6", borderpad=8, font=list(size=12)
    )
  )
fig_lorenz
riesgo <- ifelse(hhi > 0.25, "⚠️ concentración alta (HHI > 0.25)",
          ifelse(hhi > 0.15, "moderada (0.15 < HHI < 0.25)", "baja (HHI < 0.15)"))

HHI = 0.165 — concentración moderada (0.15 < HHI < 0.25). Daniel Loeza King acumula el 26.2% de la facturación foco. Los tres vendedores principales concentran el 66.8%. Un HHI > 0.25 indica dependencia de pocos comerciales.


7. Detalle auditable

Tabla completa de todas las unidades vendidas en proyectos foco. Filtra por cualquier columna para drill-down.

detalle <- foco |>
  select(
    Proyecto    = Project_OS,
    Unidad      = X_id,
    Fecha       = fecha_venta,
    Vendedor    = Seller.full.name,
    Cliente     = Client.full.name,
    Origen      = Origin_OS,
    `Grupo_origen` = grupo_agg,
    m2,
    Precio      = Purchase.price,
    `Precio_m2` = precio_m2,
    Recompra    = es_recompra,
    Estatus     = Status_OS
  ) |>
  mutate(
    Precio      = MXN(Precio),
    `Precio_m2` = MXN(`Precio_m2`),
    m2          = round(m2, 1),
    Recompra    = ifelse(Recompra, "✓", "")
  ) |>
  arrange(Proyecto, desc(Fecha))

DT::datatable(detalle,
  filter="top",
  extensions="Buttons",
  options=list(
    pageLength=20, dom="Bfrtip",
    buttons=list("excel","csv"),
    scrollX=TRUE,
    columnDefs=list(list(visible=FALSE, targets=1))
  ),
  rownames=FALSE, class="compact stripe hover"
)

8. Conclusiones y recomendaciones

gbr_pct   <- mean(foco$grupo_agg=="GBR")
dir_pct   <- mean(foco$grupo_agg=="Directo + Prod. Directa")
top_orig  <- foco |> count(Origin_OS, wt=Purchase.price) |> slice_max(n,n=1) |> pull(Origin_OS)
top_orig_pct <- foco |> count(Origin_OS, wt=Purchase.price) |>
  mutate(p=n/sum(n)) |> filter(Origin_OS==top_orig) |> pull(p)

cat(glue::glue("
**Universo analizado:** {kpi$n_uds} unidades — {kpi$n_origenes} orígenes distintos — {kpi$n_vendedores} vendedores — rango 2022–2026.

**Origen dominante:** {top_orig} ({PCT(top_orig_pct)} de la facturación). La producción propia (Directo + Prod. Directa) explica el {PCT(dir_pct)}, lo que indica un modelo mayoritariamente autosustentado. GBR representa el {PCT(gbr_pct)} restante.

**Recompra por encima del benchmark:** {PCT(kpi$pct_recompra)} vs {PCT(kpi$b_recompra)} del resto del portafolio, señal de alta satisfacción y fidelización en los proyectos foco.

**Concentración comercial:** {top1_name} concentra {PCT(top1_share)} de la facturación (HHI {round(hhi,3)}). Una estrategia de diversificación de vendedores reduciría el riesgo.

**Precio_m2:** la mediana del foco ({MXN(kpi$med_pm2)}/m²) es ligeramente inferior al benchmark ({MXN(kpi$b_pm2)}/m²). Oficinas Pininfarina lidera en volumen absoluto; Silenzio muestra los precios/m² más altos del grupo.
", .open="{{", .close="}}"))

Universo analizado: {kpi\(n_uds} unidades <U+2014> {kpi\)n_origenes} or<U+00ED>genes distintos <U+2014> {kpi$n_vendedores} vendedores <U+2014> rango 2022<U+2013>2026.

Origen dominante: {top_orig} ({PCT(top_orig_pct)} de la facturaci<U+00F3>n). La producci<U+00F3>n propia (Directo + Prod. Directa) explica el {PCT(dir_pct)}, lo que indica un modelo mayoritariamente autosustentado. GBR representa el {PCT(gbr_pct)} restante.

Recompra por encima del benchmark: {PCT(kpi\(pct_recompra)} vs {PCT(kpi\)b_recompra)} del resto del portafolio, se<U+00F1>al de alta satisfacci<U+00F3>n y fidelizaci<U+00F3>n en los proyectos foco.

Concentraci<U+00F3>n comercial: {top1_name} concentra {PCT(top1_share)} de la facturaci<U+00F3>n (HHI {round(hhi,3)}). Una estrategia de diversificaci<U+00F3>n de vendedores reducir<U+00ED>a el riesgo.

Precio_m2: la mediana del foco ({MXN(kpi\(med_pm2)}/m<U+00B2>) es ligeramente inferior al benchmark ({MXN(kpi\)b_pm2)}/m<U+00B2>). Oficinas Pininfarina lidera en volumen absoluto; Silenzio muestra los precios/m<U+00B2> m<U+00E1>s altos del grupo.


Datos: latest.rds — actualizado 2026-05-25 15:56. Grano: soldproperty (1 fila = 1 unidad). Cierres = Firmadas + En proceso con Approval.in.Progress = TRUE. Excluidos: cancelados, draft, anulados. Benchmark = resto del portafolio con los mismos filtros de estatus.