OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

company.php

46 KB
<?php
// ── Kosten-Zusammenfassung berechnen ────────────────────────────────────────
$totalMonthlyGross = 0.0;
$totalMonthlyNet   = 0.0;
$hasTax            = false;
$activeCount       = 0;
$expiringCount     = 0;
$expiredCount      = 0;
$cancelledCount    = 0;
$futureCount       = 0;

foreach ($contracts as $c) {
    switch ($c['status']) {
        case 'active':    $activeCount++;    break;
        case 'expiring':  $expiringCount++;  break;
        case 'expired':   $expiredCount++;   break;
        case 'cancelled': $cancelledCount++; break;
        case 'future':    $futureCount++;    break;
    }

    if (!in_array($c['status'], ['active', 'expiring'])) continue;
    if (empty($c['cost_amount']) || (float)$c['cost_amount'] <= 0) continue;

    $amount  = (float)$c['cost_amount'];
    if (($c['cost_interval'] ?? 'monthly') === 'one_time') continue;
    $monthly = match($c['cost_interval'] ?? 'monthly') {
        'yearly'    => $amount / 12,
        'quarterly' => $amount / 3,
        default     => $amount,
    };
    $totalMonthlyGross += $monthly;

    $rate = !empty($c['tax_rate']) ? (float)$c['tax_rate'] : 0.0;
    if ($rate > 0) {
        $hasTax = true;
        $totalMonthlyNet += $monthly / (1 + $rate / 100);
    } else {
        $totalMonthlyNet += $monthly;
    }
}

$totalYearlyGross = $totalMonthlyGross * 12;
$totalYearlyNet   = $totalMonthlyNet   * 12;

$this->layout('layouts/main', [
    'page_title'    => $company['name'] . ' – Verträge',
    'current_route' => 'contracts',
    'full_width'    => true,
    'breadcrumbs'   => [],
]);

require_once dirname(__DIR__) . '/partials/_attachment_helpers.php';
?>

