/** Deck engine types. Shape matches the 2 Nov 2026 deck package. */ export const DECK_IDS = [ "decisionApproaches", "membership", "conflictManagement", "communication", ] as const; export type DeckId = (typeof DECK_IDS)[number]; export const SIZE_BANDS = [ "oneMember", "twoToFive", "sixToTwelve", "thirteenToOneHundred", "oneHundredToOneHundredK", ] as const; export type SizeBand = (typeof SIZE_BANDS)[number]; export const KINDS = [ "workersCoop", "mutualAid", "nonprofit", "forProfit", "openSource", "dao", ] as const; export type Kind = (typeof KINDS)[number]; export const SCALES = ["local", "regional", "national", "global"] as const; export type Scale = (typeof SCALES)[number]; export const STAGES = [ "earlyStage", "growthStage", "established", "enterprise", ] as const; export type Stage = (typeof STAGES)[number]; export const TRAIT_KEYS = [ "network", "nonvoters", "employer", "sponsor", "records", "risky", ] as const; export type TraitKey = (typeof TRAIT_KEYS)[number]; export const DISPLAY_TIERS = ["frame", "safety", "fitted", "floor", "none"] as const; export type DisplayTier = (typeof DISPLAY_TIERS)[number]; export type RankTier = Exclude | "answers"; export interface CardFacets { size: Record; orgType: Record; scale: Record; maturity: Record; } export type FacetFile = Record; export interface CardTraits { beside?: TraitKey[]; besideJob?: string; fits?: TraitKey[]; opens?: TraitKey[]; } export interface CardEngineEntry { job: string; priority: number; everyRuleHas?: boolean; traits?: CardTraits; } export interface JobDefinition { id: string; label: string; displayTier: DisplayTier; rank?: number; why: string; } export interface DeckEngine { jobs: JobDefinition[]; addedOrder: string[]; cards: Record; } export interface JobsFile { about: string; version: string; displayLimit: number; maxAddedInSeven: number; tierOrder: RankTier[]; traitKeys: TraitKey[]; sizeAnswers: Record; decks: Record; } export interface GroupAnswers { size?: string | null; mainKind?: Kind | null; otherKinds?: Kind[]; scale?: Scale[]; stage?: Stage | null; traits?: Partial>; } export type MatchedFacet = "size" | "kind" | "scale" | "stage"; export type RecommendationReason = | { kind: "fit"; matched: MatchedFacet[]; answer?: TraitKey } | { kind: "opened"; matched: MatchedFacet[]; answer: TraitKey } | { kind: "added"; answer: TraitKey }; export interface RecommendedCard { id: string; job: string; showsWith: string; tier: RankTier; tag: "recommended" | "everyRuleHas"; reason: RecommendationReason; alternative?: string; score?: number; decidedBy?: "only" | "score" | "otherKinds" | "rowOrder"; } export interface DeckRecommendation { deck: DeckId; fallback: boolean; recommended: RecommendedCard[]; shown: RecommendedCard[]; waiting: RecommendedCard[]; seeAll: string[]; }