Global-2026-06-30

This commit is contained in:
Dekart Deploy Bot 2026-06-30 13:31:13 +00:00
parent 62b6b1eaa0
commit 8afa7ed71d
17 changed files with 1385 additions and 1200 deletions

View File

@ -2042,221 +2042,6 @@ html {
} }
/* contact END */ /* contact END */
/*
REVIEWS Yandex-style via lazeweb utilities
*/
.lw-scroll-x {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
padding-bottom: 8px;
}
.lw-scroll-x::-webkit-scrollbar {
height: 6px;
}
.lw-scroll-x::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 8px;
}
.lw-grid {
display: grid;
}
.lw-grid--3 {
grid-template-columns: repeat(3, 1fr);
}
.lw-grid--2 {
grid-template-columns: repeat(2, 1fr);
}
.lw-gap-20 {
gap: 20px;
}
.lw-flex {
display: flex;
}
.lw-flex--row {
flex-direction: row;
}
.lw-flex--col {
flex-direction: column;
}
.lw-gap-12 {
gap: 12px;
}
.lw-gap-8 {
gap: 8px;
}
.lw-items-center {
align-items: center;
}
.lw-justify-between {
justify-content: space-between;
}
.lw-card {
background: var(--color-bg);
border-radius: var(--card-radius);
padding: 20px;
box-shadow: var(--card-shadow);
display: flex;
flex-direction: column;
transition: box-shadow var(--transition-normal), transform var(--transition-normal);
}
.lw-card:hover {
box-shadow: var(--card-shadow-hover);
transform: translateY(-2px);
}
.lw-avatar {
border-radius: 50%;
overflow: hidden;
flex-shrink: 0;
background: rgba(59, 178, 160, 0.1);
display: flex;
align-items: center;
justify-content: space-between;
}
.lw-avatar--48 {
width: 48px;
height: 48px;
}
.lw-avatar__img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.lw-text-dark {
color: #1c2b2d;
}
.lw-text-gray {
color: #888;
}
.lw-text-sm {
font-size: 14px;
line-height: 1.4;
}
.lw-text-xs {
font-size: 12px;
line-height: 1.3;
}
.lw-font-medium {
font-weight: 500;
}
.lw-font-semibold {
font-weight: 600;
}
.lw-font-bold {
font-weight: 700;
}
.lw-mt-8 {
margin-top: 8px;
}
.lw-mb-8 {
margin-bottom: 8px;
}
.lw-mb-12 {
margin-bottom: 12px;
}
.lw-badge {
display: inline-flex;
align-items: center;
padding: 4px 10px;
border-radius: 50px;
font-size: 11px;
font-weight: 600;
line-height: 1.2;
white-space: nowrap;
margin-left: auto;
flex-shrink: 0;
}
.lw-badge--verified {
background: rgba(59, 178, 160, 0.1);
color: var(--color-secondary);
}
.lw-stars {
display: flex;
gap: 2px;
align-items: center;
}
.lw-star {
color: var(--color-text-light);
flex-shrink: 0;
}
.lw-star--filled {
color: #FFD43E;
}
.lw-card__text {
font-size: 14px;
line-height: 1.55;
color: var(--color-text-muted);
word-break: break-word;
}
/* ─── Десктоп: как карточки наставников ─── */
.camp-reviews .lw-scroll-x {
overflow: visible;
padding: 0;
}
.camp-reviews .lw-grid--3 {
display: flex;
flex-wrap: wrap;
gap: 30px;
justify-content: center;
}
.camp-reviews .lw-grid--3 .lw-card {
width: calc(25% - 23px);
min-width: 280px;
padding: 24px;
border-radius: 20px;
box-shadow: 0 2px 16px rgba(0,0,0,0.06);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.camp-reviews .lw-grid--3 .lw-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
}
@media (max-width: 1200px) {
.camp-reviews .lw-grid--3 .lw-card {
width: calc(50% - 15px);
min-width: 280px;
}
}
@media (max-width: 768px) {
.camp-reviews .lw-scroll-x {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
padding-bottom: 8px;
}
.camp-reviews .lw-grid--3 {
display: flex;
gap: 16px;
overflow-x: auto;
scroll-snap-type: x mandatory;
flex-wrap: nowrap;
justify-content: flex-start;
padding-bottom: 4px;
}
.camp-reviews .lw-grid--3 .lw-card {
flex: 0 0 300px;
width: auto;
scroll-snap-align: start;
}
}
@media (max-width: 480px) {
.camp-reviews .lw-grid--3 .lw-card {
flex: 0 0 260px;
}
}
/* reviews END*/ /* reviews END*/
.modal-camp-request-form { .modal-camp-request-form {

View File

@ -4265,11 +4265,15 @@ footer a:hover,
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: #000; background-color: rgba(0,0,0,0.6);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
z-index: 99999; z-index: 99999;
padding: 20px;
box-sizing: border-box;
} }
.btn-close-slider { .btn-close-slider {
@ -4363,6 +4367,23 @@ footer a:hover,
width: 50%; width: 50%;
} }
.b24-form-placeholder {
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
padding: 40px 30px;
text-align: center;
}
.b24-form-placeholder__text {
font-family: 'Roboto', sans-serif;
font-size: 18px;
line-height: 1.5;
color: #fff;
max-width: 360px;
margin: 0;
}
.banner-circle { .banner-circle {
position: absolute; position: absolute;
border-radius: 50%; border-radius: 50%;
@ -4506,9 +4527,21 @@ footer a:hover,
.form-wrapper { .form-wrapper {
position: relative; position: relative;
width: 100%;
max-width: 560px;
margin: 0 auto;
background: #fff;
border-radius: 20px;
padding: 40px 32px 32px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
max-height: 90vh;
overflow-y: auto;
}
.form-wrapper .b24-form-container {
width: 100%;
} }
.form-wrapper .b24-form { .form-wrapper .b24-form {
border-radius: 30px; border-radius: 12px;
overflow: hidden; overflow: hidden;
} }
@ -9664,6 +9697,17 @@ footer a:hover,
--radius-lg: 16px; --radius-lg: 16px;
--radius-xl: 20px; --radius-xl: 20px;
--radius-pill: 28px; --radius-pill: 28px;
/* ── Card component (shared lw-*) ── */
--color-primary: #E8753A;
--color-bg: #FFFFFF;
--color-text-muted: #5A6B6D;
--color-text-light: #8A9A9D;
--card-radius: 20px;
--card-shadow: 0 2px 16px rgba(0,0,0,0.06);
--card-shadow-hover: 0 8px 32px rgba(0,0,0,0.1);
--transition-fast: 0.2s ease;
--transition-normal: 0.3s ease;
} }
/* ── 2. Bento Grid System ── */ /* ── 2. Bento Grid System ── */
@ -10248,6 +10292,352 @@ footer a:hover,
animation: none; animation: none;
} }
/*
Shared Review Card Components (lw-*)
Used by /otzyvy/, /lager/, and all service pages.
Page-specific grid/layout overrides in page CSS files.
*/
/* ── Layout utilities ── */
.lw-flex { display: flex; }
.lw-flex--row { flex-direction: row; }
.lw-flex--col { flex-direction: column; }
.lw-flex--wrap { flex-wrap: wrap; }
.lw-items-center { align-items: center; }
.lw-items-start { align-items: flex-start; }
.lw-justify-center { justify-content: center; }
.lw-justify-between { justify-content: space-between; }
.lw-gap-8 { gap: 8px; }
.lw-gap-12 { gap: 12px; }
.lw-gap-20 { gap: 20px; }
.lw-mt-8 { margin-top: 8px; }
.lw-mb-8 { margin-bottom: 8px; }
.lw-mb-12 { margin-bottom: 12px; }
/* ── Scroll wrapper ── */
.lw-scroll-x {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
padding-bottom: 8px;
}
.lw-scroll-x::-webkit-scrollbar { height: 6px; }
.lw-scroll-x::-webkit-scrollbar-thumb { background: #ccc; border-radius: 8px; }
/* ── Grid ── */
.lw-grid { display: grid; }
.lw-grid--2 { grid-template-columns: repeat(2, 1fr); }
.lw-grid--3 { grid-template-columns: repeat(3, 1fr); }
/* ── Card ── */
.lw-card {
background: var(--color-bg);
border-radius: var(--card-radius);
padding: 20px;
box-shadow: var(--card-shadow);
display: flex;
flex-direction: column;
transition: box-shadow var(--transition-normal), transform var(--transition-normal);
}
.lw-card:hover {
box-shadow: var(--card-shadow-hover);
transform: translateY(-2px);
}
/* ── Avatar ── */
.lw-avatar {
border-radius: 50%;
overflow: hidden;
flex-shrink: 0;
background: rgba(59, 178, 160, 0.1);
display: flex;
align-items: center;
justify-content: center;
}
.lw-avatar--48 { width: 48px; height: 48px; }
.lw-avatar__img {
width: 100%; height: 100%;
object-fit: cover;
display: block;
}
.lw-avatar--letter { background: rgba(232, 117, 58, 0.08); }
.lw-avatar__letter {
display: block;
font-size: 18px;
font-weight: 700;
color: var(--color-primary);
line-height: 1;
user-select: none;
}
/* ── Typography ── */
.lw-text-dark { color: #1c2b2d; }
.lw-text-gray { color: var(--color-text-muted); }
.lw-text-sm { font-size: 14px; line-height: 1.4; }
.lw-text-xs { font-size: 12px; line-height: 1.3; }
.lw-font-medium { font-weight: 500; }
.lw-font-semibold { font-weight: 600; }
.lw-font-bold { font-weight: 700; }
/* ── Badge ── */
.lw-badge {
display: inline-flex;
align-items: center;
padding: 4px 10px;
border-radius: 50px;
font-size: 11px;
font-weight: 600;
line-height: 1.2;
white-space: nowrap;
margin-left: auto;
flex-shrink: 0;
}
.lw-badge--verified {
background: #059669;
color: #fff;
border-radius: 50px;
padding: 3px 12px 3px 10px;
font-size: 11px;
font-weight: 600;
line-height: 1.4;
white-space: nowrap;
align-self: flex-start;
}
.lw-card .lw-text-gray + .lw-badge--verified { margin-top: 6px; }
/* ── Stars ── */
.lw-stars { display: flex; gap: 2px; align-items: center; }
.lw-star { color: var(--color-text-light); flex-shrink: 0; }
.lw-star--filled { color: #FFD43E; }
/* ── Card text ── */
.lw-card__text {
font-size: 14px;
line-height: 1.55;
color: var(--color-text-muted);
word-break: break-word;
}
/* ── Card footer (date + read-more) ── */
.review-card__footer {
display: flex;
align-items: center;
gap: 12px;
margin-top: 8px;
}
.review-card__date {
margin-left: auto;
font-size: 13px;
color: var(--color-text-muted);
white-space: nowrap;
}
/* ── Read-more button ── */
.review-card__btn-more {
display: inline-block;
padding: 0;
border: none;
background: none;
color: var(--accent);
font-weight: 600;
font-size: 14px;
cursor: pointer;
align-self: flex-start;
}
.review-card__btn-more:hover {
text-decoration: underline;
}
/* ── Clamped text (long reviews) ── */
.review-card__text--clamped {
position: relative;
max-height: 120px;
overflow: hidden;
transition: max-height .4s ease;
}
.review-card__text--clamped.review-card__text--expanded {
max-height: 2000px;
}
.review-card__text--clamped:not(.review-card__text--expanded)::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 40px;
background: linear-gradient(transparent, var(--color-bg));
}
/* ── Reveal animation (batch-loaded cards) ── */
.reveal {
opacity: 0;
transform: translateY(24px);
transition: opacity .6s ease, transform .6s ease;
}
.reveal--visible {
opacity: 1;
transform: translateY(0);
}
/* ── Teacher link ── */
.review-card__teacher-link {
color: var(--accent);
text-decoration: underline;
text-underline-offset: 3px;
text-decoration-color: currentColor;
transition: color .2s, font-weight .2s;
font-weight: 500;
}
.review-card__teacher-link:hover {
color: var(--accent-hover);
font-weight: 700;
}
/*
Shared Reviews Grid / Scroll Layout (.reviews-cards)
Same layout for /otzyvy/, /lager/, /podgotovka-k-shkole/.
*/
/* ─── Desktop: flex-wrap centered grid ─── */
.reviews-cards .lw-scroll-x {
overflow: visible;
padding: 0;
}
.reviews-cards .lw-grid--3 {
display: flex;
flex-wrap: wrap;
gap: 24px;
justify-content: center;
}
.reviews-cards .lw-grid--3 .lw-card {
width: calc(33.33% - 16px);
min-width: 280px;
padding: 24px;
border-radius: 20px;
box-shadow: 0 2px 16px rgba(0,0,0,0.06);
border: 1.5px solid rgba(0,0,0,0.12);
transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease, background 0.3s ease;
}
.reviews-cards .lw-grid--3 .lw-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
border-color: rgba(124, 58, 237, 0.15);
background: var(--accent-light);
}
/* ─── 3 → 2 columns ─── */
@media (max-width: 1200px) {
.reviews-cards .lw-grid--3 .lw-card {
width: calc(50% - 12px);
min-width: 280px;
}
}
/* ─── Mobile horizontal scroll ─── */
@media (max-width: 768px) {
.reviews-cards .lw-scroll-x {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
padding-bottom: 8px;
}
.reviews-cards .lw-grid--3 {
display: flex;
gap: 16px;
overflow-x: auto;
scroll-snap-type: x mandatory;
flex-wrap: nowrap;
justify-content: flex-start;
padding-bottom: 4px;
}
.reviews-cards .lw-grid--3 .lw-card {
flex: 0 0 88vw;
scroll-snap-align: start;
position: relative;
}
.reviews-cards .lw-card > .lw-flex.lw-flex--row {
flex-wrap: wrap;
gap: 8px 12px;
align-items: flex-start;
}
.reviews-cards .lw-card .lw-avatar {
flex-shrink: 0;
}
.reviews-cards .lw-card > .lw-flex.lw-flex--row > .lw-flex.lw-flex--col {
flex: 1;
min-width: 0;
padding-right: 90px;
}
.reviews-cards .lw-card .lw-badge--verified {
margin-top: 6px;
margin-left: 0;
}
.reviews-cards .lw-card .lw-stars {
position: absolute;
top: 24px;
right: 24px;
margin-top: 0;
}
}
@media (max-width: 480px) {
.reviews-cards .lw-grid--3 .lw-card {
padding: 16px;
}
.reviews-cards .lw-card .lw-stars {
top: 16px;
right: 16px;
}
}
/* ─── Batch loading: hide cards after first batch on desktop ─── */
@media (min-width: 769px) {
.lw-card[data-batch]:not([data-batch="1"]) {
display: none;
}
}
/* ─── Mobile: all cards visible (horizontal scroll shows all) ─── */
@media (max-width: 768px) {
.lw-card[data-batch]:not([data-batch="1"]) {
display: flex;
}
}
/* ─── Load more button ─── */
.reviews-loadmore {
text-align: center;
margin-top: 32px;
}
.reviews-loadmore__btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 14px 36px;
font-size: 16px;
font-weight: 600;
color: var(--accent);
background: var(--accent-light);
border: 2px solid var(--accent);
border-radius: 12px;
cursor: pointer;
transition: background var(--transition-fast), transform var(--transition-fast);
}
.reviews-loadmore__btn:hover {
background: rgba(124, 58, 237, 0.15);
transform: translateY(-2px);
}
.reviews-loadmore__btn:active {
transform: translateY(0);
}
.reviews-loadmore__btn:disabled {
opacity: 0.5;
cursor: default;
transform: none;
}
@media (max-width: 768px) {
.reviews-loadmore {
display: none;
}
}
/* ── Reduced Motion ── */ /* ── Reduced Motion ── */
@media (prefers-reduced-motion: reduce) { @media (prefers-reduced-motion: reduce) {
.bento-card { .bento-card {
@ -10257,8 +10647,18 @@ footer a:hover,
transition: none; transition: none;
} }
.btn-primary, .btn-primary,
.btn-secondary { .btn-secondary,
.lw-card,
.lw-card:hover {
transition: none; transition: none;
transform: none;
}
.reveal,
.reveal--visible {
transition: none !important;
transform: none !important;
animation: none !important;
opacity: 1 !important;
} }
} }