<div class="cc-fullwidth">

    <!-- Content Header -->
    <div class="content-header">
        <div>
            <h1><?= $this->e($company['name']) ?></h1>
            <ol class="breadcrumb">
                <li class="breadcrumb-item"><a href="/"><?= $this->te('Home') ?></a></li>
                <li class="breadcrumb-item"><a href="/contracts"><?= $this->te('Verträge') ?></a></li>
                <li class="breadcrumb-item active"><?= $this->e($company['name']) ?></li>
            </ol>
        </div>
        <div class="content-header-actions">
            <a href="/contacts/companies/<?= $company['id'] ?>" class="btn btn-default"><?= $this->te('Im Adressbuch') ?></a>
            <?php if ($can_manage): ?>
            <a href="/contracts/create?company_id=<?= $company['id'] ?>" class="btn btn-primary"><?= $this->te('Neuer Vertrag') ?></a>
            <?php endif; ?>
        </div>
    </div>

    <!-- ── Body ─────────────────────────────────────────────────────── -->
    <div class="cc-body">
        <!-- KPI Small Boxes -->
        <?php if ($totalMonthlyGross > 0): ?>
        <div class="kpi-row">
            <div class="kpi-col">
                <div class="small-box bg-info">
                    <div class="inner">
                        <h3><?= $this->money($totalMonthlyGross, 2) ?></h3>
                        <p><?= $this->te('Monatlich (brutto)') ?></p>
                    </div>
                    <div class="icon"><i class="fas fa-euro-sign"></i></div>
                </div>
            </div>
            <div class="kpi-col">
                <div class="small-box bg-primary">
                    <div class="inner">
                        <h3><?= $this->money($totalYearlyGross, 2) ?></h3>
                        <p><?= $this->te('Jährlich (brutto)') ?></p>
                    </div>
                    <div class="icon"><i class="fas fa-calendar-alt"></i></div>
                </div>
            </div>
            <div class="kpi-col">
                <div class="small-box bg-success">
                    <div class="inner">
                        <h3><?= $activeCount + $expiringCount ?></h3>
                        <p><?= $this->te('Aktive Verträge') ?></p>
                    </div>
                    <div class="icon"><i class="fas fa-file-contract"></i></div>
                </div>
            </div>
            <?php if ($expiringCount > 0): ?>
            <div class="kpi-col">
                <div class="small-box bg-warning">
                    <div class="inner">
                        <h3><?= $expiringCount ?></h3>
                        <p><?= $this->te('Kündigung / Läuft aus') ?></p>
                    </div>
                    <div class="icon"><i class="fas fa-exclamation-triangle"></i></div>
                </div>
            </div>
            <?php elseif ($expiredCount + $cancelledCount > 0): ?>
            <div class="kpi-col">
                <div class="small-box bg-secondary">
                    <div class="inner">
                        <h3><?= $expiredCount + $cancelledCount ?></h3>
                        <p><?= $this->te('Inaktiv / Gekündigt') ?></p>
                    </div>
                    <div class="icon"><i class="fas fa-times-circle"></i></div>
                </div>
            </div>
            <?php endif; ?>
        </div>
        <?php endif; ?>
        <div class="cc-layout">

            <!-- ── Hauptspalte ───────────────────────────────────────── -->
            <main class="cc-main">

                <!-- Verträge -->
                <div class="cc-card">
                    <div class="cc-card-head">
                        <h2 class="cc-section-title">
                            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>
                            <?= $this->te('Verträge') ?>
                        </h2>
                        <span class="cc-count-badge"><?= count($contracts) ?></span>
                    </div>

                    <?php if (empty($contracts)): ?>
                        <div class="cc-empty-state">
                            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" width="44" height="44"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
                            <p><?= $this->te('Keine Verträge für diese Firma vorhanden.') ?></p>
                            <?php if ($can_manage): ?>
                                <a href="/contracts/create?company_id=<?= $company['id'] ?>" class="btn btn-primary btn-sm"><?= $this->te('Ersten Vertrag erstellen') ?></a>
                            <?php endif; ?>
                        </div>
                    <?php else: ?>
                        <div class="cc-contract-list">
                            <?php foreach ($contracts as $c):
                                $amount  = !empty($c['cost_amount']) ? (float)$c['cost_amount'] : null;
                                $monthly = null;
                                if ($amount !== null && ($c['cost_interval'] ?? 'monthly') !== 'one_time') {
                                    $monthly = match($c['cost_interval'] ?? 'monthly') {
                                        'yearly'    => $amount / 12,
                                        'quarterly' => $amount / 3,
                                        default     => $amount,
                                    };
                                }
                                $hasCancellation = !empty($c['cancellation_notice_date'])
                                    && strtotime($c['cancellation_notice_date']) > time();
                            ?>
                            <a href="/contracts/<?= $c['id'] ?>" class="cc-contract-row cc-contract-row--<?= $this->e($c['status']) ?>">
                                <div class="cc-contract-row-left">
                                    <?php $ccPill = ['active'=>'status-pill--success','expiring'=>'status-pill--warning','expired'=>'status-pill--danger','cancelled'=>'status-pill--neutral','future'=>'status-pill--purple']; ?>
                                    <span class="status-pill <?= $ccPill[$c['status']] ?? 'status-pill--neutral' ?>" style="flex-shrink:0;margin-top:0.1rem;">
                                        <?php
                                        if ($c['status'] === 'expiring' && empty($c['auto_renew']) && empty($c['cancellation_notice_date'])) {
                                            echo 'Läuft aus';
                                        } else {
                                            echo match($c['status']) {
                                                'active'    => 'Aktiv',
                                                'expiring'  => 'Kündigung beachten',
                                                'expired'   => 'Abgelaufen',
                                                'cancelled' => 'Gekündigt',
                                                'future'    => 'Zukünftig',
                                                default     => $c['status']
                                            };
                                        }
                                        ?>
                                    </span>
                                    <div class="cc-contract-info">
                                        <span class="cc-contract-title"><?= $this->e($c['title']) ?></span>
                                        <span class="cc-contract-sub">
                                            <?php if (!empty($c['contract_number'])): ?>
                                                <?= $this->te('Nr. {nummer}', ['nummer' => $c['contract_number']]) ?>
                                                <?php if (!empty($c['start_date']) || !empty($c['end_date'])): ?> &middot; <?php endif; ?>
                                            <?php endif; ?>
                                            <?php if (!empty($c['start_date'])): ?>
                                                <?= date('d.m.Y', strtotime($c['start_date'])) ?>
                                            <?php endif; ?>
                                            <?php if (!empty($c['start_date']) && !empty($c['end_date'])): ?> – <?php endif; ?>
                                            <?php if (!empty($c['end_date'])): ?>
                                                <?= date('d.m.Y', strtotime($c['end_date'])) ?>
                                            <?php elseif (!empty($c['start_date'])): ?>
                                                <?= $this->te('– unbefristet') ?>
                                            <?php endif; ?>
                                        </span>
                                        <?php if ($hasCancellation): ?>
                                            <span class="cc-contract-warn">
                                                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="11" height="11"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
                                                Kündigen bis <?= date('d.m.Y', strtotime($c['cancellation_notice_date'])) ?>
                                            </span>
                                        <?php endif; ?>
                                    </div>
                                </div>

                                <div class="cc-contract-row-right">
                                    <?php if ($amount !== null && ($c['cost_interval'] ?? 'monthly') === 'one_time'): ?>
                                        <div class="cc-cost-display">
                                            <span class="cc-cost-monthly"><?= $this->money($amount, 2) ?><span class="cc-cost-period"> <?= $this->te('einmalig') ?></span></span>
                                        </div>
                                    <?php elseif ($monthly !== null): ?>
                                        <div class="cc-cost-display">
                                            <span class="cc-cost-monthly"><?= $this->money($monthly, 2) ?><span class="cc-cost-period"><?= $this->te('/Mo.') ?></span></span>
                                            <span class="cc-cost-yearly"><?= $this->te('{betrag}/Jahr', ['betrag' => $this->money($monthly * 12, 2)]) ?></span>
                                        </div>
                                    <?php else: ?>
                                        <span class="cc-cost-none">–</span>
                                    <?php endif; ?>
                                    <?php if ((int)$c['file_count'] > 0): ?>
                                        <span class="cc-file-badge" title="<?= $this->te((int)$c['file_count'] === 1 ? '{anzahl} Dokument' : '{anzahl} Dokumente', ['anzahl' => (int)$c['file_count']]) ?>">
                                            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="12" height="12"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
                                            <?= $c['file_count'] ?>
                                        </span>
                                    <?php endif; ?>
                                    <svg class="cc-row-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><polyline points="9 18 15 12 9 6"/></svg>
                                </div>
                            </a>
                            <?php endforeach; ?>
                        </div>
                    <?php endif; ?>
                </div>

                <!-- Firmendokumente + Angebote untereinander -->

                <!-- Firmendokumente -->
                <div class="cc-card">
                    <div class="cc-card-head">
                        <h2 class="cc-section-title">
                            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
                            <?= $this->te('Firmendokumente') ?>
                        </h2>
                        <span class="cc-count-badge"><?= count($company_files) ?></span>
                    </div>

                    <?php if ($can_manage): ?>
                    <form action="/contracts/company/<?= $company['id'] ?>/files" method="POST" enctype="multipart/form-data" class="cc-upload-form">
                        <input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">
                        <input type="hidden" name="file_type" value="document">
                        <label class="cc-upload-label" for="ccFileInput">
                            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
                            <span id="ccFileName"><?= $this->te('Datei auswählen&hellip;') ?></span>
                        </label>
                        <input type="file" name="file" id="ccFileInput" class="cc-upload-hidden" accept=".pdf,.doc,.docx,.xls,.xlsx,.odt,.ods,.png,.jpg,.jpeg,.gif,.webp,.tif,.tiff,.txt,.csv,.eml,.msg,.zip" required>
                        <button type="submit" class="btn btn-primary btn-sm"><?= $this->te('Hochladen') ?></button>
                    </form>
                    <script>
                    document.getElementById('ccFileInput').addEventListener('change', function () {
                        var el = document.getElementById('ccFileName');
                        el.textContent = this.files[0] ? this.files[0].name : 'Datei auswählen\u2026';
                        el.style.color = this.files[0] ? '#111827' : '';
                        el.style.fontWeight = this.files[0] ? '500' : '';
                    });
                    </script>
                    <?php endif; ?>

                    <?php if (empty($company_files)): ?>
                        <p class="cc-muted"><?= $this->te('Keine Firmendokumente vorhanden.') ?></p>
                    <?php else: ?>
                        <div class="cc-file-list">
                            <?php foreach ($company_files as $f):
                                $ext = strtolower(pathinfo($f['original_filename'], PATHINFO_EXTENSION));
                                $extColors = ['pdf'=>['#dc2626','#fee2e2'],'doc'=>['#2563eb','#dbeafe'],'docx'=>['#2563eb','#dbeafe'],'xls'=>['#16a34a','#dcfce7'],'xlsx'=>['#16a34a','#dcfce7'],'zip'=>['#d97706','#fef3c7'],'rar'=>['#d97706','#fef3c7'],'png'=>['#7c3aed','#f3e8ff'],'jpg'=>['#7c3aed','#f3e8ff'],'jpeg'=>['#7c3aed','#f3e8ff'],'gif'=>['#7c3aed','#f3e8ff']];
                                [$extColor, $extBg] = $extColors[$ext] ?? ['#6b7280', '#f3f4f6'];
                            ?>
                            <div class="cc-file-row">
                                <div class="cc-file-icon" style="background:<?= $extBg ?>;color:<?= $extColor ?>">
                                    <?= strtoupper($ext ?: '?') ?>
                                </div>
                                <div class="cc-file-info">
                                    <span class="cc-file-name"><?= $this->e($f['original_filename']) ?></span>
                                    <span class="cc-file-meta"><?= $this->formatFileSize((int)$f['file_size']) ?> &middot; <?= $this->relativeTime($f['created_at']) ?></span>
                                </div>
                                <div class="cc-file-actions">
                                    <?= att_view_link('/contracts/company-files/' . $f['id'] . '/view', $f['original_filename'], $f['mime_type'] ?? '', 'cc-icon-btn') ?>
                                    <a href="/contracts/company-files/<?= $f['id'] ?>/download" class="cc-icon-btn" title="<?= $this->te('Herunterladen') ?>">
                                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
                                    </a>
                                    <?php if ($can_manage): ?>
                                    <form action="/contracts/company-files/<?= $f['id'] ?>" method="POST" onsubmit="return confirm('Datei löschen?');" style="display:inline">
                                        <input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">
                                        <input type="hidden" name="_method" value="DELETE">
                                        <button type="submit" class="cc-icon-btn cc-icon-btn-danger" title="<?= $this->te('Löschen') ?>">
                                            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/></svg>
                                        </button>
                                    </form>
                                    <?php endif; ?>
                                </div>
                            </div>
                            <?php endforeach; ?>
                        </div>
                    <?php endif; ?>
                </div>

                <!-- Angebote -->
                <?php $companyQuotes = $company_quotes ?? []; ?>
                <div class="cc-card">
                    <div class="cc-card-head">
                        <h2 class="cc-section-title">
                            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
                            <?= $this->te('Angebote') ?>
                        </h2>
                        <span class="cc-count-badge"><?= count($companyQuotes) ?></span>
                    </div>

                    <?php if ($can_manage): ?>
                    <form action="/contracts/company/<?= $company['id'] ?>/files" method="POST" enctype="multipart/form-data" class="cc-upload-form">
                        <input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">
                        <input type="hidden" name="file_type" value="quote">
                        <label class="cc-upload-label" for="ccQuoteInput">
                            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
                            <span id="ccQuoteName"><?= $this->te('Datei auswählen&hellip;') ?></span>
                        </label>
                        <input type="file" name="file" id="ccQuoteInput" class="cc-upload-hidden" accept=".pdf,.doc,.docx,.xls,.xlsx,.odt,.ods,.png,.jpg,.jpeg,.gif,.webp,.tif,.tiff,.txt,.csv,.eml,.msg,.zip" required>
                        <button type="submit" class="btn btn-primary btn-sm"><?= $this->te('Hochladen') ?></button>
                    </form>
                    <script>
                    document.getElementById('ccQuoteInput').addEventListener('change', function () {
                        var el = document.getElementById('ccQuoteName');
                        el.textContent = this.files[0] ? this.files[0].name : 'Datei auswählen\u2026';
                        el.style.color = this.files[0] ? '#111827' : '';
                        el.style.fontWeight = this.files[0] ? '500' : '';
                    });
                    </script>
                    <?php endif; ?>

                    <?php if (empty($companyQuotes)): ?>
                        <p class="cc-muted"><?= $this->te('Keine Angebote vorhanden.') ?></p>
                    <?php else: ?>
                        <div class="cc-file-list">
                            <?php foreach ($companyQuotes as $f):
                                $ext = strtolower(pathinfo($f['original_filename'], PATHINFO_EXTENSION));
                                $extColors = ['pdf'=>['#dc2626','#fee2e2'],'doc'=>['#2563eb','#dbeafe'],'docx'=>['#2563eb','#dbeafe'],'xls'=>['#16a34a','#dcfce7'],'xlsx'=>['#16a34a','#dcfce7'],'zip'=>['#d97706','#fef3c7'],'rar'=>['#d97706','#fef3c7'],'png'=>['#7c3aed','#f3e8ff'],'jpg'=>['#7c3aed','#f3e8ff'],'jpeg'=>['#7c3aed','#f3e8ff'],'gif'=>['#7c3aed','#f3e8ff']];
                                [$extColor, $extBg] = $extColors[$ext] ?? ['#6b7280', '#f3f4f6'];
                            ?>
                            <div class="cc-file-row">
                                <div class="cc-file-icon" style="background:<?= $extBg ?>;color:<?= $extColor ?>">
                                    <?= strtoupper($ext ?: '?') ?>
                                </div>
                                <div class="cc-file-info">
                                    <span class="cc-file-name"><?= $this->e($f['original_filename']) ?></span>
                                    <span class="cc-file-meta"><?= $this->formatFileSize((int)$f['file_size']) ?> &middot; <?= $this->relativeTime($f['created_at']) ?></span>
                                </div>
                                <div class="cc-file-actions">
                                    <?= att_view_link('/contracts/company-files/' . $f['id'] . '/view', $f['original_filename'], $f['mime_type'] ?? '', 'cc-icon-btn') ?>
                                    <a href="/contracts/company-files/<?= $f['id'] ?>/download" class="cc-icon-btn" title="<?= $this->te('Herunterladen') ?>">
                                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
                                    </a>
                                    <?php if ($can_manage): ?>
                                    <form action="/contracts/company-files/<?= $f['id'] ?>" method="POST" onsubmit="return confirm('Angebot löschen?');" style="display:inline">
                                        <input type="hidden" name="_csrf" value="<?= $this->csrf() ?>">
                                        <input type="hidden" name="_method" value="DELETE">
                                        <button type="submit" class="cc-icon-btn cc-icon-btn-danger" title="<?= $this->te('Löschen') ?>">
                                            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/></svg>
                                        </button>
                                    </form>
                                    <?php endif; ?>
                                </div>
                            </div>
                            <?php endforeach; ?>
                        </div>
                    <?php endif; ?>
                </div>


            </main>

            <!-- ── Sidebar ────────────────────────────────────────────── -->
            <aside class="cc-sidebar">

                <!-- Kosten-Übersicht (nur wenn Verträge mit Kosten vorhanden) -->
                <?php if ($totalMonthlyGross > 0): ?>
                <div class="cc-sidebar-card cc-sidebar-card-costs">
                    <h3 class="cc-sidebar-title">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>
                        <?= $this->te('Gesamtkosten (aktiv)') ?>
                    </h3>
                    <div class="cc-cost-tiles">
                        <div class="cc-cost-tile cc-cost-tile-blue">
                            <span class="cc-tile-label"><?= $this->te('Monatlich brutto') ?></span>
                            <span class="cc-tile-value"><?= $this->money($totalMonthlyGross, 2) ?></span>
                        </div>
                        <div class="cc-cost-tile cc-cost-tile-indigo">
                            <span class="cc-tile-label"><?= $this->te('Jährlich brutto') ?></span>
                            <span class="cc-tile-value"><?= $this->money($totalYearlyGross, 2) ?></span>
                        </div>
                        <?php if ($hasTax): ?>
                        <div class="cc-cost-tile cc-cost-tile-green">
                            <span class="cc-tile-label"><?= $this->te('Monatlich netto') ?></span>
                            <span class="cc-tile-value"><?= $this->money($totalMonthlyNet, 2) ?></span>
                        </div>
                        <div class="cc-cost-tile cc-cost-tile-teal">
                            <span class="cc-tile-label"><?= $this->te('Jährlich netto') ?></span>
                            <span class="cc-tile-value"><?= $this->money($totalYearlyNet, 2) ?></span>
                        </div>
                        <?php endif; ?>
                    </div>
                    <p class="cc-cost-note">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="11" height="11"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
                        <?= $this->te('Nur aktive und ablaufende Verträge') ?>
                    </p>
                </div>
                <?php endif; ?>

                <!-- Firmenkontaktdaten -->
                <div class="cc-sidebar-card">
                    <h3 class="cc-sidebar-title">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15"><path d="M3 21h18"/><path d="M5 21V7l8-4v18"/><path d="M19 21V11l-6-4"/></svg>
                        <?= $this->te('Firmendaten') ?>
                    </h3>
                    <dl class="cc-detail-list">
                        <?php if (!empty($company['phone'])): ?>
                        <dt><?= $this->te('Telefon') ?></dt>
                        <dd><a href="tel:<?= $this->e($company['phone']) ?>" class="cc-link"><?= $this->e($company['phone']) ?></a></dd>
                        <?php endif; ?>
                        <?php if (!empty($company['email'])): ?>
                        <dt><?= $this->t('E-Mail') ?></dt>
                        <dd><a href="mailto:<?= $this->e($company['email']) ?>" class="cc-link"><?= $this->e($company['email']) ?></a></dd>
                        <?php endif; ?>
                        <?php if (!empty($company['website'])): ?>
                        <dt><?= $this->te('Website') ?></dt>
                        <dd>
                            <a href="<?= $this->e($company['website']) ?>" target="_blank" rel="noopener" class="cc-link">
                                <?= $this->e(preg_replace('#^https?://#', '', rtrim($company['website'], '/'))) ?>
                                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="10" height="10"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
                            </a>
                        </dd>
                        <?php endif; ?>
                        <?php if (!empty($company['address'])): ?>
                        <dt><?= $this->te('Adresse') ?></dt>
                        <dd class="cc-address"><?= nl2br($this->e($company['address'])) ?></dd>
                        <?php endif; ?>
                        <?php if (empty($company['phone']) && empty($company['email']) && empty($company['website']) && empty($company['address'])): ?>
                        <dd class="cc-muted" style="grid-column:1/-1"><?= $this->te('Keine Kontaktdaten hinterlegt.') ?></dd>
                        <?php endif; ?>
                    </dl>
                    <a href="/contacts/companies/<?= $company['id'] ?>" class="cc-sidebar-link">
                        <?= $this->te('Im Adressbuch öffnen') ?>
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="11" height="11"><polyline points="9 18 15 12 9 6"/></svg>
                    </a>
                </div>

                <!-- Ansprechpartner -->
                <?php if (!empty($contacts)): ?>
                <div class="cc-sidebar-card">
                    <h3 class="cc-sidebar-title">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="15" height="15"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
                        <?= $this->te('Ansprechpartner') ?>
                        <span class="cc-count-badge cc-count-badge-inline"><?= count($contacts) ?></span>
                    </h3>
                    <div class="cc-contact-list">
                        <?php foreach ($contacts as $ct):
                            $ctName = trim($ct['first_name'] . ' ' . $ct['last_name']);
                        ?>
                        <div class="cc-contact-item">
                            <a href="/contacts/companies/<?= $company['id'] ?>" class="cc-contact-link-wrap">
                                <div class="cc-contact-avatar">
                                    <?php if (!empty($ct['image_path'])): ?>
                                        <img src="<?= $this->e($ct['image_path']) ?>" alt="">
                                    <?php else: ?>
                                        <span><?= mb_strtoupper(mb_substr($ctName, 0, 1)) ?></span>
                                    <?php endif; ?>
                                </div>
                                <div>
                                    <div class="cc-contact-name"><?= $this->e($ctName) ?></div>
                                    <?php if (!empty($ct['position'])): ?>
                                        <div class="cc-contact-role"><?= $this->e($ct['position']) ?></div>
                                    <?php endif; ?>
                                </div>
                            </a>
                            <?php if (!empty($ct['phone']) || !empty($ct['mobile']) || !empty($ct['email'])): ?>
                            <div class="cc-contact-chips">
                                <?php if (!empty($ct['phone'])): ?>
                                    <a href="tel:<?= $this->e($ct['phone']) ?>" class="cc-chip">
                                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="11" height="11"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.69 12a19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 3.18 1h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L7.91 8.15a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 22 16.92z"/></svg>
                                        <?= $this->e($ct['phone']) ?>
                                    </a>
                                <?php endif; ?>
                                <?php if (!empty($ct['mobile'])): ?>
                                    <a href="tel:<?= $this->e($ct['mobile']) ?>" class="cc-chip">
                                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="11" height="11"><rect x="5" y="2" width="14" height="20" rx="2" ry="2"/><line x1="12" y1="18" x2="12.01" y2="18"/></svg>
                                        <?= $this->e($ct['mobile']) ?>
                                    </a>
                                <?php endif; ?>
                                <?php if (!empty($ct['email'])): ?>
                                    <a href="mailto:<?= $this->e($ct['email']) ?>" class="cc-chip">
                                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="11" height="11"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>
                                        <?= $this->e($ct['email']) ?>
                                    </a>
                                <?php endif; ?>
                            </div>
                            <?php endif; ?>
                        </div>
                        <?php endforeach; ?>
                    </div>
                </div>
                <?php endif; ?>

            </aside>
        </div>
    </div>
