diff --git a/partials/landing/main/material-matrix.php b/partials/landing/main/material-matrix.php
index 36263f5..3362985 100644
--- a/partials/landing/main/material-matrix.php
+++ b/partials/landing/main/material-matrix.php
@@ -52,6 +52,8 @@ $app->assets()->addScript('/assets/app.js', 'footer', true);
+
diff --git a/public/assets/app.css b/public/assets/app.css
index c584e42..27b0629 100644
--- a/public/assets/app.css
+++ b/public/assets/app.css
@@ -28,9 +28,9 @@
}
.mm-shell {
- max-width: 1200px;
+ max-width: 1500px;
margin: 0 auto;
- padding: 3rem 2rem 4rem;
+ padding: 2.5rem 1.5rem 4rem;
animation: fadeUp 0.6s ease both;
}
@@ -161,8 +161,81 @@
vertical-align: top;
}
-.mm-table tbody td[title] {
- cursor: help;
+
+.mm-info-btn {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.35rem;
+ font-size: 0.7rem;
+ font-weight: 600;
+ border-radius: 999px;
+ border: 1px solid var(--line);
+ background: #fff7ed;
+ color: #9a3412;
+ padding: 0.15rem 0.5rem;
+ margin-top: 0.3rem;
+}
+
+.mm-tooltip {
+ position: fixed;
+ z-index: 50;
+ max-width: 280px;
+ background: #101018;
+ color: #f4f4f7;
+ border-radius: 12px;
+ padding: 0.6rem 0.75rem;
+ box-shadow: 0 16px 40px rgba(0, 0, 0, 0.25);
+ font-size: 0.75rem;
+ line-height: 1.35;
+ pointer-events: none;
+ opacity: 0;
+ transform: translateY(6px);
+ transition: opacity 0.12s ease, transform 0.12s ease;
+}
+
+.mm-tooltip.is-visible {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+.mm-details-row {
+ background: #fffaf3;
+}
+
+.mm-details {
+ padding: 0.9rem 1rem;
+ border-left: 3px solid var(--accent);
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
+ gap: 0.6rem 1rem;
+ font-size: 0.85rem;
+ color: var(--muted);
+ position: relative;
+}
+
+.mm-details strong {
+ color: var(--ink);
+ display: block;
+ font-size: 0.75rem;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+}
+
+.mm-row-toggle {
+ cursor: pointer;
+}
+
+.mm-details-close {
+ position: absolute;
+ top: 0.6rem;
+ right: 0.8rem;
+ border: 1px solid var(--line);
+ background: #fff;
+ border-radius: 999px;
+ padding: 0.2rem 0.6rem;
+ font-size: 0.7rem;
+ color: var(--muted);
+ cursor: pointer;
}
.mm-table tbody tr:nth-child(even) {
diff --git a/public/assets/app.js b/public/assets/app.js
index 41f471f..9905be2 100644
--- a/public/assets/app.js
+++ b/public/assets/app.js
@@ -6,6 +6,7 @@
const tableHead = document.getElementById('tableHead');
const statusEl = document.getElementById('status');
const errorBox = document.getElementById('errorBox');
+ const tooltipEl = document.getElementById('mmTooltip');
if (!printerSelect || !printerCompare || !matBody || !tableHead) {
return;
@@ -142,17 +143,20 @@
? { icon: '✅', text: 'niedrig' }
: (m.emission === 'medium' ? { icon: '⚠️', text: 'mittel' } : { icon: '⛔', text: 'hoch' });
- const tooltipLines = [
- m.tg_celsius ? `Tg °C: ${m.tg_celsius}` : 'Tg °C: –',
- m.nozzle_req ? `Düse: ${m.nozzle_req}` : 'Düse: –',
- m.plate_req ? `Platte: ${m.plate_req}` : 'Platte: –',
- m.extra_req ? `Zusatz: ${m.extra_req}` : 'Zusatz: –',
- m.emission ? `Emission: ${m.emission}` : 'Emission: –'
- ];
- const tooltip = escapeHtml(tooltipLines.join(' | '));
-
let html = '';
- html += `${escapeHtml(m.code)} ${escapeHtml(m.short_desc || '')} | `;
+ const detailPayload = {
+ tg: m.tg_celsius ?? '–',
+ nozzle: m.nozzle_req ?? '–',
+ plate: m.plate_req ?? '–',
+ extra: m.extra_req ?? '–',
+ emission: m.emission ?? '–'
+ };
+ const detailAttr = escapeHtml(JSON.stringify(detailPayload));
+ html += `` +
+ `${escapeHtml(m.code)}` +
+ ` ${escapeHtml(m.short_desc || '')} ` +
+ `` +
+ ` | `;
html += `${escapeHtml(m.properties || '')} | `;
html += `${escapeHtml(m.application || '')} | `;
html += `${kid.icon} | `;
@@ -186,6 +190,101 @@
});
}
+ function setTooltip(content, x, y) {
+ if (!tooltipEl) return;
+ tooltipEl.textContent = content;
+ const padding = 12;
+ const maxX = window.innerWidth - tooltipEl.offsetWidth - padding;
+ const maxY = window.innerHeight - tooltipEl.offsetHeight - padding;
+ const left = Math.min(x + 14, maxX);
+ const top = Math.min(y + 14, maxY);
+ tooltipEl.style.left = Math.max(left, padding) + 'px';
+ tooltipEl.style.top = Math.max(top, padding) + 'px';
+ tooltipEl.classList.add('is-visible');
+ tooltipEl.setAttribute('aria-hidden', 'false');
+ }
+
+ function hideTooltip() {
+ if (!tooltipEl) return;
+ tooltipEl.classList.remove('is-visible');
+ tooltipEl.setAttribute('aria-hidden', 'true');
+ }
+
+ function buildDetailsHtml(details) {
+ return `
+
+ Tg °C${escapeHtml(details.tg)}
+ Düse${escapeHtml(details.nozzle)}
+ Platte${escapeHtml(details.plate)}
+ Zusatz${escapeHtml(details.extra)}
+ Emission${escapeHtml(details.emission)}
+ `;
+ }
+
+ function closeActiveDetails() {
+ const open = matBody.querySelector('tr.mm-details-row');
+ if (open) {
+ open.remove();
+ }
+ const active = matBody.querySelector('tr.is-active');
+ if (active) {
+ active.classList.remove('is-active');
+ }
+ }
+
+ matBody.addEventListener('mouseover', (e) => {
+ const cell = e.target.closest('[data-details]');
+ if (!cell) return;
+ let details;
+ try {
+ details = JSON.parse(cell.dataset.details || '{}');
+ } catch {
+ details = {};
+ }
+ const hoverText = `Tg °C: ${details.tg ?? '–'} | Düse: ${details.nozzle ?? '–'} | Platte: ${details.plate ?? '–'} | Zusatz: ${details.extra ?? '–'} | Emission: ${details.emission ?? '–'}`;
+ setTooltip(hoverText, e.clientX, e.clientY);
+ });
+
+ matBody.addEventListener('mousemove', (e) => {
+ if (!tooltipEl || tooltipEl.getAttribute('aria-hidden') === 'true') return;
+ setTooltip(tooltipEl.textContent, e.clientX, e.clientY);
+ });
+
+ matBody.addEventListener('mouseout', (e) => {
+ if (e.target.closest('[data-details]')) {
+ hideTooltip();
+ }
+ });
+
+ matBody.addEventListener('click', (e) => {
+ if (e.target.closest('.mm-details-close')) {
+ closeActiveDetails();
+ return;
+ }
+
+ const cell = e.target.closest('[data-details]');
+ if (!cell) return;
+
+ const row = cell.closest('tr');
+ const isActive = row.classList.contains('is-active');
+ closeActiveDetails();
+ if (isActive) return;
+
+ let details;
+ try {
+ details = JSON.parse(cell.dataset.details || '{}');
+ } catch {
+ details = {};
+ }
+
+ const colCount = row.children.length;
+ const detailRow = document.createElement('tr');
+ detailRow.className = 'mm-details-row';
+ detailRow.innerHTML = `${buildDetailsHtml(details)} | `;
+ row.classList.add('is-active');
+ row.parentNode.insertBefore(detailRow, row.nextSibling);
+ });
+
printerSelect.addEventListener('change', e => {
const id = e.target.value;
if (id) {