# Slide Components — PPTX building blocks

These are the reusable visual components for Pysae PPTX decks.
Every content slide is composed from these blocks.

## Layout grid

All content slides share a consistent grid:
- **Left margin**: `x: 1.05`
- **Right margin**: content ends at `x: 9.55` (width `8.5"`)
- **Top area**: section label at `y: 0.45`, title at `y: 0.8`
- **Content area**: starts at `y: 1.6`
- **Footer bar**: at `y: 7.0` (bottom of slide)

## Section label

Every content slide has a small uppercase label at top-left:

```javascript
// Green line before label
slide.addShape("rectangle", {
  x: 1.05, y: 0.52, w: 0.4, h: 0.03,
  fill: { color: "00b871" }, line: { width: 0 },
});
// Label text
slide.addText("01 — VOS ENJEUX", {
  x: 1.55, y: 0.35, w: 4.0, h: 0.35,
  fontSize: 8.5, fontFace: "Poppins", color: "00b871",
  bold: true, letterSpacing: 2,
});
```

Format: `"01 — SECTION NAME"` — zero-padded number, em-dash, uppercase label.

## Feature blocks (cards with left accent bar)

The most-used component. A card with a green left border, light green background,
icon top-left, title, and body text.

```javascript
function addFeatureBlock(slide, { x, y, w = 3.8, h = 1.5, icon, title, body }) {
  // Card background
  slide.addShape("roundedRectangle", {
    x, y, w, h,
    rectRadius: 0.08,
    fill: { color: "f0faf5" },
    line: { color: "e8e8e8", pt: 0.5 },
  });
  // Green left accent bar
  slide.addShape("roundedRectangle", {
    x: x, y: y + 0.1, w: 0.07, h: h - 0.2,
    rectRadius: 0.03,
    fill: { color: "00b871" }, line: { width: 0 },
  });
  // Icon (green circle with white icon — use emoji or shape)
  slide.addShape("roundedRectangle", {
    x: x + 0.25, y: y + 0.2, w: 0.4, h: 0.4,
    rectRadius: 0.08,
    fill: { color: "0a4b4d" }, line: { width: 0 },
  });
  // Title
  slide.addText(title, {
    x: x + 0.8, y: y + 0.15, w: w - 1.0, h: 0.4,
    fontSize: 11.5, bold: true, color: "0a4b4d", fontFace: "Poppins",
  });
  // Body text
  if (body) {
    slide.addText(body, {
      x: x + 0.25, y: y + 0.7, w: w - 0.5, h: h - 0.9,
      fontSize: 10, color: "1a1a1a", fontFace: "Poppins", wrap: true,
    });
  }
}
```

**Layout patterns:**
- 2 columns: `x: 1.05, w: 3.8` and `x: 5.35, w: 3.8`
- 3 columns: `x: 1.05, w: 2.5` and `x: 3.75, w: 2.5` and `x: 6.45, w: 2.5`
- 2x2 grid: combine 2-column x positions with `y: 1.6` and `y: 3.3`

## KPI cards

Rounded rectangle with green border, light background, big green number, small label.

```javascript
function addKpiCard(slide, { x, y, w = 2.0, h = 1.1, stat, label }) {
  slide.addShape("roundedRectangle", {
    x, y, w, h,
    rectRadius: 0.12,
    fill: { color: "f0faf5" },
    line: { color: "00b871", pt: 1.5 },
  });
  slide.addText(stat, {
    x, y: y + 0.05, w, h: 0.65,
    fontSize: 28, bold: true, color: "00b871", fontFace: "Poppins",
    align: "center", valign: "middle",
  });
  slide.addText(label, {
    x, y: y + 0.6, w, h: 0.4,
    fontSize: 9.5, color: "0a4b4d", fontFace: "Poppins",
    align: "center", valign: "top",
  });
}
```

**Important**: cards use `fill: "f0faf5"` (light green) with `line: "00b871"` (green border).
NOT a grey fill, NOT a drop shadow without border.

## KPI bar (full-width stats row)

A horizontal row of 3-4 KPI stats, usually at the bottom of a slide or as a standalone element.
Stats use the `f0faf5` background strip with green borders.

```javascript
function addKpiBar(slide, kpis, { y = 5.8 } = {}) {
  const count = kpis.length;
  const cardW = 8.5 / count - 0.15;
  kpis.forEach((kpi, i) => {
    const x = 1.05 + i * (cardW + 0.15);
    addKpiCard(slide, { x, y, w: cardW, h: 0.9, stat: kpi.stat, label: kpi.label });
  });
}
```

## Call-out banner

Full-width colored bar with a big stat + message. Used for impact statements.

```javascript
function addCalloutBanner(slide, { y, stat, message, submessage }) {
  // Green banner background
  slide.addShape("roundedRectangle", {
    x: 1.05, y, w: 8.5, h: 1.0,
    rectRadius: 0.12,
    fill: { color: "00b871" }, line: { width: 0 },
  });
  // Stat left
  slide.addText(stat, {
    x: 1.2, y, w: 1.5, h: 1.0,
    fontSize: 28, bold: true, color: "FFFFFF", fontFace: "Poppins",
    align: "center", valign: "middle",
  });
  // Message right
  slide.addText(message, {
    x: 2.8, y: y + 0.15, w: 6.5, h: 0.4,
    fontSize: 12, bold: true, color: "0a4b4d", fontFace: "Poppins",
  });
  if (submessage) {
    slide.addText(submessage, {
      x: 2.8, y: y + 0.55, w: 6.5, h: 0.3,
      fontSize: 9, color: "0a4b4d", fontFace: "Poppins", italic: true,
    });
  }
}
```