View File

@ -745,16 +745,88 @@ background: rgba(124, 58, 237, 0.2);
} }
/* ============================================================ /* ============================================================
14. OVERRIDE: fix CTA gap 640860px 14. MOBILE STICKY CTA only shown on mobile (< 861px)
Sticky CTA appears at 860px to match when banner CTA hides ============================================================ */
============================================================ */ .sticky-cta-mobile {
display: none;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 999;
background: rgba(255,255,255,0.97);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border-top: 1px solid #E2E8F0;
padding: 12px 16px;
box-shadow: 0 -4px 20px rgba(0,0,0,0.08);
animation: stickyFadeIn 0.3s ease;
}
.sticky-cta-mobile__inner {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
max-width: 500px;
margin: 0 auto;
}
.sticky-cta-mobile__text {
font-size: 0.9375rem;
color: #0F172A;
font-weight: 500;
line-height: 1.3;
}
.sticky-cta-mobile__text strong {
color: #7C3AED;
}
.sticky-cta-mobile__btn {
flex-shrink: 0;
padding: 12px 24px;
font-size: 0.9375rem;
font-weight: 700;
border: none;
border-radius: 32px;
background: linear-gradient(135deg, #7C3AED, #8B5CF6);
color: #fff;
cursor: pointer;
font-family: 'Roboto', sans-serif;
transition: opacity 0.15s, transform 0.15s;
white-space: nowrap;
min-height: 48px;
}
.sticky-cta-mobile__btn:hover {
opacity: 0.95;
transform: translateY(-1px);
}
@media (max-width: 860px) { @media (max-width: 860px) {
.sticky-cta-mobile { .sticky-cta-mobile {
display: block; display: block;
} }
body { body {
padding-bottom: 80px; padding-bottom: 76px !important;
} }
}
@media (max-width: 380px) {
.sticky-cta-mobile__text {
font-size: 0.8125rem;
}
.sticky-cta-mobile__btn {
padding: 10px 18px;
font-size: 0.875rem;
}
}
@media (min-width: 861px) {
.sticky-cta-mobile {
display: none !important;
}
} }
/* ============================================================ /* ============================================================
@ -779,17 +851,20 @@ background: rgba(124, 58, 237, 0.2);
19. OVERRIDE: Header btn-lilac use accent 19. OVERRIDE: Header btn-lilac use accent
Legacy header button should match brand Legacy header button should match brand
============================================================ */ ============================================================ */
.page-pksh button.btn-lilac,
.page-pksh a.btn-lilac,
.page-pksh .btn-lilac { .page-pksh .btn-lilac {
background: linear-gradient(135deg, var(--accent, #7C3AED), var(--accent-500, #8B5CF6)) !important; background: linear-gradient(135deg, var(--accent, #7C3AED), var(--accent-500, #8B5CF6));
font-family: 'Roboto', sans-serif !important; font-family: 'Roboto', sans-serif;
font-weight: 700 !important; font-weight: 700;
text-transform: none !important; text-transform: none;
border-radius: var(--radius-pill, 28px) !important; border-radius: var(--radius-pill, 28px);
border: none !important; border: none;
} }
.page-pksh .btn-lilac:hover { .page-pksh .btn-lilac:hover,
background: linear-gradient(135deg, var(--accent-hover, #6D28D9), var(--accent-700, #5B21B6)) !important; .page-pksh .btn-lilac:focus {
background: linear-gradient(135deg, var(--accent-hover, #6D28D9), var(--accent-700, #5B21B6));
} }
/* ============================================================ /* ============================================================
@ -2312,244 +2387,10 @@ background: rgba(124, 58, 237, 0.2);
margin: 0 auto; margin: 0 auto;
} }
/* ── Layout utilities (scoped) ── */
.page-pksh .pksh-reviews .lw-scroll-x {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
padding-bottom: 8px;
}
.page-pksh .pksh-reviews .lw-scroll-x::-webkit-scrollbar {
height: 6px;
}
.page-pksh .pksh-reviews .lw-scroll-x::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 8px;
}
.page-pksh .pksh-reviews .lw-grid {
display: grid;
}
.page-pksh .pksh-reviews .lw-grid--3 {
grid-template-columns: repeat(3, 1fr);
}
.page-pksh .pksh-reviews .lw-gap-20 {
gap: 20px;
}
.page-pksh .pksh-reviews .lw-flex {
display: flex;
}
.page-pksh .pksh-reviews .lw-flex--row {
flex-direction: row;
}
.page-pksh .pksh-reviews .lw-flex--col {
flex-direction: column;
}
.page-pksh .pksh-reviews .lw-gap-12 {
gap: 12px;
}
.page-pksh .pksh-reviews .lw-items-center {
align-items: center;
}
/* ── Card ── */
.page-pksh .pksh-reviews .lw-card {
background: #FFFFFF;
border-radius: 20px;
padding: 20px;
display: flex;
flex-direction: column;
transition: box-shadow 0.3s ease, transform 0.3s ease;
}
/* ── Avatar ── */
.page-pksh .pksh-reviews .lw-avatar {
border-radius: 50%;
overflow: hidden;
flex-shrink: 0;
background: rgba(124, 58, 237, 0.08);
display: flex;
align-items: center;
justify-content: center;
}
.page-pksh .pksh-reviews .lw-avatar--48 {
width: 48px;
height: 48px;
}
.page-pksh .pksh-reviews .lw-avatar__img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
/* ── Typography ── */
.page-pksh .pksh-reviews .lw-text-dark {
color: #1c2b2d;
}
.page-pksh .pksh-reviews .lw-font-semibold {
font-weight: 600;
}
/* ── Spacing ── */
.page-pksh .pksh-reviews .lw-mt-8 {
margin-top: 8px;
}
/* ── Badge ── */
.page-pksh .pksh-reviews .lw-badge {
display: inline-flex;
align-items: center;
padding: 4px 10px;
border-radius: 50px;
font-size: 11px;
font-weight: 600;
line-height: 1.2;
white-space: nowrap;
margin-left: auto;
flex-shrink: 0;
}
.page-pksh .pksh-reviews .lw-badge--verified {
background: rgba(124, 58, 237, 0.08);
color: #7C3AED;
}
/* ── Stars ── */
.page-pksh .pksh-reviews .lw-stars {
display: flex;
gap: 2px;
align-items: center;
}
.page-pksh .pksh-reviews .lw-star {
color: #D1D5DB;
flex-shrink: 0;
}
.page-pksh .pksh-reviews .lw-star--filled {
color: #FFD43E;
}
/* ── Card text ── */
.page-pksh .pksh-reviews .lw-card__text {
font-size: 14px;
line-height: 1.55;
color: #475569;
word-break: break-word;
}
/* ── Desktop: flex-wrap centered grid ── */
.page-pksh .pksh-reviews .lw-scroll-x {
overflow: visible;
padding: 0;
}
.page-pksh .pksh-reviews .lw-grid--3 {
display: flex;
flex-wrap: wrap;
gap: 30px;
justify-content: center;
}
.page-pksh .pksh-reviews .lw-grid--3 .lw-card {
width: calc(25% - 23px);
min-width: 280px;
padding: 24px;
box-shadow: 0 2px 16px rgba(0,0,0,0.06);
}
.page-pksh .pksh-reviews .lw-grid--3 .lw-card:hover {
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
transform: translateY(-4px);
}
@media (max-width: 1200px) {
.page-pksh .pksh-reviews .lw-grid--3 .lw-card {
width: calc(50% - 15px);
min-width: 280px;
}
}
@media (max-width: 768px) { @media (max-width: 768px) {
.page-pksh .pksh-reviews { .page-pksh .pksh-reviews {
padding: 40px 0; padding: 40px 0;
} }
.page-pksh .pksh-reviews .lw-scroll-x {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
padding: 0 0 8px 16px;
margin: 0;
}
.page-pksh .pksh-reviews .lw-grid--3 {
display: flex;
gap: 12px;
overflow-x: auto;
scroll-snap-type: x mandatory;
flex-wrap: nowrap;
justify-content: flex-start;
padding: 0 0 4px 0;
margin: 0;
-webkit-overflow-scrolling: touch;
}
.page-pksh .pksh-reviews .lw-grid--3 .lw-card {
flex: 0 0 280px;
width: auto;
min-width: 0;
scroll-snap-align: start;
}
/* Mobile: all cards visible regardless of pagination state */
.page-pksh .pksh-reviews .lw-card {
display: flex !important;
}
.page-pksh .pksh-reviews__actions {
display: none !important;
}
}
@media (max-width: 480px) {
.page-pksh .pksh-reviews .lw-grid--3 .lw-card {
flex: 0 0 250px;
}
}
/* ============================================================
43. REVIEWS pagination / load more
============================================================ */
/* Default collapsed: show 2 rows per breakpoint */
.page-pksh .pksh-reviews [data-pksh-collapsed] .lw-card:nth-child(n+9) {
display: none;
}
@media (max-width: 1200px) {
.page-pksh .pksh-reviews [data-pksh-collapsed] .lw-card:nth-child(n+5) {
display: none;
}
}
/* Expanded: override nth-child, show all */
.page-pksh .pksh-reviews [data-pksh-expanded] .lw-card {
display: flex;
}
.page-pksh .pksh-reviews__actions {
display: flex;
justify-content: center;
margin-top: 32px;
}
.page-pksh .pksh-reviews__toggle {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 32px;
font-size: 15px;
font-weight: 600;
font-family: inherit;
color: #7C3AED;
background: rgba(124, 58, 237, 0.08);
border: 1.5px solid rgba(124, 58, 237, 0.2);
border-radius: 100px;
cursor: pointer;
transition: background 0.2s, border-color 0.2s, transform 0.15s;
}
.page-pksh .pksh-reviews__toggle:hover {
background: rgba(124, 58, 237, 0.15);
border-color: rgba(124, 58, 237, 0.35);
transform: translateY(-1px);
}
.page-pksh .pksh-reviews__toggle:active {
transform: translateY(0);
} }
/* ============================================================ /* ============================================================
@ -2986,3 +2827,350 @@ background: rgba(124, 58, 237, 0.2);
radial-gradient(ellipse at 50% 0%, rgba(124, 58, 237, 0.025) 0%, transparent 60%); radial-gradient(ellipse at 50% 0%, rgba(124, 58, 237, 0.025) 0%, transparent 60%);
} }
} }
/* ============================================================
50. TRUST AUTHORITY Why Trust Us block
============================================================ */
.trust-authority {
max-width: 1000px;
margin: 0 auto;
text-align: center;
}
.trust-authority__grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
margin-top: 32px;
}
.trust-authority__item {
background: #fff;
border-radius: 20px;
padding: 32px 24px;
text-align: center;
box-shadow: 0 4px 20px rgba(0,0,0,0.05);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.trust-authority__item:hover {
transform: translateY(-4px);
box-shadow: 0 12px 36px rgba(0,0,0,0.10);
}
.trust-authority__icon {
font-size: 2.5rem;
display: block;
margin-bottom: 16px;
}
.trust-authority__title {
display: block;
font-size: 1.125rem;
font-weight: 700;
color: #0F172A;
margin-bottom: 8px;
}
.trust-authority__text {
font-size: 0.9375rem;
color: #475569;
line-height: 1.55;
margin: 0;
}
@media (max-width: 768px) {
.trust-authority__grid {
grid-template-columns: 1fr;
gap: 16px;
}
.trust-authority__item {
padding: 24px 20px;
}
}
/* ============================================================
51. EXTERNAL REVIEWS Cross-links
============================================================ */
.external-reviews {
max-width: 1000px;
margin: 0 auto;
text-align: center;
}
.external-reviews__grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
margin-top: 32px;
}
.external-reviews__card {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
padding: 24px 16px;
background: #fff;
border-radius: 16px;
text-decoration: none;
box-shadow: 0 2px 12px rgba(0,0,0,0.05);
transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.external-reviews__card:hover {
transform: translateY(-3px);
box-shadow: 0 8px 24px rgba(0,0,0,0.10);
}
.external-reviews__icon {
font-size: 1.5rem;
font-weight: 800;
color: #7C3AED;
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
background: rgba(124,58,237,0.08);
border-radius: 12px;
}
.external-reviews__name {
font-size: 0.9375rem;
font-weight: 600;
color: #0F172A;
}
.external-reviews__rating {
font-size: 0.875rem;
color: #475569;
}
@media (max-width: 768px) {
.external-reviews__grid {
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
}
/* ============================================================
52. FINAL CTA Countdown timer
============================================================ */
.final-cta__timer {
margin: 20px auto 24px;
text-align: center;
}
.final-cta__timer-label {
display: block;
font-size: 0.875rem;
font-weight: 600;
color: #7C3AED;
margin-bottom: 12px;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.final-cta__timer-digits {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.final-cta__timer-unit {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
}
.final-cta__timer-num {
font-size: 2.5rem;
font-weight: 800;
color: #0F172A;
line-height: 1;
font-family: 'Oswald', sans-serif;
min-width: 60px;
text-align: center;
background: #F8FAFC;
padding: 8px 12px;
border-radius: 12px;
border: 1px solid #E2E8F0;
}
.final-cta__timer-text {
font-size: 0.75rem;
color: #94A3B8;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.final-cta__timer-sep {
font-size: 2rem;
font-weight: 700;
color: #7C3AED;
margin-top: -20px;
}
@media (max-width: 480px) {
.final-cta__timer-num {
font-size: 1.75rem;
min-width: 44px;
padding: 6px 8px;
}
.final-cta__timer-sep {
font-size: 1.5rem;
}
}
/* ============================================================
53. MICRO-COMMIT Inline form
============================================================ */
.micro-commit__form {
display: flex;
flex-direction: column;
gap: 10px;
margin-top: 12px;
}
.micro-commit__input {
padding: 14px 18px;
font-size: 1rem;
border: 1.5px solid #DED3C0;
border-radius: 12px;
font-family: inherit;
background: #fff;
transition: border-color 0.2s;
width: 100%;
max-width: 360px;
box-sizing: border-box;
}
.micro-commit__input:focus {
outline: none;
border-color: #7C3AED;
box-shadow: 0 0 0 3px rgba(124,58,237,0.1);
}
.micro-commit__form .micro-commit__btn {
margin-top: 4px;
}
@media (max-width: 639px) {
.micro-commit__input {
max-width: 100%;
}
}
/* ============================================================
54. CONTAINER QUERIES Card components adapt to container
Support: Chrome 111+, Safari 17+, Firefox 124+
============================================================ */
/* ── Program cards — container context ── */
.page-pksh .programs-grid {
container-type: inline-size;
container-name: programs-grid;
}
@container programs-grid (max-width: 400px) {
.program-card__header {
flex-direction: column;
text-align: center;
padding: 16px;
}
.program-card__pricing {
align-items: center;
text-align: center;
}
.program-card__price-main {
flex-direction: column;
align-items: center;
}
}
/* ── Trust authority cards — container context ── */
.page-pksh .trust-authority__grid {
container-type: inline-size;
container-name: trust-grid;
}
@container trust-grid (max-width: 350px) {
.trust-authority__item {
padding: 20px 16px;
}
}
/* ============================================================
55. REDUCED MOTION Comprehensive preferences
============================================================ */
@media (prefers-reduced-motion: reduce) {
/* Hero animations */
.hero-pksh__blob,
.hero-pksh__sparkle,
.hero-pksh__float,
.hero-pksh__deco,
.hero-pksh__photo-frame,
.hero-pksh__photo-ring,
.hero-pksh__scarcity,
.hero-pksh__cta {
animation: none !important;
transition: none !important;
}
/* Card hover effects */
.program-card,
.program-card__btn,
.social-counter,
.trust-authority__item,
.external-reviews__card,
.lw-card {
transition: none !important;
transform: none !important;
}
.program-card:hover,
.social-counter:hover,
.trust-authority__item:hover,
.external-reviews__card:hover,
.lw-card:hover {
transform: none !important;
}
/* Sticky elements fade */
.sticky-cta-desktop,
.sticky-cta-mobile {
animation: none !important;
}
/* Scarcity pulse */
.pksh-fomo__dot,
.banner__scarcity {
animation: none !important;
}
/* Hero CTA glow */
.hero-pksh__cta {
animation: none !important;
}
/* Ensure elements that depend on scroll-driven animations are static */
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
scroll-behavior: auto !important;
}
}
/* ============================================================
56. IMPROVED SCROLLBAR STYLING System-wide
============================================================ */
@media (prefers-reduced-motion: no-preference) {
html {
scroll-behavior: smooth;
}
}

View File

@ -469,253 +469,6 @@
padding: 8px 0 0; padding: 8px 0 0;
} }
} }
/* ─── LW-утилиты (как на странице лагеря) ─── */
.lw-grid {
display: grid;
}
.lw-grid--3 {
grid-template-columns: repeat(3, 1fr);
}
.lw-gap-20 {
gap: 20px;
}
.lw-flex {
display: flex;
}
.lw-flex--row {
flex-direction: row;
}
.lw-flex--col {
flex-direction: column;
}
.lw-gap-12 {
gap: 12px;
}
.lw-gap-8 {
gap: 8px;
}
.lw-items-center {
align-items: center;
}
.lw-justify-between {
justify-content: space-between;
}
.lw-card {
background: var(--color-bg);
border-radius: var(--card-radius);
padding: 20px;
box-shadow: var(--card-shadow);
display: flex;
flex-direction: column;
transition: box-shadow var(--transition-normal), transform var(--transition-normal);
}
.lw-card:hover {
box-shadow: var(--card-shadow-hover);
transform: translateY(-2px);
}
.lw-avatar {
border-radius: 50%;
overflow: hidden;
flex-shrink: 0;
background: rgba(59, 178, 160, 0.1);
display: flex;
align-items: center;
justify-content: center;
}
.lw-avatar--48 {
width: 48px;
height: 48px;
}
.lw-avatar__img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.lw-avatar--letter {
background: rgba(232, 117, 58, 0.08); /* --color-primary 8% */
}
.lw-avatar__letter {
display: block;
font-size: 18px;
font-weight: 700;
color: var(--color-primary);
line-height: 1;
user-select: none;
}
.lw-text-dark {
color: #1c2b2d;
}
.lw-text-gray {
color: var(--color-text-muted);
}
.lw-text-sm {
font-size: 14px;
line-height: 1.4;
}
.lw-text-xs {
font-size: 12px;
line-height: 1.3;
}
.lw-font-medium {
font-weight: 500;
}
.lw-font-semibold {
font-weight: 600;
}
.lw-font-bold {
font-weight: 700;
}
.lw-mt-8 {
margin-top: 8px;
}
.lw-mb-8 {
margin-bottom: 8px;
}
.lw-mb-12 {
margin-bottom: 12px;
}
.lw-badge {
display: inline-flex;
align-items: center;
padding: 4px 10px;
border-radius: 50px;
font-size: 11px;
font-weight: 600;
line-height: 1.2;
white-space: nowrap;
margin-left: auto;
flex-shrink: 0;
}
.lw-badge--verified {
background: #059669;
color: #fff;
border-radius: 50px;
padding: 3px 12px 3px 10px;
font-size: 11px;
font-weight: 600;
line-height: 1.4;
white-space: nowrap;
align-self: flex-start;
}
.lw-card .lw-text-gray + .lw-badge--verified {
margin-top: 6px;
}
.lw-stars {
display: flex;
gap: 2px;
align-items: center;
}
.lw-star {
color: var(--color-text-light);
flex-shrink: 0;
}
.lw-star--filled {
color: #FFD43E;
}
.lw-card__text {
font-size: 14px;
line-height: 1.55;
color: var(--color-text-muted);
word-break: break-word;
}
/* ─── Сетка отзывов (как на странице лагеря) ─── */
.reviews-cards .lw-scroll-x {
overflow: visible;
padding: 0;
}
.reviews-cards .lw-grid--3 {
display: flex;
flex-wrap: wrap;
gap: 24px;
justify-content: center;
}
.reviews-cards .lw-grid--3 .lw-card {
width: calc(33.33% - 16px);
min-width: 280px;
padding: 24px;
border-radius: 20px;
box-shadow: 0 2px 16px rgba(0,0,0,0.06);
border: 1.5px solid rgba(0,0,0,0.12);
transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease, background 0.3s ease;
}
.reviews-cards .lw-grid--3 .lw-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
border-color: rgba(124, 58, 237, 0.15);
background: var(--accent-light);
}
/* ─── Clamp текста для длинных отзывов ─── */
.review-card__text--clamped {
position: relative;
max-height: 120px;
overflow: hidden;
transition: max-height .4s ease;
}
.review-card__text--clamped.review-card__text--expanded {
max-height: 2000px;
}
.review-card__text--clamped:not(.review-card__text--expanded)::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 40px;
background: linear-gradient(transparent, var(--color-bg));
}
.review-card__btn-more {
display: inline-block;
padding: 0;
border: none;
background: none;
color: var(--accent);
font-weight: 600;
font-size: 14px;
cursor: pointer;
align-self: flex-start;
}
.review-card__btn-more:hover {
text-decoration: underline;
}
/* ─── ФУТЕР КАРТОЧКИ: дата + "Читать ещё" ─── */
.review-card__footer {
display: flex;
align-items: center;
gap: 12px;
margin-top: 8px;
}
.review-card__date {
margin-left: auto;
font-size: 13px;
color: var(--color-text-muted);
white-space: nowrap;
}
/* ─── Ссылка на преподавателя в карточке отзыва ─── */
.review-card__teacher-link {
color: var(--accent);
text-decoration: underline;
text-underline-offset: 3px;
text-decoration-color: currentColor;
transition: color .2s, font-weight .2s;
font-weight: 500;
}
.review-card__teacher-link:hover {
color: var(--accent-hover);
font-weight: 700;
}
/* ─── РЕЗУЛЬТАТЫ (блок с цифрами) ─── */ /* ─── РЕЗУЛЬТАТЫ (блок с цифрами) ─── */
.results { .results {
padding: 40px 0; padding: 40px 0;
@ -1317,26 +1070,10 @@
} }
/* ─── АНИМАЦИЯ ПОЯВЛЕНИЯ ─── */ /* ─── АНИМАЦИЯ ПОЯВЛЕНИЯ ─── */
.reveal { /* .reveal moved to main.css */
opacity: 0;
transform: translateY(24px);
transition: opacity .6s ease, transform .6s ease;
}
.reveal--visible {
opacity: 1;
transform: translateY(0);
}
/* ─── АДАПТИВНОСТЬ ─── */ /* ─── АДАПТИВНОСТЬ ─── */
/* Сетка отзывов: 3 → 2 колонки */
@media (max-width: 1200px) {
.reviews-cards .lw-grid--3 .lw-card {
width: calc(50% - 12px);
min-width: 280px;
}
}
@media (max-width: 860px) { @media (max-width: 860px) {
.reviews-hero { .reviews-hero {
padding: 40px 0; padding: 40px 0;
@ -1431,68 +1168,6 @@
width: 100%; width: 100%;
justify-content: center; justify-content: center;
} }
/* ─── Карточка: position для absolute звёзд ─── */
.reviews-cards .lw-grid--3 .lw-card {
position: relative;
}
/* ─── Шапка: wrap чтобы бейдж уходил на новую строку ─── */
.reviews-cards .lw-card > .lw-flex.lw-flex--row {
flex-wrap: wrap;
gap: 8px 12px;
align-items: flex-start;
}
/* Аватар не сжимается */
.reviews-cards .lw-card .lw-avatar {
flex-shrink: 0;
}
/* Колонка имени: занимает остаток, не даём тексту залезть под звёзды */
.reviews-cards .lw-card > .lw-flex.lw-flex--row > .lw-flex.lw-flex--col {
flex: 1;
min-width: 0;
padding-right: 90px;
}
/* Преподаватель и ФИО — на разных строках */
.reviews-cards .lw-card .review-card__teacher-link {
display: block;
}
/* ─── Бейдж в колонке имени ─── */
.reviews-cards .lw-card .lw-badge--verified {
margin-top: 6px;
margin-left: 0;
}
/* ─── Звёзды: абсолютно в правый верхний угол карточки ─── */
.reviews-cards .lw-card .lw-stars {
position: absolute;
top: 24px;
right: 24px;
margin-top: 0;
}
.reviews-cards .lw-scroll-x {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
padding-bottom: 8px;
}
.reviews-cards .lw-grid--3 {
display: flex;
gap: 16px;
overflow-x: auto;
scroll-snap-type: x mandatory;
flex-wrap: nowrap;
justify-content: flex-start;
padding-bottom: 4px;
}
.reviews-cards .lw-grid--3 .lw-card {
flex: 0 0 88vw;
scroll-snap-align: start;
}
} }
@media (max-width: 480px) { @media (max-width: 480px) {
@ -1511,14 +1186,6 @@
.reviews-intro__card-text { .reviews-intro__card-text {
font-size: 14px; font-size: 14px;
} }
.reviews-cards .lw-grid--3 .lw-card {
padding: 16px;
}
/* Звёзды: подстраиваем под меньший padding карточки */
.reviews-cards .lw-card .lw-stars {
top: 16px;
right: 16px;
}
.cross-links__grid { .cross-links__grid {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
@ -1632,57 +1299,6 @@
padding-bottom: 0; padding-bottom: 0;
} }
/* ─── DESKTOP: скрываем карточки после первого батча ─── */
@media (min-width: 769px) {
.lw-card[data-batch]:not([data-batch="1"]) {
display: none;
}
}
/* ─── MOBILE: все карточки видны в скролле ─── */
@media (max-width: 768px) {
.lw-card[data-batch]:not([data-batch="1"]) {
display: flex;
}
}
/* ─── КНОПКА "ПОКАЗАТЬ ЕЩЁ" ─── */
.reviews-loadmore {
text-align: center;
margin-top: 32px;
}
.reviews-loadmore__btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 14px 36px;
font-size: 16px;
font-weight: 600;
color: var(--accent);
background: var(--accent-light);
border: 2px solid var(--accent);
border-radius: 12px;
cursor: pointer;
transition: background var(--transition-fast), transform var(--transition-fast);
}
.reviews-loadmore__btn:hover {
background: rgba(124, 58, 237, 0.15);
transform: translateY(-2px);
}
.reviews-loadmore__btn:active {
transform: translateY(0);
}
.reviews-loadmore__btn:disabled {
opacity: 0.5;
cursor: default;
transform: none;
}
@media (max-width: 768px) {
.reviews-loadmore {
display: none;
}
}
/* ─── ВНЕШНИЕ ПЛОЩАДКИ (E-E-A-T) ─── */ /* ─── ВНЕШНИЕ ПЛОЩАДКИ (E-E-A-T) ─── */
.reviews-ext-platforms { .reviews-ext-platforms {
padding: 40px 0; padding: 40px 0;
@ -2145,9 +1761,6 @@
word-break: break-word; word-break: break-word;
hyphens: auto; hyphens: auto;
} }
.reviews-cards .lw-grid--3 {
grid-template-columns: 1fr;
}
.results__card { .results__card {
flex: 0 0 50%; flex: 0 0 50%;
max-width: 50%; max-width: 50%;

View File

@ -1,11 +1,16 @@
const btnOpenMenu = document.querySelector('.burger-btn'); try {
const headerMenu = document.querySelector('.bottom-header-row'); var btnOpenMenu = document.querySelector('.burger-btn');
var headerMenu = document.querySelector('.bottom-header-row');
btnOpenMenu.addEventListener('click', ()=> { if (btnOpenMenu && headerMenu) {
document.querySelector('html').style = "overflow: hidden;" btnOpenMenu.addEventListener('click', function() {
headerMenu.classList.add('open'); document.querySelector('html').style = "overflow: hidden;";
btnOpenMenu.style="opacity: 0;"; headerMenu.classList.add('open');
}); btnOpenMenu.style="opacity: 0;";
});
}
} catch(e) {
if (window.console) console.warn('add.js: burger-menu error', e);
}
const boxes = Array.from(document.querySelectorAll(".box__accordion")); const boxes = Array.from(document.querySelectorAll(".box__accordion"));
boxes.forEach((box) => { boxes.forEach((box) => {
@ -50,7 +55,9 @@ document.addEventListener("click", function (event) {
document.querySelector('html').style = ""; document.querySelector('html').style = "";
return; return;
} }
if (target.classList.contains("btn-write")) { if (target.classList.contains("btn-write") || target.closest('.btn-write-camp')) {
var campBtn = target.closest('.btn-write-camp');
if (campBtn && campBtn.tagName === 'A') event.preventDefault();
modalRequestForm.style=""; modalRequestForm.style="";
document.querySelector('html').style = "overflow: hidden;"; document.querySelector('html').style = "overflow: hidden;";
// Динамическая загрузка Bitrix24 (иначе не инициализируется в скрытом контейнере) // Динамическая загрузка Bitrix24 (иначе не инициализируется в скрытом контейнере)
@ -124,124 +131,40 @@ document.addEventListener("click", function (event) {
}); });
})(jQuery);*/ })(jQuery);*/
let swiperPopularSubjects = new Swiper(".swiper-popular-subjects", { try {
spaceBetween: 10, var swiperPopularSubjects = new Swiper(".swiper-popular-subjects", {
slidesPerView: 1, spaceBetween: 10,
speed: 400, slidesPerView: 1,
preventInteractionOnTransition: true, // запрет смены слайдов speed: 400,
keyboard: true, preventInteractionOnTransition: true,
breakpoints: { keyboard: true,
680: { breakpoints: {
slidesPerView: 2, 680: { slidesPerView: 2, speed: 400 },
speed: 400, 860: { slidesPerView: 3, speed: 400 }
},
860: {
slidesPerView: 3,
speed: 400,
}
},
navigation: {
nextEl: ".subject-next",
prevEl: ".subject-prev",
}
});
let swiperFoto = new Swiper(".swiper-foto", {
spaceBetween: 10,
slidesPerView: 1,
speed: 400,
preventInteractionOnTransition: true, // запрет смены слайдов
keyboard: true,
navigation: {
nextEl: ".foto-next",
prevEl: ".foto-prev",
},
pagination: {
el: ".swiper-pagination",
clickable: true,
},
});
let swiperNews = new Swiper(".swiper-news", {
spaceBetween: 10,
slidesPerView: 1,
speed: 400,
preventInteractionOnTransition: true, // запрет смены слайдов
keyboard: true,
breakpoints: {
680: {
slidesPerView: 2,
speed: 400,
},
860: {
slidesPerView: 3,
speed: 400,
}
},
navigation: {
nextEl: ".news-next",
prevEl: ".news-prev",
}
});
let swiperCertificates = new Swiper(".certificates-owl", {
spaceBetween: 10,
slidesPerView: 1,
speed: 400,
loop: true,
preventInteractionOnTransition: true, // запрет смены слайдов
keyboard: true,
navigation: {
nextEl: ".certificates-owl-next",
prevEl: ".certificates-owl-prev",
}
});
let swiperReviews = new Swiper(".reviews-owl", {
spaceBetween: 40,
speed: 400,
slidesPerView: 1,
/*slidesPerGroup: 2,
centeredSlidesBounds: true,
freeMode: true,
followFinger: true,
loop: false,*/
//preventInteractionOnTransition: true, // запрет смены слайдов
keyboard: true,
breakpoints: {
860: {
slidesPerView: 2,
speed: 400,
}
},
navigation: {
nextEl: ".reviews-owl-next",
prevEl: ".reviews-owl-prev",
}
});
let swiperTeachers = new Swiper(".teachers-owl", {
spaceBetween: 30,
speed: 400,
slidesPerView: 1,
keyboard: true,
breakpoints: {
540: {
slidesPerView: 2,
},
860: {
slidesPerView: 4,
}, },
992: { navigation: { nextEl: ".subject-next", prevEl: ".subject-prev" }
slidesPerView: 4, });
spaceBetween: 36, } catch(e) { /* skip — swiper not on this page */ }
},
}, try {
navigation: { var swiperFoto = new Swiper(".swiper-foto", {
nextEl: ".teachers-owl-next", spaceBetween: 10,
prevEl: ".teachers-owl-prev", slidesPerView: 1,
} speed: 400,
}); preventInteractionOnTransition: true,
keyboard: true,
navigation: { nextEl: ".foto-next", prevEl: ".foto-prev" },
pagination: { el: ".swiper-pagination", clickable: true }
});
} catch(e) { /* skip — swiper not on this page */ }
try { var swiperNews = new Swiper(".swiper-news", { spaceBetween: 10, slidesPerView: 1, speed: 400, preventInteractionOnTransition: true, keyboard: true, breakpoints: { 680: { slidesPerView: 2, speed: 400 }, 860: { slidesPerView: 3, speed: 400 } }, navigation: { nextEl: ".news-next", prevEl: ".news-prev" } }); } catch(e) { /* skip */ }
try { var swiperCertificates = new Swiper(".certificates-owl", { spaceBetween: 10, slidesPerView: 1, speed: 400, loop: true, preventInteractionOnTransition: true, keyboard: true, navigation: { nextEl: ".certificates-owl-next", prevEl: ".certificates-owl-prev" } }); } catch(e) { /* skip */ }
try { var swiperReviews = new Swiper(".reviews-owl", { spaceBetween: 40, speed: 400, slidesPerView: 1, keyboard: true, breakpoints: { 860: { slidesPerView: 2, speed: 400 } }, navigation: { nextEl: ".reviews-owl-next", prevEl: ".reviews-owl-prev" } }); } catch(e) { /* skip */ }
try { var swiperTeachers = new Swiper(".teachers-owl", { spaceBetween: 30, speed: 400, slidesPerView: 1, keyboard: true, breakpoints: { 540: { slidesPerView: 2 }, 860: { slidesPerView: 4 }, 992: { slidesPerView: 4, spaceBetween: 36 } }, navigation: { nextEl: ".teachers-owl-next", prevEl: ".teachers-owl-prev" } }); } catch(e) { /* skip */ }
setTimeout(() => { setTimeout(() => {
document.querySelectorAll('.b24-form-content .b24-form-btn').forEach(btn => { document.querySelectorAll('.b24-form-content .b24-form-btn').forEach(btn => {
@ -251,7 +174,74 @@ setTimeout(() => {
document.querySelectorAll('.header-menu').forEach(item => { document.querySelectorAll('.header-menu').forEach(item => {
item.classList.add('hover-effect'); item.classList.add('hover-effect');
}) });
/* ── "Читать ещё" (expand/collapse long reviews) ── */
(function() {
'use strict';
document.querySelectorAll('.review-card__btn-more').forEach(function(btn) {
btn.addEventListener('click', function() {
var textBlock = this.closest('.lw-card').querySelector('.lw-card__text');
if (textBlock) {
textBlock.classList.toggle('review-card__text--expanded');
this.textContent = textBlock.classList.contains('review-card__text--expanded')
? 'Свернуть'
: 'Читать ещё';
}
});
});
})();
/* ── Reveal animation (IntersectionObserver) ── */
(function() {
'use strict';
var revealElements = document.querySelectorAll('.reveal');
if (revealElements.length && 'IntersectionObserver' in window) {
var observer = new IntersectionObserver(
function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
entry.target.classList.add('reveal--visible');
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.1 }
);
revealElements.forEach(function(el) {
observer.observe(el);
});
} else {
// Fallback: show all immediately
revealElements.forEach(function(el) {
el.classList.add('reveal--visible');
});
}
})();
/* ── "Показать ещё" — batch load more ── */
(function() {
'use strict';
var loadMoreWrapper = document.getElementById('reviews-loadmore');
if (!loadMoreWrapper) return;
var btn = loadMoreWrapper.querySelector('.reviews-loadmore__btn');
if (!btn) return;
var nextBatch = 2;
btn.addEventListener('click', function() {
var cards = document.querySelectorAll('.lw-card[data-batch="' + nextBatch + '"]');
if (cards.length) {
cards.forEach(function(card) {
card.style.display = 'flex';
card.classList.add('reveal--visible'); // reveal + batch = видно
});
nextBatch++;
var remaining = document.querySelectorAll('.lw-card[data-batch="' + nextBatch + '"]');
if (!remaining.length) {
loadMoreWrapper.style.display = 'none';
}
}
});
})();
/* ── Scroll Progress Bar ── */ /* ── Scroll Progress Bar ── */
(function() { (function() {

View File

@ -33,8 +33,6 @@ const btnCloseModalMentors = document.querySelector('.btn-close-mentors');
const modalPrograms = document.querySelector('.modal-programs'); const modalPrograms = document.querySelector('.modal-programs');
const modalMentors = document.querySelector('.modal-mentors'); const modalMentors = document.querySelector('.modal-mentors');
const modalCampRequestForm = document.querySelector('.modal-camp-request-form');
btnCloseModalPrograms.addEventListener("click", function (event) { btnCloseModalPrograms.addEventListener("click", function (event) {
modalPrograms.classList.remove('open'); modalPrograms.classList.remove('open');
}); });
@ -45,37 +43,7 @@ btnCloseModalMentors.addEventListener("click", function (event) {
document.addEventListener("click", function (event) { document.addEventListener("click", function (event) {
const target = event.target; const target = event.target;
if (target.classList.contains("btn-close-request-form-camp")) { if (target.classList.contains("btn-program")) {
document.body.style.overflow = "";
modalCampRequestForm.classList.add("hidden");
return;
}
const campBtn = target.closest('.btn-write-camp');
if (campBtn) {
if (campBtn.tagName === 'A') event.preventDefault();
window.b24campLoaded = true;
document.body.style.overflow = "hidden";
modalCampRequestForm.classList.remove("hidden");
var container = modalCampRequestForm.querySelector('.b24-form-container');
if (!container.querySelector('.b24-form')) {
var fForm = modalCampRequestForm.dataset.b24Form;
var fLoader = modalCampRequestForm.dataset.b24Loader;
if (fForm && fLoader) {
var s = document.createElement('script');
s.setAttribute('data-b24-form', fForm);
s.setAttribute('data-skip-moving', 'true');
s.text = "(function(w,d,u){var s=d.createElement('script');s.async=true;s.src=u+'?'+(Date.now()/180000|0);var h=d.getElementsByTagName('script')[0];h.parentNode.insertBefore(s,h);})(window,document,'" + fLoader + "');";
container.appendChild(s);
}
}
return;
}
if (target.classList.contains("btn-program")) {
const card = target.closest('.programs__card'); const card = target.closest('.programs__card');
modalPrograms.querySelector('.modal-programs__img').innerHTML = card.querySelector('.programs__image').outerHTML; modalPrograms.querySelector('.modal-programs__img').innerHTML = card.querySelector('.programs__image').outerHTML;
modalPrograms.querySelector('.programs__item_title').textContent = card.querySelector('.programs__name').textContent; modalPrograms.querySelector('.programs__item_title').textContent = card.querySelector('.programs__name').textContent;

View File

@ -10,6 +10,7 @@ document.addEventListener('DOMContentLoaded', function () {
// ─────────────────────────────────────────────── // ───────────────────────────────────────────────
// 1. АНИМАЦИЯ ПОЯВЛЕНИЯ (Intersection Observer) // 1. АНИМАЦИЯ ПОЯВЛЕНИЯ (Intersection Observer)
// fallback — add.js тоже содержит этот код
// ─────────────────────────────────────────────── // ───────────────────────────────────────────────
const revealElements = document.querySelectorAll('.reveal'); const revealElements = document.querySelectorAll('.reveal');
if (revealElements.length && 'IntersectionObserver' in window) { if (revealElements.length && 'IntersectionObserver' in window) {
@ -28,29 +29,14 @@ document.addEventListener('DOMContentLoaded', function () {
observer.observe(el); observer.observe(el);
}); });
} else { } else {
// Fallback: показываем всё сразу
revealElements.forEach(function (el) { revealElements.forEach(function (el) {
el.classList.add('reveal--visible'); el.classList.add('reveal--visible');
}); });
} }
// ─────────────────────────────────────────────── // ───────────────────────────────────────────────
// 2. КНОПКИ "ЧИТАТЬ ЕЩЁ" // 2. КНОПКА "ПОКАЗАТЬ ЕЩЁ" (десктоп)
// ─────────────────────────────────────────────── // fallback — add.js тоже содержит этот код
document.querySelectorAll('.review-card__btn-more').forEach(function (btn) {
btn.addEventListener('click', function () {
const textBlock = this.closest('.lw-card').querySelector('.lw-card__text');
if (textBlock) {
textBlock.classList.toggle('review-card__text--expanded');
this.textContent = textBlock.classList.contains('review-card__text--expanded')
? 'Свернуть'
: 'Читать ещё';
}
});
});
// ───────────────────────────────────────────────
// 3. КНОПКА "ПОКАЗАТЬ ЕЩЁ" (десктоп)
// ─────────────────────────────────────────────── // ───────────────────────────────────────────────
const loadMoreBtn = document.getElementById('reviews-loadmore'); const loadMoreBtn = document.getElementById('reviews-loadmore');
if (loadMoreBtn) { if (loadMoreBtn) {
@ -62,9 +48,9 @@ document.addEventListener('DOMContentLoaded', function () {
if (cards.length) { if (cards.length) {
cards.forEach(function (card) { cards.forEach(function (card) {
card.style.display = 'flex'; card.style.display = 'flex';
card.classList.add('reveal--visible');
}); });
nextBatch++; nextBatch++;
// Если следующих батчей нет — прячем кнопку
const remaining = document.querySelectorAll('.lw-card[data-batch="' + nextBatch + '"]'); const remaining = document.querySelectorAll('.lw-card[data-batch="' + nextBatch + '"]');
if (!remaining.length) { if (!remaining.length) {
loadMoreBtn.style.display = 'none'; loadMoreBtn.style.display = 'none';

View File

@ -66,7 +66,24 @@
<?php <?php
?> ?>
<div class="modal-request-form" style="display:none;" aria-hidden="true" role="dialog" aria-label="Форма записи"> <?php
// === Bitrix24: парсинг скрипта из настроек филиала ===
// Приоритет: branch_button_script (Settings API) > post_meta > theme option
$b24_raw = get_option( 'branch_button_script', '' );
// Резерв: для страниц с post_meta или theme option (если филиал не настроен)
if ( empty( $b24_raw ) && is_singular() ) {
$b24_raw = carbon_get_post_meta( get_the_ID(), 'pksh_bitrix_script' );
}
if ( empty( $b24_raw ) ) {
$b24_raw = carbon_get_theme_option( 'site_bitrix_script' );
}
$b24_params = dekart_parse_b24_script( $b24_raw );
?>
<div class="modal-request-form" style="display:none;" aria-hidden="true" role="dialog" aria-label="Форма записи"
data-b24-form="<?php echo esc_attr( $b24_params['form'] ); ?>"
data-b24-loader="<?php echo esc_attr( $b24_params['loader'] ); ?>">
<div class="form-wrapper"> <div class="form-wrapper">
<button class="btn-close-request-form" aria-label="Закрыть форму"> <button class="btn-close-request-form" aria-label="Закрыть форму">
<img class="btn-close-request-form-img" <img class="btn-close-request-form-img"
@ -74,41 +91,10 @@
alt="Закрыть" alt="Закрыть"
loading="lazy"> loading="lazy">
</button> </button>
<?php <div class="b24-form-container"></div>
// Приоритет: page-specific meta > theme option
$b24_script = '';
if ( is_singular() ) {
$page_script = carbon_get_post_meta( get_the_ID(), 'pksh_bitrix_script' );
if ( ! empty( $page_script ) ) {
$b24_script = $page_script;
}
}
if ( empty( $b24_script ) ) {
$b24_script = carbon_get_theme_option('site_bitrix_script');
}
echo $b24_script;
?>
</div> </div>
</div> </div>
<script>
document.addEventListener("DOMContentLoaded", function() {
var formButton = document.querySelector('.btn-write-camp');
if (formButton) {
formButton.addEventListener('click', function() {
if (!window.b24formLoaded) {
var script = document.createElement('script');
script.src = 'https://cdn-ru.bitrix24.ru/b2215181/crm/form/loader_102.js?' + (Date.now()/180000|0);
script.async = true;
document.body.appendChild(script);
window.b24formLoaded = true;
}
}, { once: true });
}
});
</script>
<!-- Sticky CTA Mobile --> <!-- Sticky CTA Mobile -->
<div class="sticky-cta-mobile" aria-hidden="true"> <div class="sticky-cta-mobile" aria-hidden="true">
<button class="sticky-cta-btn btn-write" aria-label="Записаться на бесплатное пробное"> <button class="sticky-cta-btn btn-write" aria-label="Записаться на бесплатное пробное">

View File

@ -3,6 +3,18 @@ require_once get_template_directory() . '/inc/template-tags.php';
/* --- Удаляем мета из YOASTSEO START--- */ /* --- Удаляем мета из YOASTSEO START--- */
add_filter( 'wpseo_json_ld_output', '__return_false' ); add_filter( 'wpseo_json_ld_output', '__return_false' );
/* --- Удаляем мета из YOASTSEO END --- */ /* --- Удаляем мета из YOASTSEO END --- */
// Отключаем Reading Time для страницы Подготовки к школе
add_filter( 'wpseo_frontend_presenter_classes', 'dekart_disable_reading_time_pksh' );
function dekart_disable_reading_time_pksh( array $presenters ): array {
if ( is_page_template( 'page-podgotovka-k-shkole.php' ) ) {
return array_filter( $presenters, function( $class ) {
return false === strpos( $class, 'ReadingTime' );
} );
}
return $presenters;
}
add_theme_support('title-tag'); add_theme_support('title-tag');
/* --- #SEND Review Form --- */ /* --- #SEND Review Form --- */
add_action( 'template_redirect', 'author_archive_redirect' ); add_action( 'template_redirect', 'author_archive_redirect' );
@ -576,7 +588,20 @@ function add_carbon() {
->set_attribute( 'type', 'number' ), ->set_attribute( 'type', 'number' ),
Field::make( 'date', 'review_date', 'Дата отзыва' ) Field::make( 'date', 'review_date', 'Дата отзыва' )
->set_width( 15 ) ->set_width( 15 )
->set_help_text( 'Для Schema.org Review.datePublished.' ), ->set_storage_format( 'd.m.Y' )
->set_input_format( 'd.m.Y', 'd.m.Y' )
->set_picker_options( array( 'altInput' => false ) )
->set_help_text( 'Для Schema.org Review.datePublished. Формат: ДД.ММ.ГГГГ' ),
Field::make( 'association', 'review_teacher', 'Преподаватель' )
->set_width( 25 )
->set_types( array(
array(
'type' => 'post',
'post_type' => 'teacher',
),
) )
->set_max( 1 )
->set_help_text( 'Если родитель хвалит конкретного учителя — привяжите отзыв к нему. Необязательно.' ),
Field::make( 'textarea', 'review_text', 'Текст отзыва' ) Field::make( 'textarea', 'review_text', 'Текст отзыва' )
->set_width( 35 ), ->set_width( 35 ),
)), )),
@ -968,13 +993,32 @@ function add_carbon() {
->set_layout( 'tabbed-horizontal' ) ->set_layout( 'tabbed-horizontal' )
->set_help_text( 'Добавьте отзывы родителей. Показываются на странице лагеря.' ) ->set_help_text( 'Добавьте отзывы родителей. Показываются на странице лагеря.' )
->add_fields( array( ->add_fields( array(
Field::make( 'text', 'review_author', 'Имя автора' ) Field::make( 'image', 'review_avatar', 'Аватар' )
->set_width( 30 ),
Field::make( 'text', 'review_rating', 'Оценка (15)' )
->set_width( 15 ) ->set_width( 15 )
->set_help_text( 'Опционально. Если не указано — генерируется из имени.' ),
Field::make( 'text', 'review_author', 'Имя автора' )
->set_width( 25 ),
Field::make( 'text', 'review_rating', 'Оценка (15)' )
->set_width( 10 )
->set_attribute( 'type', 'number' ), ->set_attribute( 'type', 'number' ),
Field::make( 'date', 'review_date', 'Дата отзыва' )
->set_width( 15 )
->set_storage_format( 'd.m.Y' )
->set_input_format( 'd.m.Y', 'd.m.Y' )
->set_picker_options( array( 'altInput' => false ) )
->set_help_text( 'Для Schema.org Review.datePublished. Формат: ДД.ММ.ГГГГ' ),
Field::make( 'association', 'review_teacher', 'Преподаватель' )
->set_width( 25 )
->set_types( array(
array(
'type' => 'post',
'post_type' => 'teacher',
),
) )
->set_max( 1 )
->set_help_text( 'Если родитель хвалит конкретного учителя — привяжите отзыв к нему. Необязательно.' ),
Field::make( 'textarea', 'review_text', 'Текст отзыва' ) Field::make( 'textarea', 'review_text', 'Текст отзыва' )
->set_width( 55 ), ->set_width( 35 ),
)), )),
)) ))
->add_tab('📍 Контакты и карта', array( ->add_tab('📍 Контакты и карта', array(
@ -1339,6 +1383,24 @@ function dekart_sanitize_script_field( $value ) {
return wp_kses( $value, $allowed ); return wp_kses( $value, $allowed );
} }
/**
* Парсит Bitrix24 скрипт из настроек филиала, извлекая data-b24-form и URL загрузчика.
* Используется для динамической загрузки формы в модальном окне.
*
* @param string $script Полный HTML скрипта Bitrix24.
* @return array{form: string, loader: string} Массив с ключами 'form' и 'loader'.
*/
function dekart_parse_b24_script( string $script ): array {
$result = array( 'form' => '', 'loader' => '' );
if ( preg_match( '/data-b24-form="([^"]+)"/', $script, $m ) ) {
$result['form'] = $m[1];
}
if ( preg_match( "/\\(window,document,'([^']+)'\\)/", $script, $m ) ) {
$result['loader'] = $m[1];
}
return $result;
}
function enqueue_template_specific_styles() { function enqueue_template_specific_styles() {
if ( is_page_template('page-camp.php') ) { if ( is_page_template('page-camp.php') ) {
wp_enqueue_style( wp_enqueue_style(
@ -1422,6 +1484,8 @@ function needs_swiper(): bool {
'page-school.php', 'page-school.php',
'page-contacts.php', 'page-contacts.php',
'page-teachers.php', 'page-teachers.php',
'page-podgotovka-k-shkole.php',
'page-camp.php',
]; ];
foreach ( $swiper_templates as $tmpl ) { foreach ( $swiper_templates as $tmpl ) {
if ( is_page_template( $tmpl ) ) { if ( is_page_template( $tmpl ) ) {
@ -1553,17 +1617,16 @@ add_filter('script_loader_tag', 'dekart_add_defer_to_scripts', 10, 3);
// ==================================================== // ====================================================
// ✅ Заголовки безопасности — только на фронтенде // ✅ Заголовки безопасности — только на фронтенде
// ==================================================== // ====================================================
function dekart_security_headers() { add_action( 'send_headers', 'dekart_security_headers' );
// Не применяем в админке, AJAX и cron function dekart_security_headers(): void {
if ( is_admin() || wp_doing_ajax() || defined('DOING_CRON') ) { if ( ! is_admin() ) {
return; header( 'X-Content-Type-Options: nosniff' );
header( 'X-Frame-Options: SAMEORIGIN' );
header( 'Referrer-Policy: strict-origin-when-cross-origin' );
// Content-Security-Policy — базовый, без блокировки легаси-скриптов
header( "Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn-ru.bitrix24.ru https://api-maps.yandex.ru https://cdn.jsdelivr.net https://www.google.com https://www.gstatic.com https://www.googletagmanager.com https://mc.yandex.ru; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net; img-src 'self' data: https: blob:; font-src 'self' data: https://fonts.gstatic.com; frame-src 'self' https://cdn-ru.bitrix24.ru https://www.google.com; connect-src 'self' https://api-maps.yandex.ru https://cdn-ru.bitrix24.ru https://mc.yandex.ru; object-src 'none'; base-uri 'self'; form-action 'self';" );
} }
header('X-Frame-Options: SAMEORIGIN');
header('X-XSS-Protection: 1; mode=block');
header('X-Content-Type-Options: nosniff');
header('Referrer-Policy: strict-origin-when-cross-origin');
} }
add_action('send_headers', 'dekart_security_headers');
function dekart_add_preload_hints() { function dekart_add_preload_hints() {
// резерв для preload hints // резерв для preload hints

View File

@ -48,8 +48,8 @@ if ( is_front_page() ) {
// CSS12 // CSS12
// ───────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────
?> ?>
<link rel="stylesheet" href="<?php echo esc_url( get_template_directory_uri() ); ?>/assets/css/reset.css" media="all"> <style id="reset-css-inline">/*! reset.css inline */ *{margin:0;padding:0;box-sizing:border-box}html{scroll-behavior:smooth}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}img{max-width:100%;height:auto;display:block}a{color:inherit;text-decoration:none}button{cursor:pointer;font:inherit}ul,ol{list-style:none}table{border-collapse:collapse}input,textarea,select{font:inherit}</style>
<link rel="stylesheet" href="<?php echo esc_url( get_template_directory_uri() ); ?>/assets/css/main.css" media="all"> <link rel="stylesheet" href="<?php echo esc_url( get_template_directory_uri() . '/assets/css/main.css?ver=' . filemtime( get_template_directory() . '/assets/css/main.css' ) ); ?>" media="all">
<?php if ( function_exists( 'needs_swiper' ) && needs_swiper() ) : ?> <?php if ( function_exists( 'needs_swiper' ) && needs_swiper() ) : ?>
<link rel="preload" as="style" <link rel="preload" as="style"
@ -62,9 +62,9 @@ if ( is_front_page() ) {
// Google Fonts // Google Fonts
?> ?>
<link rel="preload" as="style" <link rel="preload" as="style"
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&family=Oswald:wght@300;400;700&family=Fredoka:wght@400;500;600;700&family=Manrope:wght@700;800&family=Montserrat:wght@800&family=Poppins:wght@500;600;900&display=swap" href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;600;700;900&family=Oswald:wght@400;500;600;700&display=swap"
onload="this.onload=null;this.rel='stylesheet'"> onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&family=Oswald:wght@300;400;700&family=Fredoka:wght@400;500;600;700&family=Manrope:wght@700;800&family=Montserrat:wght@800&family=Poppins:wght@500;600;900&display=swap"></noscript> <noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;600;700;900&family=Oswald:wght@400;500;600;700&display=swap"></noscript>
<?php <?php
@ -74,7 +74,7 @@ if ( is_front_page() ) {
<?php if ( function_exists( 'needs_swiper' ) && needs_swiper() ) : ?> <?php if ( function_exists( 'needs_swiper' ) && needs_swiper() ) : ?>
<script src="https://cdn.jsdelivr.net/npm/swiper@9/swiper-bundle.min.js" defer></script> <script src="https://cdn.jsdelivr.net/npm/swiper@9/swiper-bundle.min.js" defer></script>
<?php endif; ?> <?php endif; ?>
<script src="<?php echo esc_url( get_template_directory_uri() ); ?>/assets/js/add.js" defer></script> <script src="<?php echo esc_url( get_template_directory_uri() . '/assets/js/add.js?ver=' . filemtime( get_template_directory() . '/assets/js/add.js' ) ); ?>" defer></script>
<?php wp_head(); ?> <?php wp_head(); ?>
</head> </head>

View File

@ -105,21 +105,38 @@ function dekart_schema_output(): void {
$graph[] = $rating; $graph[] = $rating;
} }
// 9. FAQPage (conditional — есть ли вопросы) // 9. Service — сущность услуги (только для страниц услуг, не для /otzyvy/)
$service = dekart_schema_service();
if ( $service ) {
$graph[] = $service;
}
// 11. FAQPage (conditional — есть ли вопросы)
$faq = dekart_schema_faq(); $faq = dekart_schema_faq();
if ( $faq ) { if ( $faq ) {
$graph[] = $faq; $graph[] = $faq;
} }
// 10. Review[] — поштучные отзывы (conditional) // 12. ItemList — обёртка для отзывов (conditional)
$reviews = dekart_schema_reviews(); $reviews = dekart_schema_reviews();
if ( ! empty( $reviews ) && is_array( $reviews ) ) { if ( ! empty( $reviews ) && is_array( $reviews ) ) {
foreach ( $reviews as $review ) { $graph[] = array(
$graph[] = $review; '@type' => 'ItemList',
} '@id' => home_url( '/podgotovka-k-shkole/' ) . '#reviews',
'name' => 'Отзывы о подготовке к школе',
'description' => 'Отзывы родителей о курсе подготовки к школе в Детском центре «Декарт»',
'itemListElement' => array_map( function( $review, $index ) {
return array(
'@type' => 'ListItem',
'position' => $index + 1,
'item' => $review,
);
}, $reviews, array_keys( $reviews ) ),
'numberOfItems' => count( $reviews ),
);
} }
// 11. Person[] — преподаватели (conditional) // 13. Person[] — преподаватели (conditional)
$teachers = dekart_schema_teachers(); $teachers = dekart_schema_teachers();
if ( ! empty( $teachers ) && is_array( $teachers ) ) { if ( ! empty( $teachers ) && is_array( $teachers ) ) {
foreach ( $teachers as $person ) { foreach ( $teachers as $person ) {
@ -337,6 +354,7 @@ function dekart_schema_organization(): ?array {
'name' => wp_strip_all_tags( $site_name ), 'name' => wp_strip_all_tags( $site_name ),
'url' => $home_url, 'url' => $home_url,
'logo' => esc_url( $logo_url ), 'logo' => esc_url( $logo_url ),
'image' => esc_url( $logo_url ),
); );
// legalName — юридическое наименование (CF schema_legal_name → Settings API branch_legal_name) // legalName — юридическое наименование (CF schema_legal_name → Settings API branch_legal_name)
@ -616,6 +634,30 @@ function dekart_schema_local_business(): ?array {
$lb['sameAs'] = $same_as; $lb['sameAs'] = $same_as;
} }
// Гарантируем WhatsApp и Telegram в sameAs, даже если не заданы в админке
$ensure_platforms = array(
'WhatsApp' => dekart_branch_option( 'branch_whatsapp', 'https://wa.me/79269311434' ),
'Telegram' => dekart_branch_option( 'branch_telegram', 'https://t.me/dekart_school' ),
);
foreach ( $ensure_platforms as $platform => $url ) {
if ( $url && filter_var( $url, FILTER_VALIDATE_URL ) ) {
$found = false;
foreach ( $same_as as $existing ) {
if ( false !== stripos( $existing, parse_url( $url, PHP_URL_HOST ) ) ) {
$found = true;
break;
}
}
if ( ! $found ) {
$same_as[] = esc_url( $url );
}
}
}
// Если после добавления появились элементы, обновляем sameAs
if ( ! empty( $same_as ) && ! isset( $lb['sameAs'] ) ) {
$lb['sameAs'] = $same_as;
}
// image — массив URL фотографий филиала // image — массив URL фотографий филиала
// Формат 1 (CF schema_photos media_gallery): [123, 456] // Формат 1 (CF schema_photos media_gallery): [123, 456]
// Формат 2 (Settings API branch_photos): "123, 456" // Формат 2 (Settings API branch_photos): "123, 456"
@ -1029,11 +1071,45 @@ function dekart_schema_rating(): ?array {
'worstRating' => '1', 'worstRating' => '1',
'ratingCount' => (string) count( $ratings ), 'ratingCount' => (string) count( $ratings ),
'itemReviewed' => array( 'itemReviewed' => array(
'@id' => $page_url . '#course', '@id' => home_url( '/' ) . '#organization',
), ),
); );
} }
/**
* Service сущность услуги «Подготовка к школе».
* provider #organization (единая школа).
* Google видит Service как частный случай услуги организации.
*
* @see https://schema.org/Service
*/
function dekart_schema_service(): ?array {
$page_url = home_url( '/podgotovka-k-shkole/' );
$home_url = home_url( '/' );
$name = carbon_get_post_meta( 2, 'banner_h1' ) ?: 'Подготовка к школе';
$description = carbon_get_post_meta( 2, 'banner_subtitle' ) ?: '';
$service = array(
'@type' => 'Service',
'@id' => $page_url . '#service',
'name' => wp_strip_all_tags( $name ),
'provider' => array(
'@id' => $home_url . '#organization',
),
'areaServed' => array(
'@type' => 'City',
'name' => dekart_branch_option( 'branch_city', 'Щёлково' ),
),
);
if ( $description ) {
$service['description'] = wp_strip_all_tags( $description );
}
return $service;
}
/** /**
* FAQPage вопросы и ответы из pksh_faq_items. * FAQPage вопросы и ответы из pksh_faq_items.
* Если вопросов нет блок не выводится. * Если вопросов нет блок не выводится.
@ -1124,7 +1200,7 @@ function dekart_schema_reviews(): array {
), ),
'reviewBody' => wp_strip_all_tags( $body ), 'reviewBody' => wp_strip_all_tags( $body ),
'itemReviewed' => array( 'itemReviewed' => array(
'@id' => $page_url . '#course', '@id' => home_url( '/' ) . '#organization',
), ),
'reviewRating' => array( 'reviewRating' => array(
'@type' => 'Rating', '@type' => 'Rating',

View File

@ -295,16 +295,6 @@ $post_id = get_the_ID();
} }
}); });
const modalCampRequestForm = document.querySelector('.modal-camp-request-form');
document.addEventListener("click", function (event) {
if (event.target.classList.contains("btn-close-request-form-camp")) {
modalCampRequestForm.style="display: none;";
}
if (event.target.classList.contains("btn-write-camp")) {
modalCampRequestForm.style="";
}
});
window.addEventListener('load', function() { window.addEventListener('load', function() {
if (window.innerWidth < 960) { if (window.innerWidth < 960) {
const desktopRev = document.querySelector('.as-desctop'); const desktopRev = document.querySelector('.as-desctop');

View File

@ -570,54 +570,86 @@ $metrics = [
<?php endif; ?> <?php endif; ?>
</section> </section>
<section class="section-bg camp-reviews" data-bg="white" id="camp-reviews"> <section class="section-bg camp-reviews reviews-cards" data-bg="white" id="camp-reviews">
<h2 class="camp_title">Что говорят о нас родители</h2> <h2 class="camp_title">Что говорят о нас родители</h2>
<?php <?php
$review_items = carbon_get_post_meta($post_id, 'camp_reviews_list'); $review_items = carbon_get_post_meta($post_id, 'camp_reviews_list');
if (is_array($review_items) && !empty($review_items)) : $total_count = is_array($review_items) ? count($review_items) : 0;
if ($total_count > 0) :
$items = array_values($review_items);
$card_idx = 0;
?> ?>
<div class="reviews-cards">
<div class="lw-scroll-x"> <div class="lw-scroll-x">
<div class="lw-grid lw-grid--3 lw-gap-20"> <div class="lw-grid lw-grid--3">
<?php foreach ($review_items as $item) : <?php foreach ($items as $item) :
$author = $item['review_author'] ?? ''; $card_idx++;
$text = $item['review_text'] ?? ''; $author = $item['review_author'] ?? '';
$text = $item['review_text'] ?? '';
$raw_rating = $item['review_rating'] ?? ''; $raw_rating = $item['review_rating'] ?? '';
$stars = (int)$raw_rating; $avatar_id = !empty($item['review_avatar']) ? (int)$item['review_avatar'] : 0;
$date = ''; $teacher = $item['review_teacher'] ?? array();
$name = $author ?: 'Анонимно'; $date = $item['review_date'] ?? '';
if (!$stars) $stars = 5; $stars = max(1, min(5, (int)$raw_rating));
if (!$text) continue; $name = $author ?: 'Анонимно';
$is_long = strlen( wp_strip_all_tags( $text ) ) > 350;
$batch = (int) ceil( $card_idx / 12 );
if (empty($text)) continue;
?> ?>
<div class="lw-card"> <article class="lw-card reveal" data-batch="<?php echo (int) $batch; ?>">
<div class="lw-flex lw-flex--row lw-gap-12 lw-items-center"> <div class="lw-flex lw-flex--row lw-gap-12 lw-items-start">
<div class="lw-avatar lw-avatar--48"> <div class="lw-avatar lw-avatar--48">
<?php if ($avatar) : ?> <?php if ($avatar_id && wp_attachment_is_image($avatar_id)) : ?>
<img class="lw-avatar__img" src="<?php echo wp_get_attachment_url($avatar); ?>" alt="<?php echo esc_attr($name); ?>" loading="lazy"> <?php echo wp_get_attachment_image($avatar_id, [48, 48], false, ['class' => 'lw-avatar__img', 'loading' => 'lazy', 'alt' => esc_attr($name)]); ?>
<?php else : ?> <?php else : ?>
<img class="lw-avatar__img" src="https://ui-avatars.com/api/?name=<?php echo urlencode($name); ?>&amp;background=random&amp;color=fff&amp;size=96" alt="<?php echo esc_attr($name); ?>" loading="lazy" width="48" height="48"> <div class="lw-avatar lw-avatar--48 lw-avatar--letter">
<span class="lw-avatar__letter"><?php echo esc_html( $name ? mb_strtoupper( mb_substr( $name, 0, 1 ) ) : '?' ); ?></span>
</div>
<?php endif; ?> <?php endif; ?>
</div> </div>
<div class="lw-flex lw-flex--col"> <div class="lw-flex lw-flex--col" style="flex:1; min-width:0;">
<div class="lw-text-dark lw-font-semibold"><?php echo esc_html($name); ?></div> <div class="lw-text-dark lw-font-semibold"><?php echo esc_html($name); ?></div>
<div class="lw-text-xs lw-text-gray"><time datetime="<?php echo esc_attr(get_the_date('Y-m-d')); ?>"><?php echo esc_html($date); ?></time></div> <?php if ( ! empty( $teacher[0]['id'] ) ) : ?>
<div class="lw-text-xs lw-text-gray">
Преподаватель: <a href="<?php echo esc_url( get_permalink( $teacher[0]['id'] ) ); ?>" class="review-card__teacher-link"><?php echo esc_html( get_the_title( $teacher[0]['id'] ) ); ?></a>
</div>
<?php endif; ?>
<div class="lw-badge lw-badge--verified"> Проверенный отзыв</div>
</div> </div>
<div class="lw-badge lw-badge--verified">Проверенный отзыв</div>
</div> </div>
<div class="lw-stars lw-mt-8"> <div class="lw-stars lw-mt-8">
<?php for ($i = 1; $i <= 5; $i++) : ?> <?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"> <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.1823 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"></path> <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"></path>
</svg> </svg>
<?php endfor; ?> <?php endfor; ?>
</div> </div>
<div class="lw-card__text lw-mt-8"><?php echo wp_kses_post($text); ?></div> <div class="lw-card__text lw-mt-8<?php echo $is_long ? ' review-card__text--clamped' : ''; ?>">
</div> <?php echo wp_kses_post($text); ?>
</div>
<div class="review-card__footer">
<?php if ($is_long) : ?>
<button class="review-card__btn-more" aria-label="Читать ещё">Читать ещё</button>
<?php endif; ?>
<?php if ($date) : ?>
<span class="review-card__date"><?php echo esc_html($date); ?></span>
<?php endif; ?>
</div>
</article>
<?php endforeach; ?> <?php endforeach; ?>
</div> </div>
</div> </div>
</div>
<?php if ( $total_count > 12 ) : ?>
<div class="reviews-loadmore" id="reviews-loadmore">
<button type="button" class="reviews-loadmore__btn">Показать ещё</button>
</div>
<?php endif; ?>
<?php endif; ?> <?php endif; ?>
</section> </section>
<section class="section-bg camp-faq" data-bg="mint" id="camp-faq"> <section class="section-bg camp-faq" data-bg="mint" id="camp-faq">
<h2 class="camp_title">Часто задаваемые вопросы</h2> <h2 class="camp_title">Часто задаваемые вопросы</h2>
<div class="faq-wrapper"> <div class="faq-wrapper">
@ -768,24 +800,6 @@ $metrics = [
</div> </div>
</div> </div>
<?php
$_b24_raw = carbon_get_post_meta($post_id, 'camp_bitrix_script');
$_b24_form = '';
$_b24_url = '';
if (preg_match('/data-b24-form="([^"]+)"/', $_b24_raw, $_m)) $_b24_form = $_m[1];
if (preg_match("/\\(window,document,'([^']+)'\\)/", $_b24_raw, $_m)) $_b24_url = $_m[1];
?>
<div class="modal-camp-request-form hidden"
data-b24-form="<?php echo esc_attr($_b24_form); ?>"
data-b24-loader="<?php echo esc_attr($_b24_url); ?>">
<div class="form-wrapper">
<button class="btn-close-request-form">
<img class="btn-close-request-form-camp" src="<?php echo $theme_uri; ?>/assets/images/btn-close-modal.svg" alt="кнопка закрыть окно" width="152" height="152">
</button>
<div class="b24-form-container"></div>
</div>
</div>
<script> <script>
(function() { (function() {
var mapLoaded = false; var mapLoaded = false;

View File

@ -99,8 +99,12 @@ $opt_social_raw = get_option( 'branch_social' ) ?: carbon_get_post_meta( $post_
<span class="bento-label">Бесплатно</span> <span class="bento-label">Бесплатно</span>
<h2 class="bento-h2">Скачайте чек-лист готовности к школе</h2> <h2 class="bento-h2">Скачайте чек-лист готовности к школе</h2>
<p class="bento-p">10 признаков, что ваш ребёнок готов к 1-му классу. Проверьте за 5 минут и узнайте, на какие навыки обратить внимание.</p> <p class="bento-p">10 признаков, что ваш ребёнок готов к 1-му классу. Проверьте за 5 минут и узнайте, на какие навыки обратить внимание.</p>
<button class="btn-primary btn-write micro-commit__btn">Получить чек-лист бесплатно</button> <div class="micro-commit__form">
<p class="micro-commit__disclaimer">Отправляя заявку, вы соглашаетесь на обработку персональных данных</p> <input type="text" class="micro-commit__input" placeholder="Ваше имя" aria-label="Ваше имя" required>
<input type="tel" class="micro-commit__input" placeholder="Ваш телефон" aria-label="Ваш телефон" required>
<button class="btn-primary btn-write micro-commit__btn">Получить чек-лист бесплатно</button>
<p class="micro-commit__disclaimer">Отправляя заявку, вы соглашаетесь на обработку персональных данных</p>
</div>
</div> </div>
<div class="micro-commit__visual"> <div class="micro-commit__visual">
<svg class="micro-commit__svg" viewBox="0 0 130 170" fill="none" aria-hidden="true"> <svg class="micro-commit__svg" viewBox="0 0 130 170" fill="none" aria-hidden="true">
@ -518,7 +522,7 @@ $opt_social_raw = get_option( 'branch_social' ) ?: carbon_get_post_meta( $post_
<!-- ════════════════════════════════════════════ --> <!-- ════════════════════════════════════════════ -->
<!-- Reviews (lw-card inline, camp-style) --> <!-- Reviews (lw-card inline, camp-style) -->
<!-- ════════════════════════════════════════════ --> <!-- ════════════════════════════════════════════ -->
<section class="pksh-reviews" id="pksh-reviews" aria-label="Отзывы"> <section class="pksh-reviews reviews-cards" id="pksh-reviews" aria-label="Отзывы">
<h2 class="bento-h2">Что говорят родители</h2> <h2 class="bento-h2">Что говорят родители</h2>
<?php <?php
@ -526,77 +530,138 @@ $opt_social_raw = get_option( 'branch_social' ) ?: carbon_get_post_meta( $post_
$total_count = is_array($review_items) ? count($review_items) : 0; $total_count = is_array($review_items) ? count($review_items) : 0;
if ($total_count > 0) : if ($total_count > 0) :
$items = array_values($review_items); $items = array_values($review_items);
$render_card = function($item) { $card_idx = 0;
$author = $item['review_author'] ?? ''; ?>
$text = $item['review_text'] ?? ''; <div class="reviews-cards">
$raw_rating = $item['review_rating'] ?? ''; <div class="lw-scroll-x">
$avatar_id = !empty($item['review_avatar']) ? (int)$item['review_avatar'] : 0; <div class="lw-grid lw-grid--3">
$stars = max(1, min(5, (int)$raw_rating)); <?php foreach ($items as $item) :
$name = $author ?: 'Анонимно'; $card_idx++;
if (empty($text)) return ''; $author = $item['review_author'] ?? '';
ob_start(); $text = $item['review_text'] ?? '';
$raw_rating = $item['review_rating'] ?? '';
$avatar_id = !empty($item['review_avatar']) ? (int)$item['review_avatar'] : 0;
$teacher = $item['review_teacher'] ?? array();
$date = $item['review_date'] ?? '';
$stars = max(1, min(5, (int)$raw_rating));
$name = $author ?: 'Анонимно';
$is_long = strlen( wp_strip_all_tags( $text ) ) > 350;
$batch = (int) ceil( $card_idx / 12 );
if (empty($text)) continue;
?> ?>
<div class="lw-card"> <article class="lw-card reveal" data-batch="<?php echo (int) $batch; ?>">
<div class="lw-flex lw-flex--row lw-gap-12 lw-items-center"> <div class="lw-flex lw-flex--row lw-gap-12 lw-items-start">
<div class="lw-avatar lw-avatar--48"> <div class="lw-avatar lw-avatar--48">
<?php if ($avatar_id && wp_attachment_is_image($avatar_id)) : ?> <?php if ($avatar_id && wp_attachment_is_image($avatar_id)) : ?>
<?php echo wp_get_attachment_image($avatar_id, [48, 48], false, ['class' => 'lw-avatar__img', 'loading' => 'lazy', 'alt' => esc_attr($name)]); ?> <?php echo wp_get_attachment_image($avatar_id, [48, 48], false, ['class' => 'lw-avatar__img', 'loading' => 'lazy', 'alt' => esc_attr($name)]); ?>
<?php else : ?> <?php else : ?>
<img class="lw-avatar__img" src="https://ui-avatars.com/api/?name=<?php echo urlencode($name); ?>&amp;background=random&amp;color=fff&amp;size=96" alt="<?php echo esc_attr($name); ?>" loading="lazy" width="48" height="48"> <div class="lw-avatar lw-avatar--48 lw-avatar--letter">
<span class="lw-avatar__letter"><?php echo esc_html( $name ? mb_strtoupper( mb_substr( $name, 0, 1 ) ) : '?' ); ?></span>
</div>
<?php endif; ?> <?php endif; ?>
</div> </div>
<div class="lw-flex lw-flex--col"> <div class="lw-flex lw-flex--col" style="flex:1; min-width:0;">
<div class="lw-text-dark lw-font-semibold"><?php echo esc_html($name); ?></div> <div class="lw-text-dark lw-font-semibold"><?php echo esc_html($name); ?></div>
<?php if ( ! empty( $teacher[0]['id'] ) ) : ?>
<div class="lw-text-xs lw-text-gray">
Преподаватель: <a href="<?php echo esc_url( get_permalink( $teacher[0]['id'] ) ); ?>" class="review-card__teacher-link"><?php echo esc_html( get_the_title( $teacher[0]['id'] ) ); ?></a>
</div>
<?php endif; ?>
<div class="lw-badge lw-badge--verified"> Проверенный отзыв</div>
</div> </div>
<div class="lw-badge lw-badge--verified">Проверенный отзыв</div>
</div> </div>
<div class="lw-stars lw-mt-8"> <div class="lw-stars lw-mt-8">
<?php for ($i = 1; $i <= 5; $i++) : ?> <?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"> <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.1823 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"/> <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>
<?php endfor; ?> <?php endfor; ?>
</div> </div>
<div class="lw-card__text lw-mt-8"><?php echo wp_kses_post($text); ?></div> <div class="lw-card__text lw-mt-8<?php echo $is_long ? ' review-card__text--clamped' : ''; ?>">
<?php echo wp_kses_post($text); ?>
</div>
<div class="review-card__footer">
<?php if ( $is_long ) : ?>
<button class="review-card__btn-more" aria-label="Читать ещё">Читать ещё</button>
<?php endif; ?>
<?php if ( ! empty( $date ) ) : ?>
<span class="review-card__date"><?php echo esc_html( $date ); ?></span>
<?php endif; ?>
</div>
</article>
<?php endforeach; ?>
</div> </div>
<?php
return ob_get_clean();
};
?>
<div class="lw-scroll-x" data-pksh-reviews>
<div class="lw-grid lw-grid--3 lw-gap-20" data-pksh-grid data-pksh-collapsed>
<?php foreach ($items as $item) echo $render_card($item); ?>
</div> </div>
<?php if ($total_count > 4) : ?> </div>
<div class="pksh-reviews__actions"> <?php if ( $total_count > 12 ) : ?>
<button class="pksh-reviews__toggle" data-pksh-toggle type="button">Показать ещё</button> <div class="reviews-loadmore" id="reviews-loadmore">
</div> <button type="button" class="reviews-loadmore__btn">Показать ещё</button>
<?php endif; ?>
</div> </div>
<?php endif; ?> <?php endif; ?>
<script> <?php endif; ?>
(function(){
var grid = document.querySelector('[data-pksh-grid]');
var toggle = document.querySelector('[data-pksh-toggle]');
if (!grid || !toggle) return;
toggle.addEventListener('click', function(){
var expanded = grid.hasAttribute('data-pksh-expanded');
if (expanded) {
grid.removeAttribute('data-pksh-expanded');
grid.setAttribute('data-pksh-collapsed', '');
toggle.textContent = 'Показать ещё';
} else {
grid.removeAttribute('data-pksh-collapsed');
grid.setAttribute('data-pksh-expanded', '');
toggle.textContent = 'Скрыть';
}
});
})();
</script>
</section> </section>
<!-- ════════════════════════════════════════════ --> <!-- ════════════════════════════════════════════ -->
<!-- Final CTA Low Friction --> <section class="bento pksh-section" aria-label="Почему нам доверяют">
<div class="bento__full">
<div class="trust-authority">
<h2 class="bento-h2">Почему родители доверяют нам</h2>
<div class="trust-authority__grid">
<div class="trust-authority__item">
<span class="trust-authority__icon">📜</span>
<strong class="trust-authority__title">Государственная лицензия</strong>
<p class="trust-authority__text">Имеем право на образовательную деятельность. Вы можете вернуть 13% через налоговый вычет.</p>
</div>
<div class="trust-authority__item">
<span class="trust-authority__icon">🏆</span>
<strong class="trust-authority__title">12 лет на рынке</strong>
<p class="trust-authority__text">С 2014 года готовим детей к школе. Более 500 выпускников успешно учатся в лицеях и гимназиях Щёлкова.</p>
</div>
<div class="trust-authority__item">
<span class="trust-authority__icon">🛡️</span>
<strong class="trust-authority__title">Гарантия результата</strong>
<p class="trust-authority__text">Если через 3 месяца ребёнок не начнёт читать вернём деньги и продолжим обучение бесплатно.</p>
</div>
</div>
</div>
</div>
</section>
<!-- ════════════════════════════════════════════ -->
<!-- External Reviews Social Proof -->
<!-- ════════════════════════════════════════════ -->
<section class="bento pksh-section pksh-section--alt" aria-label="Отзывы на внешних площадках">
<div class="bento__full">
<div class="external-reviews">
<h2 class="bento-h2">Нас рекомендуют на площадках</h2>
<div class="external-reviews__grid">
<a href="https://yandex.ru/maps/org/detskiy_tsentr_dekart/..." target="_blank" rel="noopener noreferrer" class="external-reviews__card">
<span class="external-reviews__icon">Я</span>
<span class="external-reviews__name">Яндекс.Карты</span>
<span class="external-reviews__rating"> 4.8</span>
</a>
<a href="https://2gis.ru/search/..." target="_blank" rel="noopener noreferrer" class="external-reviews__card">
<span class="external-reviews__icon">2ГИС</span>
<span class="external-reviews__name">2ГИС</span>
<span class="external-reviews__rating"> 4.7</span>
</a>
<a href="https://vk.com/topic-..." target="_blank" rel="noopener noreferrer" class="external-reviews__card">
<span class="external-reviews__icon">ВК</span>
<span class="external-reviews__name">ВКонтакте</span>
<span class="external-reviews__rating"> 4.9</span>
</a>
<a href="https://otzovik.com/..." target="_blank" rel="noopener noreferrer" class="external-reviews__card">
<span class="external-reviews__icon">O</span>
<span class="external-reviews__name">Otzovik</span>
<span class="external-reviews__rating"> 4.6</span>
</a>
</div>
</div>
</div>
</section>
<!-- ════════════════════════════════════════════ -->
<!-- Final CTA Low Friction + Countdown Timer -->
<!-- ════════════════════════════════════════════ --> <!-- ════════════════════════════════════════════ -->
<section class="bento pksh-section pksh-section--alt" id="final-cta" aria-label="Запись"> <section class="bento pksh-section pksh-section--alt" id="final-cta" aria-label="Запись">
<div class="bento__full"> <div class="bento__full">
@ -604,7 +669,26 @@ $opt_social_raw = get_option( 'branch_social' ) ?: carbon_get_post_meta( $post_
<h2 class="bento-h2">Первое занятие бесплатно</h2> <h2 class="bento-h2">Первое занятие бесплатно</h2>
<p class="final-cta__text">Ребёнок познакомится с педагогом, попробует задания. Вы увидите методику своими глазами. Никакой оплаты и договоров.</p> <p class="final-cta__text">Ребёнок познакомится с педагогом, попробует задания. Вы увидите методику своими глазами. Никакой оплаты и договоров.</p>
<!-- Форма открывается в модалке (footer.php) скрипт из вкладки Битрикс24 в админке --> <!-- Countdown timer -->
<div class="final-cta__timer" id="cta-timer">
<span class="final-cta__timer-label">Скидка 10% действует ещё:</span>
<div class="final-cta__timer-digits">
<div class="final-cta__timer-unit">
<span class="final-cta__timer-num" id="timer-hours">24</span>
<span class="final-cta__timer-text">часов</span>
</div>
<span class="final-cta__timer-sep">:</span>
<div class="final-cta__timer-unit">
<span class="final-cta__timer-num" id="timer-minutes">00</span>
<span class="final-cta__timer-text">минут</span>
</div>
<span class="final-cta__timer-sep">:</span>
<div class="final-cta__timer-unit">
<span class="final-cta__timer-num" id="timer-seconds">00</span>
<span class="final-cta__timer-text">секунд</span>
</div>
</div>
</div>
<button class="btn-primary btn-primary--large open-bitrix-form btn-write">Записаться на бесплатное пробное</button> <button class="btn-primary btn-primary--large open-bitrix-form btn-write">Записаться на бесплатное пробное</button>
<p class="final-cta__footnote">🔥 Осталось 2 места в группе 56 лет. Успейте!</p> <p class="final-cta__footnote">🔥 Осталось 2 места в группе 56 лет. Успейте!</p>
@ -612,6 +696,28 @@ $opt_social_raw = get_option( 'branch_social' ) ?: carbon_get_post_meta( $post_
</div> </div>
</section> </section>
<script>
(function() {
var hours = 24, minutes = 0, seconds = 0;
var hEl = document.getElementById('timer-hours');
var mEl = document.getElementById('timer-minutes');
var sEl = document.getElementById('timer-seconds');
if (!hEl || !mEl || !sEl) return;
function pad(n) { return n < 10 ? '0' + n : '' + n; }
function tick() {
if (hours === 0 && minutes === 0 && seconds === 0) return;
if (seconds === 0) {
if (minutes === 0) { hours--; minutes = 59; seconds = 59; }
else { minutes--; seconds = 59; }
} else { seconds--; }
hEl.textContent = pad(hours);
mEl.textContent = pad(minutes);
sEl.textContent = pad(seconds);
}
setInterval(tick, 1000);
})();
</script>
<!-- ════════════════════════════════════════════ --> <!-- ════════════════════════════════════════════ -->
<!-- Contacts как на странице лагеря --> <!-- Contacts как на странице лагеря -->
<!-- ════════════════════════════════════════════ --> <!-- ════════════════════════════════════════════ -->
@ -706,6 +812,16 @@ $opt_social_raw = get_option( 'branch_social' ) ?: carbon_get_post_meta( $post_
})(); })();
</script> </script>
<!-- ════════════════════════════════════════════ -->
<!-- Sticky CTA Mobile -->
<!-- ════════════════════════════════════════════ -->
<div class="sticky-cta-mobile" aria-label="Запись">
<div class="sticky-cta-mobile__inner">
<span class="sticky-cta-mobile__text">Первое занятие <strong>бесплатно</strong></span>
<button class="sticky-cta-mobile__btn btn-write">Записаться</button>
</div>
</div>
</main> </main>
<?php <?php

View File

@ -39,7 +39,10 @@ $current_term = $tags[0];
<div class="title_form-bt24 mobile">Запишитесь на бесплатное пробное занятие и тестирование</div> <div class="title_form-bt24 mobile">Запишитесь на бесплатное пробное занятие и тестирование</div>
</div> </div>
<div class="vacancies__banner-right"> <div class="vacancies__banner-right">
<?php echo carbon_get_theme_option( 'site_bitrix_script' ); ?> <div class="b24-form-placeholder">
<p class="b24-form-placeholder__text">Запишитесь на бесплатное пробное занятие и тестирование</p>
<button class="btn-write btn-lilac">Записаться</button>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -128,11 +128,12 @@ $branch_address = get_option( 'branch_address', 'ул. Комсомольска
'class' => 'hero-pksh__photo', 'class' => 'hero-pksh__photo',
'loading' => 'eager', 'loading' => 'eager',
'decoding' => 'async', 'decoding' => 'async',
'alt' => 'Подготовка к школе в Щёлково — занятия для детей 57 лет',
) ); ?> ) ); ?>
<?php else : ?> <?php else : ?>
<img <img
src="<?php echo esc_url( get_template_directory_uri() . '/assets/images/girl_and_a_boy.webp' ); ?>" src="<?php echo esc_url( get_template_directory_uri() . '/assets/images/girl_and_a_boy.webp' ); ?>"
alt="Девочка и мальчик — весёлые занятия подготовкой к школе" alt="Подготовка к школе в Щёлково — занятия для детей 57 лет"
class="hero-pksh__photo" class="hero-pksh__photo"
loading="eager" loading="eager"
decoding="async" decoding="async"

View File

@ -25,7 +25,13 @@
</div> </div>
</div> </div>
<div class="promo-form-left-part"> <div class="promo-form-left-part">
<?php echo carbon_get_theme_option( 'site_bitrix_script' ); ?> <?php
$promo_b24 = get_option( 'branch_button_script', '' );
if ( empty( $promo_b24 ) ) {
$promo_b24 = carbon_get_theme_option( 'site_bitrix_script' );
}
echo $promo_b24; // WPCS: XSS ok — sanitized on save
?>
<p class="text-block_label mobile">Заполните форму<br> или позвоните по телефону</p> <p class="text-block_label mobile">Заполните форму<br> или позвоните по телефону</p>
<div class="phone mobile"> <div class="phone mobile">
<a href="tel:<?php echo carbon_get_theme_option( 'site_phone' ); ?>"><?php echo carbon_get_theme_option( 'site_phone' ); ?></a> <a href="tel:<?php echo carbon_get_theme_option( 'site_phone' ); ?>"><?php echo carbon_get_theme_option( 'site_phone' ); ?></a>