<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://www.pandoraburo.ru/" xml:lang="ru">
  <id>https://www.pandoraburo.ru/dykhatelnyy-trenazher</id>
  <link href="https://www.pandoraburo.ru/dykhatelnyy-trenazher.xml" rel="self"/>
  <title>Дыхательный тренажер</title>
  <subtitle type="html">
&lt;html lang="ru"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;&lt;/meta&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;&lt;/meta&gt;
    &lt;title&gt;? Нейро-дыхание | Тренажёр&lt;/title&gt;
    &lt;style&gt;
        /* ========== RESET &amp; BASE ========== */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            user-select: none;
        }

        body {
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
            padding: 16px;
            background: #0b0e1a;
            overflow: hidden;
            position: relative;
        }

        /* ========== ANIMATED BACKGROUND ========== */
        .bg-canvas {
            position: fixed;
            inset: 0;
            z-index: 0;
            background: radial-gradient(ellipse at 20% 50%, #1a1040 0%, #0b0e1a 70%);
            overflow: hidden;
        }
        .bg-canvas::before {
            content: '';
            position: absolute;
            inset: 0;
            background:
                radial-gradient(circle at 70% 30%, rgba(120, 80, 255, 0.15) 0%, transparent 50%),
                radial-gradient(circle at 20% 80%, rgba(255, 80, 180, 0.10) 0%, transparent 50%),
                radial-gradient(circle at 80% 70%, rgba(0, 200, 255, 0.08) 0%, transparent 50%);
            animation: bgShift 20s ease-in-out infinite alternate;
        }
        @keyframes bgShift {
            0% {
                transform: scale(1) rotate(0deg);
            }
            100% {
                transform: scale(1.2) rotate(5deg);
            }
        }

        /* ========== FLOATING PARTICLES ========== */
        .particles {
            position: absolute;
            inset: 0;
            pointer-events: none;
            overflow: hidden;
        }
        .particle {
            position: absolute;
            border-radius: 50%;
            background: radial-gradient(circle, rgba(255, 255, 255, 0.6), transparent 70%);
            animation: floatParticle linear infinite;
            opacity: 0;
        }
        .particle:nth-child(1) {
            width: 4px;
            height: 4px;
            left: 10%;
            top: 20%;
            animation-duration: 18s;
            animation-delay: 0s;
        }
        .particle:nth-child(2) {
            width: 6px;
            height: 6px;
            left: 30%;
            top: 60%;
            animation-duration: 22s;
            animation-delay: 2s;
        }
        .particle:nth-child(3) {
            width: 3px;
            height: 3px;
            left: 55%;
            top: 15%;
            animation-duration: 16s;
            animation-delay: 4s;
        }
        .particle:nth-child(4) {
            width: 5px;
            height: 5px;
            left: 75%;
            top: 50%;
            animation-duration: 20s;
            animation-delay: 1s;
        }
        .particle:nth-child(5) {
            width: 7px;
            height: 7px;
            left: 45%;
            top: 80%;
            animation-duration: 24s;
            animation-delay: 3s;
        }
        .particle:nth-child(6) {
            width: 4px;
            height: 4px;
            left: 88%;
            top: 25%;
            animation-duration: 19s;
            animation-delay: 5s;
        }
        .particle:nth-child(7) {
            width: 5px;
            height: 5px;
            left: 15%;
            top: 45%;
            animation-duration: 21s;
            animation-delay: 7s;
        }
        .particle:nth-child(8) {
            width: 3px;
            height: 3px;
            left: 65%;
            top: 88%;
            animation-duration: 17s;
            animation-delay: 2.5s;
        }
        @keyframes floatParticle {
            0% {
                transform: translate(0, 0) scale(0);
                opacity: 0;
            }
            10% {
                opacity: 0.8;
            }
            90% {
                opacity: 0.8;
            }
            100% {
                transform: translate(var(--tx, 80px), var(--ty, -120px)) scale(1);
                opacity: 0;
            }
        }
        .particle:nth-child(1) {
            --tx: 60px;
            --ty: -100px;
        }
        .particle:nth-child(2) {
            --tx: -80px;
            --ty: -70px;
        }
        .particle:nth-child(3) {
            --tx: 100px;
            --ty: -140px;
        }
        .particle:nth-child(4) {
            --tx: -60px;
            --ty: -90px;
        }
        .particle:nth-child(5) {
            --tx: 50px;
            --ty: -110px;
        }
        .particle:nth-child(6) {
            --tx: -90px;
            --ty: -130px;
        }
        .particle:nth-child(7) {
            --tx: 70px;
            --ty: -80px;
        }
        .particle:nth-child(8) {
            --tx: -50px;
            --ty: -100px;
        }

        /* ========== MAIN CONTAINER ========== */
        .container {
            position: relative;
            z-index: 1;
            background: rgba(255, 255, 255, 0.06);
            backdrop-filter: blur(24px) saturate(1.4);
            -webkit-backdrop-filter: blur(24px) saturate(1.4);
            border-radius: 40px;
            padding: 32px 28px 28px;
            max-width: 580px;
            width: 100%;
            border: 1px solid rgba(255, 255, 255, 0.08);
            box-shadow:
                0 40px 80px rgba(0, 0, 0, 0.6),
                inset 0 1px 0 rgba(255, 255, 255, 0.05);
            transition: border-color 0.6s;
        }

        /* ========== HEADER ========== */
        .header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin-bottom: 6px;
        }
        .header h1 {
            font-size: 1.5rem;
            font-weight: 700;
            background: linear-gradient(135deg, #f0e6ff, #b8a5ff);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
            letter-spacing: -0.3px;
        }
        .header-badge {
            font-size: 0.7rem;
            background: rgba(255, 255, 255, 0.06);
            padding: 4px 14px;
            border-radius: 30px;
            color: rgba(255, 255, 255, 0.5);
            border: 1px solid rgba(255, 255, 255, 0.05);
            font-weight: 500;
            letter-spacing: 0.3px;
        }
        .subtitle {
            text-align: center;
            color: rgba(255, 255, 255, 0.35);
            font-size: 0.85rem;
            margin-bottom: 22px;
            font-weight: 400;
            letter-spacing: 0.2px;
        }

        /* ========== STATS ROW ========== */
        .stats-row {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 10px;
            margin-bottom: 24px;
        }
        .stat-card {
            background: rgba(255, 255, 255, 0.04);
            border-radius: 16px;
            padding: 12px 8px;
            text-align: center;
            border: 1px solid rgba(255, 255, 255, 0.04);
            transition: background 0.3s, border-color 0.3s;
            backdrop-filter: blur(4px);
        }
        .stat-card:hover {
            background: rgba(255, 255, 255, 0.07);
        }
        .stat-label {
            font-size: 0.7rem;
            color: rgba(255, 255, 255, 0.35);
            text-transform: uppercase;
            letter-spacing: 0.5px;
            font-weight: 600;
            margin-bottom: 4px;
        }
        .stat-value {
            font-size: 1.6rem;
            font-weight: 700;
            color: #fff;
            font-variant-numeric: tabular-nums;
            letter-spacing: -0.5px;
            transition: color 0.4s;
        }
        .stat-value.cycles {
            color: #8ab4ff;
        }
        .stat-value.time {
            color: #a8e6cf;
        }
        .stat-value.accuracy {
            color: #ffb07c;
        }

        /* ========== BREATHING CIRCLE ========== */
        .breath-wrapper {
            position: relative;
            width: 100%;
            max-width: 320px;
            margin: 0 auto 22px;
            aspect-ratio: 1/1;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        /* ——— Ring Progress ——— */
        .progress-ring {
            position: absolute;
            inset: -12px;
            border-radius: 50%;
        }
        .progress-ring svg {
            width: 100%;
            height: 100%;
            transform: rotate(-90deg);
        }
        .progress-ring .track {
            fill: none;
            stroke: rgba(255, 255, 255, 0.05);
            stroke-width: 3;
        }
        .progress-ring .progress {
            fill: none;
            stroke: #6c5ce7;
            stroke-width: 3;
            stroke-linecap: round;
            transition: stroke-dashoffset 0.08s linear, stroke 0.4s;
            filter: drop-shadow(0 0 8px rgba(108, 92, 231, 0.3));
        }

        /* ——— Outer Glow Rings ——— */
        .glow-rings {
            position: absolute;
            inset: -20px;
            border-radius: 50%;
            pointer-events: none;
        }
        .glow-ring {
            position: absolute;
            inset: 0;
            border-radius: 50%;
            border: 1px solid transparent;
            animation: ringPulse 4s ease-out infinite;
            opacity: 0;
        }
        .glow-ring:nth-child(1) {
            animation-delay: 0s;
        }
        .glow-ring:nth-child(2) {
            animation-delay: 1.3s;
        }
        .glow-ring:nth-child(3) {
            animation-delay: 2.6s;
        }
        @keyframes ringPulse {
            0% {
                transform: scale(0.8);
                opacity: 0.6;
                border-color: rgba(108, 92, 231, 0.2);
            }
            100% {
                transform: scale(1.5);
                opacity: 0;
                border-color: rgba(108, 92, 231, 0);
            }
        }
        .breath-wrapper.active .glow-ring {
            animation: ringPulseActive 3s ease-out infinite;
        }
        @keyframes ringPulseActive {
            0% {
                transform: scale(0.85);
                opacity: 0.7;
                border-color: rgba(108, 92, 231, 0.25);
            }
            100% {
                transform: scale(1.6);
                opacity: 0;
                border-color: rgba(108, 92, 231, 0);
            }
        }

        /* ——— Breathing Sphere ——— */
        .breath-sphere {
            position: relative;
            z-index: 2;
            width: 90px;
            height: 90px;
            border-radius: 50%;
            background: radial-gradient(circle at 30% 30%, #a78bfa, #6c5ce7);
            box-shadow:
                0 0 60px rgba(108, 92, 231, 0.25),
                inset 0 -8px 30px rgba(0, 0, 0, 0.2),
                inset 0 8px 30px rgba(255, 255, 255, 0.15);
            transition: width 0.08s linear, height 0.08s linear, box-shadow 0.4s, background 0.6s;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 2.2rem;
            color: rgba(255, 255, 255, 0.9);
            text-shadow: 0 2px 20px rgba(0, 0, 0, 0.3);
            will-change: width, height;
        }
        /* Phase-based colors */
        .breath-sphere.phase-inhale {
            background: radial-gradient(circle at 30% 30%, #74b9ff, #0984e3);
            box-shadow: 0 0 80px rgba(9, 132, 227, 0.35), inset 0 -8px 30px rgba(0, 0, 0, 0.2), inset 0 8px 30px rgba(255, 255, 255, 0.15);
        }
        .breath-sphere.phase-hold1 {
            background: radial-gradient(circle at 30% 30%, #a29bfe, #6c5ce7);
            box-shadow: 0 0 80px rgba(108, 92, 231, 0.35), inset 0 -8px 30px rgba(0, 0, 0, 0.2), inset 0 8px 30px rgba(255, 255, 255, 0.15);
        }
        .breath-sphere.phase-exhale {
            background: radial-gradient(circle at 30% 30%, #fd79a8, #e84393);
            box-shadow: 0 0 80px rgba(232, 67, 147, 0.30), inset 0 -8px 30px rgba(0, 0, 0, 0.2), inset 0 8px 30px rgba(255, 255, 255, 0.15);
        }
        .breath-sphere.phase-hold2 {
            background: radial-gradient(circle at 30% 30%, #fdcb6e, #fdcb6e);
            box-shadow: 0 0 80px rgba(253, 203, 110, 0.25), inset 0 -8px 30px rgba(0, 0, 0, 0.2), inset 0 8px 30px rgba(255, 255, 255, 0.15);
        }

        .breath-sphere .icon {
            font-size: 1.8rem;
            transition: opacity 0.3s;
            line-height: 1;
        }

        /* ========== INSTRUCTION ========== */
        .instruction-text {
            text-align: center;
            font-size: 1.6rem;
            font-weight: 700;
            color: #fff;
            min-height: 56px;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            letter-spacing: -0.3px;
            margin-bottom: 16px;
            transition: color 0.4s;
        }
        .instruction-text .phase-icon {
            font-size: 1.8rem;
        }
        .instruction-text .phase-label {
            background: rgba(255, 255, 255, 0.04);
            padding: 2px 16px;
            border-radius: 30px;
            font-size: 0.9rem;
            font-weight: 500;
            color: rgba(255, 255, 255, 0.4);
            border: 1px solid rgba(255, 255, 255, 0.04);
        }

        /* ========== PATTERN SELECTOR ========== */
        .pattern-selector {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 8px;
            margin-bottom: 18px;
        }
        .pattern-btn {
            padding: 10px 6px;
            background: rgba(255, 255, 255, 0.03);
            border: 1px solid rgba(255, 255, 255, 0.06);
            border-radius: 14px;
            cursor: pointer;
            transition: all 0.25s;
            font-size: 0.75rem;
            font-weight: 600;
            color: rgba(255, 255, 255, 0.4);
            line-height: 1.3;
            text-align: center;
            font-family: inherit;
        }
        .pattern-btn:hover {
            background: rgba(255, 255, 255, 0.06);
            border-color: rgba(255, 255, 255, 0.10);
            color: rgba(255, 255, 255, 0.7);
        }
        .pattern-btn.active {
            background: rgba(108, 92, 231, 0.20);
            border-color: rgba(108, 92, 231, 0.35);
            color: #c8bfff;
            box-shadow: 0 0 30px rgba(108, 92, 231, 0.05);
        }
        .pattern-btn .pname {
            display: block;
            font-size: 0.9rem;
            font-weight: 700;
            color: #fff;
            margin-bottom: 1px;
        }
        .pattern-btn .pdesc {
            font-size: 0.6rem;
            font-weight: 400;
            opacity: 0.5;
            display: block;
        }
        .pattern-btn.active .pdesc {
            opacity: 0.7;
        }

        /* ========== CONTROLS ========== */
        .controls {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
            margin-bottom: 14px;
        }
        .btn {
            padding: 14px 10px;
            font-size: 1rem;
            font-weight: 700;
            border: none;
            border-radius: 16px;
            cursor: pointer;
            transition: all 0.2s;
            font-family: inherit;
            letter-spacing: 0.2px;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 6px;
        }
        .btn:active {
            transform: scale(0.96);
        }
        .btn-primary {
            background: linear-gradient(135deg, #6c5ce7, #a29bfe);
            color: #fff;
            box-shadow: 0 4px 20px rgba(108, 92, 231, 0.25);
        }
        .btn-primary:hover:not(:disabled) {
            box-shadow: 0 6px 30px rgba(108, 92, 231, 0.35);
            transform: translateY(-1px);
        }
        .btn-primary:disabled {
            opacity: 0.3;
            cursor: not-allowed;
            transform: none;
        }
        .btn-secondary {
            background: rgba(255, 255, 255, 0.04);
            color: rgba(255, 255, 255, 0.5);
            border: 1px solid rgba(255, 255, 255, 0.06);
        }
        .btn-secondary:hover:not(:disabled) {
            background: rgba(255, 255, 255, 0.08);
            color: #fff;
        }
        .btn-secondary:disabled {
            opacity: 0.2;
            cursor: not-allowed;
        }
        .btn-export {
            grid-column: 1 / -1;
            background: rgba(255, 255, 255, 0.03);
            color: rgba(255, 255, 255, 0.35);
            border: 1px solid rgba(255, 255, 255, 0.04);
            border-radius: 16px;
            padding: 12px;
            font-size: 0.85rem;
            font-weight: 600;
        }
        .btn-export:hover {
            background: rgba(255, 255, 255, 0.06);
            color: rgba(255, 255, 255, 0.7);
            border-color: rgba(255, 255, 255, 0.08);
        }

        /* ========== MESSAGE ========== */
        .message {
            text-align: center;
            padding: 12px 16px;
            border-radius: 16px;
            font-weight: 500;
            font-size: 0.9rem;
            min-height: 48px;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            background: rgba(255, 255, 255, 0.02);
            border: 1px solid rgba(255, 255, 255, 0.03);
            color: rgba(255, 255, 255, 0.4);
            transition: all 0.4s;
        }
        .message.info {
            background: rgba(9, 132, 227, 0.08);
            border-color: rgba(9, 132, 227, 0.10);
            color: #74b9ff;
        }
        .message.success {
            background: rgba(0, 206, 201, 0.08);
            border-color: rgba(0, 206, 201, 0.10);
            color: #81ecec;
        }
        .message.error {
            background: rgba(232, 67, 147, 0.08);
            border-color: rgba(232, 67, 147, 0.10);
            color: #fd79a8;
        }

        /* ========== RESPONSIVE ========== */
        @media (max-width: 520px) {
            .container {
                padding: 20px 16px 20px;
                border-radius: 28px;
            }
            .header h1 {
                font-size: 1.2rem;
            }
            .header-badge {
                font-size: 0.6rem;
                padding: 3px 10px;
            }
            .stats-row {
                gap: 6px;
            }
            .stat-card {
                padding: 8px 4px;
            }
            .stat-value {
                font-size: 1.3rem;
            }
            .breath-wrapper {
                max-width: 240px;
            }
            .breath-sphere {
                width: 70px;
                height: 70px;
                font-size: 1.6rem;
            }
            .breath-sphere .icon {
                font-size: 1.4rem;
            }
            .instruction-text {
                font-size: 1.2rem;
                min-height: 44px;
            }
            .pattern-selector {
                grid-template-columns: 1fr 1fr 1fr;
                gap: 5px;
            }
            .pattern-btn {
                padding: 8px 4px;
                font-size: 0.65rem;
            }
            .pattern-btn .pname {
                font-size: 0.75rem;
            }
            .controls {
                gap: 8px;
            }
            .btn {
                padding: 12px 8px;
                font-size: 0.85rem;
            }
            .progress-ring {
                inset: -6px;
            }
            .glow-rings {
                inset: -12px;
            }
        }
        @media (max-width: 400px) {
            .pattern-selector {
                grid-template-columns: 1fr;
            }
            .breath-wrapper {
                max-width: 200px;
            }
            .breath-sphere {
                width: 60px;
                height: 60px;
            }
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;

    
    &lt;div class="bg-canvas"&gt;
        &lt;div class="particles"&gt;
            &lt;div class="particle"&gt;&lt;/div&gt;
            &lt;div class="particle"&gt;&lt;/div&gt;
            &lt;div class="particle"&gt;&lt;/div&gt;
            &lt;div class="particle"&gt;&lt;/div&gt;
            &lt;div class="particle"&gt;&lt;/div&gt;
            &lt;div class="particle"&gt;&lt;/div&gt;
            &lt;div class="particle"&gt;&lt;/div&gt;
            &lt;div class="particle"&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;

    
    &lt;div class="container" id="app"&gt;

        
        &lt;div class="header"&gt;
            &lt;h1&gt;? Нейро-дыхание&lt;/h1&gt;
            &lt;span class="header-badge"&gt;v2.0&lt;/span&gt;
        &lt;/div&gt;
        &lt;p class="subtitle"&gt;Дыши в ритме, синхронизируй сознание&lt;/p&gt;

        
        &lt;div class="stats-row"&gt;
            &lt;div class="stat-card"&gt;
                &lt;div class="stat-label"&gt;? Циклы&lt;/div&gt;
                &lt;div class="stat-value cycles" id="cycleCount"&gt;0&lt;/div&gt;
            &lt;/div&gt;
            &lt;div class="stat-card"&gt;
                &lt;div class="stat-label"&gt;⏱ Время&lt;/div&gt;
                &lt;div class="stat-value time" id="sessionTime"&gt;0:00&lt;/div&gt;
            &lt;/div&gt;
            &lt;div class="stat-card"&gt;
                &lt;div class="stat-label"&gt;? Точность&lt;/div&gt;
                &lt;div class="stat-value accuracy" id="accuracy"&gt;0%&lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;

        
        &lt;div class="breath-wrapper" id="breathWrapper"&gt;
            &lt;div class="glow-rings"&gt;
                &lt;div class="glow-ring"&gt;&lt;/div&gt;
                &lt;div class="glow-ring"&gt;&lt;/div&gt;
                &lt;div class="glow-ring"&gt;&lt;/div&gt;
            &lt;/div&gt;
            &lt;div class="progress-ring"&gt;
                &lt;svg viewbox="0 0 100 100"&gt;
                    &lt;circle class="track" cx="50" cy="50" r="42"&gt;&lt;/circle&gt;
                    &lt;circle class="progress" id="progressCircle" cx="50" cy="50" r="42" stroke-dasharray="263.89" stroke-dashoffset="263.89"&gt;&lt;/circle&gt;
                &lt;/svg&gt;
            &lt;/div&gt;
            &lt;div class="breath-sphere" id="breathSphere"&gt;
                &lt;span class="icon"&gt;●&lt;/span&gt;
            &lt;/div&gt;
        &lt;/div&gt;

        
        &lt;div class="instruction-text" id="instruction"&gt;
            &lt;span class="phase-icon"&gt;?&lt;/span&gt;
            &lt;span&gt;Нажмите «Старт»&lt;/span&gt;
            &lt;span class="phase-label"&gt;готов&lt;/span&gt;
        &lt;/div&gt;

        
        &lt;div class="pattern-selector" id="patternSelector"&gt;
            &lt;button class="pattern-btn active" data-pattern="478"&gt;
                &lt;span class="pname"&gt;4-7-8&lt;/span&gt;
                &lt;span class="pdesc"&gt;расслабление&lt;/span&gt;
            &lt;/button&gt;
            &lt;button class="pattern-btn" data-pattern="box"&gt;
                &lt;span class="pname"&gt;Квадрат&lt;/span&gt;
                &lt;span class="pdesc"&gt;баланс&lt;/span&gt;
            &lt;/button&gt;
            &lt;button class="pattern-btn" data-pattern="coherence"&gt;
                &lt;span class="pname"&gt;Когерентность&lt;/span&gt;
                &lt;span class="pdesc"&gt;фокус&lt;/span&gt;
            &lt;/button&gt;
        &lt;/div&gt;

        
        &lt;div class="controls"&gt;
            &lt;button class="btn btn-primary" id="startBtn"&gt;▶ Старт&lt;/button&gt;
            &lt;button class="btn btn-secondary" id="stopBtn" disabled="disabled"&gt;⏹ Стоп&lt;/button&gt;
            &lt;button class="btn btn-export" id="exportBtn"&gt;? Экспорт отчёта (CSV)&lt;/button&gt;
        &lt;/div&gt;

        
        &lt;div class="message info" id="message"&gt;
            ? Выберите паттерн и начните тренировку
        &lt;/div&gt;
    &lt;/div&gt;

    &lt;script&gt;
        (function() {
            'use strict';

            // ====== DOM refs ======
            const sphere = document.getElementById('breathSphere');
            const wrapper = document.getElementById('breathWrapper');
            const instruction = document.getElementById('instruction');
            const message = document.getElementById('message');
            const progressCircle = document.getElementById('progressCircle');

            const startBtn = document.getElementById('startBtn');
            const stopBtn = document.getElementById('stopBtn');
            const exportBtn = document.getElementById('exportBtn');

            const cycleCountEl = document.getElementById('cycleCount');
            const sessionTimeEl = document.getElementById('sessionTime');
            const accuracyEl = document.getElementById('accuracy');

            const patternBtns = document.querySelectorAll('.pattern-btn');

            // ====== State ======
            let isRunning = false;
            let animId = null;
            let cycleCount = 0;
            let startTime = 0;
            let currentPattern = '478';
            let phase = 'inhale';
            let phaseStartTime = 0;
            let totalPhases = 0;
            let correctPhases = 0;
            let lastPhase = '';

            // ====== Patterns ======
            const patterns = {
                '478': { inhale: 4000, hold1: 7000, exhale: 8000, hold2: 0, name: '4-7-8' },
                'box': { inhale: 4000, hold1: 4000, exhale: 4000, hold2: 4000, name: 'Квадрат' },
                'coherence': { inhale: 5000, hold1: 0, exhale: 5000, hold2: 0, name: 'Когерентность' }
            };

            // ====== Pattern switching ======
            patternBtns.forEach(btn =&gt; {
                btn.addEventListener('click', () =&gt; {
                    if (isRunning) return;
                    patternBtns.forEach(b =&gt; b.classList.remove('active'));
                    btn.classList.add('active');
                    currentPattern = btn.dataset.pattern;
                    updatePatternMessage();
                });
            });

            function updatePatternMessage() {
                const p = patterns[currentPattern];
                message.className = 'message info';
                message.textContent = `? Паттерн «${p.name}» — вдох ${p.inhale/1000}с, выдох ${p.exhale/1000}с${p.hold1&gt;0 ? `, задержка ${p.hold1/1000}с` : ''}`;
            }

            // ====== Progress ring ======
            const circumference = 2 * Math.PI * 42; // ~263.89

            function setProgress(fraction) {
                const offset = circumference * (1 - Math.min(1, Math.max(0, fraction)));
                progressCircle.setAttribute('stroke-dashoffset', offset);
            }

            // ====== Sphere update ======
            function updateSphereSize(progress, phase) {
                const minSize = 70;
                const maxSize = 280;
                let size;
                if (phase === 'inhale') {
                    size = minSize + (maxSize - minSize) * progress;
                } else if (phase === 'exhale') {
                    size = maxSize - (maxSize - minSize) * progress;
                } else if (phase === 'hold1') {
                    size = maxSize;
                } else { // hold2
                    size = minSize;
                }
                // clamp
                size = Math.min(maxSize, Math.max(minSize, size));
                sphere.style.width = size + 'px';
                sphere.style.height = size + 'px';
            }

            function getPhaseIcon(phase) {
                switch (phase) {
                    case 'inhale':
                        return '⬆️';
                    case 'hold1':
                        return '⏸';
                    case 'exhale':
                        return '⬇️';
                    case 'hold2':
                        return '⏸';
                    default:
                        return '●';
                }
            }

            function getPhaseLabel(phase) {
                switch (phase) {
                    case 'inhale':
                        return 'ВДОХ';
                    case 'hold1':
                        return 'ЗАДЕРЖКА';
                    case 'exhale':
                        return 'ВЫДОХ';
                    case 'hold2':
                        return 'ПАУЗА';
                    default:
                        return '';
                }
            }

            function getPhaseColorClass(phase) {
                switch (phase) {
                    case 'inhale':
                        return 'phase-inhale';
                    case 'hold1':
                        return 'phase-hold1';
                    case 'exhale':
                        return 'phase-exhale';
                    case 'hold2':
                        return 'phase-hold2';
                    default:
                        return '';
                }
            }

            // ====== Main loop ======
            function updateBreathCycle() {
                if (!isRunning) return;

                const now = Date.now();
                const pattern = patterns[currentPattern];
                const elapsed = now - phaseStartTime;

                let phaseDuration;
                switch (phase) {
                    case 'inhale':
                        phaseDuration = pattern.inhale;
                        break;
                    case 'hold1':
                        phaseDuration = pattern.hold1;
                        break;
                    case 'exhale':
                        phaseDuration = pattern.exhale;
                        break;
                    case 'hold2':
                        phaseDuration = pattern.hold2;
                        break;
                    default:
                        phaseDuration = 1000;
                }

                const progress = Math.min(1, elapsed / phaseDuration);

                // Update sphere
                updateSphereSize(progress, phase);

                // Update progress ring
                setProgress(progress);

                // Update instruction
                const icon = getPhaseIcon(phase);
                const label = getPhaseLabel(phase);
                const timeLeft = Math.max(0, Math.ceil((phaseDuration - elapsed) / 1000));
                instruction.innerHTML = `
                    &lt;span class="phase-icon"&gt;${icon}&lt;/span&gt;
                    &lt;span&gt;${label}&lt;/span&gt;
                    &lt;span class="phase-label"&gt;${timeLeft}с&lt;/span&gt;
                `;

                // Update sphere color class
                sphere.className = 'breath-sphere ' + getPhaseColorClass(phase);

                // Phase transition
                if (elapsed &gt;= phaseDuration) {
                    totalPhases++;
                    correctPhases++;

                    // Move to next phase
                    if (phase === 'inhale') {
                        phase = (pattern.hold1 &gt; 0) ? 'hold1' : (pattern.exhale &gt; 0 ? 'exhale' : 'inhale');
                    } else if (phase === 'hold1') {
                        phase = 'exhale';
                    } else if (phase === 'exhale') {
                        phase = (pattern.hold2 &gt; 0) ? 'hold2' : 'inhale';
                        cycleCount++;
                    } else if (phase === 'hold2') {
                        phase = 'inhale';
                        cycleCount++;
                    }

                    phaseStartTime = now;
                    updateStats();

                    // If we just completed a cycle, update message
                    if (phase === 'inhale' || phase === 'hold1') {
                        // subtle feedback
                    }
                }

                // Update session time
                const sessionDuration = Math.floor((now - startTime) / 1000);
                const mins = Math.floor(sessionDuration / 60);
                const secs = sessionDuration % 60;
                sessionTimeEl.textContent = `${mins}:${secs.toString().padStart(2, '0')}`;

                animId = requestAnimationFrame(updateBreathCycle);
            }

            // ====== Stats ======
            function updateStats() {
                cycleCountEl.textContent = cycleCount;
                const acc = totalPhases &gt; 0 ? Math.round((correctPhases / totalPhases) * 100) : 0;
                accuracyEl.textContent = acc + '%';
            }

            // ====== Session control ======
            function startSession() {
                if (isRunning) return;
                isRunning = true;
                cycleCount = 0;
                totalPhases = 0;
                correctPhases = 0;
                phase = 'inhale';
                startTime = Date.now();
                phaseStartTime = Date.now();

                startBtn.disabled = true;
                stopBtn.disabled = false;
                wrapper.classList.add('active');

                // Reset progress ring
                setProgress(0);

                // Message
                const p = patterns[currentPattern];
                message.className = 'message success';
                message.textContent = `? Дышим по паттерну «${p.name}» — следуй за сферой`;

                // Start loop
                if (animId) cancelAnimationFrame(animId);
                updateBreathCycle();
            }

            function stopSession() {
                if (!isRunning) return;
                isRunning = false;
                if (animId) {
                    cancelAnimationFrame(animId);
                    animId = null;
                }

                startBtn.disabled = false;
                stopBtn.disabled = true;
                wrapper.classList.remove('active');

                const sessionDuration = Math.floor((Date.now() - startTime) / 1000);
                const mins = Math.floor(sessionDuration / 60);
                const secs = sessionDuration % 60;
                const acc = totalPhases &gt; 0 ? Math.round((correctPhases / totalPhases) * 100) : 0;

                message.className = 'message info';
                message.textContent =
                    `⏹ Сессия завершена: ${cycleCount} циклов за ${mins}:${secs.toString().padStart(2, '0')}, точность ${acc}%`;

                instruction.innerHTML = `
                    &lt;span class="phase-icon"&gt;✅&lt;/span&gt;
                    &lt;span&gt;Готово&lt;/span&gt;
                    &lt;span class="phase-label"&gt;${cycleCount} циклов&lt;/span&gt;
                `;
                sphere.className = 'breath-sphere';

                // Save to history
                const session = {
                    date: new Date().toISOString(),
                    duration: sessionDuration,
                    cycles: cycleCount,
                    pattern: patterns[currentPattern].name,
                    accuracy: acc
                };
                const history = JSON.parse(localStorage.getItem('breath_history') || '[]');
                history.push(session);
                localStorage.setItem('breath_history', JSON.stringify(history));

                updateStats();
            }

            // ====== Export ======
            exportBtn.addEventListener('click', () =&gt; {
                const history = JSON.parse(localStorage.getItem('breath_history') || '[]');
                if (history.length === 0) {
                    message.className = 'message error';
                    message.textContent = '? Нет данных для экспорта. Проведите хотя бы одну сессию.';
                    return;
                }

                let csv = 'Дата,Длительность(с),Циклы,Паттерн,Точность(%)\n';
                history.forEach(s =&gt; {
                    const d = new Date(s.date).toLocaleString('ru-RU', { hour12: false });
                    csv += `${d},${s.duration},${s.cycles},${s.pattern},${s.accuracy}\n`;
                });

                const blob = new Blob(['\uFEFF' + csv], { type: 'text/csv;charset=utf-8;' });
                const link = document.createElement('a');
                link.href = URL.createObjectURL(blob);
                const dateStr = new Date().toISOString().split('T')[0];
                link.download = `breath_tracker_${dateStr}.csv`;
                link.click();
                URL.revokeObjectURL(link.href);

                message.className = 'message success';
                message.textContent = `✅ Экспортировано ${history.length} записей в CSV`;
            });

            // ====== Event listeners ======
            startBtn.addEventListener('click', startSession);
            stopBtn.addEventListener('click', stopSession);

            // ====== Keyboard shortcuts ======
            document.addEventListener('keydown', (e) =&gt; {
                if (e.key === ' ' || e.key === 'Enter') {
                    e.preventDefault();
                    if (!isRunning) startSession();
                    else stopSession();
                }
            });

            // ====== Init ======
            updatePatternMessage();
            setProgress(0);
            instruction.innerHTML = `
                &lt;span class="phase-icon"&gt;?&lt;/span&gt;
                &lt;span&gt;Нажмите «Старт»&lt;/span&gt;
                &lt;span class="phase-label"&gt;готов&lt;/span&gt;
            `;
            sphere.className = 'breath-sphere';

            console.log('? Нейро-дыхание v2.0 — нажмите пробел для старта/стопа');
        })();
    &lt;/script&gt;

&lt;/body&gt;
&lt;/html&gt;</subtitle>
  <updated>2026-08-15T13:27:16Z</updated>
  <logo>https://pandoraburo.ru/ssl/u/pic/e2/6850fe98a211f18279a3cef0e847cc/-/logo.png</logo>
  <author>
    <name>1592962</name>
    <uri>https://www.pandoraburo.ru/</uri>
  </author>
</feed>
