design optimizations.
Build and Push Container Image / Build & Push to Gitea Package Registry (push) Canceled after 0s

This commit is contained in:
chriz committed 2026-10-26 20:55:59 +01:00
1 parent 1e33c525f1
commit af5177e8b1
8 files changed
+350 -16

No files matched your search

+1
View File
@@ -1,4 +1,5 @@
.git
.gitea
.gitignore
.dockerignore
Dockerfile
+58
View File
@@ -0,0 +1,58 @@
name: Build and Push Container Image
on:
push:
branches:
- main
- multilingual
- redesign
tags:
- 'v*'
workflow_dispatch:
jobs:
build-and-push:
name: Build & Push to Gitea Package Registry
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to Gitea Container Registry
env:
REGISTRY_USER: ${{ gitea.actor }}
REGISTRY_TOKEN: ${{ secrets.GITEATOKEN }}
SERVER_URL: ${{ gitea.server_url }}
run: |
REGISTRY_HOST=$(echo "${SERVER_URL}" | sed -E 's#^https?://##; s#/$##')
echo "Logging in to ${REGISTRY_HOST} as ${REGISTRY_USER}..."
echo "${REGISTRY_TOKEN}" | docker login "${REGISTRY_HOST}" -u "${REGISTRY_USER}" --password-stdin
- name: Build, Validate, and Push Docker Image
env:
SERVER_URL: ${{ gitea.server_url }}
REPO_NAME: ${{ gitea.repository }}
REF_NAME: ${{ gitea.ref_name }}
SHA: ${{ gitea.sha }}
run: |
REGISTRY_HOST=$(echo "${SERVER_URL}" | sed -E 's#^https?://##; s#/$##')
IMAGE_PATH=$(echo "${REPO_NAME}" | tr '[:upper:]' '[:lower:]')
FULL_IMAGE="${REGISTRY_HOST}/${IMAGE_PATH}"
SHORT_SHA=$(echo "${SHA}" | cut -c1-7)
SAFE_REF=$(echo "${REF_NAME}" | sed -E 's#[^a-zA-Z0-9_.-]#-#g')
echo "Building image ${FULL_IMAGE}..."
docker build --pull \
-t "${FULL_IMAGE}:${SAFE_REF}" \
-t "${FULL_IMAGE}:${SHORT_SHA}" \
-t "${FULL_IMAGE}:latest" \
.
echo "Validating PHP syntax inside built container..."
docker run --rm "${FULL_IMAGE}:${SHORT_SHA}" sh -c 'find /var/www/html -name "*.php" -exec php -l {} +'
echo "Pushing tags to Gitea Package Registry..."
docker push "${FULL_IMAGE}:${SAFE_REF}"
docker push "${FULL_IMAGE}:${SHORT_SHA}"
docker push "${FULL_IMAGE}:latest"
+239 -6
View File
@@ -68,6 +68,52 @@
--container-max: 1200px;
}
/* ==========================================================================
Dark Mode Theme Variables & Overrides
========================================================================== */
[data-theme="dark"] {
--primary: #15658a;
--primary-dark: #e2f1f8;
--primary-light: #1a3650;
--primary-hover: #1b7aa6;
--accent: #38bdf8;
--accent-hover: #7dd3fc;
--accent-light: #1e3a52;
--accent-dark: #bae6fd;
--secondary: #14b8a6;
--secondary-light: #134e4a;
--bg-body: #0b1520;
--bg-card: #122130;
--bg-alt: #182b3e;
--text-main: #e2e8f0;
--text-muted: #94a3b8;
--text-light: #64748b;
--text-white: #ffffff;
--border: #23394f;
--border-focus: #38bdf8;
--success: #86efac;
--success-bg: #064e3b;
--success-border: #059669;
--danger: #fca5a5;
--danger-bg: #450a0a;
--danger-border: #dc2626;
--warning: #fcd34d;
--warning-bg: #451a03;
--shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.35);
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.45), 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.5), 0 2px 4px -2px rgba(0, 0, 0, 0.35);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.55), 0 4px 6px -4px rgba(0, 0, 0, 0.4);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.6), 0 8px 10px -6px rgba(0, 0, 0, 0.45);
color-scheme: dark;
}
/* ==========================================================================
Reset & Base Styles
========================================================================== */
@@ -374,6 +420,18 @@ li {
display: block;
}
.site-logo-dark {
display: none;
}
[data-theme="dark"] .site-logo-light {
display: none;
}
[data-theme="dark"] .site-logo-dark {
display: block;
}
.logo-badge {
width: 44px;
height: 44px;
@@ -443,6 +501,7 @@ li {
text-decoration: none;
transition: var(--transition);
position: relative;
white-space: nowrap;
}
.nav-link:hover {
@@ -514,6 +573,8 @@ li {
text-decoration: none;
transition: var(--transition);
box-shadow: 0 2px 8px rgba(2, 132, 199, 0.25);
white-space: nowrap;
flex-shrink: 0;
}
.header-cta-btn:hover {
@@ -527,6 +588,7 @@ li {
width: 16px;
height: 16px;
fill: currentColor;
flex-shrink: 0;
}
/* Mobile Toggle Hamburger */
@@ -578,7 +640,7 @@ li {
.hero-content {
position: relative;
z-index: 2;
max-width: 820px;
max-width: 100%;
}
.hero-badge {
@@ -710,6 +772,12 @@ li {
cursor: pointer;
transition: var(--transition);
line-height: 1.2;
white-space: nowrap;
flex-shrink: 0;
}
.btn svg {
flex-shrink: 0;
}
.btn:hover {
@@ -1563,15 +1631,168 @@ textarea.form-control {
gap: 1rem;
}
.footer-bottom-links {
display: inline-flex;
align-items: center;
flex-wrap: wrap;
gap: 1rem;
}
.footer-bottom a {
color: #cbd5e1;
margin-left: 1rem;
margin-left: 0;
}
.footer-bottom a:hover {
color: #ffffff;
}
/* Unobtrusive Footer Dark Mode Toggle */
.theme-toggle-btn {
background: transparent;
border: none;
border-left: 1px solid rgba(255, 255, 255, 0.15);
padding: 0 0 0 1rem;
margin: 0;
color: #94a3b8;
font-family: inherit;
font-size: 0.82rem;
line-height: 1.4;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 0.35rem;
transition: var(--transition);
}
.theme-toggle-btn:hover {
color: #e2e8f0;
}
.theme-toggle-btn svg {
width: 14px;
height: 14px;
fill: currentColor;
opacity: 0.8;
flex-shrink: 0;
}
.theme-icon-sun {
display: none;
}
[data-theme="dark"] .theme-icon-moon {
display: none;
}
[data-theme="dark"] .theme-icon-sun {
display: inline-block;
}
/* ==========================================================================
Dark Mode Component Overrides
========================================================================== */
.team-staff-card {
background: linear-gradient(135deg, #f8fafc 0%, #e0f2fe 100%);
}
.info-callout-box {
background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
}
[data-theme="dark"] .top-bar {
background-color: #060d14;
}
[data-theme="dark"] .site-header {
border-bottom: 1px solid var(--border);
}
[data-theme="dark"] .site-footer {
background-color: #060d14;
border-top: 1px solid var(--border);
}
[data-theme="dark"] .skip-link {
background-color: #0c2b3d;
}
[data-theme="dark"] .page-banner {
background: linear-gradient(135deg, #071926 0%, #0d354a 100%);
border-bottom: 1px solid var(--border);
}
[data-theme="dark"] .hero-banner {
background: linear-gradient(135deg, #061520 0%, #092c3e 55%, #0c3b50 100%);
}
[data-theme="dark"] .btn-primary,
[data-theme="dark"] .header-cta-btn {
background-color: #0284c7;
color: #ffffff;
}
[data-theme="dark"] .btn-primary:hover,
[data-theme="dark"] .header-cta-btn:hover {
background-color: #0369a1;
color: #ffffff;
}
[data-theme="dark"] .card:hover,
[data-theme="dark"] .doctor-card:hover {
border-color: #335372;
}
[data-theme="dark"] .highlight-panel {
background: linear-gradient(to right, #152738, #122130);
}
[data-theme="dark"] .team-staff-card,
[data-theme="dark"] .info-callout-box {
background: linear-gradient(135deg, #152738 0%, #1a3650 100%);
}
[data-theme="dark"] .condition-warning {
background-color: #3b1219;
border-color: #7f1d1d;
color: #fecdd3;
}
[data-theme="dark"] .condition-info {
background-color: #132d42;
border-color: #1e496b;
color: #bae6fd;
}
[data-theme="dark"] .chamber-badge {
color: #bae6fd;
}
[data-theme="dark"] .form-control {
background-color: #0e1a27;
color: var(--text-main);
border-color: var(--border);
}
[data-theme="dark"] .form-control::placeholder {
color: #64748b;
}
[data-theme="dark"] .holiday-notice-banner {
background: linear-gradient(135deg, #102436 0%, #16324a 100%);
border-bottom-color: #1e496b;
color: #bae6fd;
}
[data-theme="dark"] .holiday-dismiss-btn {
border-color: #38bdf8;
color: #bae6fd;
}
[data-theme="dark"] .map-iframe-wrapper iframe {
filter: invert(90%) hue-rotate(180deg) brightness(95%) contrast(90%);
}
/* ==========================================================================
Responsive Media Queries
========================================================================== */
@@ -1586,16 +1807,16 @@ textarea.form-control {
min-width: 0;
}
h1, h2, h3, h4, p, li, .card, .location-card, .contact-detail-value, .btn {
h1, h2, h3, h4, p, li, .card, .location-card, .contact-detail-value {
overflow-wrap: break-word;
word-wrap: break-word;
hyphens: auto;
}
.btn {
flex-wrap: wrap;
text-align: center;
max-width: 100%;
hyphens: none;
}
/* Prioritized Address Hiding when space is limited */
@@ -1603,6 +1824,11 @@ h1, h2, h3, h4, p, li, .card, .location-card, .contact-detail-value, .btn {
.top-bar-addr-satellite {
display: none !important;
}
.site-logo-img {
height: 62px;
max-width: 300px;
}
}
/* Compact Header for Medium Laptops & Tablets (max 1100px) */
@@ -1770,8 +1996,8 @@ h1, h2, h3, h4, p, li, .card, .location-card, .contact-detail-value, .btn {
text-align: center;
}
.footer-bottom a {
margin: 0 0.5rem;
.footer-bottom-links {
justify-content: center;
}
.content-card {
@@ -1852,6 +2078,13 @@ h1, h2, h3, h4, p, li, .card, .location-card, .contact-detail-value, .btn {
flex-direction: column;
}
.hero-actions .btn,
.btn {
white-space: normal;
flex-wrap: wrap;
flex-shrink: 1;
}
.hero-actions .btn {
width: 100%;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

+1 -1
View File
@@ -139,7 +139,7 @@
title="<?= $isEn ? 'Map Center Dialysis Berlin-Mahlsdorf' : 'Karte Zentrumsdialyse Berlin-Mahlsdorf' ?>"></iframe>
</div>
<div style="padding: 1rem 1.25rem; background-color: #ffffff; border-top: 1px solid var(--border); font-size: 0.85rem; color: var(--text-muted); display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 0.5rem;">
<div style="padding: 1rem 1.25rem; background-color: var(--bg-card); border-top: 1px solid var(--border); font-size: 0.85rem; color: var(--text-muted); display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 0.5rem;">
<span id="mapAddressText">Thorner Straße 1, 12623 Berlin</span>
<a id="mapExternalLink" href="https://www.google.com/maps/place/Dialysezentrum+Berlin-Mahlsdorf/@52.5078291,13.6092903,17z/data=!3m1!4b1!4m6!3m5!1s0x47a84991f9c57f7f:0xad4486f559442067!8m2!3d52.5078291!4d13.6092903!16s%2Fg%2F1tdqghgn" target="_blank" rel="noopener noreferrer" style="font-weight: 600;">
<?= $isEn ? 'Large Route Map' : 'Große Routenkarte' ?> <span aria-hidden="true">&raquo;</span>
+6 -6
View File
@@ -100,7 +100,7 @@ $pdfPrivat = '/files/' . rawurlencode('Behandlunsvertrag Privatpatienten.pdf');
</div>
<!-- Wichtiger Hinweis zu Originalbefunden -->
<div style="background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%); border-left: 4px solid var(--accent); border-radius: var(--radius-md); padding: 1rem 1.15rem;">
<div class="info-callout-box" style="border-left: 4px solid var(--accent); border-radius: var(--radius-md); padding: 1rem 1.15rem;">
<div style="font-weight: 700; color: var(--primary-dark); margin-bottom: 0.25rem; display: flex; align-items: center; gap: 0.4rem;">
<svg aria-hidden="true" focusable="false" style="width: 18px; height: 18px; fill: var(--accent); flex-shrink: 0;" viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>
<?= $isEn ? 'Important Note on Original Reports:' : 'Wichtiger Hinweis zu Ihren Originalbefunden:' ?>
@@ -131,7 +131,7 @@ $pdfPrivat = '/files/' . rawurlencode('Behandlunsvertrag Privatpatienten.pdf');
<div class="grid-2" style="margin-bottom: 0;">
<!-- 1. Anamnesebogen -->
<div class="card" id="form-anamnese" style="display: flex; flex-direction: column; justify-content: space-between; background: #ffffff;">
<div class="card" id="form-anamnese" style="display: flex; flex-direction: column; justify-content: space-between; background: var(--bg-card);">
<div>
<div style="display: flex; justify-content: space-between; align-items: flex-start; gap: 0.75rem; margin-bottom: 0.5rem;">
<h3 style="font-size: 1.1rem; color: var(--primary-dark); margin: 0;">
@@ -160,7 +160,7 @@ $pdfPrivat = '/files/' . rawurlencode('Behandlunsvertrag Privatpatienten.pdf');
</div>
<!-- 2. Datenschutz & Schweigepflichtentbindung -->
<div class="card" id="form-datenschutz" style="display: flex; flex-direction: column; justify-content: space-between; background: #ffffff;">
<div class="card" id="form-datenschutz" style="display: flex; flex-direction: column; justify-content: space-between; background: var(--bg-card);">
<div>
<div style="display: flex; justify-content: space-between; align-items: flex-start; gap: 0.75rem; margin-bottom: 0.5rem;">
<h3 style="font-size: 1.1rem; color: var(--primary-dark); margin: 0;">
@@ -189,7 +189,7 @@ $pdfPrivat = '/files/' . rawurlencode('Behandlunsvertrag Privatpatienten.pdf');
</div>
<!-- 3. Einverständniserklärung zur Ausfallhonorarregelung -->
<div class="card" id="form-ausfallhonorar" style="display: flex; flex-direction: column; justify-content: space-between; background: #ffffff;">
<div class="card" id="form-ausfallhonorar" style="display: flex; flex-direction: column; justify-content: space-between; background: var(--bg-card);">
<div>
<div style="display: flex; justify-content: space-between; align-items: flex-start; gap: 0.75rem; margin-bottom: 0.5rem;">
<h3 style="font-size: 1.1rem; color: var(--primary-dark); margin: 0;">
@@ -218,13 +218,13 @@ $pdfPrivat = '/files/' . rawurlencode('Behandlunsvertrag Privatpatienten.pdf');
</div>
<!-- 4. Behandlungsvertrag Privatpatienten / Selbstzahler -->
<div class="card" id="form-privat" style="display: flex; flex-direction: column; justify-content: space-between; background: #ffffff;">
<div class="card" id="form-privat" style="display: flex; flex-direction: column; justify-content: space-between; background: var(--bg-card);">
<div>
<div style="display: flex; justify-content: space-between; align-items: flex-start; gap: 0.75rem; margin-bottom: 0.5rem;">
<h3 style="font-size: 1.1rem; color: var(--primary-dark); margin: 0;">
<?= $isEn ? '4. Treatment Contract (Private Patients &amp; Self-Payers)' : '4. Behandlungsvertrag (Privatpatienten &amp; Selbstzahler)' ?>
</h3>
<span style="background: #f1f5f9; color: var(--text-muted); font-size: 0.75rem; font-weight: 700; padding: 0.2rem 0.6rem; border-radius: var(--radius-full); white-space: nowrap;">
<span style="background: var(--bg-alt); color: var(--text-muted); font-size: 0.75rem; font-weight: 700; padding: 0.2rem 0.6rem; border-radius: var(--radius-full); white-space: nowrap;">
<?= $isEn ? 'If Applicable' : 'Bei Bedarf' ?>
</span>
</div>
+44 -2
View File
@@ -226,6 +226,17 @@ if ($canonicalUrl && $currentAction !== 'main') {
<link rel="icon" href="/img/favicon.png?v=<?=filemtime(__DIR__ . '/../img/favicon.png')?>" type="image/png">
<link rel="apple-touch-icon" href="/img/apple-touch-icon.png?v=<?=filemtime(__DIR__ . '/../img/apple-touch-icon.png')?>">
<!-- Theme Initialization (prevents FOUC) -->
<script type="text/javascript">
(function() {
try {
if (localStorage.getItem('theme') === 'dark') {
document.documentElement.setAttribute('data-theme', 'dark');
}
} catch (e) {}
})();
</script>
<!-- Modern Stylesheets -->
<link href="/css/frontend.css?v=<?=filemtime(__DIR__ . '/../css/frontend.css')?>" rel="stylesheet" media="screen">
<link href="/css/lightbox.min.css" rel="stylesheet" media="screen">
@@ -276,7 +287,11 @@ if ($canonicalUrl && $currentAction !== 'main') {
<img src="/img/logo_dialysezentrum.png?v=<?=filemtime(__DIR__ . '/../img/logo_dialysezentrum.png')?>"
alt="<?=$isEn ? 'Dialysis Center Berlin-Mahlsdorf – Center for Nephrology & Dialysis' : 'Dialysezentrum Berlin-Mahlsdorf – Zentrum für Nephrologie & Dialyse'?>"
width="915" height="199"
class="site-logo-img">
class="site-logo-img site-logo-light">
<img src="/img/logo_dialysezentrum_dark.png?v=<?=filemtime(__DIR__ . '/../img/logo_dialysezentrum_dark.png')?>"
alt="<?=$isEn ? 'Dialysis Center Berlin-Mahlsdorf – Center for Nephrology & Dialysis' : 'Dialysezentrum Berlin-Mahlsdorf – Zentrum für Nephrologie & Dialyse'?>"
width="915" height="199"
class="site-logo-img site-logo-dark">
</a>
<!-- Navigation Menu -->
@@ -435,10 +450,15 @@ if ($canonicalUrl && $currentAction !== 'main') {
<div>
&copy; <?=date('Y')?> <?=$isEn ? 'Dialysis Center Berlin-Mahlsdorf &bull; All rights reserved.' : 'Dialysezentrum Berlin-Mahlsdorf &bull; Alle Rechte vorbehalten.'?>
</div>
<div>
<div class="footer-bottom-links">
<a href="<?=Helper::url('/impressum.html')?>"><?=$isEn ? 'Legal Notice' : 'Impressum'?></a>
<a href="<?=Helper::url('/datenschutz.html')?>"><?=$isEn ? 'Privacy Policy' : 'Datenschutz'?></a>
<a href="<?=Helper::url('/kontakt.html')?>"><?=$isEn ? 'Contact' : 'Kontakt'?></a>
<button type="button" id="themeToggle" class="theme-toggle-btn" aria-pressed="false" title="<?=$isEn ? 'Toggle color scheme (Dark / Light)' : 'Farbschema umschalten (Dunkel / Hell)'?>">
<svg class="theme-icon-moon" aria-hidden="true" focusable="false" viewBox="0 0 24 24"><path d="M12 3a9 9 0 1 0 9 9c0-.46-.04-.92-.1-1.36a5.389 5.389 0 0 1-4.4 2.26 5.403 5.403 0 0 1-3.14-9.8c-.44-.06-.9-.1-1.36-.1z"/></svg>
<svg class="theme-icon-sun" aria-hidden="true" focusable="false" viewBox="0 0 24 24"><path d="M6.76 4.84l-1.8-1.79-1.41 1.41 1.79 1.79 1.42-1.41zM4 10.5H1v2h3v-2zm9-9.95h-2V3.5h2V.55zm7.45 3.91l-1.41-1.41-1.79 1.79 1.41 1.41 1.79-1.79zm-3.21 13.7l1.79 1.8 1.41-1.41-1.8-1.79-1.4 1.4zM20 10.5v2h3v-2h-3zm-8-5c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6zm-1 16.95h2V19.5h-2v2.95zm-7.45-3.91l1.41 1.41 1.79-1.8-1.41-1.41-1.79 1.8z"/></svg>
<span id="themeToggleLabel"><?=$isEn ? 'Dark Mode' : 'Dunkelmodus'?></span>
</button>
</div>
</div>
</footer>
@@ -452,6 +472,28 @@ if ($canonicalUrl && $currentAction !== 'main') {
var labelOpen = isEn ? 'Open menu' : 'Menü öffnen';
var labelClose = isEn ? 'Close menu' : 'Menü schließen';
// Unobtrusive Footer Dark Mode Toggle
var $themeToggle = $('#themeToggle');
var $themeLabel = $('#themeToggleLabel');
function syncThemeButton() {
var isDark = document.documentElement.getAttribute('data-theme') === 'dark';
$themeToggle.attr('aria-pressed', isDark ? 'true' : 'false');
$themeLabel.text(isDark ? (isEn ? 'Light Mode' : 'Hellmodus') : (isEn ? 'Dark Mode' : 'Dunkelmodus'));
}
syncThemeButton();
$themeToggle.on('click', function() {
var isDark = document.documentElement.getAttribute('data-theme') === 'dark';
if (isDark) {
document.documentElement.removeAttribute('data-theme');
try { localStorage.setItem('theme', 'light'); } catch (e) {}
} else {
document.documentElement.setAttribute('data-theme', 'dark');
try { localStorage.setItem('theme', 'dark'); } catch (e) {}
}
syncThemeButton();
});
// Anti-Spam Email De-Obfuscation
$('.mail-obf').each(function() {
var $el = $(this);
+1 -1
View File
@@ -65,7 +65,7 @@ $isEn = (isset($lang) && $lang === 'en') || Helper::getLang() === 'en';
</div>
<!-- Mitarbeiter & Pflegekräfte Card -->
<div class="card" style="background: linear-gradient(135deg, #f8fafc 0%, #e0f2fe 100%); border-left: 4px solid var(--accent); padding: clamp(1.25rem, 3vw, 2rem);">
<div class="card team-staff-card" style="border-left: 4px solid var(--accent); padding: clamp(1.25rem, 3vw, 2rem);">
<div style="display: flex; gap: 1.5rem; align-items: center; flex-wrap: wrap;">
<div aria-hidden="true" style="width: 60px; height: 60px; border-radius: var(--radius-full); background: var(--accent); color: #fff; display: flex; align-items: center; justify-content: center; flex-shrink: 0; box-shadow: 0 4px 10px rgba(2, 132, 199, 0.25);">
<svg aria-hidden="true" focusable="false" style="width: 32px; height: 32px; fill: currentColor;" viewBox="0 0 24 24"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></svg>