## Timeline (horizontal steps)

A 3-4 step horizontal timeline with badges, dates, and descriptions.

```javascript
function addTimeline(slide, steps, { y = 2.5 } = {}) {
  const count = steps.length;
  const stepW = 8.5 / count;

  // Connecting line
  slide.addShape("rectangle", {
    x: 1.05, y: y + 0.2, w: 8.5, h: 0.03,
    fill: { color: "00b871" }, line: { width: 0 },
  });

  steps.forEach((step, i) => {
    const x = 1.05 + i * stepW;

    // Badge circle
    slide.addShape("ellipse", {
      x: x + stepW / 2 - 0.15, y: y + 0.05, w: 0.35, h: 0.35,
      fill: { color: "00b871" }, line: { width: 0 },
    });
    slide.addText(String(i + 1).padStart(2, "0"), {
      x: x + stepW / 2 - 0.15, y: y + 0.05, w: 0.35, h: 0.35,
      fontSize: 10, bold: true, color: "FFFFFF", fontFace: "Poppins",
      align: "center", valign: "middle",
    });

    // Date range (if provided)
    if (step.date) {
      slide.addText(step.date, {
        x, y: y - 0.35, w: stepW, h: 0.3,
        fontSize: 8, color: "00b871", fontFace: "Poppins",
        align: "center", italic: true,
      });
    }

    // Title
    slide.addText(step.title, {
      x, y: y + 0.5, w: stepW - 0.1, h: 0.35,
      fontSize: 11, bold: true, color: "0a4b4d", fontFace: "Poppins",
      align: "center",
    });

    // Description
    if (step.desc) {
      slide.addText(step.desc, {
        x, y: y + 0.85, w: stepW - 0.2, h: 0.8,
        fontSize: 9, color: "1a1a1a", fontFace: "Poppins",
        align: "center", wrap: true,
      });
    }
  });
}
```

## Status badges (pills)

Small colored labels like "CONTRACTUEL", "VÉRIFIABLE", "OPÉRATIONNEL EN 2 MINUTES".

```javascript
function addBadge(slide, { x, y, text, bgColor = "f0faf5", textColor = "00b871" }) {
  const w = Math.max(text.length * 0.085, 1.0);
  slide.addShape("roundedRectangle", {
    x, y, w, h: 0.28,
    rectRadius: 0.14,
    fill: { color: bgColor },
    line: { color: textColor, pt: 1 },
  });
  slide.addText(text, {
    x, y, w, h: 0.28,
    fontSize: 8, bold: true, color: textColor, fontFace: "Poppins",
    align: "center", valign: "middle", letterSpacing: 1,
  });
}
```

## Footer bar

Every slide (except title/conclusion) should have a footer with the Pysae logo and contact info.

```javascript
function addFooter(slide) {
  // Thin green line separator
  slide.addShape("rectangle", {
    x: 1.05, y: 6.85, w: 8.5, h: 0.01,
    fill: { color: "e0e0e0" }, line: { width: 0 },
  });
  // Logo
  // slide.addImage({ path: "logo-pysae-dark.png", x: 1.05, y: 6.95, w: 0.8, h: 0.27 });
  slide.addText("Pysae", {
    x: 1.05, y: 6.95, w: 1.0, h: 0.3,
    fontSize: 9, bold: true, color: "0a4b4d", fontFace: "Poppins",
  });
}
```

## Split-screen layout (photo + content)

For product showcase slides: photo/screenshot on the right half, content on the left.

Used in the reference decks for: driver app, operator interface, passenger app.

```
Layout:
┌──────────────────────┬──────────────────────┐
│  Section label       │                      │
│  Title (bicolor)     │   Photo/screenshot   │
│  Subtitle            │   (full height,      │
│                      │    cover, rounded)    │
│  Feature block 1     │                      │
│  Feature block 2     │                      │
│  Feature block 3     │                      │
│  Feature block 4     │                      │
│                      │                      │
│  Footer              │                      │
└──────────────────────┴──────────────────────┘

Left content: x: 1.05, w: 4.5
Photo: x: 5.8, w: 4.2, h: 7.5 (full slide height, position y: 0)
```

## Citations / quotes

```javascript
function addQuote(slide, { x, y, w, quote, author }) {
  // Light background
  slide.addShape("roundedRectangle", {
    x, y, w, h: 1.2,
    rectRadius: 0.08,
    fill: { color: "f0faf5" }, line: { width: 0 },
  });
  // Green left bar
  slide.addShape("rectangle", {
    x, y: y + 0.1, w: 0.05, h: 1.0,
    fill: { color: "00b871" }, line: { width: 0 },
  });
  // Quote text
  slide.addText(quote, {
    x: x + 0.2, y: y + 0.1, w: w - 0.4, h: 0.7,
    fontSize: 10.5, italic: true, color: "0a4b4d", fontFace: "Poppins", wrap: true,
  });
  // Author
  slide.addText(`— ${author}`, {
    x: x + 0.2, y: y + 0.85, w: w - 0.4, h: 0.3,
    fontSize: 10, bold: true, color: "00b871", fontFace: "Poppins",
  });
}
```

## Client reference cards

For "partners who look like you" slides: logo + name + description + highlight badge.

```
Layout (3 columns):
┌─────────────┬─────────────┬─────────────┐
│  [Logo]     │  [Logo]     │  [Logo]     │
│  Name       │  Name       │  Name       │
│  Region     │  Region     │  Region     │
│  Desc       │  Desc       │  Desc       │
│  [Badge]    │  [Badge]    │  [Badge]    │
└─────────────┴─────────────┴─────────────┘
  + KPI bar at bottom
```
