diff --git a/post2.html b/post2.html
index c534ba8..32a196d 100644
--- a/post2.html
+++ b/post2.html
@@ -373,6 +373,8 @@
width: var(--vis-w, 896px);
color: var(--head-color);
}
+ .vis svg { display: block; width: 100%; height: auto; }
+
.vis-kasten {
position: relative; padding: 30px 34px;
background: var(--frame-bg);
@@ -451,59 +453,14 @@
.vis-lose .feld:nth-child(odd) .stummel { right: -84px; }
.vis-lose .feld:nth-child(even) .stummel { left: -84px; }
- /* Slide 5: das ERP bleibt in der Mitte, das Neue haengt drumherum. */
- .vis-verbinden { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; }
- .vis-verbinden .saeule { display: grid; gap: 24px; }
- .vis-verbinden .saeule .vis-kasten { min-height: 340px; }
- .vis-verbinden .mitte { position: relative; width: 452px; padding: 0 30px; }
- .vis-nabe {
- position: relative; width: 392px; height: 340px; margin: 0 auto;
- background: var(--shape-fill);
- clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
- display: flex; flex-direction: column; align-items: center; justify-content: center;
- color: #fff; text-align: center;
- }
- .vis-nabe b { font-size: 34px; font-weight: 800; letter-spacing: -0.02em; }
- .vis-nabe small { margin-top: 6px; font-size: 21px; font-weight: 600; opacity: .74; }
- .vis-verbinden .quer { position: absolute; top: 50%; width: 30px; height: 8px; background: var(--shape-line); }
- .vis-verbinden .quer.li { left: 0; }
- .vis-verbinden .quer.re { right: 0; }
+ /* Slide 5 ist gezeichnet und braucht kein eigenes Layout mehr: das SVG
+ fuellt den Container. Das alte Raster stand hier noch und hat die
+ Zeichnung als Rasterzelle auf ein Drittel zusammengeschoben. Wer eine
+ Visualisierung auf SVG umstellt, muss ihr Layout-CSS mit entfernen. */
- /* Slide 6: der Abschluss ist ein Feld, kein Bild. */
- .vis-warteliste {
- border: 6px solid var(--shape-line); padding: 54px 48px; text-align: center;
- clip-path: polygon(
- 22px 0, calc(100% - 22px) 0, 100% 22px, 100% calc(100% - 22px),
- calc(100% - 22px) 100%, 22px 100%, 0 calc(100% - 22px), 0 22px
- );
- }
- .vis-warteliste .oben {
- font-size: 21px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
- color: var(--body-color);
- }
- .vis-warteliste .feldzeile { display: flex; align-items: stretch; gap: 18px; margin-top: 26px; }
- .vis-warteliste .eingabe {
- flex: 1; padding: 30px 32px; text-align: left;
- font-size: 30px; font-weight: 500; color: var(--body-color);
- background: var(--frame-bg);
- clip-path: polygon(
- 16px 0, calc(100% - 16px) 0, 100% 16px, 100% calc(100% - 16px),
- calc(100% - 16px) 100%, 16px 100%, 0 calc(100% - 16px), 0 16px
- );
- }
- .vis-warteliste .knopf {
- flex: none; display: flex; align-items: center; padding: 30px 40px;
- font-size: 30px; font-weight: 800;
- background: var(--accent-yellow); color: #3E2C0A;
- clip-path: polygon(
- 16px 0, calc(100% - 16px) 0, 100% 16px, 100% calc(100% - 16px),
- calc(100% - 16px) 100%, 16px 100%, 0 calc(100% - 16px), 0 16px
- );
- }
- .vis-warteliste .adresse {
- margin-top: 30px; font-size: 30px; font-weight: 800; letter-spacing: -0.01em;
- color: var(--head-color);
- }
+ /* Slide 6 ist gezeichnet, das alte Formular-Layout ist entfallen. Die
+ Klasse .vis-warteliste haengt weiter am Container: Layout-CSS darf hier
+ nicht wieder auftauchen, sonst rahmt es das SVG ein. */
/* ─── Teamkarte ──────────────────────────────────────────────────────────
Nachbau der Karte von der Ueber-uns-Seite im aktiven Zustand: Hintergrund
@@ -1251,7 +1208,7 @@
eyebrow: "Warteliste",
head: 'Gebaut im Betrieb.
Für den Betrieb.',
body: "Setz dich auf die Warteliste.",
- vis: "warteliste", visW: 820, visLeft: 130, visBottom: 281,
+ vis: "warteliste", visW: 896, visLeft: 92, visBottom: 120,
},
];
@@ -1299,6 +1256,409 @@
(zeile ? '
' + zeile + '
' : '') +
'';
+ /* ─── Skizzen-Primitive ─────────────────────────────────────────────────────
+ Handzeichnung aus gesetztem Zufall. Der Keim ist fest: der Export rendert
+ bei fehlgeschlagener Pruefung bis zu fuenfmal neu, und jeder Durchgang muss
+ denselben Strich ergeben. Mit ungesetztem Math.random zittert jedes Bild
+ anders und die Kontrolle vergleicht gegen etwas, das es nie wieder gibt. */
+ let _s = 0;
+ function keim(n) { _s = n >>> 0; }
+ function rnd() {
+ _s = (_s + 0x6D2B79F5) >>> 0;
+ let t = Math.imul(_s ^ (_s >>> 15), 1 | _s);
+ t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
+ }
+ const zit = m => (rnd() * 2 - 1) * m;
+ const n1 = v => Math.round(v * 10) / 10;
+
+ /* Ein Strich, leicht gebogen und an den Enden verwackelt. Der Bogen waechst
+ mit der Laenge: eine kurze Kante zittert, eine lange schwingt. */
+ function strich(x1, y1, x2, y2, o) {
+ o = o || {};
+ const j = o.j == null ? 1.5 : o.j;
+ const ue = o.ue == null ? 0 : o.ue; // Ueberschuss an den Enden
+ let dx = x2 - x1, dy = y2 - y1;
+ const len = Math.hypot(dx, dy) || 1, ux = dx / len, uy = dy / len;
+ const ax = x1 - ux * rnd() * ue + zit(j), ay = y1 - uy * rnd() * ue + zit(j);
+ const bx = x2 + ux * rnd() * ue + zit(j), by = y2 + uy * rnd() * ue + zit(j);
+ dx = bx - ax; dy = by - ay;
+ const nx = -dy / len, ny = dx / len;
+ const b = o.b == null ? len * 0.008 + 1 : o.b;
+ const o1 = zit(b), o2 = zit(b);
+ return "M" + n1(ax) + "," + n1(ay) + "C" +
+ n1(ax + dx / 3 + nx * o1) + "," + n1(ay + dy / 3 + ny * o1) + " " +
+ n1(ax + dx * 2 / 3 + nx * o2) + "," + n1(ay + dy * 2 / 3 + ny * o2) + " " +
+ n1(bx) + "," + n1(by);
+ }
+
+ /* Punktfolge zu einer weichen Kurve (Catmull-Rom als Bezier). */
+ function glatt(pts, zu) {
+ const n = pts.length;
+ const at = i => pts[zu ? (i + n) % n : Math.max(0, Math.min(n - 1, i))];
+ let d = "M" + n1(pts[0][0]) + "," + n1(pts[0][1]);
+ const bis = zu ? n : n - 1;
+ for (let i = 0; i < bis; i++) {
+ const p0 = at(i - 1), p1 = at(i), p2 = at(i + 1), p3 = at(i + 2);
+ d += "C" + n1(p1[0] + (p2[0] - p0[0]) / 6) + "," + n1(p1[1] + (p2[1] - p0[1]) / 6) +
+ " " + n1(p2[0] - (p3[0] - p1[0]) / 6) + "," + n1(p2[1] - (p3[1] - p1[1]) / 6) +
+ " " + n1(p2[0]) + "," + n1(p2[1]);
+ }
+ return d;
+ }
+
+ /* Kringel statt Kreis: der Zug faengt irgendwo an, laeuft einmal herum und
+ schiesst ein Stueck ueber den Anfang hinaus. Genau das macht die Hand. */
+ function kringel(cx, cy, rx, ry, o) {
+ o = o || {};
+ ry = ry == null ? rx : ry;
+ const wack = o.wack == null ? Math.min(rx, ry) * 0.02 + 1 : o.wack;
+ const a0 = o.a0 == null ? rnd() * 6.283 : o.a0;
+ const ueber = o.ueber == null ? 0.16 + rnd() * 0.2 : o.ueber;
+ const schritte = 18, pts = [];
+ const spanne = 6.283 + ueber;
+ for (let i = 0; i <= schritte; i++) {
+ const a = a0 + spanne * (i / schritte);
+ pts.push([cx + Math.cos(a) * (rx + zit(wack)), cy + Math.sin(a) * (ry + zit(wack))]);
+ }
+ return glatt(pts, false);
+ }
+
+ /* Vier einzelne Kanten mit Ueberschuss an den Ecken. Der Ueberschuss ist das
+ eigentliche Erkennungsmerkmal von Handzeichnung, nicht das Zittern. */
+ function rechteck(x, y, w, h, o) {
+ o = o || {};
+ const ue = o.ue == null ? 3.5 : o.ue;
+ return [
+ strich(x, y, x + w, y, { ue: ue }),
+ strich(x + w, y, x + w, y + h, { ue: ue }),
+ strich(x + w, y + h, x, y + h, { ue: ue }),
+ strich(x, y + h, x, y, { ue: ue }),
+ ].join("");
+ }
+
+ /* Schraffur als Schattierung: parallele Striche, an den Enden kuerzer, damit
+ das Feld nicht als Block steht. */
+ function schraff(x, y, w, h, abstand, neig) {
+ neig = neig == null ? 0.55 : neig;
+ let d = "";
+ for (let t = -h * neig; t < w; t += abstand) {
+ const x1 = x + t, x2 = x + t + h * neig;
+ const a = Math.max(x, Math.min(x + w, x1)), b = Math.max(x, Math.min(x + w, x2));
+ if (b - a < 3) continue;
+ const y1 = y + h - (a - x1) / neig, y2 = y + h - (b - x1) / neig;
+ d += strich(a, Math.min(y + h, Math.max(y, y1)), b, Math.min(y + h, Math.max(y, y2)), { j: .8, b: .8 });
+ }
+ return d;
+ }
+
+ /* Bodenschatten: ein paar kurze Striche unter dem Gegenstand. Sie sitzen eng
+ am Fuss, sonst schwebt der Gegenstand ueber seinem eigenen Schatten. */
+ function boden(cx, y, w) {
+ let d = "";
+ for (let i = 0; i < 4; i++) {
+ const f = 1 - Math.abs(i - 1.5) * 0.26;
+ const b = w * f * (0.62 + rnd() * 0.26);
+ d += strich(cx - b / 2 + zit(3), y + i * 3.6, cx + b / 2 + zit(3), y + i * 3.6 - 4, { j: .9, b: 1.2 });
+ }
+ return d;
+ }
+
+ /* ─── Bausteine ────────────────────────────────────────────────────────── */
+ const TINTE = "#2A2C33", GELB = "#E9A81C";
+ const zug = (d, o) => {
+ o = o || {};
+ return '';
+ };
+ const schatten = d => zug(d, { w: 1.9, op: .34 });
+
+ /* ─── Die Satelliten ─────────────────────────────────────────────────────
+ Jedes Ikon meldet zurueck, wie weit es reicht (rad) und wo seine
+ Beschriftung hingehoert (unten). Sonst haengt der Knoten am kleinen Ikon
+ zu weit weg und am grossen klebt er drin. */
+ function ikonKi(cx, cy) {
+ const zack = (x, y, r) => {
+ const k = r * 0.28, p = [];
+ for (let i = 0; i < 8; i++) {
+ const a = -Math.PI / 2 + i * Math.PI / 4, rr = i % 2 ? k : r;
+ p.push([x + Math.cos(a) * rr + zit(1.4), y + Math.sin(a) * rr + zit(1.4)]);
+ }
+ return glatt(p, true);
+ };
+ return zug(zack(cx - 8, cy - 6, 46), { w: 3.4 }) +
+ zug(zack(cx + 38, cy + 30, 17), { w: 2.7 }) +
+ zug(zack(cx + 34, cy - 34, 12), { w: 2.5 }) +
+ schatten(boden(cx, cy + 54, 88));
+ }
+ ikonKi.rad = 52; ikonKi.unten = 92;
+
+ function ikonChat(cx, cy) {
+ const blase = (x, y, rx, ry, sx) =>
+ zug(kringel(x, y, rx, ry, { ueber: .12 })) +
+ zug(glatt([[x + sx * rx * .42, y + ry * .82], [x + sx * rx * .86, y + ry * 1.6],
+ [x + sx * rx * .08, y + ry * .98]], false));
+ return blase(cx + 20, cy - 4, 38, 30, 1) +
+ blase(cx - 22, cy - 16, 47, 37, -1) +
+ [-18, 0, 18].map(o => zug(kringel(cx - 22 + o, cy - 16, 4.6), { w: 2.5 })).join("") +
+ schatten(boden(cx, cy + 52, 100));
+ }
+ ikonChat.rad = 58; ikonChat.unten = 90;
+
+ function ikonCrm(cx, cy) {
+ const kopf = (x, y, r, w) => zug(kringel(x, y, r), { w: w }) +
+ zug(glatt([[x - r * 1.55, y + r * 2.7], [x - r * 1.5, y + r * 1.05],
+ [x, y + r * .55], [x + r * 1.5, y + r * 1.05], [x + r * 1.55, y + r * 2.7]], false), { w: w });
+ return kopf(cx - 42, cy - 16, 17, 2.8) + kopf(cx + 42, cy - 16, 17, 2.8) +
+ kopf(cx, cy + 2, 22, 3.3) +
+ schatten(boden(cx, cy + 62, 116));
+ }
+ ikonCrm.rad = 72; ikonCrm.unten = 92;
+
+ function ikonAuto(cx, cy) {
+ const r = 39, zaehne = 10;
+ let d = "";
+ for (let i = 0; i < zaehne; i++) {
+ const a = i * 6.283 / zaehne, br = 0.22;
+ const p = [];
+ [[-br, r], [-br * .8, r + 14], [br * .8, r + 14], [br, r]].forEach(v => {
+ const aa = a + v[0];
+ p.push([cx + Math.cos(aa) * v[1] + zit(.9), cy + Math.sin(aa) * v[1] + zit(.9)]);
+ });
+ d += glatt(p, false);
+ }
+ return zug(kringel(cx, cy, r)) + zug(d, { w: 2.9 }) + zug(kringel(cx, cy, 15), { w: 2.7 }) +
+ schatten(boden(cx, cy + 60, 96));
+ }
+ ikonAuto.rad = 56; ikonAuto.unten = 88;
+
+ function ikonBoard(cx, cy) {
+ const w = 116, h = 88, x = cx - w / 2, y = cy - h / 2;
+ let d = rechteck(x, y, w, h);
+ let k = "";
+ for (let i = 1; i < 3; i++) k += strich(x + w * i / 3, y + 7, x + w * i / 3, y + h - 7, { j: 1, b: 1 });
+ const karte = (sx, sy, sh) => rechteck(x + sx, y + sy, w / 3 - 16, sh, { ue: 2 });
+ k += karte(8, 11, 19) + karte(8, 36, 19) + karte(w / 3 + 8, 11, 19) + karte(2 * w / 3 + 8, 11, 31);
+ return zug(d) + zug(k, { w: 2.4 }) + schatten(boden(cx, cy + h / 2 + 7, 116));
+ }
+ ikonBoard.rad = 64; ikonBoard.unten = 84;
+
+ function ikonFormular(cx, cy) {
+ const w = 90, h = 116, x = cx - w / 2, y = cy - h / 2;
+ let d = rechteck(x, y, w, h);
+ d += rechteck(x + w / 2 - 19, y - 12, 38, 22, { ue: 2 });
+ let k = "";
+ [32, 50, 68].forEach(o => { k += strich(x + 15, y + o, x + w - 34, y + o, { j: 1, b: 1 }); });
+ k += rechteck(x + 15, y + 80, 23, 23, { ue: 2 });
+ const hak = [[x + 19, y + 91], [x + 25, y + 98], [x + 35, y + 81]];
+ return zug(d) + zug(k, { w: 2.4 }) + zug(glatt(hak, false), { w: 3.6, f: GELB }) +
+ schatten(boden(cx, cy + h / 2 + 7, 92));
+ }
+ ikonFormular.rad = 62; ikonFormular.unten = 96;
+
+ /* Ein Strich mit Spitze am Ende. Die Spitze sind zwei kurze Zuege, keine
+ gefuellte Flaeche: gezeichnet wird sie so, gefuellt sieht sie gesetzt aus. */
+ function pfeil(x1, y1, x2, y2, gr) {
+ gr = gr == null ? 16 : gr;
+ const a = Math.atan2(y2 - y1, x2 - x1), oeff = 0.42;
+ return strich(x1, y1, x2, y2, { j: 1.1 }) +
+ strich(x2, y2, x2 - Math.cos(a - oeff) * gr, y2 - Math.sin(a - oeff) * gr, { j: .8, b: .8 }) +
+ strich(x2, y2, x2 - Math.cos(a + oeff) * gr, y2 - Math.sin(a + oeff) * gr, { j: .8, b: .8 });
+ }
+
+ /* Schraffur innerhalb einer Wabe. Eine gezeichnete Flaeche wird nicht
+ gefuellt, sie wird schraffiert: so bleibt der Raster-Grund sichtbar und
+ es sieht trotzdem nach "voll" aus wie auf der Website. */
+ function wabeSchraff(cx, cy, r, abstand) {
+ const h = r * 0.866;
+ let d = "";
+ for (let y = -h + abstand; y < h - abstand * 0.5; y += abstand) {
+ const halb = r - (r / 2) * (Math.abs(y) / h) - 8;
+ if (halb < 7) continue;
+ d += strich(cx - halb, cy + y - 3, cx + halb, cy + y + 3, { j: .9, b: 1 });
+ }
+ return d;
+ }
+
+ function ikonBrief(cx, cy, f) {
+ const w = 46, h = 31, x = cx - w / 2, y = cy - h / 2;
+ return zug(rechteck(x, y, w, h, { ue: 2.5 }), { w: 2.9, f: f }) +
+ zug(glatt([[x + 3, y + 4], [cx, y + h * 0.66], [x + w - 3, y + 4]], false),
+ { w: 2.7, f: f });
+ }
+
+ function ikonBlaseKlein(cx, cy, f) {
+ return zug(kringel(cx, cy - 5, 25, 19, { ueber: .1 }), { w: 2.9, f: f }) +
+ zug(glatt([[cx - 8, cy + 12], [cx - 13, cy + 23], [cx + 3, cy + 13]], false),
+ { w: 2.7, f: f }) +
+ [-9, 0, 9].map(o => zug(kringel(cx + o, cy - 5, 2.8), { w: 2.2, f: f })).join("");
+ }
+
+ function ikonKonfetti(cx, cy, f) {
+ // Knallbonbon: Tuete unten links, Funken nach oben rechts.
+ const tuete = glatt([[cx - 28, cy + 24], [cx - 6, cy - 2],
+ [cx + 10, cy + 19], [cx - 28, cy + 24]], false) +
+ strich(cx - 20, cy + 15, cx - 2, cy + 19, { j: .9, b: .8 });
+ let funken = "";
+ [-1.42, -1.06, -0.68, -0.28].forEach((a, i) => {
+ const r0 = 16, r1 = 30 + (i % 2) * 7;
+ funken += strich(cx + 2 + Math.cos(a) * r0, cy + 3 + Math.sin(a) * r0,
+ cx + 2 + Math.cos(a) * r1, cy + 3 + Math.sin(a) * r1, { j: 1 });
+ });
+ let punkte = "";
+ [[20, -27], [31, -11], [26, -35], [8, -33]].forEach(v => {
+ punkte += kringel(cx + v[0], cy + v[1], 3.1);
+ });
+ return zug(tuete, { w: 2.9, f: f }) + zug(funken, { w: 2.4, f: f }) +
+ zug(punkte, { w: 2.2, f: f });
+ }
+
+ /* Die Wabe, flat-top, Seitenverhaeltnis 2/Wurzel3 wie in rules.md Paragraf 3.
+ Bei dieser Form liegen die sechs Ecken auf einem Kreis vom Radius r. Genau
+ deshalb ist sie hier richtig: jede Speiche setzt an einer Ecke an, nicht
+ irgendwo auf einer Kante. Gezogen wird sie aus sechs einzelnen Strichen
+ mit Ueberschuss, nicht als geschlossenes Polygon. */
+ function wabeEcken(cx, cy, r) {
+ const p = [];
+ for (let i = 0; i < 6; i++) {
+ const a = i * Math.PI / 3;
+ p.push([cx + Math.cos(a) * r, cy + Math.sin(a) * r]);
+ }
+ return p;
+ }
+
+ function wabe(cx, cy, r) {
+ const p = wabeEcken(cx, cy, r);
+ let d = "";
+ for (let i = 0; i < 6; i++) {
+ const q = p[i], w = p[(i + 1) % 6];
+ d += strich(q[0], q[1], w[0], w[1], { ue: 5, j: 1.8 });
+ }
+ return d;
+ }
+
+ /* ─── Die Mitte: das bestehende System ───────────────────────────────────
+ Bewusst als Liste gezeichnet, nicht als Kachel-Dashboard: so sieht eine
+ Warenwirtschaft aus. Und bewusst der schwerste Strich auf der Slide, denn
+ sie ist das, was bleibt. Das Fenster passt ganz in den Ring, sonst kreuzen
+ sich Ringbogen und Fensterecke, und weil der Grund durchscheinen soll gibt
+ es keine Fuellung, die das verdecken koennte. */
+ function nabe(cx, cy) {
+ const w = 216, h = 150, x = cx - w / 2, y = cy - h / 2, kopf = 40;
+ let d = rechteck(x, y, w, h, { ue: 4 });
+ d += strich(x, y + kopf, x + w, y + kopf, { ue: 3 });
+ let k = "";
+ [0, 1, 2].forEach(i => { k += kringel(x + 18 + i * 15, y + kopf / 2, 4.4, 4.4, { ueber: .1 }); });
+ let z = "";
+ for (let i = 0; i < 4; i++) {
+ const yy = y + kopf + 22 + i * 23;
+ z += strich(x + 17, yy, x + 59, yy, { j: 1, b: 1 });
+ z += strich(x + 72, yy, x + w - 48, yy, { j: 1, b: 1 });
+ z += strich(x + w - 38, yy, x + w - 17, yy, { j: 1, b: 1 });
+ }
+ return zug(d, { w: 3.6 }) + zug(k, { w: 2.4 }) + zug(z, { w: 2.2, op: .8 }) +
+ 'HiveGrid';
+ }
+
+ /* ─── Aufbau ───────────────────────────────────────────────────────────── */
+ /* ─── Slide 6: was nach der Anmeldung passiert ───────────────────────────
+ Uebernahme der Sektion "So geht\'s weiter" von der Website, in derselben
+ Handschrift wie Slide 5. Drei Schritte an einer Leitung, Wabe statt Kreis,
+ der dritte Schritt blass: er hat noch nicht stattgefunden. */
+ function visWarteliste() {
+ keim(20260814);
+ const W = 896, H = 730, HX = 66, R = 54, TX = 176, HOEH = R * 0.866;
+
+ const schritte = [
+ { y: 112, titel: "Du trägst dich ein", ikon: ikonBrief,
+ zeilen: ["Eine E-Mail genügt. Kein Vertrag,", "keine Kreditkarte, unverbindlich."] },
+ { y: 352, titel: "Wir melden uns", ikon: ikonBlaseKlein,
+ zeilen: ["Sobald HiveGrid für deinen Betrieb", "bereit ist, persönlich und ohne Spam."] },
+ { y: 592, titel: "Du bist von Anfang an dabei", ikon: ikonKonfetti,
+ zeilen: ["Unter den Ersten, die HiveGrid", "nutzen und mitgestalten."] },
+ ];
+
+ const txt = (x, y, groesse, gewicht, farbe, sperr, inhalt) =>
+ '' + inhalt + '';
+
+ let raus = "";
+
+ // Von Wabe zu Wabe ein Pfeil. Er endet kurz vor der naechsten Wabe, sonst
+ // laeuft die Spitze in die Kante und ist nicht mehr als Spitze zu lesen.
+ let pfeile = "";
+ for (let i = 0; i < schritte.length - 1; i++) {
+ pfeile += pfeil(HX, schritte[i].y + HOEH + 8, HX, schritte[i + 1].y - HOEH - 9);
+ }
+ raus += zug(pfeile, { f: GELB, w: 3.8 });
+
+ schritte.forEach(sc => {
+ raus += zug(wabeSchraff(HX, sc.y, R, 11), { f: GELB, w: 2, op: .5 });
+ raus += zug(wabe(HX, sc.y, R), { f: GELB, w: 4 });
+ raus += sc.ikon(HX, sc.y, TINTE);
+ raus += txt(TX, sc.y - 26, 40, 800, TINTE, "-0.02em", sc.titel);
+ sc.zeilen.forEach((z, k) => {
+ raus += txt(TX, sc.y + 24 + k * 34, 26, 500, "#555555", "0", z);
+ });
+ });
+
+ return '';
+ }
+
+ function visVerbinden() {
+ keim(20260812);
+ const W = 896, H = 730, cx = 448, cy = 350, R = 160;
+ const RX = 352, RY = 300;
+
+ // Die Winkel sind nicht frei gewaehlt: sie sind die sechs Eckwinkel der
+ // Wabe. Dadurch sitzt jeder Knoten auf einer Ecke.
+ const sats = [
+ { a: 240, name: "KI", ikon: ikonKi },
+ { a: 300, name: "Chat", ikon: ikonChat },
+ { a: 0, name: "Mitarbeiter", ikon: ikonCrm },
+ { a: 60, name: "Automation", ikon: ikonAuto },
+ { a: 120, name: "Projekte", ikon: ikonBoard },
+ { a: 180, name: "Formulare", ikon: ikonFormular },
+ ];
+
+ let speichen = "", knoten = "", bilder = "", schrift = "";
+
+ sats.forEach(s => {
+ const r = s.a * Math.PI / 180;
+ const sx = cx + Math.cos(r) * RX, sy = cy + Math.sin(r) * RY;
+ const ix = cx + Math.cos(r) * R, iy = cy + Math.sin(r) * R; // Ecke der Wabe
+ const vx = sx - ix, vy = sy - iy, vl = Math.hypot(vx, vy) || 1;
+ const ux = vx / vl, uy = vy / vl;
+ const ax = sx - ux * (s.ikon.rad + 20), ay = sy - uy * (s.ikon.rad + 20);
+ speichen += strich(ix + ux * 12, iy + uy * 12, ax - ux * 11, ay - uy * 11, { j: 1.2 });
+ knoten += kringel(ix, iy, 10.5, 10.5, { ueber: .1 }) + kringel(ax, ay, 10.5, 10.5, { ueber: .1 });
+ bilder += s.ikon(sx, sy);
+ schrift += '' + s.name + '';
+ });
+
+ // Die Wabe wird zweimal gezogen. Ein zweiter Umriss auf groesserem Radius
+ // sah nach Versehen aus, derselbe Radius nach zweitem Zug.
+ // Breite und Hoehe stehen als Attribute mit dran, nicht nur im viewBox.
+ // Ohne sie hat Chrome die Hoehe nicht aus dem Seitenverhaeltnis abgeleitet,
+ // das SVG wurde zu hoch und die Zeichnung lief in den Fliesstext.
+ return '';
+ }
+
const VIS = {
karte: () =>
'' +
@@ -1338,26 +1698,9 @@
'
' + kasten("ERP", "läuft, redet aber mit niemandem") + '
' +
'
',
- verbinden: () =>
- '' +
- '
' + kasten("KI") + kasten("CRM") + '
' +
- '
' +
- '
' +
- '
Dein ERPbleibt, wo es ist
' +
- '
' +
- '
' +
- '
' + kasten("Automation") + kasten("Chat") + '
' +
- '
',
+ verbinden: () => visVerbinden(),
- warteliste: () =>
- '' +
- '
Frühzugang
' +
- '
' +
- '
deine@firma.de
' +
- '
Auf die Warteliste
' +
- '
' +
- '
hivegrid.de
' +
- '
',
+ warteliste: () => visWarteliste(),
};
/* ─── Das Deck ────────────────────────────────────────────────────────────