Fix dashboard tool cards min-height — cards were collapsing to ~100px

Restored min-height:200px + display:flex on .dashboard-tool-card in CSS,
and removed the conflicting min-height:0 inline overrides on each card div.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-24 16:33:29 +02:00
parent 897771597e
commit f609da6ad7
2 changed files with 70 additions and 165 deletions
+7 -31
View File
@@ -240,14 +240,17 @@ body {
.dashboard-tool-card { .dashboard-tool-card {
position: relative; position: relative;
min-height: 250px; display: flex;
padding: 22px; flex-direction: column;
padding: 18px 20px;
border: 1px solid var(--dbn-line); border: 1px solid var(--dbn-line);
border-radius: 8px; border-radius: 8px;
background: rgba(255, 255, 255, 0.82); background: rgba(255, 255, 255, 0.82);
color: var(--dbn-ink); color: var(--dbn-ink);
text-decoration: none; text-decoration: none;
overflow: hidden; overflow: hidden;
min-height: 200px;
cursor: pointer;
} }
.dashboard-tool-card:hover { .dashboard-tool-card:hover {
@@ -255,37 +258,13 @@ body {
border-color: rgba(186, 12, 47, 0.36); border-color: rgba(186, 12, 47, 0.36);
} }
.dashboard-tool-card__icon {
color: rgba(0, 32, 91, 0.14);
font-size: 4.8rem;
font-weight: 900;
line-height: 1;
}
.dashboard-tool-card__badge {
position: absolute;
top: 20px;
right: 18px;
color: var(--dbn-red);
font-size: 0.75rem;
font-weight: 900;
text-transform: uppercase;
}
.dashboard-tool-card h2 {
margin: 12px 0 8px;
font-size: 1.45rem;
}
.dashboard-tool-card p { .dashboard-tool-card p {
color: #514b43; color: #514b43;
line-height: 1.48; line-height: 1.48;
} }
.dashboard-tool-card strong { .dashboard-tool-card--workbench {
position: absolute; border-color: rgba(0, 32, 91, 0.2);
bottom: 20px;
color: var(--dbn-blue);
} }
.dbn-public-tools { .dbn-public-tools {
@@ -466,9 +445,6 @@ body {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
.dashboard-tool-card {
min-height: 220px;
}
} }
* { * {
+60 -131
View File
@@ -51,6 +51,23 @@ if ($dashIsSso && $dashDetail) {
} }
} }
// Tool emoji icons
$toolEmoji = [
'transcribe' => '🎙️',
'timeline' => '📅',
'redact' => '🔒',
'summarize' => '📝',
'legal-analysis'=> '🏛️',
'korrespond' => '✉️',
'barnevernet' => '🔍',
'advocate' => '⚖️',
'deep-research' => '🔬',
'discrepancy' => '🔎',
'corpus' => '📚',
'citations' => '🔗',
'translate' => '🌐',
];
// Tool → MCP slug // Tool → MCP slug
$toolMcpSlugs = [ $toolMcpSlugs = [
'transcribe' => 'dbn.transcribe_audio', 'transcribe' => 'dbn.transcribe_audio',
@@ -65,11 +82,11 @@ $toolMcpSlugs = [
'citations' => 'dbn.citation_graph', 'citations' => 'dbn.citation_graph',
]; ];
// Tool → About page // Tool → [about, guide, tech] doc page links
$toolAboutPages = [ $toolDocLinks = [
'advocate' => '/advocate-about.php', 'advocate' => ['/advocate-about.php', '/advocate-guide.php', '/advocate-tech.php'],
'timeline' => '/timeline-about.php', 'timeline' => ['/timeline-about.php', '/timeline-guide.php', '/timeline-tech.php'],
'korrespond' => '/korrespond-about.php', 'korrespond' => ['/korrespond-about.php', '/korrespond-guide.php', '/korrespond-tech.php'],
]; ];
// Localized strings for new sections // Localized strings for new sections
@@ -185,55 +202,6 @@ $dashL = [
]; ];
$dl = $dashL[$uiLang] ?? $dashL['en']; $dl = $dashL[$uiLang] ?? $dashL['en'];
// Three flagship tools reference data
$toolRefCards = [
'advocate' => [
'icon' => '⚖️',
'mcp' => 'dbn.advocate_brief',
'about' => '/advocate-about.php',
'guide' => '/advocate-guide.php',
'tech' => '/advocate-tech.php',
'tool' => '/advocate.php',
'name' => ['en' => 'Advocate', 'no' => 'Advokat', 'uk' => 'Адвокат', 'pl' => 'Adwokat'],
'desc' => [
'en' => 'AI-generated partisan brief grounded in Lovdata + ECHR, framed for your party role. 9 role presets, 220 K+ verified legal passages.',
'no' => 'AI-generert partisk prosedyre basert på Lovdata + EMD, formulert for din partsrolle. 9 roller, 220 K+ verifiserte rettskilder.',
'uk' => 'ШІ-стислий виклад позиції на основі Lovdata + ЄСПЛ. 9 ролей, 220 K+ верифікованих правових пасажів.',
'pl' => 'Brief AI oparty na Lovdata + ETPC, z Twojej perspektywy. 9 ról, 220 K+ zweryfikowanych źródeł prawnych.',
],
],
'timeline' => [
'icon' => '📅',
'mcp' => 'dbn.timeline',
'about' => '/timeline-about.php',
'guide' => '/timeline-guide.php',
'tech' => '/timeline-tech.php',
'tool' => '/timeline.php',
'name' => ['en' => 'Timeline', 'no' => 'Tidslinje', 'uk' => 'Хронологія', 'pl' => 'Oś czasu'],
'desc' => [
'en' => 'Extract every key date from case documents into a confidence-scored chronology. Recognises 12+ Norwegian date formats, 5 event types.',
'no' => 'Trekk ut alle viktige datoer til en konfidensscorert kronologi. Gjenkjenner 12+ norske datoformater og 5 hendelsestyper.',
'uk' => 'Витягуйте ключові дати з документів справи. 12+ форматів, 5 типів подій, оцінка достовірності.',
'pl' => 'Wyodrębnij daty z dokumentów sprawy w ocenioną chronologię. 12+ formatów dat, 5 typów zdarzeń.',
],
],
'korrespond' => [
'icon' => '✉️',
'mcp' => 'dbn.korrespond',
'about' => '/korrespond-about.php',
'guide' => '/korrespond-guide.php',
'tech' => '/korrespond-tech.php',
'tool' => '/korrespond.php',
'name' => ['en' => 'Korrespond', 'no' => 'Korrespond', 'uk' => 'Кореспонд', 'pl' => 'Korrespond'],
'desc' => [
'en' => 'Statute-grounded authority letters in Norwegian bokmål + your language, side-by-side. Hard-RAG: every § verified — no hallucinated citations.',
'no' => 'Lovsikre myndighetsbrev på norsk bokmål + ditt språk, side ved side. Hard-RAG: alle §§ verifisert — ingen hallusinerte kilder.',
'uk' => 'Офіційні листи, підкріплені законами, норвезькою та вашою мовою. Hard-RAG: кожен § перевірений.',
'pl' => 'Pisma urzędowe oparte na przepisach, po norwesku i w Twoim języku. Hard-RAG: każdy § zweryfikowany.',
],
],
];
require_once __DIR__ . '/includes/tool-svgs.php'; require_once __DIR__ . '/includes/tool-svgs.php';
$langSuffix = $uiLang !== 'en' ? '?lang=' . urlencode($uiLang) : ''; $langSuffix = $uiLang !== 'en' ? '?lang=' . urlencode($uiLang) : '';
?> ?>
@@ -363,66 +331,61 @@ window.DBN_TOOLS_LANG = <?= json_encode($uiLang, JSON_UNESCAPED_UNICODE) ?>;
<section class="tool-dashboard-grid" aria-label="Available tools"> <section class="tool-dashboard-grid" aria-label="Available tools">
<?php /* Workbench card */ ?> <?php /* Workbench card */ ?>
<?php $wbUrl = htmlspecialchars($workbench['url']); ?>
<div class="dashboard-tool-card dashboard-tool-card--workbench" <div class="dashboard-tool-card dashboard-tool-card--workbench"
style="display:flex; flex-direction:column; cursor:pointer;"
tabindex="0" role="link" tabindex="0" role="link"
onclick="location.href='<?= htmlspecialchars($workbench['url']) ?>'" onclick="location.href='<?= $wbUrl ?>'"
onkeydown="if(event.key==='Enter'||event.key===' ')location.href='<?= htmlspecialchars($workbench['url']) ?>'"> onkeydown="if(event.key==='Enter'||event.key===' ')location.href='<?= $wbUrl ?>'">
<span class="dashboard-tool-card__icon"><?= htmlspecialchars($workbench['icon']) ?></span> <div style="display:flex; align-items:center; gap:.55rem; margin-bottom:.55rem; flex-wrap:wrap;">
<span class="dashboard-tool-card__badge"><?= htmlspecialchars($workbench['badge']) ?></span> <span style="font-size:1.5rem; line-height:1; flex-shrink:0;" aria-hidden="true">🗂️</span>
<h2><?= htmlspecialchars($workbench['label']) ?></h2> <span style="font-size:1rem; font-weight:700; color:#111827; flex:1; min-width:0;"><?= htmlspecialchars($workbench['label']) ?></span>
<p><?= htmlspecialchars($workbench['description']) ?></p> <code onclick="event.stopPropagation();" data-copy-slug="dbn.case_workbench_plan"
title="<?= htmlspecialchars($dl['mcp_copy_slug']) ?>"
style="font-size:.68rem; background:#f1f5f9; border:1px solid #e2e8f0; color:#64748b; padding:1px 7px; border-radius:4px; cursor:pointer; white-space:nowrap; flex-shrink:0;">dbn.case_workbench_plan</code>
</div>
<p style="margin:0; font-size:.84rem; color:#4b5563; line-height:1.5;"><?= htmlspecialchars($workbench['description']) ?></p>
<div class="dash-card-footer"> <div class="dash-card-footer">
<a href="<?= htmlspecialchars($workbench['url']) ?>" <a href="<?= $wbUrl ?>" onclick="event.stopPropagation();"
onclick="event.stopPropagation();" style="margin-left:auto; color:#00205B; font-size:.82rem; font-weight:700; text-decoration:none; white-space:nowrap;">
style="color:#00205B; font-size:.82rem; font-weight:700; text-decoration:none; white-space:nowrap;">
<?= htmlspecialchars(dbnToolsT('enter_workbench', $uiLang)) ?> <?= htmlspecialchars(dbnToolsT('enter_workbench', $uiLang)) ?>
</a> </a>
<button class="dash-mcp-slug-btn" data-slug="dbn.case_workbench_plan"
onclick="event.stopPropagation(); copyDashSlug(this);"
title="<?= htmlspecialchars($dl['mcp_copy_slug']) ?>"
style="margin-left:auto; font-family:monospace; font-size:.69rem; background:#f1f5f9; border:1px solid #e2e8f0; color:#475569; padding:2px 8px; border-radius:4px; cursor:pointer; white-space:nowrap;">
dbn.case_workbench_plan
</button>
</div> </div>
</div> </div>
<?php foreach ($tools as $slug => $item): <?php foreach ($tools as $slug => $item):
$mcpSlug = $toolMcpSlugs[$slug] ?? null; $mcpSlug = $toolMcpSlugs[$slug] ?? null;
$aboutUrl = isset($toolAboutPages[$slug]) ? htmlspecialchars($toolAboutPages[$slug] . $langSuffix) : null; $docs = $toolDocLinks[$slug] ?? null;
$emoji = $toolEmoji[$slug] ?? '🛠️';
$cardUrl = htmlspecialchars($item['url']); $cardUrl = htmlspecialchars($item['url']);
?> ?>
<div class="dashboard-tool-card" <div class="dashboard-tool-card"
style="display:flex; flex-direction:column; cursor:pointer;"
tabindex="0" role="link" tabindex="0" role="link"
onclick="location.href='<?= $cardUrl ?>'" onclick="location.href='<?= $cardUrl ?>'"
onkeydown="if(event.key==='Enter'||event.key===' ')location.href='<?= $cardUrl ?>'"> onkeydown="if(event.key==='Enter'||event.key===' ')location.href='<?= $cardUrl ?>'">
<span class="dashboard-tool-card__icon"><?= htmlspecialchars($item['icon']) ?></span> <div style="display:flex; align-items:center; gap:.55rem; margin-bottom:.55rem; flex-wrap:wrap;">
<span class="dashboard-tool-card__badge"><?= htmlspecialchars($item['badge']) ?></span> <span style="font-size:1.5rem; line-height:1; flex-shrink:0;" aria-hidden="true"><?= $emoji ?></span>
<h2><?= htmlspecialchars($item['label']) ?></h2> <span style="font-size:1rem; font-weight:700; color:#111827; flex:1; min-width:0;"><?= htmlspecialchars($item['label']) ?></span>
<p><?= htmlspecialchars($item['description']) ?></p>
<div class="dash-card-footer">
<a href="<?= $cardUrl ?>"
onclick="event.stopPropagation();"
style="color:#00205B; font-size:.82rem; font-weight:700; text-decoration:none; white-space:nowrap;">
<?= htmlspecialchars(dbnToolsT('open_tool', $uiLang)) ?>
</a>
<?php if ($aboutUrl): ?>
<a href="<?= $aboutUrl ?>"
onclick="event.stopPropagation();"
style="color:#6b7280; font-size:.78rem; text-decoration:none; white-space:nowrap;">
<?= htmlspecialchars($dl['about_link']) ?>
</a>
<?php endif; ?>
<?php if ($mcpSlug): ?> <?php if ($mcpSlug): ?>
<button class="dash-mcp-slug-btn" data-slug="<?= htmlspecialchars($mcpSlug) ?>" <code onclick="event.stopPropagation();" data-copy-slug="<?= htmlspecialchars($mcpSlug) ?>"
onclick="event.stopPropagation(); copyDashSlug(this);"
title="<?= htmlspecialchars($dl['mcp_copy_slug']) ?>" title="<?= htmlspecialchars($dl['mcp_copy_slug']) ?>"
style="margin-left:auto; font-family:monospace; font-size:.69rem; background:#f1f5f9; border:1px solid #e2e8f0; color:#475569; padding:2px 8px; border-radius:4px; cursor:pointer; white-space:nowrap;"> style="font-size:.68rem; background:#f1f5f9; border:1px solid #e2e8f0; color:#64748b; padding:1px 7px; border-radius:4px; cursor:pointer; white-space:nowrap; flex-shrink:0;"><?= htmlspecialchars($mcpSlug) ?></code>
<?= htmlspecialchars($mcpSlug) ?>
</button>
<?php endif; ?> <?php endif; ?>
</div> </div>
<p style="margin:0; font-size:.84rem; color:#4b5563; line-height:1.5;"><?= htmlspecialchars($item['description']) ?></p>
<div class="dash-card-footer">
<?php if ($docs): ?>
<a href="<?= htmlspecialchars($docs[0] . $langSuffix) ?>" onclick="event.stopPropagation();"
style="color:#00205B; font-size:.78rem; font-weight:600; text-decoration:none; white-space:nowrap;"><?= htmlspecialchars($dl['about_link']) ?></a>
<span style="color:#d1d5db;" aria-hidden="true">·</span>
<a href="<?= htmlspecialchars($docs[1] . $langSuffix) ?>" onclick="event.stopPropagation();"
style="color:#374151; font-size:.78rem; text-decoration:none; white-space:nowrap;"><?= htmlspecialchars($dl['guide_link']) ?></a>
<span style="color:#d1d5db;" aria-hidden="true">·</span>
<a href="<?= htmlspecialchars($docs[2] . $langSuffix) ?>" onclick="event.stopPropagation();"
style="color:#374151; font-size:.78rem; text-decoration:none; white-space:nowrap;"><?= htmlspecialchars($dl['tech_link']) ?></a>
<?php endif; ?>
<a href="<?= $cardUrl ?>" onclick="event.stopPropagation();"
style="margin-left:auto; color:#00205B; font-size:.82rem; font-weight:700; text-decoration:none; white-space:nowrap;"><?= htmlspecialchars($dl['open_tool']) ?> →</a>
</div>
</div> </div>
<?php endforeach; ?> <?php endforeach; ?>
@@ -478,41 +441,6 @@ Authorization: Bearer <span id="dashRemoteToken" style="color:#86efac;">dbn_user
</div> </div>
</details> </details>
<!-- ── Tool reference cards ─────────────────────────────────────── -->
<section style="margin:0 0 2rem;" aria-label="Tool reference">
<div style="display:flex; align-items:baseline; gap:.75rem; margin-bottom:1rem; flex-wrap:wrap;">
<h2 style="margin:0; font-family:'Crimson Pro',serif; font-size:1.55rem; color:#111827; line-height:1.1;"><?= htmlspecialchars($dl['tool_ref_title']) ?></h2>
<p style="margin:0; color:#6b7280; font-size:.85rem;"><?= htmlspecialchars($dl['tool_ref_sub']) ?></p>
</div>
<div style="display:grid; grid-template-columns:repeat(auto-fit, minmax(270px, 1fr)); gap:1rem;">
<?php foreach ($toolRefCards as $refSlug => $ref):
$refName = $ref['name'][$uiLang] ?? $ref['name']['en'];
$refDesc = $ref['desc'][$uiLang] ?? $ref['desc']['en'];
?>
<div style="background:#fff; border:1px solid #e5e7eb; border-radius:10px; padding:1.1rem 1.25rem; display:flex; flex-direction:column;">
<div style="display:flex; align-items:center; gap:.6rem; margin-bottom:.6rem;">
<span style="font-size:1.4rem; line-height:1;" aria-hidden="true"><?= $ref['icon'] ?></span>
<strong style="font-size:1rem; color:#111827;"><?= htmlspecialchars($refName) ?></strong>
<code data-copy-slug="<?= htmlspecialchars($ref['mcp']) ?>"
title="<?= htmlspecialchars($dl['mcp_copy_slug']) ?>"
style="margin-left:auto; font-size:.68rem; background:#f1f5f9; border:1px solid #e2e8f0; color:#64748b; padding:1px 7px; border-radius:4px; cursor:pointer; white-space:nowrap; flex-shrink:0;">
<?= htmlspecialchars($ref['mcp']) ?>
</code>
</div>
<p style="margin:0 0 .8rem; font-size:.84rem; color:#4b5563; line-height:1.55; flex:1;"><?= htmlspecialchars($refDesc) ?></p>
<div style="display:flex; align-items:center; gap:.4rem; flex-wrap:wrap; font-size:.78rem; border-top:1px solid #f3f4f6; padding-top:.6rem;">
<a href="<?= htmlspecialchars($ref['about'] . $langSuffix) ?>" style="color:#00205B; text-decoration:none; font-weight:600;"><?= htmlspecialchars($dl['about_link']) ?></a>
<span style="color:#d1d5db;">·</span>
<a href="<?= htmlspecialchars($ref['guide'] . $langSuffix) ?>" style="color:#374151; text-decoration:none;"><?= htmlspecialchars($dl['guide_link']) ?></a>
<span style="color:#d1d5db;">·</span>
<a href="<?= htmlspecialchars($ref['tech'] . $langSuffix) ?>" style="color:#374151; text-decoration:none;"><?= htmlspecialchars($dl['tech_link']) ?></a>
<a href="<?= htmlspecialchars($ref['tool']) ?>" style="margin-left:auto; color:#00205B; font-weight:600; text-decoration:none;"><?= htmlspecialchars($dl['open_tool']) ?> →</a>
</div>
</div>
<?php endforeach; ?>
</div>
</section>
<!-- ── Welcome modal ────────────────────────────────────────────── --> <!-- ── Welcome modal ────────────────────────────────────────────── -->
<div id="welcomeModal" class="wlc-backdrop" role="dialog" aria-modal="true" aria-labelledby="wlcTitle" hidden> <div id="welcomeModal" class="wlc-backdrop" role="dialog" aria-modal="true" aria-labelledby="wlcTitle" hidden>
<div class="wlc-card"> <div class="wlc-card">
@@ -696,9 +624,10 @@ foreach ($tools as $slug => $item):
}).catch(function () {}); }).catch(function () {});
}; };
/* copy MCP slug from tool reference cards */ /* copy MCP slug from tool cards */
document.querySelectorAll('[data-copy-slug]').forEach(function (el) { document.querySelectorAll('[data-copy-slug]').forEach(function (el) {
el.addEventListener('click', function () { el.addEventListener('click', function (e) {
e.stopPropagation();
var slug = el.getAttribute('data-copy-slug'); var slug = el.getAttribute('data-copy-slug');
if (!slug) return; if (!slug) return;
navigator.clipboard.writeText(slug).then(function () { navigator.clipboard.writeText(slug).then(function () {