Global-2026-07-13

This commit is contained in:
Dekart Deploy Bot 2026-07-13 06:39:32 +00:00
parent ca70d76648
commit b484d7ca19
12 changed files with 444 additions and 75 deletions

1
.gitignore vendored
View File

@ -128,3 +128,4 @@ wp-content/upgrade-temp-backup/
data/
llms.txt
test.php
.agents/

275
AGENTS.md
View File

@ -1,24 +1,251 @@
# Site1 — WordPress project
## Primary agent
- @site1 — dedicated WordPress agent (auto-activated, see `.opencode/AGENTS.md`)
## Quick rules
- PHP: PSR-12, type declarations, Composer
- JS: TypeScript strict, ESM, async/await
- Commits: conventional commits (`feat:`, `fix:`, `chore:`, etc.)
## Security
- NEVER modify wp-config.php without explicit confirmation
- NEVER delete files in uploads/ or wp-content/ without confirmation
- ALWAYS ask before destructive actions (rm, overwrite, DB write, git push)
## Commands
- PHP test: `vendor/bin/phpunit`
- PHP lint: `vendor/bin/phpstan analyse`
- JS build: `npm run build`
- JS test: `npm test`
- JS lint: `npm run lint`
## All details
See `.opencode/AGENTS.md` for full architecture, skills, agents list, and directory structure.
# Site1 — WordPress Project
## Agent
Primary agent:
- @site1
This agent manages the WordPress project architecture, development workflow, frontend changes, SEO safety, and deployment preparation.
---
# Project Context
Project type:
- Custom WordPress website.
Architecture:
- WordPress core.
- Custom theme:
`wp-content/themes/dekart/`
Theme contains:
- Templates
- Custom frontend styles
- Carbon Fields integration
- Schema.org JSON-LD logic
- Custom business data logic
Repository:
- Git is the source of truth.
- Theme changes are deployed through Git.
- Production and development environments are separated.
Important:
Before any changes, inspect existing architecture.
Do not assume standard WordPress structure.
---
# Critical Rules
## Forbidden without explicit confirmation
NEVER modify:
- wp-config.php
- database structure
- production environment files
- uploads directory
- user data
- existing production configuration
Before executing:
- rm
- delete
- overwrite
- database write
- git push
Ask for confirmation.
---
# WordPress Architecture Rules
## Theme
Location:
wp-content/themes/dekart/
Rules:
Preserve:
- existing PHP templates
- template hierarchy
- hooks
- filters
- Carbon Fields compatibility
- schema.org output
- SEO logic
Do not:
- rebuild templates
- replace theme architecture
- move functionality into plugins without approval
- introduce page builders
---
# Carbon Fields
Carbon Fields is intentionally located inside the theme.
Rules:
Do not:
- move Carbon Fields into a plugin
- rename fields
- change option keys
- modify stored data structure
Any changes must preserve backward compatibility.
---
# Frontend / Redesign Rules
Goal:
Improve visual design without changing markup.
Allowed:
- CSS
- SCSS
- CSS variables
- typography
- colors
- spacing
- borders
- shadows
- animations
- responsive improvements
Forbidden:
- changing HTML structure
- changing block layout
- changing forms
- replacing components
- adding Elementor
- adding visual builders
Priority:
1. Preserve functionality
2. Preserve SEO
3. Preserve accessibility
4. Improve UI consistency
---
# Modern Web Development
Use Google Chrome Modern Web Guidance principles.
Priorities:
- Accessibility
- Performance
- Responsive design
- Maintainable CSS
- Browser compatibility
Prefer:
- CSS variables
- reusable design tokens
- semantic CSS naming
- modern CSS compatible with Baseline
Avoid:
- unnecessary JavaScript
- duplicated CSS
- layout shifts
- heavy dependencies
Consider:
- Core Web Vitals
- CLS
- LCP
- accessibility contrast
- responsive behavior
---
# Frontend Workflow
Before changing styles:
1. Audit existing CSS.
2. Identify:
- colors
- typography
- spacing
- components
- duplicated rules
- inconsistent UI patterns
Create design tokens when possible:
Example:
```css
:root {
--color-primary:
--color-secondary:
--color-text:
--color-background:
--border-radius:
--shadow:
}
Do not make blind global replacements.
SEO Safety
Never break:
title/meta logic
schema.org JSON-LD
breadcrumbs
canonical URLs
indexing behavior
structured data
Frontend changes must not affect SEO output.
Performance
Keep:
Core Web Vitals
minimal CSS overhead
optimized assets
no unnecessary scripts
Avoid:
additional libraries without approval
duplicate dependencies
blocking resources
Redis Object Cache
Current architecture:
Redis Object Cache plugin
mu-plugin bootstrap
WordPress object cache API
Rules:
Do not create another caching layer.
Do not create custom Redis clients.
Do not create custom object-cache.php.
Use:
wp_cache_get()
wp_cache_set()
Runtime files:
Never commit:
wp-content/object-cache.php
Development Standards
PHP
Use:
PSR-12
type declarations where appropriate
WordPress coding standards
JavaScript
Use:
TypeScript strict
ESM
async/await
Avoid unnecessary frameworks.
Git Rules
Commit format:
feat:
fix:
refactor:
style:
chore:
docs:
Before commit:
Run:
git status
git diff
Never commit:
.env
uploads/
logs/
wp-content/object-cache.php
cache files
temporary files
Testing
PHP:
vendor/bin/phpunit
vendor/bin/phpstan analyse
JavaScript:
npm run build
npm test
npm run lint
Run only relevant checks for changed area.
Deployment Rules
Before deployment verify:
changed files
dependencies
environment requirements
database impact
cache impact
Never assume production environment matches development.
Required Work Process
For complex tasks:
Analyze current implementation.
Explain planned changes.
Wait for confirmation if architecture changes are required.
Implement minimal changes.
Verify result.
Provide report.
Final Response Format
After completing tasks always provide:
Summary
What was changed.
Files Changed
List files.
Technical Details
Explain implementation.
Validation
Tests and checks performed.
Risks
Possible issues.
Deployment Notes
Required production actions.

View File

@ -1,14 +1,21 @@
<?php
// Auto-enable Redis object cache if available
if ( extension_loaded("redis") ) {
$host = getenv("WP_REDIS_HOST") ?: "127.0.0.1";
$port = (int)(getenv("WP_REDIS_PORT") ?: 6379);
$db = (int)(getenv("WP_REDIS_DATABASE") ?: 0);
if ( @fsockopen($host, $port, $errno, $errstr, 0.5) ) {
define("WP_REDIS_HOST", $host);
define("WP_REDIS_PORT", $port);
define("WP_REDIS_DATABASE", $db);
define("WP_CACHE", true);
}
if ( ! defined( 'WP_REDIS_HOST' ) ) {
define(
'WP_REDIS_HOST',
getenv( 'WP_REDIS_HOST' ) ?: '127.0.0.1'
);
}
if ( ! defined( 'WP_REDIS_PORT' ) ) {
define(
'WP_REDIS_PORT',
( int ) ( getenv( 'WP_REDIS_PORT' ) ?: 6379 )
);
}
if ( ! defined( 'WP_REDIS_DATABASE' ) ) {
define(
'WP_REDIS_DATABASE',
( int ) ( getenv( 'WP_REDIS_DATABASE' ) ?: 0 )
);
}

View File

@ -324,7 +324,7 @@ background: rgba(124, 58, 237, 0.2);
grid-template-columns: 1fr 1fr;
gap: 24px;
margin: 28px 0 0;
align-items: stretch;
align-items: start;
}
/* ── Карточка ── */
@ -428,7 +428,6 @@ background: rgba(124, 58, 237, 0.2);
/* ── Тело карточки ── */
.prog-card__body {
flex-grow: 1;
display: flex;
flex-direction: column;
}

View File

@ -1881,16 +1881,19 @@ function dekart_branch_add_menu() {
add_action( 'admin_init', 'dekart_branch_register_settings' );
function dekart_branch_register_settings() {
$text_fields = array(
'branch_city_prep' => 'text',
'branch_city' => 'text',
'branch_region' => 'text',
'branch_address' => 'text',
'branch_coords' => 'text',
'branch_postal_code' => 'text',
'branch_phone' => 'text',
'branch_email' => 'email',
'branch_name' => 'text',
'branch_price_range' => 'text',
'branch_city_prep' => 'text',
'branch_city' => 'text',
'branch_region' => 'text',
'branch_address' => 'text',
'branch_coords' => 'text',
'branch_postal_code' => 'text',
'branch_phone' => 'text',
'branch_email' => 'email',
'branch_name' => 'text',
'branch_price_range' => 'text',
'branch_logistics_walk' => 'text',
'branch_logistics_parking' => 'text',
'branch_logistics_schools' => 'text',
);
foreach ( $text_fields as $slug => $type ) {
register_setting( 'dekart_branch_group', $slug, array( 'sanitize_callback' => $type === 'email' ? 'sanitize_email' : ( $type === 'url' ? 'esc_url_raw' : 'sanitize_text_field' ) ) );
@ -1912,6 +1915,9 @@ function dekart_branch_register_settings() {
register_setting( 'dekart_branch_group', 'branch_remaining_seats', array( 'sanitize_callback' => 'absint' ) );
register_setting( 'dekart_branch_group', 'branch_schema_description', array( 'sanitize_callback' => 'sanitize_textarea_field' ) );
register_setting( 'dekart_branch_group', 'branch_area_served', array( 'sanitize_callback' => 'sanitize_text_field' ) );
register_setting( 'dekart_branch_group', 'branch_logistics_walk', array( 'sanitize_callback' => 'sanitize_textarea_field' ) );
register_setting( 'dekart_branch_group', 'branch_logistics_parking', array( 'sanitize_callback' => 'sanitize_textarea_field' ) );
register_setting( 'dekart_branch_group', 'branch_logistics_nearby', array( 'sanitize_callback' => 'sanitize_textarea_field' ) );
// Поля branch_map_url, branch_founded, branch_photos — удалены.
// Они дублировали CF таб «SEO и микроразметка» (schema_*).
// Чтение: inc/schema.php → dekart_schema_option() → CF → Settings API (backward compat).
@ -1970,6 +1976,21 @@ function dekart_branch_settings_page() {
<label>Почтовый индекс</label>
<input type="text" name="branch_postal_code" value="<?php echo esc_attr( get_option( 'branch_postal_code', '' ) ); ?>">
</div>
<div class="branch-field">
<label>Пешком от ориентира</label>
<input type="text" name="branch_logistics_walk" value="<?php echo esc_attr( get_option( 'branch_logistics_walk', '5 минут пешком от ТЦ «Глобус»' ) ); ?>">
<p class="desc">Например: «5 минут пешком от ТЦ «Глобус»</p>
</div>
<div class="branch-field">
<label>Парковка</label>
<input type="text" name="branch_logistics_parking" value="<?php echo esc_attr( get_option( 'branch_logistics_parking', 'Есть бесплатная парковка у входа' ) ); ?>">
<p class="desc">Например: «Есть бесплатная парковка у входа»</p>
</div>
<div class="branch-field">
<label>Рядом с школами/садами</label>
<input type="text" name="branch_logistics_schools" value="<?php echo esc_attr( get_option( 'branch_logistics_schools', 'Рядом со школами №9 и №12, детским садом №15' ) ); ?>">
<p class="desc">Например: «Рядом со школами №9 и №12, детским садом №15»</p>
</div>
</div>
</div>

View File

@ -211,8 +211,38 @@ class Pksh_Data {
[];
$this->branch['social'] = is_array( $raw ) ? $raw : [];
}
wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECONDS );
return $this->branch['social'];
wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECONDS );
return $this->branch['social'];
}
/**
* Логистика пешком от ТЦ (branch_logistics_walk)
*/
public function get_logistics_walk(): string {
if ( ! array_key_exists( 'logistics_walk', $this->branch ) ) {
$this->branch['logistics_walk'] = get_option( 'branch_logistics_walk', '5 минут пешком от ТЦ «Глобус»' );
}
return $this->branch['logistics_walk'];
}
/**
* Логистика парковка (branch_logistics_parking)
*/
public function get_logistics_parking(): string {
if ( ! array_key_exists( 'logistics_parking', $this->branch ) ) {
$this->branch['logistics_parking'] = get_option( 'branch_logistics_parking', 'Есть бесплатная парковка у входа' );
}
return $this->branch['logistics_parking'];
}
/**
* Логистика соседние школы/сад (branch_logistics_schools)
*/
public function get_logistics_nearby(): string {
if ( ! array_key_exists( 'logistics_nearby', $this->branch ) ) {
$this->branch['logistics_nearby'] = get_option( 'branch_logistics_schools', 'Рядом со школами №9 и №12, детским садом №15' );
}
return $this->branch['logistics_nearby'];
}
// ============================================================

View File

@ -22,6 +22,8 @@ $data = Pksh_Data::instance();
get_header();
?>
<?php get_template_part( 'template-parts/svg-sprite' ); ?>
<main class="page page-pksh">
<?php

View File

@ -10,13 +10,16 @@ if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$data = Pksh_Data::instance();
$opt_phone = $data->get_phone();
$opt_email = $data->get_email();
$opt_address = $data->get_address();
$opt_social = $data->get_social_links();
$opt_coords = $data->get_coords();
$opt_name = $data->get_name();
$data = Pksh_Data::instance();
$opt_phone = $data->get_phone();
$opt_email = $data->get_email();
$opt_address = $data->get_address();
$opt_social = $data->get_social_links();
$opt_coords = $data->get_coords();
$opt_name = $data->get_name();
$opt_logistics_walk = $data->get_logistics_walk();
$opt_logistics_parking = $data->get_logistics_parking();
$opt_logistics_nearby = $data->get_logistics_nearby();
?>
<section class="bento pksh-section" id="pksh-contact" aria-label="Контакты">
<div class="bento__full section-header--centered">
@ -43,18 +46,24 @@ $opt_name = $data->get_name();
<?php endif; ?>
<div class="pksh-contact__logistics">
<?php if ( ! empty( $opt_logistics_walk ) ) : ?>
<span class="pksh-contact__logistics-item">
<span class="pksh-contact__logistics-icon">📍</span>
<span class="pksh-contact__logistics-text">5 минут пешком от ТЦ «Глобус»</span>
<span class="pksh-contact__logistics-text"><?php echo esc_html( $opt_logistics_walk ); ?></span>
</span>
<?php endif; ?>
<?php if ( ! empty( $opt_logistics_parking ) ) : ?>
<span class="pksh-contact__logistics-item">
<span class="pksh-contact__logistics-icon">🅿️</span>
<span class="pksh-contact__logistics-text">Есть бесплатная парковка у входа</span>
<span class="pksh-contact__logistics-text"><?php echo esc_html( $opt_logistics_parking ); ?></span>
</span>
<?php endif; ?>
<?php if ( ! empty( $opt_logistics_nearby ) ) : ?>
<span class="pksh-contact__logistics-item">
<span class="pksh-contact__logistics-icon">🚸</span>
<span class="pksh-contact__logistics-text">Рядом со школами №9 и №12, детским садом №15</span>
<span class="pksh-contact__logistics-text"><?php echo esc_html( $opt_logistics_nearby ); ?></span>
</span>
<?php endif; ?>
</div>
<?php if ( ! empty( $opt_social ) && is_array( $opt_social ) ) : ?>

View File

@ -30,10 +30,7 @@ $hero_metrics = $data->get_social_counters();
<div class="ds-hero__content">
<div class="ds-hero__address">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/>
<circle cx="12" cy="10" r="3"/>
</svg>
<svg aria-hidden="true" width="16" height="16"><use href="#icon-location-pin"/></svg>
<span><?php echo esc_html( $opt_address ?: 'ул. Талсинская, 24' ); ?> — центр <?php echo esc_html( $branch_city_clean ?: 'Щёлково' ); ?></span>
</div>

View File

@ -24,7 +24,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<div class="steps-3">
<div class="step">
<div class="step__icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
<svg class="step-icon" aria-hidden="true"><use href="#icon-check"/></svg>
</div>
<div>
<strong>Вход в тему</strong>
@ -33,7 +33,7 @@ if ( ! defined( 'ABSPATH' ) ) {
</div>
<div class="step">
<div class="step__icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6-1.6 1.6a1 1 0 0 0 1.4 1.4l2.3-2.3a1 1 0 0 0 0-1.4L16.1 6.3a1 1 0 0 0-1.4 0z" fill="currentColor"/><path d="M4 6h13M4 12h9M4 18h13" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
<svg class="step-icon" aria-hidden="true"><use href="#icon-document"/></svg>
</div>
<div>
<strong>Игровое задание</strong>
@ -42,7 +42,7 @@ if ( ! defined( 'ABSPATH' ) ) {
</div>
<div class="step">
<div class="step__icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
<svg class="step-icon" aria-hidden="true"><use href="#icon-clock"/></svg>
</div>
<div>
<strong>Рефлексия</strong>
@ -59,7 +59,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<div class="objection-list">
<div class="objection-item">
<div class="objection-item__icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" stroke="#059669" stroke-width="2" stroke-linecap="round"/></svg>
<svg aria-hidden="true" width="24" height="24"><use href="#icon-check-circle"/></svg>
</div>
<div>
<strong>Не перегрузят ли ребёнка?</strong>
@ -68,22 +68,23 @@ if ( ! defined( 'ABSPATH' ) ) {
</div>
<div class="objection-item">
<div class="objection-item__icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" stroke="#059669" stroke-width="2" stroke-linecap="round"/></svg>
<svg aria-hidden="true" width="24" height="24"><use href="#icon-calendar"/></svg>
</div>
<div>
<strong>Успеем ли до сентября?</strong>
<p>Да. Наша программа рассчитана на 46 месяцев. Первые результаты через 3 недели.</p>
</div>
</div>
<div class="objection-item">
<div class="objection-item">
<div class="objection-item__icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" stroke="#059669" stroke-width="2" stroke-linecap="round"/></svg>
<svg aria-hidden="true" width="24" height="24"><use href="#icon-coin"/></svg>
</div>
<div>
<strong>Дорого?</strong>
<p>От 600 за занятие. Первое бесплатно. А если не понравится вернём деньги.</p>
<p>От 600&nbsp; за занятие. Первое бесплатно.</p>
</div>
</div>
</div>
</div>
</div>
</section>

View File

@ -71,9 +71,7 @@ $total_count = count( $review_items );
</div>
<div class="lw-stars lw-mt-8">
<?php for ( $i = 1; $i <= 5; $i++ ) : ?>
<svg class="lw-star <?php echo $i <= $stars ? 'lw-star--filled' : ''; ?>" width="16" height="16" viewBox="0 0 21 19" fill="none">
<path d="M9.58463 1.50884C9.89101 0.602477 11.1729 0.602476 11.4793 1.50884L13.1158 6.35007C13.2531 6.75637 13.6343 7.02985 14.0631 7.02985H19.2721C20.2504 7.02985 20.6467 8.28958 19.8447 8.84971L15.6995 11.7446C15.335 11.9991 15.1822 12.4636 15.3247 12.8847L16.9239 17.6158C17.233 18.5302 16.1954 19.3085 15.404 18.7559L11.1045 15.7533C10.7606 15.5131 10.3033 15.5131 9.95941 15.7533L5.65991 18.7559C4.86857 19.3085 3.83092 18.5302 4.14001 17.6158L5.73926 12.8847C5.8816 12.4636 5.72891 11.9991 5.36448 11.7446L1.21924 8.84971C0.417196 8.28958 0.813532 7.02985 1.79181 7.02985H7.00081C7.42969 7.02985 7.81081 6.75637 7.94815 6.35007L9.58463 1.50884Z" fill="currentColor"/>
</svg>
<svg class="lw-star <?php echo $i <= $stars ? 'lw-star--filled' : ''; ?>" aria-hidden="true" width="16" height="16"><use href="#<?php echo $i <= $stars ? 'icon-star-filled' : 'icon-star'; ?>"/></svg>
<?php endfor; ?>
</div>
<div class="lw-card__text lw-mt-8<?php echo $is_long ? ' review-card__text--clamped' : ''; ?>">

View File

@ -0,0 +1,77 @@
<?php
/**
* SVG Sprite общие иконки для page-podgotovka-k-shkole.php
* Подключается в футере через get_template_part('template-parts/svg-sprite')
*
* @package Dekart
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<svg xmlns="http://www.w3.org/2000/svg" style="display:none;" aria-hidden="true">
<symbol id="icon-check-circle" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</symbol>
<symbol id="icon-calendar" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"/>
<line x1="16" y1="2" x2="16" y2="6"/>
<line x1="8" y1="2" x2="8" y2="6"/>
<line x1="3" y1="10" x2="21" y2="10"/>
</symbol>
<symbol id="icon-coin" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
<path d="M12 6v12M6 12h12"/>
</symbol>
<symbol id="icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6-1.6 1.6a1 1 0 0 0 1.4 1.4l2.3-2.3a1 1 0 0 0 0-1.4L16.1 6.3a1 1 0 0 0-1.4 0z" fill="currentColor"/>
<path d="M4 6h13M4 12h9M4 18h13" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</symbol>
<symbol id="icon-document" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
</symbol>
<symbol id="icon-coin" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
<path d="M12 6v12M6 12h12"/>
</symbol>
<symbol id="icon-calendar" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"/>
<line x1="16" y1="2" x2="16" y2="6"/>
<line x1="8" y1="2" x2="8" y2="6"/>
<line x1="3" y1="10" x2="21" y2="10"/>
</symbol>
<symbol id="icon-location-pin" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/>
<circle cx="12" cy="10" r="3"/>
</symbol>
<symbol id="icon-star" viewBox="0 0 21 19" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polygon points="10.5 0 12.5 7.5 20 7.5 14 12.5 16 19.5 10.5 16 5 19.5 7 12.5 1 7.5 6 12.5"/>
</symbol>
<symbol id="icon-star-filled" viewBox="0 0 21 19" fill="currentColor">
<polygon points="10.5 0 12.5 7.5 20 7.5 14 12.5 16 19.5 10.5 16 5 19.5 7 12.5 1 7.5 6 12.5"/>
</symbol>
<symbol id="icon-clock" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
<path d="M12 6v6l4 2"/>
</symbol>
<symbol id="icon-menu" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 12h18M3 6h18M3 18h18"/>
</symbol>
<symbol id="icon-arrow-right" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M5 12h14M12 5l7 7-7 7"/>
</symbol>
</symbol>
</svg>