# QualificationContent

> The body of a BANT qualification snapshot: a score, a verdict, a confirmed count, and one tile per criterion with its status, rationale and first piece of transcript evidence.

## Facts

- **Product**: Max
- **Family**: Analytics
- **Global**: `window.DigitalCrew.QualificationContent`
- **Source**: `max-agent: src/features/meeting-hub/ui/qualification-card.tsx`
- **Import in the app**: `import { QualificationContent } from "@/features/meeting-hub/ui/qualification-card";`
- **Live preview**: /design/components/qualification-content/preview.html
- **Page**: /design/components/qualification-content

## Guidelines

**Use it for** a meeting's qualification panel. In Max, `QualificationCard` wraps it in a [`Card`](/design/components/card.md) whose title has a `Target` icon and a secondary `BANT` badge. That wrapper is not exported, so the preview builds the same header from [`Card`](/design/components/card.md).

**What you provide**:
- `qualification: ConversationQualificationDto`, shaped `{ framework: "BANT", score, confirmedCount, criteria }`.
- Each criterion is `{ key: "budget" | "authority" | "need" | "timing", label, status: "confirmed" | "partial" | "missing" | "negative", rationale, evidence: [{ sequenceNumber, excerpt }] }`.
- `compact` (default `false`) stacks the tiles in one column instead of `sm:grid-cols-2`.

The server scores confirmed as 100, partial as 50 and anything else as 0, then averages the four.

**Verdict**: any negative criterion shows "Blocker to resolve". Otherwise ≥ 75 shows "Well qualified", ≥ 50 "Partially qualified", and anything lower "Needs discovery".

**Anatomy**:
- The score is `text-2xl` semibold `tabular-nums`. Tiles are `rounded-lg border p-3`.
- Status badges are `h-5 px-1.5 text-[10px]`: Confirmed is emerald, Discussed (partial) is blue, Missing is muted, and Blocker (negative) is amber.
- Icons: `CircleCheck` in emerald-500, `CircleAlert` in amber-500, and `CircleDashed` in muted for the rest.
- Evidence is a blockquote with `border-l-2 border-primary/35 pl-2 text-xs`.

**Don't** write these readings to the CRM. They come from transcript evidence only, as the card's footer says.

## API

```ts
export declare function QualificationContent({ qualification, compact, }: {
    qualification: ConversationQualificationDto;
    compact?: boolean;
}): JSX.Element;
export declare function QualificationCard({ qualification, }: {
    qualification: ConversationQualificationDto | null | undefined;
}): JSX.Element;
```

## Example

```html
<div id="root" class="p-6"></div>
<script>
(function () {
  var h = React.createElement, DC = window.DigitalCrew, I = DC.Icons;
  // ConversationQualificationDto. Score = confirmed 100, partial 50, else 0,
  // averaged over the four criteria (conversation-intelligence.core.ts).
  var QUALIFICATION = {
    framework: "BANT",
    score: 38,
    confirmedCount: 1,
    criteria: [
      { key: "budget", label: "Budget", status: "partial",
        rationale: "Budget was discussed but not confirmed by the buyer.",
        evidence: [{ sequenceNumber: 6, excerpt: "What would a pilot cost for the DACH segment?" }] },
      { key: "authority", label: "Authority", status: "missing",
        rationale: "No authority evidence was found in this transcript.", evidence: [] },
      { key: "need", label: "Need", status: "confirmed",
        rationale: "Need is explicitly confirmed by an external participant.",
        evidence: [{ sequenceNumber: 2, excerpt: "We doubled the SDR team last year and reply rates went the other way." }] },
      { key: "timing", label: "Timing", status: "negative",
        rationale: "Timing has a stated blocker from an external participant.",
        evidence: [{ sequenceNumber: 11, excerpt: "Nothing new gets rolled out before the January budget freeze lifts." }] }
    ]
  };
  function App() {
    return h(DC.Card, null,
      h(DC.CardHeader, { className: "pb-2" },
        h(DC.CardTitle, { className: "flex items-center gap-2 text-base" },
          h(I.Target, { className: "h-4 w-4 text-primary" }), "Qualification",
          h(DC.Badge, { variant: "secondary", className: "h-5 text-[10px]" }, QUALIFICATION.framework))),
      h(DC.CardContent, null, h(DC.QualificationContent, { qualification: QUALIFICATION })));
  }
  ReactDOM.createRoot(document.getElementById("root")).render(h(DC.TooltipProvider, { delayDuration: 80 }, h(App)));
})();
</script>
```

## More in Analytics

- [ActivityChart](/design/components/activity-chart.md): A day-bucketed Recharts chart in Max's glass panel: each series is drawn as an area, a line or a bar, with a dot legend and a popover tooltip.
- [ChartContainer](/design/components/chart-container.md): The shell every Crew OS chart sits in: it wraps a Recharts 2 chart in a `ResponsiveContainer`, turns a config object into per-series colour variables and styles axes, grid, tooltip and legend with the theme tokens.
- [FunnelChart](/design/components/funnel-chart.md): A vertical column funnel with a summary panel.
- [InsightsCard](/design/components/insights-card.md): A meeting's numbers (sentiment, stat tiles, per-speaker talk share, an over-talk hint), all derived on the client from the transcript.