</div>

<style>
/* ── Layout ─────────────────────────────────────────────────────────────── */

/* ── Body ─────────────────────────────────────────────────────────────────── */
.cc-body { padding: 1.5rem 1rem 3rem; background: var(--slate-50); min-height: calc(100vh - 320px); }
.cc-layout { display: grid; grid-template-columns: 1fr 300px; gap: 1.75rem; }
.cc-main { display: flex; flex-direction: column; gap: 1.25rem; min-width: 0; }

/* ── Cards ────────────────────────────────────────────────────────────────── */
.cc-card { background: var(--color-bg); border-radius: 0.25rem; padding: 1.5rem; box-shadow: 0 1px 3px rgba(0,0,0,0.06); }
.cc-card-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.25rem; }
.cc-section-title { margin: 0; font-size: 1rem; font-weight: 600; color: var(--gray-700); display: flex; align-items: center; gap: 0.5rem; }
.cc-section-title svg { color: var(--gray-500); flex-shrink: 0; }
.cc-count-badge {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 1.5rem; height: 1.5rem; padding: 0 0.375rem;
    background: var(--gray-100); border-radius: 9999px; font-size: 0.72rem; font-weight: 600; color: var(--gray-500);
}
.cc-count-badge-inline { margin-left: auto; }
.cc-muted { color: var(--gray-400); font-size: 0.85rem; margin: 0; }

