SPB Git forge

spb/groupe-ka

Public

Groupe KA — site du holding + KA ID (compte unique & SSO des 7 plateformes). Next.js 16, SQLite, Google & Apple login.

81commits 1branches 0releases
89.2 MBsize
maindefault branch
22 days agolast push
TypeScript 70.4% HTML 18.4% JavaScript 4% Python 3.8% CSS 3.4%
53.5 KB · 1,008 lines html
Raw Blame History
1<!DOCTYPE html>2<!-- Auteur : Simon-Pierre Boucher — contact@spboucher.ai -->3<!-- Document « L'agrégation, expliquée » — 12 pages A4 paysage.4     Rendu PDF : chromium --headless --print-to-pdf (les figures sont générées en JS). -->5<html lang="fr">6<head>7<meta charset="UTF-8" />8<title>Groupe KA — L'agrégation, expliquée</title>9<link rel="preconnect" href="https://fonts.googleapis.com" />10<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />11<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;700&family=Inter:wght@400;600&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet" />12<style>13  :root {14    --paper: #f5f3ee;15    --surface: #ffffff;16    --ink: #141814;17    --ink-2: #4d5551;18    --ink-3: #8b928c;19    --green: #1c5c41;20    --green-deep: #123f2e;21    --lime: #d9f26b;22    --lime-soft: #f0f9d2;23    --display: "Space Grotesk", system-ui, sans-serif;24    --body: "Inter", system-ui, sans-serif;25    --mono: "JetBrains Mono", ui-monospace, monospace;26  }27  * { margin: 0; padding: 0; box-sizing: border-box; }28  @page { size: 297mm 210mm; margin: 0; }29  html, body { background: #1a1e1a; }30  body { font-family: var(--body); color: var(--ink); }3132  .page {33    width: 297mm;34    height: 210mm;35    background: var(--paper);36    position: relative;37    overflow: hidden;38    page-break-after: always;39    padding: 12mm 14mm 11mm;40    display: flex;41    flex-direction: column;42  }43  .page::after {44    content: "";45    position: absolute; inset: 0;46    pointer-events: none;47    opacity: 0.05;48    background-image: radial-gradient(var(--ink) 0.6px, transparent 0.6px);49    background-size: 5px 5px;50  }51  .page.dark { background: var(--ink); color: var(--paper); }52  .page.dark::after { background-image: radial-gradient(var(--lime) 0.6px, transparent 0.6px); opacity: 0.04; }5354  .mono { font-family: var(--mono); }55  .display { font-family: var(--display); }5657  /* ---------- En-tête / pied de page communs ---------- */58  .phead {59    display: flex;60    align-items: baseline;61    justify-content: space-between;62    border-bottom: 2px solid var(--ink);63    padding-bottom: 4mm;64  }65  .dark .phead { border-bottom-color: rgba(245,243,238,0.25); }66  .wordmark {67    font-family: var(--display);68    font-weight: 700;69    font-size: 17px;70    letter-spacing: -0.04em;71    display: inline-flex;72    align-items: baseline;73    gap: 5px;74  }75  .kabox {76    display: inline-block;77    background: var(--ink);78    color: var(--lime);79    border-radius: 5px;80    padding: 0 6px 2px;81    transform: rotate(-2deg);82  }83  .dark .kabox { background: var(--lime); color: var(--ink); }84  .phead .doc {85    font-family: var(--mono);86    font-weight: 700;87    font-size: 9px;88    letter-spacing: 0.16em;89    text-transform: uppercase;90    color: var(--ink-3);91  }92  .dark .phead .doc { color: rgba(245,243,238,0.55); }93  .pnum { font-family: var(--mono); font-weight: 700; font-size: 10px; color: var(--green); }94  .dark .pnum { color: var(--lime); }9596  .pfoot {97    margin-top: auto;98    border-top: 1.5px dashed rgba(20,24,20,0.3);99    padding-top: 3mm;100    display: flex;101    justify-content: space-between;102    font-family: var(--mono);103    font-size: 8.5px;104    letter-spacing: 0.1em;105    text-transform: uppercase;106    color: var(--ink-3);107  }108  .dark .pfoot { border-top-color: rgba(245,243,238,0.2); color: rgba(245,243,238,0.5); }109110  /* ---------- Typo de section ---------- */111  .kicker {112    font-family: var(--mono);113    font-weight: 700;114    font-size: 10px;115    letter-spacing: 0.18em;116    text-transform: uppercase;117    color: var(--green);118    display: inline-flex;119    align-items: center;120    gap: 8px;121    margin-top: 6mm;122  }123  .kicker::before { content: ""; width: 22px; height: 2px; background: var(--green); }124  .dark .kicker { color: var(--lime); }125  .dark .kicker::before { background: var(--lime); }126  h2 {127    font-family: var(--display);128    font-weight: 700;129    font-size: 34px;130    line-height: 1;131    letter-spacing: -0.03em;132    text-transform: uppercase;133    margin-top: 3.5mm;134  }135  .hl {136    display: inline-block;137    background: var(--lime);138    color: var(--ink);139    border-radius: 6px;140    padding: 0 8px 2px;141    transform: rotate(-1deg);142  }143  .outline { color: transparent; -webkit-text-stroke: 2px var(--ink); }144  .dark .outline { -webkit-text-stroke: 2px var(--paper); }145  .lede { margin-top: 3.5mm; font-size: 12px; line-height: 1.55; color: var(--ink-2); max-width: 150mm; }146  .dark .lede { color: rgba(245,243,238,0.75); }147148  /* ---------- Cartes & pilules ---------- */149  .card {150    background: var(--surface);151    border: 1.5px solid var(--ink);152    border-radius: 9px;153    box-shadow: 6px 6px 0 rgba(20,24,20,0.12);154  }155  .chip {156    display: inline-flex;157    align-items: center;158    gap: 6px;159    padding: 5px 11px;160    background: var(--surface);161    border: 1.5px solid var(--ink);162    border-radius: 999px;163    font-family: var(--mono);164    font-size: 9.5px;165    font-weight: 700;166    box-shadow: 3px 3px 0 rgba(20,24,20,0.12);167    white-space: nowrap;168  }169  .caption {170    border-top: 1.5px solid var(--ink);171    background: #faf9f5;172    padding: 3mm 5mm;173    font-size: 10.5px;174    color: var(--ink-2);175    border-radius: 0 0 8px 8px;176  }177  .caption b { font-family: var(--mono); color: var(--green); }178179  /* ---------- Page 1 : couverture ---------- */180  .cover h1 {181    font-family: var(--display);182    font-weight: 700;183    font-size: 96px;184    line-height: 0.95;185    letter-spacing: -0.04em;186    text-transform: uppercase;187    margin-top: 8mm;188  }189  .cover .sub { margin-top: 7mm; font-size: 14.5px; color: var(--ink-2); max-width: 165mm; line-height: 1.6; }190  .cover-chips { display: flex; gap: 8px; margin-top: 8mm; flex-wrap: wrap; }191  .cover-marks { display: flex; gap: 6px; margin-top: auto; flex-wrap: wrap; padding-bottom: 2mm; }192  .markpill {193    font-family: var(--display); font-weight: 700; font-size: 12.5px;194    border: 1.5px solid var(--ink); border-radius: 999px; padding: 4px 12px 5px;195    background: var(--surface); box-shadow: 3px 3px 0 rgba(20,24,20,0.15);196  }197  .markpill i { font-style: normal; border-radius: 4px; padding: 0 4px 1px; margin-left: 2px; display: inline-block; transform: rotate(-2deg); }198199  /* ---------- Page 2 : définition ---------- */200  .def-grid { display: grid; grid-template-columns: 1.15fr 1fr; gap: 8mm; margin-top: 7mm; align-items: stretch; }201  .defcard { padding: 8mm 9mm; }202  .defcard .word { font-family: var(--display); font-weight: 700; font-size: 52px; letter-spacing: -0.03em; }203  .defcard .pos { font-family: var(--mono); font-size: 12px; color: var(--ink-3); margin-left: 8px; }204  .defcard ol { margin-top: 6mm; list-style: none; }205  .defcard li { display: flex; gap: 10px; font-size: 12.5px; line-height: 1.55; color: var(--ink-2); margin-top: 4mm; }206  .defcard li b.n { font-family: var(--mono); color: var(--green); }207  .defcard .quote { margin-top: 6mm; border-top: 1.5px dashed rgba(20,24,20,0.3); padding-top: 5mm; font-style: italic; font-size: 12.5px; color: var(--ink-2); }208  .eqcard { background: var(--ink); color: var(--paper); border-radius: 9px; border: 1.5px solid var(--ink); padding: 8mm 9mm; box-shadow: 6px 6px 0 rgba(20,24,20,0.25); display: flex; flex-direction: column; }209  .eqcard .k { font-family: var(--mono); font-weight: 700; font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--lime); }210  .eqcard .eq { font-family: var(--display); font-weight: 700; font-size: 33px; line-height: 1.12; letter-spacing: -0.03em; text-transform: uppercase; margin-top: 5mm; }211  .eqcard .eq .lime { color: var(--lime); }212  .eqcard p { margin-top: 5mm; font-size: 11.5px; line-height: 1.6; color: rgba(245,243,238,0.75); }213214  /* ---------- Figures pleine page ---------- */215  .figwrap { margin-top: 5mm; border: 1.5px solid var(--ink); border-radius: 9px; background: var(--surface); box-shadow: 6px 6px 0 rgba(20,24,20,0.12); overflow: hidden; flex: 1; display: flex; flex-direction: column; }216  .figwrap svg { display: block; width: 100%; flex: 1; }217  .figbody { flex: 1; display: flex; align-items: center; justify-content: center; padding: 4mm 6mm; }218219  /* ---------- Pages barres & matrice ---------- */220  .bars { padding: 5.5mm 9mm 4mm; }221  .barrow { margin-top: 3.8mm; }222  .barrow:first-child { margin-top: 0; }223  .barhead { display: flex; justify-content: space-between; align-items: baseline; }224  .barhead .nm { font-family: var(--display); font-weight: 700; font-size: 13px; display: inline-flex; align-items: center; gap: 7px; }225  .brand { width: 13px; height: 13px; border-radius: 3.5px; background: var(--ink); display: inline-flex; align-items: center; justify-content: center; }226  .brand i { width: 8px; height: 8px; border-radius: 2px; display: block; }227  .barhead .u { font-family: var(--mono); font-size: 9px; color: var(--ink-3); font-weight: 400; margin-left: 4px; }228  .barhead .v { font-family: var(--mono); font-weight: 700; font-size: 11.5px; }229  .bartrack { margin-top: 1.5mm; height: 4.4mm; background: rgba(20,24,20,0.06); border-radius: 0 3px 3px 0; }230  .barfill { height: 100%; background: var(--green); border-radius: 0 3px 3px 0; }231232  .dots-block { margin-top: 4.2mm; }233  .dots-block:first-child { margin-top: 0; }234  .dots { display: flex; flex-wrap: wrap; gap: 2.1px; margin-top: 1.6mm; max-width: 235mm; }235  .dots i { width: 6.5px; height: 6.5px; border-radius: 2px; background: var(--green); display: block; }236237  /* ---------- Page moteurs d'évaluation ---------- */238  .eval-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8mm; margin-top: 6mm; flex: 1; }239  .evalcard { padding: 8mm 9mm; display: flex; flex-direction: column; }240  .evalcard .k { font-family: var(--mono); font-weight: 700; font-size: 9.5px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-3); display: flex; align-items: center; gap: 7px; }241  .evalcard .big { font-family: var(--display); font-weight: 700; font-size: 46px; letter-spacing: -0.03em; margin-top: 4mm; }242  .evalcard .lbl { font-family: var(--display); font-weight: 700; font-size: 13px; text-transform: uppercase; color: var(--green); margin-top: 1mm; }243  .evalcard p { font-size: 11px; color: var(--ink-2); margin-top: 3mm; line-height: 1.55; }244  .gauge { margin-top: auto; padding-top: 6mm; }245  .gauge .glab { display: flex; justify-content: space-between; font-family: var(--mono); font-size: 8.5px; color: var(--ink-3); margin-bottom: 1.4mm; }246  .gtrack { position: relative; height: 7mm; border: 1.5px solid var(--ink); border-radius: 5px; background: var(--surface); overflow: hidden; }247  .gband { position: absolute; top: 0; bottom: 0; background: var(--lime); opacity: 0.85; }248  .gmid { position: absolute; top: -1mm; bottom: -1mm; width: 2.2px; background: var(--ink); }249250  /* ---------- Page socle : tableau ---------- */251  .tbl { margin-top: 6mm; border: 1.5px solid var(--ink); border-radius: 9px; overflow: hidden; background: var(--surface); box-shadow: 6px 6px 0 rgba(20,24,20,0.12); }252  table { width: 100%; border-collapse: collapse; font-size: 11px; }253  th { font-family: var(--mono); font-size: 8.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; text-align: left; color: var(--ink-3); background: #faf9f5; padding: 2.6mm 4mm; border-bottom: 1.5px solid var(--ink); }254  td { padding: 2.45mm 4mm; border-bottom: 1px solid rgba(20,24,20,0.14); vertical-align: middle; }255  tr:last-child td { border-bottom: none; }256  td.nm { font-family: var(--display); font-weight: 700; white-space: nowrap; }257  td.url { font-family: var(--mono); font-size: 9.5px; white-space: nowrap; color: var(--green); }258  td .brand { vertical-align: -2px; margin-right: 6px; }259260  /* ---------- Page manifeste (fin, sombre) ---------- */261  .mani-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7mm; margin-top: 8mm; }262  .mani { border: 1.5px solid rgba(245,243,238,0.3); border-radius: 9px; padding: 7mm; }263  .mani .n { font-family: var(--mono); font-weight: 700; font-size: 11px; color: var(--lime); }264  .mani h3 { font-family: var(--display); font-weight: 700; font-size: 16.5px; text-transform: uppercase; margin-top: 3mm; }265  .mani p { font-size: 11px; line-height: 1.6; color: rgba(245,243,238,0.75); margin-top: 3mm; }266  .contact { margin-top: 10mm; display: flex; gap: 6mm; align-items: baseline; flex-wrap: wrap; }267  .contact .mail { font-family: var(--mono); font-weight: 700; font-size: 13px; color: var(--lime); }268  .contact .role { font-family: var(--mono); font-size: 9px; color: rgba(245,243,238,0.5); }269270  /* ---------- Légendes SVG en HTML ---------- */271  svg text { font-family: var(--mono); }272  svg .t-display { font-family: var(--display); }273  svg .t-body { font-family: var(--body); }274</style>275</head>276<body>277278<!-- ============================ PAGE 1 — COUVERTURE ============================ -->279<section class="page cover">280  <header class="phead">281    <span class="wordmark">Groupe <span class="kabox">KA</span></span>282    <span class="doc">Document de référence · 2026</span>283    <span class="pnum">01 / 12</span>284  </header>285  <p class="kicker">Holding d'agrégateurs automatisés · Québec</p>286  <h1>L'agrégation,<br /><span class="outline">expliquée</span> <span class="hl">·Ka</span></h1>287  <p class="sub">288    Comment mille sites deviennent un seul endroit : les connecteurs, le pipeline, le cycle,289    les éclaireurs, le moteur de recherche et les dix plateformes du Groupe KA — chaque290    mécanisme dessiné, chaque chiffre compté. Zéro saisie manuelle, zéro boîte noire.291  </p>292  <div class="cover-chips">293    <span class="chip">10 agrégateurs en ligne</span>294    <span class="chip">1 moteur de recherche québécois</span>295    <span class="chip">450+ connecteurs sources</span>296    <span class="chip">22 M+ d'observations immobilières</span>297    <span class="chip">100 % données à la source</span>298  </div>299  <div class="cover-marks" id="cover-marks"></div>300  <footer class="pfoot"><span>groupe-ka.com</span><span>© 2026 Groupe KA — Simon-Pierre Boucher</span></footer>301</section>302303<!-- ============================ PAGE 2 — LE NOM ============================ -->304<section class="page">305  <header class="phead">306    <span class="wordmark">Groupe <span class="kabox">KA</span></span>307    <span class="doc">L'agrégation, expliquée</span>308    <span class="pnum">02 / 12</span>309  </header>310  <p class="kicker">Chapitre 01 · Le nom</p>311  <h2>·Ka, le suffixe qui veut dire <span class="hl">agréger</span></h2>312  <div class="def-grid">313    <div class="card defcard">314      <span class="word">·Ka</span><span class="pos">/ka/ suffixe</span>315      <ol>316        <li><b class="n">1.</b><span><b>Agréger</b> — rassembler en un seul endroit ce qui était éparpillé317          sur des centaines de sites : annonces, prix, menus, événements, profils.</span></li>318        <li><b class="n">2.</b><span>Marque de fabrique du groupe : Lou·Ka loge, Immo·Ka vend, Auto·Ka roule,319          Fabri·Ka fabrique, Food·Ka nourrit, Resto·Ka régale, Sorti·Ka divertit, Créa·Ka rassemble.</span></li>320        <li><b class="n">3.</b><span>Par extension : toute machine qui lit les sources en continu, normalise la321          donnée et publie sans jamais rien inventer.</span></li>322      </ol>323      <p class="quote">« Tout ce qui finit en <b class="display">·Ka</b> agrège. »</p>324    </div>325    <div class="eqcard">326      <span class="k">L'équation ·Ka</span>327      <p class="eq">1 000+ sites lus<br /><span class="lime">→ 450+ connecteurs</span><br />→ 10 plateformes</p>328      <p>La donnée entre éparpillée, elle ressort rangée. Entre les deux, aucune main humaine —329      c'est le suffixe ·Ka qui travaille : lecture à la source, normalisation, dédoublonnage,330      géocodage, publication traçable. Les pages qui suivent montrent la machine, à découvert.</p>331    </div>332  </div>333  <footer class="pfoot"><span>groupe-ka.com</span><span>Chapitre 01 · Le nom</span></footer>334</section>335336<!-- ============================ PAGE 3 — LE SABLIER ============================ -->337<section class="page">338  <header class="phead">339    <span class="wordmark">Groupe <span class="kabox">KA</span></span>340    <span class="doc">L'agrégation, expliquée</span>341    <span class="pnum">03 / 12</span>342  </header>343  <p class="kicker">Chapitre 02 · Le geste fondateur</p>344  <h2>Plein de sites. <span class="hl">Une seule flèche.</span></h2>345  <div class="figwrap">346    <div class="figbody" id="fig-sablier"></div>347    <div class="caption"><b>LE SABLIER ·KA —</b> des centaines de sites éparpillés, lus à la source par des348    connecteurs dédiés ; tout converge vers KA, qui normalise, dédoublonne et redistribue vers dix349    plateformes. Une flèche entre, dix flèches sortent : c'est ça, agréger.</div>350  </div>351  <footer class="pfoot"><span>groupe-ka.com</span><span>Chapitre 02 · Le sablier</span></footer>352</section>353354<!-- ============================ PAGE 4 — LE PIPELINE ============================ -->355<section class="page">356  <header class="phead">357    <span class="wordmark">Groupe <span class="kabox">KA</span></span>358    <span class="doc">L'agrégation, expliquée</span>359    <span class="pnum">04 / 12</span>360  </header>361  <p class="kicker">Chapitre 03 · De la page web à la donnée propre</p>362  <h2>Le pipeline, <span class="hl">station par station</span></h2>363  <div class="figwrap">364    <div class="figbody" id="fig-pipeline"></div>365    <div class="caption"><b>LE PIPELINE —</b> cinq stations, aucune main humaine. La boucle verte est le secret :366    tout le pipeline se rejoue en continu, donc une annonce retirée à la source disparaît d'elle-même.</div>367  </div>368  <footer class="pfoot"><span>groupe-ka.com</span><span>Chapitre 03 · Le pipeline</span></footer>369</section>370371<!-- ============================ PAGE 5 — LE CYCLE ============================ -->372<section class="page">373  <header class="phead">374    <span class="wordmark">Groupe <span class="kabox">KA</span></span>375    <span class="doc">L'agrégation, expliquée</span>376    <span class="pnum">05 / 12</span>377  </header>378  <p class="kicker">Chapitre 04 · La boucle jour et nuit</p>379  <h2>Pas un instantané, <span class="hl">un battement</span></h2>380  <div class="figwrap">381    <div class="figbody" id="fig-cycle"></div>382    <div class="caption"><b>LE CYCLE ·KA —</b> quatre gestes, en boucle, sans intervention humaine : lire les383    sources, comparer à hier, mettre à jour, publier et tracer. C'est la définition maison de l'agrégation.</div>384  </div>385  <footer class="pfoot"><span>groupe-ka.com</span><span>Chapitre 04 · Le cycle</span></footer>386</section>387388<!-- ============================ PAGE 6 — LES ÉCLAIREURS ============================ -->389<section class="page">390  <header class="phead">391    <span class="wordmark">Groupe <span class="kabox">KA</span></span>392    <span class="doc">L'agrégation, expliquée</span>393    <span class="pnum">06 / 12</span>394  </header>395  <p class="kicker">Chapitre 05 · Avant d'agréger, découvrir</p>396  <h2>Les éclaireurs : <span class="hl">Ka2 · Ka4 · Ka6</span></h2>397  <div class="figwrap">398    <div class="figbody" id="fig-bots"></div>399    <div class="caption"><b>LA DÉCOUVERTE —</b> les connecteurs lisent des sources connues ; les bots IA les400    trouvent. Ka2, Ka4 et Ka6 cartographient le web québécois entité par entité (robots.txt respecté,401    données publiques seulement) et alimentent tout l'écosystème en nouvelles sources.</div>402  </div>403  <footer class="pfoot"><span>groupe-ka.com</span><span>Chapitre 05 · Les éclaireurs</span></footer>404</section>405406<!-- ============================ PAGE 7 — TROUVE·KA ============================ -->407<section class="page">408  <header class="phead">409    <span class="wordmark">Groupe <span class="kabox">KA</span></span>410    <span class="doc">L'agrégation, expliquée</span>411    <span class="pnum">07 / 12</span>412  </header>413  <p class="kicker">Chapitre 06 · Le produit phare</p>414  <h2>Trouve·Ka <span class="hl">cherche le Québec</span></h2>415  <div class="figwrap">416    <div class="figbody" id="fig-trouveka"></div>417    <div class="caption"><b>LE MOTEUR —</b> les grands moteurs cherchent le monde ; Trouve·Ka ne contient que418    le web d'ici. Un commerce de Rimouski ou un blogue de Limoilou, noyés dans un index mondial, sont en419    première page dans un index 100 % Québec. C'est l'agrégation poussée à sa conclusion logique.</div>420  </div>421  <footer class="pfoot"><span>groupe-ka.com</span><span>Chapitre 06 · Trouve·Ka</span></footer>422</section>423424<!-- ============================ PAGE 8 — L'INVENTAIRE ============================ -->425<section class="page">426  <header class="phead">427    <span class="wordmark">Groupe <span class="kabox">KA</span></span>428    <span class="doc">L'agrégation, expliquée</span>429    <span class="pnum">08 / 12</span>430  </header>431  <p class="kicker">Chapitre 07 · La preuve par les nombres</p>432  <h2>L'inventaire <span class="hl">vivant</span></h2>433  <div class="figwrap" style="flex:1">434    <div class="bars" id="fig-bars" style="flex:1"></div>435    <div class="caption"><b>L'INVENTAIRE —</b> chaque barre est vivante : elle grossit quand les connecteurs436    trouvent du neuf, elle maigrit quand une annonce disparaît à la source. Compté aujourd'hui, pas promis.</div>437  </div>438  <footer class="pfoot"><span>groupe-ka.com</span><span>Chapitre 07 · L'inventaire</span></footer>439</section>440441<!-- ============================ PAGE 9 — LA FLOTTE ============================ -->442<section class="page">443  <header class="phead">444    <span class="wordmark">Groupe <span class="kabox">KA</span></span>445    <span class="doc">L'agrégation, expliquée</span>446    <span class="pnum">09 / 12</span>447  </header>448  <p class="kicker">Chapitre 08 · Un point = un connecteur</p>449  <h2>340 connecteurs, <span class="hl">dessinés un par un</span></h2>450  <div class="figwrap" style="flex:1">451    <div class="bars" id="fig-dots" style="flex:1"></div>452    <div class="caption"><b>LA FLOTTE —</b> chaque point est un petit programme qui connaît un site par cœur et453    le relit sans arrêt. S'y ajoutent les flux des 1 204 boutiques de Fabri·Ka, les données publiques de454    Vrai-Prix et ValoPlex, et l'annuaire multi-plateformes de Créa·Ka.</div>455  </div>456  <footer class="pfoot"><span>groupe-ka.com</span><span>Chapitre 08 · La flotte</span></footer>457</section>458459<!-- ============================ PAGE 10 — LES MOTEURS D'ÉVALUATION ============================ -->460<section class="page">461  <header class="phead">462    <span class="wordmark">Groupe <span class="kabox">KA</span></span>463    <span class="doc">L'agrégation, expliquée</span>464    <span class="pnum">10 / 12</span>465  </header>466  <p class="kicker">Chapitre 09 · Agréger pour évaluer</p>467  <h2>Deux moteurs, <span class="hl">tout le Québec</span></h2>468  <div class="eval-grid">469    <div class="card evalcard">470      <span class="k"><span class="brand"><i style="background:#ff5148"></i></span>Vrai-Prix · résidentiel</span>471      <span class="big">3 747 008</span>472      <span class="lbl">propriétés couvertes</span>473      <p>Toutes les unités du rôle foncier du Québec, estimées par un moteur hybride — modèle hédonique +474      comparables réels ajustés (745 119 ventes publiées 2021-2026, MdAPE 11 %). Chaque ajustement est475      affiché en dollars.</p>476      <div class="gauge">477        <div class="glab"><span>P10</span><span>fourchette honnête — jamais un faux prix unique</span><span>P90</span></div>478        <div class="gtrack"><div class="gband" style="left:18%;width:64%"></div><div class="gmid" style="left:50%"></div></div>479      </div>480    </div>481    <div class="card evalcard">482      <span class="k"><span class="brand"><i style="background:#ff9f45"></i></span>ValoPlex · immeubles à revenus</span>483      <span class="big">393 867</span>484      <span class="lbl">plex évalués · 1 733 744 portes</span>485      <p>Le moteur spécialisé des plex, entraîné exclusivement sur ~91 060 ventes réelles d'immeubles à486      revenus. L'unité d'analyse : la porte. Fourchette calibrée — 8 fois sur 10, le vrai prix tombe dedans.</p>487      <div class="gauge">488        <div class="glab"><span>P10</span><span>valeur totale et valeur par porte, calcul montré en entier</span><span>P90</span></div>489        <div class="gtrack"><div class="gband" style="left:22%;width:56%"></div><div class="gmid" style="left:50%"></div></div>490      </div>491    </div>492  </div>493  <footer class="pfoot"><span>groupe-ka.com</span><span>Chapitre 09 · Les moteurs d'évaluation</span></footer>494</section>495496<!-- ============================ PAGE 11 — LE SOCLE ============================ -->497<section class="page">498  <header class="phead">499    <span class="wordmark">Groupe <span class="kabox">KA</span></span>500    <span class="doc">L'agrégation, expliquée</span>501    <span class="pnum">11 / 12</span>502  </header>503  <p class="kicker">Chapitre 10 · Une seule fondation</p>504  <h2>Le socle : <span class="hl">onze plateformes</span></h2>505  <div class="tbl">506    <table id="socle-table">507      <thead><tr><th>Plateforme</th><th>Marché</th><th>Moteur</th><th>Adresse</th></tr></thead>508      <tbody></tbody>509    </table>510  </div>511  <footer class="pfoot"><span>groupe-ka.com</span><span>Chapitre 10 · Le socle</span></footer>512</section>513514<!-- ============================ PAGE 12 — MANIFESTE ============================ -->515<section class="page dark">516  <header class="phead">517    <span class="wordmark">Groupe <span class="kabox">KA</span></span>518    <span class="doc">L'agrégation, expliquée</span>519    <span class="pnum">12 / 12</span>520  </header>521  <p class="kicker">Notre manifeste</p>522  <h2>Trois principes, <span class="hl">aucune exception</span></h2>523  <div class="mani-grid">524    <div class="mani"><span class="n">01</span><h3>Zéro boîte noire</h3>525      <p>Un score magique n'est pas une réponse. Chaque estimation montre ses comparables, ses ajustements526      en dollars et sa fourchette d'incertitude. Si le calcul ne peut pas être montré, il ne sort pas.</p></div>527    <div class="mani"><span class="n">02</span><h3>Données réelles</h3>528      <p>Rôles d'évaluation foncière, ventes publiées, annonces vérifiées à la source. Aucun prix inventé :529      quand la donnée n'existe pas, on affiche qu'elle n'existe pas. Validé sur des ventes jamais vues.</p></div>530    <div class="mani"><span class="n">03</span><h3>Indépendance</h3>531      <p>Aucun courtier ni annonceur ne paie pour influencer un résultat. Pas de traceur publicitaire, pas de532      revente de données. Le français d'abord, le Québec comme terrain, la Loi 25 comme plancher.</p></div>533  </div>534  <div class="contact">535    <span><span class="mail">contact@groupe-ka.com</span><br /><span class="role">Projets, partenariats &amp; données</span></span>536    <span><span class="mail">info@groupe-ka.com</span><br /><span class="role">Médias &amp; questions générales</span></span>537    <span><span class="mail">admin@groupe-ka.com</span><br /><span class="role">Légal, vie privée &amp; Loi 25</span></span>538  </div>539  <footer class="pfoot"><span>groupe-ka.com</span><span>© 2026 Groupe KA — Simon-Pierre Boucher · contact@spboucher.ai</span></footer>540</section>541542<script>543"use strict";544/* Figures générées : mêmes données et même langage graphique que le site groupe-ka.com. */545546const INK = "#141814", GREEN = "#1c5c41", LIME = "#d9f26b", PAPER = "#f5f3ee",547      INK3 = "#8b928c", WHITE = "#ffffff";548549const PLATFORMS = [550  { name: "Lou·Ka",   accent: "#d9f26b", domain: "lou-ka.com" },551  { name: "Immo·Ka",  accent: "#e23744", domain: "immo-ka.com" },552  { name: "Vrai-Prix",accent: "#ff5148", domain: "vrai-prix.com" },553  { name: "ValoPlex", accent: "#ff9f45", domain: "valoplex.com" },554  { name: "Auto·Ka",  accent: "#ff5a2a", domain: "auto-ka.com" },555  { name: "Fabri·Ka", accent: "#C4532E", domain: "fabri-ka.com" },556  { name: "Food·Ka",  accent: "#d9f26b", domain: "food-ka.com" },557  { name: "Resto·Ka", accent: "#ffc53d", domain: "resto-ka.com" },558  { name: "Sorti·Ka", accent: "#ff6a00", domain: "sorti-ka.com" },559  { name: "Créa·Ka",  accent: "#7da2ff", domain: "crea-ka.com" },560];561const ACCENT = Object.fromEntries(PLATFORMS.map(p => [p.name, p.accent]));562563const SOURCES = [564  "Gestionnaires immobiliers", "Agences de courtage", "Rôles fonciers (MAMH)",565  "Registres de ventes", "Concessionnaires autos", "Marchands d'occasion",566  "Boutiques québécoises", "Sites de fabricants", "Bannières d'épicerie",567  "Circulaires & soldes", "Menus de restaurants", "Billetteries d'événements",568  "Profils de créateurs",569];570571/* ---------- Couverture : pilules des marques ---------- */572(function () {573  const wrap = document.getElementById("cover-marks");574  const marks = [575    ["Trouve","Ka","#b9cfee","#141814"], ["Lou","Ka","#d9f26b","#141814"],576    ["Immo","Ka","#e23744","#1a1214"], ["Vrai","Prix","#ff5148","#141814"],577    ["Valo","Plex","#ff9f45","#141814"], ["Auto","Ka","#ff5a2a","#17181c"],578    ["Fabri","Ka","#C4532E","#1E1B16"], ["Food","Ka","#d9f26b","#14231a"],579    ["Resto","Ka","#ffc53d","#1a1410"], ["Sorti","Ka","#ff6a00","#0b1330"],580    ["Créa","Ka","#7da2ff","#10162b"],581  ];582  for (const [l, r, accent, box] of marks) {583    const s = document.createElement("span");584    s.className = "markpill";585    s.innerHTML = `${l}<i style="background:${box};color:${accent}">${r}</i>`;586    wrap.appendChild(s);587  }588})();589590/* ---------- Utilitaire SVG ---------- */591function svgEl(tag, attrs, text) {592  const el = document.createElementNS("http://www.w3.org/2000/svg", tag);593  for (const k in attrs) el.setAttribute(k, attrs[k]);594  if (text != null) el.textContent = text;595  return el;596}597function makeSvg(w, h, label) {598  const svg = svgEl("svg", { viewBox: `0 0 ${w} ${h}`, role: "img", "aria-label": label });599  const marker = svgEl("marker", { id: "arr" + Math.floor(w), viewBox: "0 0 10 10", refX: 8, refY: 5, markerWidth: 6.5, markerHeight: 6.5, orient: "auto-start-reverse" });600  marker.appendChild(svgEl("path", { d: "M0,0 L10,5 L0,10 z", fill: INK }));601  const defs = svgEl("defs", {});602  defs.appendChild(marker);603  svg.appendChild(defs);604  svg.dataset.marker = "arr" + Math.floor(w);605  return svg;606}607function brandChip(svg, x, y, accent, s = 16) {608  svg.appendChild(svgEl("rect", { x, y, width: s, height: s, rx: 4, fill: INK }));609  svg.appendChild(svgEl("rect", { x: x + 3, y: y + 3, width: s - 6, height: s - 6, rx: 2.5, fill: accent }));610}611612/* ---------- 1. Le sablier (page 3) ---------- */613(function () {614  const W = 1150, H = 640;615  const svg = makeSvg(W, H, "Le sablier de l'agrégation KA");616  const M = svg.dataset.marker;617  const srcX = 218, kaL = 500, kaR = 648, kaY = H / 2, dstX = 900;618619  const srcYs = SOURCES.map((_, i) => 50 + i * (H - 100) / (SOURCES.length - 1));620  const dstYs = PLATFORMS.map((_, i) => 62 + i * (H - 124) / (PLATFORMS.length - 1));621622  srcYs.forEach((y, i) => svg.appendChild(svgEl("path", {623    d: `M ${srcX} ${y} C ${srcX + 140} ${y}, ${kaL - 120} ${kaY}, ${kaL - 8} ${kaY + (i - (SOURCES.length - 1) / 2) * 6}`,624    fill: "none", stroke: INK, "stroke-width": 1.5, "stroke-opacity": 0.5, "stroke-dasharray": "7 7",625  })));626  dstYs.forEach((y, i) => svg.appendChild(svgEl("path", {627    d: `M ${kaR + 4} ${kaY + (i - (PLATFORMS.length - 1) / 2) * 8} C ${kaR + 120} ${kaY}, ${dstX - 130} ${y}, ${dstX - 12} ${y}`,628    fill: "none", stroke: INK, "stroke-width": 2, "stroke-opacity": 0.75, "marker-end": `url(#${M})`, "stroke-dasharray": "7 7",629  })));630631  SOURCES.forEach((label, i) => {632    svg.appendChild(svgEl("rect", { x: 16, y: srcYs[i] - 15, width: srcX - 16, height: 30, rx: 6, fill: WHITE, stroke: INK, "stroke-width": 1.5 }));633    svg.appendChild(svgEl("circle", { cx: 33, cy: srcYs[i], r: 3.5, fill: GREEN }));634    svg.appendChild(svgEl("text", { x: 46, y: srcYs[i] + 3.5, "font-size": 11, "font-weight": 700, fill: INK }, label));635  });636  svg.appendChild(svgEl("text", { x: 16, y: 24, "font-size": 11.5, "font-weight": 700, "letter-spacing": 1.5, fill: INK3 }, "DES CENTAINES DE SITES"));637638  const gLbl = svgEl("g", { transform: `translate(${(srcX + kaL) / 2 - 6} ${kaY - 128}) rotate(-4)` });639  gLbl.appendChild(svgEl("rect", { x: -102, y: -25, width: 204, height: 50, rx: 13, fill: LIME, stroke: INK, "stroke-width": 1.5 }));640  gLbl.appendChild(svgEl("text", { x: 0, y: -4, "text-anchor": "middle", "font-size": 12, "font-weight": 700, "letter-spacing": 1, fill: INK }, "450+ CONNECTEURS"));641  gLbl.appendChild(svgEl("text", { x: 0, y: 14, "text-anchor": "middle", "font-size": 9, fill: "#2c3a2c" }, "lecture à la source · normalisation"));642  svg.appendChild(gLbl);643644  const gKa = svgEl("g", { transform: `translate(${(kaL + kaR) / 2} ${kaY}) rotate(-2)` });645  gKa.appendChild(svgEl("rect", { x: -(kaR - kaL) / 2 + 6, y: -66, width: kaR - kaL, height: 146, rx: 12, fill: "rgba(20,24,20,0.18)" }));646  gKa.appendChild(svgEl("rect", { x: -(kaR - kaL) / 2, y: -72, width: kaR - kaL, height: 146, rx: 12, fill: INK }));647  const kaTxt = svgEl("text", { x: 0, y: 8, "text-anchor": "middle", "font-size": 62, "font-weight": 700, "letter-spacing": -2, fill: LIME }, "KA");648  kaTxt.setAttribute("class", "t-display");649  gKa.appendChild(kaTxt);650  gKa.appendChild(svgEl("text", { x: 0, y: 37, "text-anchor": "middle", "font-size": 11, "font-weight": 700, "letter-spacing": 2, fill: "rgba(245,243,238,0.75)" }, "= AGRÉGATION"));651  gKa.appendChild(svgEl("text", { x: 0, y: 55, "text-anchor": "middle", "font-size": 8.5, fill: "rgba(245,243,238,0.55)" }, "dédoublonner · géocoder"));652  svg.appendChild(gKa);653654  PLATFORMS.forEach((p, i) => {655    const y = dstYs[i];656    svg.appendChild(svgEl("rect", { x: dstX, y: y - 21, width: W - dstX - 14, height: 42, rx: 8, fill: WHITE, stroke: INK, "stroke-width": 1.5 }));657    brandChip(svg, dstX + 13, y - 8, p.accent);658    const nm = svgEl("text", { x: dstX + 40, y: y - 1, "font-size": 15.5, "font-weight": 700, fill: INK }, p.name);659    nm.setAttribute("class", "t-display");660    svg.appendChild(nm);661    svg.appendChild(svgEl("text", { x: dstX + 40, y: y + 14, "font-size": 9, fill: INK3 }, p.domain));662  });663  svg.appendChild(svgEl("text", { x: dstX, y: 30, "font-size": 11.5, "font-weight": 700, "letter-spacing": 1.5, fill: INK3 }, "DIX PLATEFORMES"));664665  document.getElementById("fig-sablier").appendChild(svg);666})();667668/* ---------- 2. Le pipeline horizontal (page 4) ---------- */669(function () {670  const STEPS = [671    ["01", "Site source", "La page publique, telle que tout le monde la voit."],672    ["02", "Connecteur", "Un lecteur dédié par site — il connaît sa structure par cœur."],673    ["03", "Normalisation", "Mêmes champs, mêmes unités : un 3½ est un 3½ partout."],674    ["04", "Dédoublonnage & géocodage", "Une seule fiche par annonce réelle, posée sur la carte."],675    ["05", "Publication", "En ligne, datée, traçable jusqu'à la source originale."],676  ];677  const W = 1150, H = 430, boxW = 205, boxH = 210, gap = (W - 40 - 5 * boxW) / 4, top = 90;678  const svg = makeSvg(W, H, "Le pipeline de la donnée KA");679  const M = svg.dataset.marker;680681  STEPS.forEach((s, i) => {682    const x = 20 + i * (boxW + gap);683    const last = i === STEPS.length - 1;684    svg.appendChild(svgEl("rect", { x: x + 5, y: top + 5, width: boxW, height: boxH, rx: 12, fill: "rgba(20,24,20,0.14)" }));685    svg.appendChild(svgEl("rect", { x, y: top, width: boxW, height: boxH, rx: 12, fill: last ? INK : WHITE, stroke: INK, "stroke-width": 1.5 }));686    svg.appendChild(svgEl("text", { x: x + 18, y: top + 36, "font-size": 13, "font-weight": 700, fill: last ? LIME : GREEN }, s[0]));687    const t = svgEl("text", { x: x + 18, y: top + 68, "font-size": 16.5, "font-weight": 700, fill: last ? PAPER : INK });688    t.setAttribute("class", "t-display");689    // titre sur 1-2 lignes690    const words = s[1].split(" ");691    let line = "", lines = [];692    for (const w of words) {693      if ((line + " " + w).trim().length > 15) { lines.push(line.trim()); line = w; } else line += " " + w;694    }695    lines.push(line.trim());696    lines.forEach((ln, li) => t.appendChild(svgEl("tspan", { x: x + 18, dy: li === 0 ? 0 : 21 }, ln)));697    svg.appendChild(t);698    // description699    const d = svgEl("text", { x: x + 18, y: top + 68 + lines.length * 21 + 12, "font-size": 10.5, fill: last ? "rgba(245,243,238,0.7)" : "#4d5551" });700    d.setAttribute("class", "t-body");701    let dl = "", dls = [];702    for (const w of s[2].split(" ")) {703      if ((dl + " " + w).trim().length > 28) { dls.push(dl.trim()); dl = w; } else dl += " " + w;704    }705    dls.push(dl.trim());706    dls.forEach((ln, li) => d.appendChild(svgEl("tspan", { x: x + 18, dy: li === 0 ? 0 : 15 }, ln)));707    svg.appendChild(d);708    if (!last) svg.appendChild(svgEl("line", {709      x1: x + boxW + 6, y1: top + boxH / 2, x2: x + boxW + gap - 8, y2: top + boxH / 2,710      stroke: INK, "stroke-width": 2, "marker-end": `url(#${M})`, "stroke-dasharray": "7 7",711    }));712  });713714  // boucle de resynchronisation : dernière station → première715  const y0 = top + boxH + 44;716  svg.appendChild(svgEl("path", {717    d: `M ${20 + 4 * (boxW + gap) + boxW / 2} ${top + boxH + 6} L ${20 + 4 * (boxW + gap) + boxW / 2} ${y0}718        L ${20 + boxW / 2} ${y0} L ${20 + boxW / 2} ${top + boxH + 14}`,719    fill: "none", stroke: GREEN, "stroke-width": 2.5, "marker-end": `url(#${M})`, "stroke-dasharray": "7 7",720  }));721  const gR = svgEl("g", { transform: `translate(${W / 2} ${y0}) rotate(-2)` });722  gR.appendChild(svgEl("rect", { x: -110, y: -17, width: 220, height: 34, rx: 17, fill: LIME, stroke: INK, "stroke-width": 1.5 }));723  gR.appendChild(svgEl("text", { x: 0, y: 4.5, "text-anchor": "middle", "font-size": 11.5, "font-weight": 700, "letter-spacing": 1, fill: INK }, "RESYNC EN CONTINU"));724  svg.appendChild(gR);725  svg.appendChild(svgEl("text", { x: 20, y: 34, "font-size": 11.5, "font-weight": 700, "letter-spacing": 1.5, fill: INK3 }, "CINQ STATIONS · AUCUNE MAIN HUMAINE"));726727  document.getElementById("fig-pipeline").appendChild(svg);728})();729730/* ---------- 3. Le cycle (page 5) ---------- */731(function () {732  const STEPS = [733    ["01", "Lire les sources", -90], ["02", "Comparer à hier", 0],734    ["03", "Mettre à jour", 90], ["04", "Publier & tracer", 180],735  ];736  const W = 1150, S = 440, cx = W / 2, cy = S / 2 + 4, R = 150;737  const svg = makeSvg(W, S, "Le cycle KA, jour et nuit");738  const M = svg.dataset.marker;739740  svg.appendChild(svgEl("circle", { cx, cy, r: R, fill: "none", stroke: INK, "stroke-width": 2, "stroke-opacity": 0.65, "stroke-dasharray": "7 7" }));741  [-45, 45, 135, 225].forEach((a) => {742    const rad = a * Math.PI / 180, x = cx + R * Math.cos(rad), y = cy + R * Math.sin(rad);743    const tx = -Math.sin(rad), ty = Math.cos(rad);744    svg.appendChild(svgEl("line", { x1: x - tx, y1: y - ty, x2: x + tx * 2, y2: y + ty * 2, stroke: INK, "stroke-width": 2, "marker-end": `url(#${M})` }));745  });746747  const gKa = svgEl("g", { transform: `translate(${cx} ${cy}) rotate(-2)` });748  gKa.appendChild(svgEl("rect", { x: -43, y: -37, width: 96, height: 88, rx: 10, fill: "rgba(20,24,20,0.18)" }));749  gKa.appendChild(svgEl("rect", { x: -48, y: -42, width: 96, height: 88, rx: 10, fill: INK }));750  const t = svgEl("text", { x: 0, y: 8, "text-anchor": "middle", "font-size": 40, "font-weight": 700, "letter-spacing": -1.5, fill: LIME }, "KA");751  t.setAttribute("class", "t-display");752  gKa.appendChild(t);753  gKa.appendChild(svgEl("text", { x: 0, y: 30, "text-anchor": "middle", "font-size": 8, "letter-spacing": 1.5, fill: "rgba(245,243,238,0.65)" }, "JOUR ET NUIT"));754  svg.appendChild(gKa);755756  STEPS.forEach(([num, label, angle]) => {757    const rad = angle * Math.PI / 180, x = cx + R * Math.cos(rad), y = cy + R * Math.sin(rad), w = 178;758    const g = svgEl("g", { transform: `translate(${x} ${y})` });759    g.appendChild(svgEl("rect", { x: -w / 2, y: -21, width: w, height: 42, rx: 9, fill: WHITE, stroke: INK, "stroke-width": 1.5 }));760    g.appendChild(svgEl("text", { x: -w / 2 + 13, y: 5, "font-size": 11, "font-weight": 700, fill: GREEN }, num));761    const l = svgEl("text", { x: -w / 2 + 38, y: 5, "font-size": 14, "font-weight": 700, fill: INK }, label);762    l.setAttribute("class", "t-display");763    g.appendChild(l);764    svg.appendChild(g);765  });766767  // légendes latérales768  const notes = [769    [30, "Une annonce retirée à la source", "disparaît d'elle-même du site."],770    [W - 260, "Une baisse de prix est détectée", "et historisée automatiquement."],771  ];772  notes.forEach(([x, l1, l2]) => {773    svg.appendChild(svgEl("rect", { x, y: cy - 34, width: 230, height: 68, rx: 9, fill: "#faf9f5", stroke: INK, "stroke-width": 1.5, "stroke-dasharray": "5 5" }));774    const n = svgEl("text", { x: x + 16, y: cy - 8, "font-size": 11, fill: "#4d5551" });775    n.setAttribute("class", "t-body");776    n.appendChild(svgEl("tspan", { x: x + 16, dy: 0 }, l1));777    n.appendChild(svgEl("tspan", { x: x + 16, dy: 17 }, l2));778    svg.appendChild(n);779  });780781  document.getElementById("fig-cycle").appendChild(svg);782})();783784/* ---------- 4. Les éclaireurs (page 6) ---------- */785(function () {786  const W = 1300, H = 470;787  const svg = makeSvg(W, H, "Les bots de découverte Ka2, Ka4 et Ka6");788  const M = svg.dataset.marker;789790  // nuage du web québécois (points)791  const cloud = { x: 30, y: 60, w: 260, h: 340 };792  svg.appendChild(svgEl("rect", { x: cloud.x, y: cloud.y, width: cloud.w, height: cloud.h, rx: 14, fill: WHITE, stroke: INK, "stroke-width": 1.5 }));793  let seed = 7;794  const rnd = () => (seed = (seed * 16807) % 2147483647) / 2147483647;795  for (let i = 0; i < 130; i++) {796    svg.appendChild(svgEl("circle", {797      cx: cloud.x + 18 + rnd() * (cloud.w - 36), cy: cloud.y + 34 + rnd() * (cloud.h - 56),798      r: 2 + rnd() * 2.4, fill: rnd() > 0.82 ? GREEN : "rgba(20,24,20,0.35)",799    }));800  }801  svg.appendChild(svgEl("text", { x: cloud.x + 16, y: cloud.y + 22, "font-size": 10.5, "font-weight": 700, "letter-spacing": 1.2, fill: INK3 }, "LE WEB QUÉBÉCOIS"));802803  // bots804  const bots = [805    ["Ka", "2", "#d9f26b", "cartographie les entités", 96],806    ["Ka", "4", "#ff9f45", "activité à découvert", 232],807    ["Ka", "6", "#b9cfee", "nourrit Trouve·Ka", 368],808  ];809  const botX = 430, botW = 250;810  bots.forEach(([l, d, accent, sub, y]) => {811    svg.appendChild(svgEl("path", { d: `M ${cloud.x + cloud.w + 6} ${cloud.y + cloud.h / 2} C ${botX - 90} ${cloud.y + cloud.h / 2}, ${botX - 90} ${y}, ${botX - 8} ${y}`, fill: "none", stroke: INK, "stroke-width": 1.7, "stroke-opacity": 0.6, "stroke-dasharray": "7 7", "marker-end": `url(#${M})` }));812    svg.appendChild(svgEl("rect", { x: botX, y: y - 36, width: botW, height: 72, rx: 11, fill: WHITE, stroke: INK, "stroke-width": 1.5 }));813    const t = svgEl("text", { x: botX + 18, y: y + 2, "font-size": 25, "font-weight": 700, "letter-spacing": -1, fill: INK });814    t.setAttribute("class", "t-display");815    t.appendChild(svgEl("tspan", {}, l));816    svg.appendChild(t);817    svg.appendChild(svgEl("rect", { x: botX + 55, y: y - 20, width: 28, height: 28, rx: 6, fill: INK, transform: `rotate(-4 ${botX + 69} ${y - 6})` }));818    const dt = svgEl("text", { x: botX + 69, y: y + 2, "text-anchor": "middle", "font-size": 19, "font-weight": 700, fill: accent });819    dt.setAttribute("class", "t-display");820    dt.textContent = d;821    svg.appendChild(dt);822    svg.appendChild(svgEl("text", { x: botX + 100, y: y - 2, "font-size": 10.5, "font-weight": 700, fill: GREEN }, "BOT IA"));823    const s = svgEl("text", { x: botX + 100, y: y + 15, "font-size": 10.5, fill: "#4d5551" }, sub);824    s.setAttribute("class", "t-body");825    svg.appendChild(s);826    svg.appendChild(svgEl("path", { d: `M ${botX + botW + 4} ${y} C ${botX + botW + 80} ${y}, ${botX + botW + 80} ${H / 2}, ${botX + botW + 130} ${H / 2}`, fill: "none", stroke: INK, "stroke-width": 1.7, "stroke-opacity": 0.6, "stroke-dasharray": "7 7", "marker-end": `url(#${M})` }));827  });828829  // registre d'entités830  const regX = botX + botW + 140, regW = 180;831  svg.appendChild(svgEl("rect", { x: regX + 5, y: H / 2 - 55 + 5, width: regW, height: 110, rx: 12, fill: "rgba(20,24,20,0.14)" }));832  svg.appendChild(svgEl("rect", { x: regX, y: H / 2 - 55, width: regW, height: 110, rx: 12, fill: INK }));833  const rt = svgEl("text", { x: regX + regW / 2, y: H / 2 - 12, "text-anchor": "middle", "font-size": 17, "font-weight": 700, fill: LIME });834  rt.setAttribute("class", "t-display");835  rt.textContent = "Registre";836  svg.appendChild(rt);837  const rt2 = svgEl("text", { x: regX + regW / 2, y: H / 2 + 10, "text-anchor": "middle", "font-size": 17, "font-weight": 700, fill: LIME });838  rt2.setAttribute("class", "t-display");839  rt2.textContent = "d'entités";840  svg.appendChild(rt2);841  svg.appendChild(svgEl("text", { x: regX + regW / 2, y: H / 2 + 34, "text-anchor": "middle", "font-size": 8.5, "letter-spacing": 1, fill: "rgba(245,243,238,0.6)" }, "entreprises · personnes · sites"));842843  // vers les connecteurs844  svg.appendChild(svgEl("line", { x1: regX + regW + 6, y1: H / 2, x2: regX + regW + 78, y2: H / 2, stroke: INK, "stroke-width": 2.2, "marker-end": `url(#${M})`, "stroke-dasharray": "7 7" }));845  const outX = regX + regW + 90;846  svg.appendChild(svgEl("rect", { x: outX, y: H / 2 - 62, width: W - outX - 16, height: 124, rx: 12, fill: LIME, stroke: INK, "stroke-width": 1.5 }));847  const ot = svgEl("text", { x: outX + 18, y: H / 2 - 26, "font-size": 16, "font-weight": 700, fill: INK });848  ot.setAttribute("class", "t-display");849  ot.textContent = "Nouvelles sources";850  svg.appendChild(ot);851  const ol = svgEl("text", { x: outX + 18, y: H / 2 - 2, "font-size": 10.5, fill: "#2c3a2c" });852  ol.setAttribute("class", "t-body");853  ["Boutique qui ouvre, gestionnaire,", "concessionnaire : repérés par les", "bots, branchés par les ·Ka."].forEach((ln, i) =>854    ol.appendChild(svgEl("tspan", { x: outX + 18, dy: i === 0 ? 0 : 16 }, ln)));855  svg.appendChild(ol);856857  document.getElementById("fig-bots").appendChild(svg);858})();859860/* ---------- 5. Trouve·Ka (page 7) ---------- */861(function () {862  const W = 1150, H = 470;863  const svg = makeSvg(W, H, "Trouve·Ka, le moteur de recherche du web québécois");864  const M = svg.dataset.marker;865866  // robot → index → barre de recherche → résultats867  const steps = [868    { x: 30, w: 250, title: "Le robot", sub: ["Parcourt le web québécois", "jour et nuit — et lui seul.", "robots.txt respecté."], tag: "CRAWLER DÉDIÉ" },869    { x: 330, w: 250, title: "L'index", sub: ["Des milliers de domaines d'ici,", "recherche plein texte,", "croissance heure par heure."], tag: "100 % QUÉBEC" },870  ];871  steps.forEach((s) => {872    svg.appendChild(svgEl("rect", { x: s.x, y: 80, width: s.w, height: 170, rx: 12, fill: WHITE, stroke: INK, "stroke-width": 1.5 }));873    svg.appendChild(svgEl("text", { x: s.x + 18, y: 112, "font-size": 10, "font-weight": 700, "letter-spacing": 1.2, fill: GREEN }, s.tag));874    const t = svgEl("text", { x: s.x + 18, y: 144, "font-size": 21, "font-weight": 700, fill: INK });875    t.setAttribute("class", "t-display");876    t.textContent = s.title;877    svg.appendChild(t);878    const d = svgEl("text", { x: s.x + 18, y: 170, "font-size": 11, fill: "#4d5551" });879    d.setAttribute("class", "t-body");880    s.sub.forEach((ln, i) => d.appendChild(svgEl("tspan", { x: s.x + 18, dy: i === 0 ? 0 : 17 }, ln)));881    svg.appendChild(d);882  });883  svg.appendChild(svgEl("line", { x1: 284, y1: 165, x2: 322, y2: 165, stroke: INK, "stroke-width": 2, "marker-end": `url(#${M})`, "stroke-dasharray": "7 7" }));884  svg.appendChild(svgEl("line", { x1: 584, y1: 165, x2: 622, y2: 165, stroke: INK, "stroke-width": 2, "marker-end": `url(#${M})`, "stroke-dasharray": "7 7" }));885886  // barre de recherche887  const sbX = 634, sbW = 480;888  svg.appendChild(svgEl("rect", { x: sbX + 4, y: 134 + 4, width: sbW, height: 62, rx: 31, fill: "rgba(20,24,20,0.5)" }));889  svg.appendChild(svgEl("rect", { x: sbX, y: 134, width: sbW, height: 62, rx: 31, fill: WHITE, stroke: INK, "stroke-width": 2 }));890  svg.appendChild(svgEl("text", { x: sbX + 26, y: 172, "font-size": 18, "font-weight": 700, fill: INK }, "⌕"));891  svg.appendChild(svgEl("text", { x: sbX + 54, y: 171, "font-size": 12.5, fill: INK3 }, "poutine · plex à vendre · Gaspésie…"));892  svg.appendChild(svgEl("rect", { x: sbX + sbW - 116, y: 145, width: 102, height: 40, rx: 20, fill: INK }));893  const st = svgEl("text", { x: sbX + sbW - 65, y: 170, "text-anchor": "middle", "font-size": 13.5, "font-weight": 700, fill: "#b9cfee" });894  st.setAttribute("class", "t-display");895  st.textContent = "Chercher";896  svg.appendChild(st);897  const wm = svgEl("text", { x: sbX, y: 118, "font-size": 21, "font-weight": 700, "letter-spacing": -0.7, fill: INK });898  wm.setAttribute("class", "t-display");899  wm.textContent = "Trouve";900  svg.appendChild(wm);901  svg.appendChild(svgEl("rect", { x: sbX + 78, y: 98, width: 34, height: 26, rx: 6, fill: INK, transform: `rotate(-3 ${sbX + 95} 111)` }));902  const wk = svgEl("text", { x: sbX + 95, y: 117, "text-anchor": "middle", "font-size": 16, "font-weight": 700, fill: "#b9cfee" });903  wk.setAttribute("class", "t-display");904  wk.textContent = "Ka";905  svg.appendChild(wk);906  svg.appendChild(svgEl("text", { x: sbX + 124, y: 114, "font-size": 9.5, fill: INK3 }, "www.trouve-ka.com"));907908  // résultats (3 lignes)909  ["Microbrasserie — Rimouski", "Érablière — Lanaudière", "Blogue de quartier — Limoilou"].forEach((r, i) => {910    const y = 232 + i * 46;911    svg.appendChild(svgEl("rect", { x: sbX, y, width: sbW, height: 36, rx: 8, fill: "#faf9f5", stroke: INK, "stroke-width": 1.2 }));912    svg.appendChild(svgEl("circle", { cx: sbX + 20, cy: y + 18, r: 3.5, fill: GREEN }));913    const rt = svgEl("text", { x: sbX + 34, y: y + 23, "font-size": 12.5, "font-weight": 600, fill: INK });914    rt.setAttribute("class", "t-body");915    rt.textContent = r;916    svg.appendChild(rt);917    svg.appendChild(svgEl("text", { x: sbX + sbW - 20, y: y + 23, "text-anchor": "end", "font-size": 9, fill: GREEN }, "1re page"));918  });919920  // note comparaison921  svg.appendChild(svgEl("rect", { x: 30, y: 290, width: 554, height: 130, rx: 12, fill: INK }));922  const nt = svgEl("text", { x: 56, y: 330, "font-size": 20, "font-weight": 700, "letter-spacing": -0.5, fill: PAPER });923  nt.setAttribute("class", "t-display");924  nt.appendChild(svgEl("tspan", { x: 56, dy: 0 }, "LES GRANDS MOTEURS CHERCHENT LE MONDE."));925  const sp = svgEl("tspan", { x: 56, dy: 28, fill: LIME }, "TROUVE·KA CHERCHE LE QUÉBEC.");926  nt.appendChild(sp);927  svg.appendChild(nt);928  svg.appendChild(svgEl("text", { x: 56, y: 396, "font-size": 10, "letter-spacing": 1, fill: "rgba(245,243,238,0.6)" }, "NOURRI PAR LES ÉCLAIREURS KA2 · KA4 · KA6 — ZÉRO PUBLICITÉ, ZÉRO PROFILAGE"));929930  document.getElementById("fig-trouveka").appendChild(svg);931})();932933/* ---------- 6. Barres d'inventaire (page 8) ---------- */934(function () {935  const INVENTORY = [936    ["Fabri·Ka", 281000, "produits québécois"],937    ["Resto·Ka", 61000, "plats & prix réels"],938    ["Immo·Ka", 54000, "propriétés à vendre"],939    ["Food·Ka", 23700, "prix d'épicerie"],940    ["Auto·Ka", 15900, "véhicules d'occasion"],941    ["Sorti·Ka", 11100, "événements & sorties"],942    ["Lou·Ka", 7000, "logements à louer"],943    ["Créa·Ka", 2200, "créateurs d'ici"],944  ];945  const max = Math.max(...INVENTORY.map((d) => d[1]));946  const fmt = (n) => n.toLocaleString("fr-CA");947  const wrap = document.getElementById("fig-bars");948  for (const [name, value, unit] of INVENTORY) {949    const row = document.createElement("div");950    row.className = "barrow";951    row.innerHTML =952      `<div class="barhead"><span class="nm"><span class="brand"><i style="background:${ACCENT[name]}"></i></span>${name}<span class="u">${unit}</span></span>` +953      `<span class="v">${fmt(value)}+</span></div>` +954      `<div class="bartrack"><div class="barfill" style="width:${Math.max((value / max) * 100, 1.6)}%"></div></div>`;955    wrap.appendChild(row);956  }957})();958959/* ---------- 7. Matrice de connecteurs (page 9) ---------- */960(function () {961  const CONNECTORS = [962    ["Auto·Ka", 124, "concessionnaires"],963    ["Lou·Ka", 108, "gestionnaires"],964    ["Immo·Ka", 65, "agences"],965    ["Food·Ka", 20, "bannières"],966    ["Resto·Ka", 19, "chaînes de restos"],967    ["Sorti·Ka", 4, "billetteries & données ouvertes"],968  ];969  const wrap = document.getElementById("fig-dots");970  for (const [name, count, kind] of CONNECTORS) {971    const b = document.createElement("div");972    b.className = "dots-block";973    b.innerHTML =974      `<div class="barhead"><span class="nm"><span class="brand"><i style="background:${ACCENT[name]}"></i></span>${name}<span class="u">${kind}</span></span>` +975      `<span class="v">${count}</span></div>` +976      `<div class="dots">${"<i></i>".repeat(count)}</div>`;977    wrap.appendChild(b);978  }979})();980981/* ---------- 8. Tableau du socle (page 11) ---------- */982(function () {983  const ROWS = [984    ["Trouve·Ka", "#b9cfee", "Recherche — tout le web québécois", "Crawler dédié + index de recherche plein texte", "www.trouve-ka.com"],985    ["Lou·Ka", "#d9f26b", "Location résidentielle", "108 connecteurs sources + synchronisation horaire", "www.lou-ka.com"],986    ["Immo·Ka", "#e23744", "Propriétés à vendre", "65 connecteurs d'agences + détection des ventes", "www.immo-ka.com"],987    ["Vrai-Prix", "#ff5148", "Résidentiel — tout le Québec", "Hédonique LightGBM + comparables réels ajustés", "www.vrai-prix.com"],988    ["ValoPlex", "#ff9f45", "Immeubles à revenus (plex)", "Hédonique monotone + ventes de plex comparables", "www.valoplex.com"],989    ["Auto·Ka", "#ff5a2a", "Voitures usagées", "125 connecteurs concessionnaires + suivi des prix", "www.auto-ka.com"],990    ["Fabri·Ka", "#C4532E", "Produits québécois", "1 204 boutiques en ligne indexées par région", "www.fabri-ka.com"],991    ["Food·Ka", "#d9f26b", "Épicerie", "20 bannières — prix, soldes et prix unitaires", "www.food-ka.com"],992    ["Resto·Ka", "#ffc53d", "Restaurants — menus & prix", "19 chaînes intégrées — 61 000+ plats suivis", "www.resto-ka.com"],993    ["Sorti·Ka", "#ff6a00", "Sorties & événements", "Billetteries + données ouvertes — MàJ horaire", "www.sorti-ka.com"],994    ["Créa·Ka", "#7da2ff", "Créateurs de contenu", "Annuaire multi-plateformes + résolution d'identité", "www.crea-ka.com"],995  ];996  const tbody = document.querySelector("#socle-table tbody");997  for (const [name, accent, market, engine, url] of ROWS) {998    const tr = document.createElement("tr");999    tr.innerHTML =1000      `<td class="nm"><span class="brand"><i style="background:${accent}"></i></span>${name}</td>` +1001      `<td>${market}</td><td>${engine}</td><td class="url">${url}</td>`;1002    tbody.appendChild(tr);1003  }1004})();1005</script>1006</body>1007</html>1008