/* ── Empty State ─────────────────────────────────────────────────────────── */
.cc-empty-state {
    text-align: center; padding: 2.5rem 1rem;
    display: flex; flex-direction: column; align-items: center; gap: 0.75rem;
    color: var(--gray-400);
}
.cc-empty-state p { margin: 0; font-size: 0.875rem; }

/* ── Contract List ────────────────────────────────────────────────────────── */
.cc-contract-list { display: flex; flex-direction: column; gap: 0; }
.cc-contract-row {
    display: flex; justify-content: space-between; align-items: center;
    padding: 0.875rem 1rem; gap: 1rem;
    border-bottom: 1px solid var(--gray-100); border-radius: 0.25rem;
    text-decoration: none; color: inherit; transition: background 0.12s;
}
.cc-contract-list .cc-contract-row:last-child { border-bottom: none; }
.cc-contract-row:hover { background: var(--sky-50); text-decoration: none; }
.cc-contract-row--expiring:hover { background: var(--amber-50); }
.cc-contract-row--expired, .cc-contract-row--cancelled { opacity: 0.65; }
.cc-contract-row--expired:hover, .cc-contract-row--cancelled:hover { background: var(--gray-50); opacity: 1; }

.cc-contract-row-left { display: flex; align-items: flex-start; gap: 0.75rem; min-width: 0; flex: 1; }

.cc-contract-info { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.cc-contract-title { font-size: 0.9rem; font-weight: 600; color: var(--gray-900); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cc-contract-sub { font-size: 0.75rem; color: var(--gray-400); }
.cc-contract-warn { display: inline-flex; align-items: center; gap: 0.25rem; font-size: 0.72rem; color: var(--amber-700); font-weight: 500; }
.cc-contract-warn svg { flex-shrink: 0; }

.cc-contract-row-right { display: flex; align-items: center; gap: 0.75rem; flex-shrink: 0; }
.cc-cost-display { display: flex; flex-direction: column; align-items: flex-end; gap: 0.1rem; }
.cc-cost-monthly { font-size: 0.9rem; font-weight: 700; color: var(--gray-900); }
.cc-cost-period { font-size: 0.72rem; font-weight: 400; color: var(--gray-500); }
.cc-cost-yearly { font-size: 0.7rem; color: var(--gray-400); }
.cc-cost-none { color: var(--gray-300); font-size: 0.85rem; }
.cc-file-badge {
    display: inline-flex; align-items: center; gap: 0.3rem;
    padding: 0.2rem 0.5rem; background: var(--gray-100); border-radius: 9999px;
    font-size: 0.72rem; color: var(--gray-500);
}
.cc-row-arrow { color: var(--gray-300); transition: transform 0.15s, color 0.15s; flex-shrink: 0; }
.cc-contract-row:hover .cc-row-arrow { color: var(--sky-500); transform: translateX(2px); }

/* ── File List ────────────────────────────────────────────────────────────── */
.cc-upload-hidden { display: none; }
.cc-upload-form { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 1rem; }
.cc-upload-label {
    display: flex; align-items: center; gap: 0.5rem; flex: 1; min-width: 0;
    padding: 0.375rem 0.75rem; background: var(--gray-50); border: 1px solid var(--gray-200);
    border-radius: 0.375rem; cursor: pointer; font-size: 0.82rem; color: var(--gray-400);
    transition: border-color 0.15s, background 0.15s;
}
.cc-upload-label svg { flex-shrink: 0; color: var(--gray-400); }
.cc-upload-label:hover { border-color: var(--sky-500); background: var(--sky-50); }

.cc-file-list { display: flex; flex-direction: column; gap: 0.5rem; }
.cc-file-row {
    display: flex; align-items: center; gap: 0.75rem;
    padding: 0.625rem 0.75rem; background: var(--gray-50);
    border-radius: 0.25rem; border: 1px solid var(--gray-100);
}
.cc-file-icon {
    flex-shrink: 0; width: 36px; height: 36px; border-radius: 0.375rem;
    display: flex; align-items: center; justify-content: center;
    font-size: 0.6rem; font-weight: 700; letter-spacing: 0.02em;
}
.cc-file-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.cc-file-name { font-size: 0.82rem; font-weight: 500; color: var(--blue-600); text-decoration: none; word-break: break-all; }
.cc-file-name:hover { text-decoration: underline; }
.cc-file-meta { font-size: 0.7rem; color: var(--gray-400); }
.cc-file-actions { display: flex; align-items: center; gap: 0.25rem; flex-shrink: 0; }
.cc-icon-btn {
    background: transparent; border: none; border-radius: 0.375rem;
    padding: 0.3rem; cursor: pointer; color: var(--gray-400);
    display: inline-flex; align-items: center; transition: background 0.12s, color 0.12s;
    text-decoration: none;
}
.cc-icon-btn:hover { background: var(--gray-200); color: var(--gray-700); text-decoration: none; }
.cc-icon-btn-danger:hover { background: var(--red-100); color: var(--red-600); }

/* ── Sidebar ──────────────────────────────────────────────────────────────── */
.cc-sidebar { display: flex; flex-direction: column; gap: 1rem; }
.cc-sidebar-card {
    background: var(--color-bg); border-radius: 0.25rem; padding: 1.25rem;
    box-shadow: 0 1px 3px rgba(0,0,0,0.06);
}
.cc-sidebar-title {
    margin: 0 0 1rem; font-size: 0.875rem; font-weight: 600; color: var(--gray-700);
    display: flex; align-items: center; gap: 0.45rem;
}
.cc-sidebar-title svg { color: var(--gray-500); flex-shrink: 0; }

/* Kosten-Tiles */
.cc-sidebar-card-costs { border-top: 3px solid var(--sky-500); }
.cc-cost-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 0.625rem; margin-bottom: 0.75rem; }
.cc-cost-tile {
    border-radius: 0.25rem; padding: 0.75rem 0.875rem;
    display: flex; flex-direction: column; gap: 0.2rem;
}
.cc-cost-tile-blue   { background: var(--blue-50); }
.cc-cost-tile-indigo { background: var(--indigo-50); }
.cc-cost-tile-green  { background: var(--green-50); }
.cc-cost-tile-teal   { background: var(--teal-50); }
.cc-tile-label { font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--gray-500); font-weight: 600; }
.cc-tile-value { font-size: 0.95rem; font-weight: 700; color: var(--gray-900); }
.cc-cost-note {
    display: flex; align-items: center; gap: 0.35rem;
    font-size: 0.72rem; color: var(--gray-400); margin: 0;
}
.cc-cost-note svg { flex-shrink: 0; }

/* Detail list */
.cc-detail-list {
    margin: 0 0 1rem; display: grid;
    grid-template-columns: auto 1fr; gap: 0.125rem 0.75rem;
}
.cc-detail-list dt { font-size: 0.7rem; color: var(--gray-400); text-transform: uppercase; letter-spacing: 0.04em; align-self: start; padding-top: 0.1rem; }
.cc-detail-list dd { margin: 0; font-size: 0.85rem; color: var(--gray-900); }
.cc-detail-list dt + dd { margin-top: 0.5rem; }
.cc-detail-list dt:first-child, .cc-detail-list dt:first-child + dd { margin-top: 0; }
.cc-address { white-space: pre-line; line-height: 1.5; }
.cc-link { color: var(--blue-600); text-decoration: none; }
.cc-link:hover { text-decoration: underline; }
.cc-sidebar-link {
    display: inline-flex; align-items: center; gap: 0.3rem;
    font-size: 0.8rem; color: var(--sky-500); text-decoration: none; font-weight: 500;
}
.cc-sidebar-link:hover { text-decoration: underline; }

/* Contacts */
.cc-contact-list { display: flex; flex-direction: column; gap: 0.875rem; }
.cc-contact-item { }
.cc-contact-link-wrap {
    display: flex; align-items: center; gap: 0.625rem;
    text-decoration: none; color: inherit; padding: 0.375rem;
    border-radius: 0.25rem; transition: background 0.12s; margin: 0 -0.375rem 0.25rem;
}
.cc-contact-link-wrap:hover { background: var(--gray-100); text-decoration: none; }
.cc-contact-avatar {
    width: 36px; height: 36px; border-radius: 50%; flex-shrink: 0;
    background: linear-gradient(135deg, var(--sky-500), var(--color-primary-strong));
    display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.cc-contact-avatar img { width: 100%; height: 100%; object-fit: cover; }
.cc-contact-avatar span { font-size: 0.95rem; font-weight: 700; color: var(--color-on-accent); }
.cc-contact-name { font-size: 0.875rem; font-weight: 600; color: var(--gray-900); }
.cc-contact-role { font-size: 0.75rem; color: var(--gray-500); }
.cc-contact-chips { display: flex; flex-wrap: wrap; gap: 0.35rem; padding-left: 0; }
.cc-chip {
    display: inline-flex; align-items: center; gap: 0.3rem;
    padding: 0.25rem 0.625rem; background: var(--gray-100); border: 1px solid var(--gray-200);
    border-radius: 9999px; font-size: 0.72rem; font-weight: 500; color: var(--gray-700);
    text-decoration: none; transition: all 0.12s; white-space: nowrap;
}
.cc-chip:hover { background: var(--sky-100); border-color: var(--sky-200); color: var(--color-primary-strong); transform: translateY(-1px); text-decoration: none; }
.cc-chip svg { flex-shrink: 0; color: var(--gray-500); }
/* ── Responsive ─────────────────────────────────────────────────────────── */
@media (max-width: 1100px) {
    .cc-layout { grid-template-columns: 1fr; }
    .cc-sidebar { order: -1; display: grid; grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 768px) {
    .cc-body { padding: 1rem; }
    .cc-layout { gap: 1rem; }
    .cc-sidebar { grid-template-columns: 1fr; }
    .cc-card { padding: 1rem; }
    .cc-cost-tiles { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 480px) {
    .cc-body { padding: 0.75rem; }
    .cc-card { padding: 0.875rem; }
    .cc-contract-row { flex-direction: column; align-items: flex-start; gap: 0.5rem; }
    .cc-contract-row-right { width: 100%; justify-content: space-between; }
    .cc-cost-tiles { grid-template-columns: 1fr; }
}
</style>