<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:yandex="http://news.yandex.ru" xmlns:turbo="http://turbo.yandex.ru" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>инструменты</title>
    <link>https://xn--90ahkamccj8mi.xn--p1ai</link>
    <description/>
    <language>ru</language>
    <lastBuildDate>Tue, 21 Jul 2026 14:29:18 +0300</lastBuildDate>
    <item turbo="true">
      <title>Карточки терминов</title>
      <link>https://xn--90ahkamccj8mi.xn--p1ai/tpost/snxlrssx91-kartochki-terminov</link>
      <amplink>https://xn--90ahkamccj8mi.xn--p1ai/tpost/snxlrssx91-kartochki-terminov?amp=true</amplink>
      <pubDate>Tue, 21 Jul 2026 14:29:00 +0300</pubDate>
      <turbo:content><![CDATA[<header><h1>Карточки терминов</h1></header><div class="t-redactor__embedcode"><!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Карточка терминов — «В балансе с собой и другими»</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,450;9..144,600;9..144,700&family=Inter:wght@400;500;600;700&family=IBM+Plex+Mono:wght@500&display=swap" rel="stylesheet">
<style>
  :root{
    --bg:#FAF3F6;
    --surface:#FFFFFF;
    --ink:#2B2233;
    --ink-soft:#7A6E82;
    --berry:#9C2A5E;
    --berry-light:#F1DCE6;
    --teal:#1E6F63;
    --teal-light:#DDEDE9;
    --gold:#C98A2E;
    --gold-light:#F5E6CC;
    --line:#E9DCE2;
    --shadow: 0 10px 30px -14px rgba(43,34,51,0.22);
  }
  *{box-sizing:border-box;}
  html,body{margin:0;padding:0;}
  body{
    background:
      radial-gradient(circle at 1px 1px, rgba(156,42,94,0.07) 1px, transparent 1px) 0 0/22px 22px,
      var(--bg);
    color:var(--ink);
    font-family:'Inter',system-ui,sans-serif;
    min-height:100vh;
  }
  .wrap{max-width:980px;margin:0 auto;padding:28px 20px 80px;}

  /* ---------- Header ---------- */
  header.top{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;flex-wrap:wrap;margin-bottom:22px;}
  .brand{display:flex;align-items:center;gap:12px;}
  .brand svg{flex:none;}
  .brand h1{
    font-family:'Fraunces',serif;font-weight:600;font-size:clamp(24px,4vw,34px);
    margin:0; line-height:1.05; letter-spacing:-0.01em;
  }
  .brand p{margin:2px 0 0; color:var(--ink-soft); font-size:13.5px;}
  .profile-pill{
    display:flex; align-items:center; gap:8px;
    background:var(--surface); border:1px solid var(--line); border-radius:999px;
    padding:6px 8px 6px 14px; font-size:13px; color:var(--ink-soft); box-shadow:var(--shadow);
  }
  .profile-pill b{color:var(--ink); font-weight:600;}
  .profile-pill button{
    border:none; background:var(--berry-light); color:var(--berry); font-weight:600;
    font-size:12px; padding:6px 10px; border-radius:999px; cursor:pointer;
  }
  .profile-pill button:hover{background:var(--berry); color:#fff;}

  .progress-row{display:flex; align-items:center; gap:10px; margin-bottom:26px;}
  .progress-track{flex:1; height:8px; background:var(--berry-light); border-radius:999px; overflow:hidden;}
  .progress-fill{height:100%; background:linear-gradient(90deg,var(--berry),var(--gold)); border-radius:999px; transition:width .4s ease;}
  .progress-label{font-size:12.5px; color:var(--ink-soft); white-space:nowrap; font-family:'IBM Plex Mono',monospace;}

  /* ---------- Layout ---------- */
  .layout{display:grid; grid-template-columns:230px 1fr; gap:26px; align-items:start;}
  @media (max-width:760px){ .layout{grid-template-columns:1fr;} }

  /* ---------- Rail ---------- */
  .rail{position:relative; padding-left:18px;}
  .rail::before{
    content:""; position:absolute; left:11px; top:6px; bottom:6px; width:2px;
    background:repeating-linear-gradient(to bottom, var(--line) 0 6px, transparent 6px 11px);
  }
  .rail-item{
    position:relative; display:flex; align-items:center; gap:10px; width:100%;
    background:none; border:none; text-align:left; cursor:pointer; padding:9px 6px 9px 0;
    font-family:'Inter',sans-serif; color:var(--ink-soft); border-radius:10px;
  }
  .rail-item:hover{color:var(--ink);}
  .rail-item .stamp{margin-left:-18px;}
  .rail-item .txt{display:flex; flex-direction:column; line-height:1.2;}
  .rail-item .n{font-size:11px; font-family:'IBM Plex Mono',monospace; letter-spacing:.03em;}
  .rail-item .t{font-size:13.5px; font-weight:600;}
  .rail-item.active{background:var(--surface); box-shadow:var(--shadow); color:var(--ink);}
  .rail-item.active .t{color:var(--berry);}

  /* ---------- Stamp badge (signature element) ---------- */
  .stamp{
    flex:none; width:26px; height:26px; display:flex; align-items:center; justify-content:center;
    border:2px dashed var(--ink-soft); border-radius:47% 53% 52% 48% / 48% 45% 55% 52%;
    color:var(--ink-soft); font-size:11px; font-weight:700; transform:rotate(-4deg);
    background:transparent; transition:all .25s ease;
  }
  .stamp.big{width:52px; height:52px; font-size:19px; border-width:2.5px;}
  .stamp.filled{
    border-style:solid; border-color:var(--berry); background:var(--berry); color:#fff; transform:rotate(-2deg);
  }

  /* ---------- Content card ---------- */
  .panel{background:var(--surface); border-radius:18px; box-shadow:var(--shadow); padding:26px 28px; border:1px solid var(--line);}
  .panel h2{font-family:'Fraunces',serif; font-weight:600; font-size:22px; margin:0 0 4px;}
  .panel .sub{color:var(--ink-soft); font-size:13.5px; margin:0 0 22px;}

  .term{border-top:1px solid var(--line); padding:20px 0;}
  .term:first-of-type{border-top:none; padding-top:6px;}
  .term-head{display:flex; align-items:flex-start; gap:14px;}
  .term-head .term-name{font-weight:700; font-size:16px; flex:1;}
  .synonym-chip{
    display:inline-block; margin-top:4px; font-size:12.5px; color:var(--teal); background:var(--teal-light);
    padding:3px 9px; border-radius:999px; font-style:italic;
  }
  details.def{margin-top:8px;}
  details.def summary{
    cursor:pointer; font-size:12.5px; color:var(--berry); font-weight:600; list-style:none;
  }
  details.def summary::-webkit-details-marker{display:none;}
  details.def summary::before{content:"Что это значит? ";}
  details.def[open] summary::before{content:"Свернуть ";}
  details.def p{font-size:13.5px; color:var(--ink-soft); margin:8px 0 0; line-height:1.5;}

  label.field-label{display:block; font-size:12px; color:var(--ink-soft); margin:12px 0 6px; font-weight:600;}
  textarea{
    width:100%; min-height:58px; resize:vertical; border:1.5px solid var(--line); border-radius:10px;
    padding:10px 12px; font-family:'Inter',sans-serif; font-size:14px; color:var(--ink); background:#FEFCFB;
  }
  textarea:focus{outline:none; border-color:var(--berry);}
  .save-hint{font-size:11.5px; color:var(--teal); min-height:14px; margin-top:4px; opacity:0; transition:opacity .3s;}
  .save-hint.show{opacity:1;}

  /* ---------- Self-check (session 7) ---------- */
  .collection{display:flex; flex-wrap:wrap; gap:10px; margin-bottom:22px;}
  .summary-row{display:flex; gap:14px; margin-bottom:22px; flex-wrap:wrap;}
  .summary-chip{flex:1; min-width:120px; border-radius:12px; padding:12px 14px; font-size:13px;}
  .summary-chip b{display:block; font-size:22px; font-family:'Fraunces',serif;}
  .sc-remember{background:var(--teal-light); color:var(--teal);}
  .sc-unsure{background:var(--gold-light); color:#8a5f1c;}
  .sc-forgot{background:var(--berry-light); color:var(--berry);}

  .sc-term{border-top:1px solid var(--line); padding:16px 0;}
  .sc-term:first-of-type{border-top:none;}
  .sc-term .top-row{display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap;}
  .sc-term .from{font-size:11.5px; color:var(--ink-soft); font-family:'IBM Plex Mono',monospace;}
  .chip-group{display:flex; gap:6px;}
  .chip{
    border:1.5px solid var(--line); background:#fff; border-radius:999px; padding:6px 12px; font-size:12.5px;
    cursor:pointer; font-weight:600; color:var(--ink-soft);
  }
  .chip[data-v="remember"].on{background:var(--teal); border-color:var(--teal); color:#fff;}
  .chip[data-v="unsure"].on{background:var(--gold); border-color:var(--gold); color:#fff;}
  .chip[data-v="forgot"].on{background:var(--berry); border-color:var(--berry); color:#fff;}
  .sc-term input.ex{
    width:100%; margin-top:10px; border:1.5px solid var(--line); border-radius:10px; padding:8px 12px;
    font-family:'Inter',sans-serif; font-size:13.5px; background:#FEFCFB;
  }
  .sc-term input.ex:focus{outline:none; border-color:var(--berry);}

  /* ---------- Gate overlay ---------- */
  .gate{
    position:fixed; inset:0; background:rgba(43,34,51,0.55); backdrop-filter:blur(2px);
    display:flex; align-items:center; justify-content:center; z-index:50; padding:20px;
  }
  .gate-card{
    background:var(--surface); border-radius:20px; padding:34px 30px; max-width:380px; width:100%;
    box-shadow:0 30px 60px -20px rgba(43,34,51,0.4); text-align:center;
  }
  .gate-card h2{font-family:'Fraunces',serif; font-size:22px; margin:10px 0 6px;}
  .gate-card p{color:var(--ink-soft); font-size:13.5px; margin:0 0 18px;}
  .gate-card input{
    width:100%; padding:11px 14px; border-radius:10px; border:1.5px solid var(--line); font-size:14px;
    margin-bottom:14px; font-family:'Inter',sans-serif;
  }
  .gate-card input:focus{outline:none; border-color:var(--berry);}
  .gate-card button{
    width:100%; padding:12px; border:none; border-radius:10px; background:var(--berry); color:#fff;
    font-weight:600; font-size:14.5px; cursor:pointer;
  }
  .gate-card button:hover{background:#831f4d;}
  .gate-note{font-size:11.5px; color:var(--ink-soft); margin-top:12px;}
  .err{color:var(--berry); font-size:12.5px; margin:-6px 0 12px; display:none;}
</style>
</head>
<body>

<div class="wrap">
  <header class="top">
    <div class="brand">
      <svg width="40" height="40" viewBox="0 0 40 40" fill="none">
        <path d="M4 20C4 11 11 5 20 5C29 5 36 11 36 20" stroke="#9C2A5E" stroke-width="2.4" stroke-linecap="round"/>
        <path d="M4 20C4 20 6 17 9 20C12 23 14 17 17 20C20 23 22 17 25 20C28 23 30 17 33 20C34.5 21.5 36 20 36 20" stroke="#9C2A5E" stroke-width="2.4" stroke-linecap="round"/>
        <line x1="20" y1="20" x2="20" y2="32" stroke="#1E6F63" stroke-width="2.4" stroke-linecap="round"/>
      </svg>
      <div>
        <h1>Карточка терминов</h1>
        <p>курс «В балансе с собой и другими» · 7 занятий</p>
      </div>
    </div>
    <div class="profile-pill" id="profilePill" style="display:none;">
      <span>Карточка: <b id="profileName">—</b></span>
      <button id="switchProfileBtn">сменить</button>
    </div>
  </header>

  <div class="progress-row">
    <div class="progress-track"><div class="progress-fill" id="progressFill" style="width:0%"></div></div>
    <div class="progress-label" id="progressLabel">0 / 13 своими словами</div>
  </div>

  <div class="layout">
    <nav class="rail" id="rail"></nav>
    <main class="panel" id="panel"></main>
  </div>
</div>

<div class="gate" id="gate">
  <div class="gate-card">
    <svg width="34" height="34" viewBox="0 0 40 40" fill="none" style="margin:0 auto;display:block;">
      <path d="M4 20C4 11 11 5 20 5C29 5 36 11 36 20" stroke="#9C2A5E" stroke-width="2.4" stroke-linecap="round"/>
      <path d="M4 20C4 20 6 17 9 20C12 23 14 17 17 20C20 23 22 17 25 20C28 23 30 17 33 20C34.5 21.5 36 20 36 20" stroke="#9C2A5E" stroke-width="2.4" stroke-linecap="round"/>
      <line x1="20" y1="20" x2="20" y2="32" stroke="#1E6F63" stroke-width="2.4" stroke-linecap="round"/>
    </svg>
    <h2>Как тебя записать?</h2>
    <p>Впиши имя или любой ник — карточка будет твоей на все 7 занятий.</p>
    <div class="err" id="gateErr">Впиши хотя бы одну букву :)</div>
    <input id="nameInput" type="text" placeholder="Например: Аня или Тигр77" maxlength="30" autocomplete="off">
    <button id="startBtn">Открыть карточку</button>
    <div class="gate-note">Ответы сохраняются автоматически и видны только тебе.</div>
  </div>
</div>

<script>
(function(){
  const SESSIONS = [
    {id:1, title:'Общие понятия', terms:[
      {id:'assert', term:'Ассертивность', official:'Уверенное неагрессивное поведение — баланс между своими интересами и уважением к другим.', synonym:'Уверенно и без драки'},
      {id:'aggr', term:'Агрессия (в конфликте)', official:'Ставлю свои интересы выше интересов другого.', synonym:'Продавил своё'},
      {id:'yield', term:'Уступка', official:'Ставлю интересы другого выше своих.', synonym:'Слился ради отношений'},
      {id:'leave', term:'Уход', official:'Никто не остаётся в выигрыше, проблема замалчивается.', synonym:'Сделал вид, что всё ок'},
      {id:'coop', term:'Компромисс / Сотрудничество', official:'Оба немного уступают друг другу либо ищут решение вместе.', synonym:'Договорились по-честному'},
    ]},
    {id:2, title:'Мои состояния', terms:[
      {id:'selfreg', term:'Саморегуляция', official:'Способность управлять своим эмоциональным состоянием.', synonym:'Умею сам себя «настроить»'},
      {id:'zones', term:'Зоны состояния', official:'Синяя (отдохни) / зелёная (полный вперёд) / жёлтая (замедлись) / красная (стоп).', synonym:'Мой «светофор состояния»'},
    ]},
    {id:3, title:'Мои эмоции', terms:[
      {id:'emotions', term:'Базовые эмоции (Плутчик)', official:'Набор из 8 основных эмоций, из которых складываются остальные.', synonym:'«Цветок эмоций»'},
    ]},
    {id:4, title:'Мои убеждения I', terms:[
      {id:'triangle', term:'Мысли — чувства — поведение', official:'Три взаимосвязанных процесса, которые влияют друг на друга.', synonym:'Что подумал → что почувствовал → что сделал'},
    ]},
    {id:5, title:'Мои убеждения II', terms:[
      {id:'limitbelief', term:'Ограничивающее убеждение', official:'Установка про себя или мир, которая мешает действовать.', synonym:'«Вредная программа в голове»'},
      {id:'distortion', term:'Когнитивное искажение', official:'Типичная ошибка мышления — например, катастрофизация или чтение мыслей.', synonym:'«Мысль-ловушка»'},
    ]},
    {id:6, title:'Мои стратегии поведения', terms:[
      {id:'imsg', term:'Я-сообщение', official:'4-шаговая техника: Когда… Я чувствую… Мне хочется… Пожалуйста…', synonym:'«Говорю о себе, а не обвиняю»'},
    ]},
    {id:7, title:'Управляю собой', terms:[
      {id:'grounding', term:'Техника «5-4-3-2-1»', official:'Метод переключения внимания через органы чувств.', synonym:'«Заземление»'},
    ]},
  ];
  const ALL_TERMS = SESSIONS.flatMap(s => s.terms.map(t => ({...t, sessionId:s.id})));

  let state = { name:'', mine:{}, selfcheck:{} };
  let storageKey = null;
  let activeSession = 1;

  const rail = document.getElementById('rail');
  const panel = document.getElementById('panel');
  const gate = document.getElementById('gate');
  const profilePill = document.getElementById('profilePill');
  const profileName = document.getElementById('profileName');

  function slugify(str){
    return str.trim().toLowerCase().normalize('NFKD').replace(/[\u0300-\u036f]/g,'')
      .replace(/[^a-z0-9а-яё]+/gi,'-').replace(/^-+|-+$/g,'').slice(0,40) || 'guest';
  }

  async function loadProfile(name){
    state = { name, mine:{}, selfcheck:{} };
    storageKey = 'termcard:' + slugify(name);
    try{
      const res = await window.storage.get(storageKey, false);
      if(res && res.value){
        const parsed = JSON.parse(res.value);
        state = Object.assign({name, mine:{}, selfcheck:{}}, parsed);
      }
    }catch(e){ /* нет сохранённых данных — начинаем с чистой карточки */ }
    profileName.textContent = state.name;
    profilePill.style.display = 'flex';
    renderRail();
    selectSession(1);
  }

  let saveTimer = null;
  function persist(hintEl){
    clearTimeout(saveTimer);
    saveTimer = setTimeout(async () => {
      try{
        await window.storage.set(storageKey, JSON.stringify(state), false);
        if(hintEl){ hintEl.textContent = 'Сохранено'; hintEl.classList.add('show'); setTimeout(()=>hintEl.classList.remove('show'), 1400); }
      }catch(e){
        if(hintEl){ hintEl.textContent = 'Не сохранилось, попробуй ещё раз'; hintEl.classList.add('show'); }
      }
    }, 350);
  }

  function filledCount(){
    return ALL_TERMS.filter(t => (state.mine[t.id]||'').trim().length > 0).length;
  }

  function updateProgress(){
    const n = filledCount();
    document.getElementById('progressFill').style.width = Math.round(n/ALL_TERMS.length*100) + '%';
    document.getElementById('progressLabel').textContent = n + ' / ' + ALL_TERMS.length + ' своими словами';
  }

  function renderRail(){
    rail.innerHTML = '';
    SESSIONS.forEach(s => {
      const done = s.terms.every(t => (state.mine[t.id]||'').trim().length > 0);
      const btn = document.createElement('button');
      btn.className = 'rail-item' + (s.id===activeSession ? ' active':'');
      btn.innerHTML = `
        <span class="stamp${done?' filled':''}">${s.id}</span>
        <span class="txt"><span class="n">ЗАНЯТИЕ ${s.id}</span><span class="t">${s.title}</span></span>`;
      btn.onclick = () => selectSession(s.id);
      rail.appendChild(btn);
    });
  }

  function escapeHtml(str){
    return String(str).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
  }

  function termCardHTML(t){
    const val = escapeHtml(state.mine[t.id] || '');
    return `
      <div class="term" data-term="${t.id}">
        <div class="term-head">
          <div>
            <div class="term-name">${t.term}</div>
            <span class="synonym-chip">${t.synonym}</span>
            <details class="def"><summary></summary><p>${t.official}</p></details>
          </div>
        </div>
        <label class="field-label">Своими словами</label>
        <textarea placeholder="Как бы ты объяснил(а) это другу?">${val}</textarea>
        <div class="save-hint"></div>
      </div>`;
  }

  function renderSession(s){
    panel.innerHTML = `
      <h2>Занятие ${s.id} · ${s.title}</h2>
      <p class="sub">Впиши каждый термин своими словами — так он лучше запомнится.</p>
      ${s.terms.map(termCardHTML).join('')}
    `;
    panel.querySelectorAll('.term').forEach(card => {
      const id = card.dataset.term;
      const ta = card.querySelector('textarea');
      const hint = card.querySelector('.save-hint');
      ta.addEventListener('input', () => {
        state.mine[id] = ta.value;
        updateProgress();
        renderRail();
        persist(hint);
      });
    });
  }

  function renderSelfCheck(){
    const counts = {remember:0, unsure:0, forgot:0};
    ALL_TERMS.forEach(t => { const v = state.selfcheck[t.id+'_state']; if(v) counts[v]++; });
    panel.innerHTML = `
      <h2>Занятие 7 · Проверь себя</h2>
      <p class="sub">Курс пройден — посмотри на все термины и честно отметь, что осталось с тобой.</p>
      <div class="collection">
        ${ALL_TERMS.map(t => `<span class="stamp big${(state.mine[t.id]||'').trim()?' filled':''}" title="${t.term}">${t.term[0]}</span>`).join('')}
      </div>
      <div class="summary-row">
        <div class="summary-chip sc-remember"><b id="cntRemember">${counts.remember}</b>помню</div>
        <div class="summary-chip sc-unsure"><b id="cntUnsure">${counts.unsure}</b>смутно</div>
        <div class="summary-chip sc-forgot"><b id="cntForgot">${counts.forgot}</b>забыл(а)</div>
      </div>
      ${ALL_TERMS.map(t => `
        <div class="sc-term" data-term="${t.id}">
          <div class="top-row">
            <div>
              <div class="term-name">${t.term}</div>
              <span class="from">занятие ${t.sessionId}</span>
            </div>
            <div class="chip-group">
              <button class="chip" data-v="remember">помню</button>
              <button class="chip" data-v="unsure">смутно</button>
              <button class="chip" data-v="forgot">забыл(а)</button>
            </div>
          </div>
          <input class="ex" type="text" placeholder="Пример из своей жизни, когда это пригодилось (необязательно)">
        </div>`).join('')}
    `;
    panel.querySelectorAll('.sc-term').forEach(row => {
      const id = row.dataset.term;
      const chips = row.querySelectorAll('.chip');
      const exInput = row.querySelector('.ex');
      const savedState = state.selfcheck[id+'_state'];
      const savedEx = state.selfcheck[id+'_ex'] || '';
      exInput.value = savedEx;
      chips.forEach(c => { if(c.dataset.v === savedState) c.classList.add('on'); });
      chips.forEach(c => {
        c.addEventListener('click', () => {
          chips.forEach(x=>x.classList.remove('on'));
          c.classList.add('on');
          state.selfcheck[id+'_state'] = c.dataset.v;
          persist();
          refreshCounts();
        });
      });
      exInput.addEventListener('input', () => {
        state.selfcheck[id+'_ex'] = exInput.value;
        persist();
      });
    });
  }

  function refreshCounts(){
    const counts = {remember:0, unsure:0, forgot:0};
    ALL_TERMS.forEach(t => { const v = state.selfcheck[t.id+'_state']; if(v) counts[v]++; });
    const r = document.getElementById('cntRemember'), u = document.getElementById('cntUnsure'), f = document.getElementById('cntForgot');
    if(r){ r.textContent = counts.remember; u.textContent = counts.unsure; f.textContent = counts.forgot; }
  }

  function selectSession(id){
    activeSession = id;
    renderRail();
    updateProgress();
    if(id === 7){ renderSelfCheck(); }
    else { renderSession(SESSIONS.find(s=>s.id===id)); }
  }

  document.getElementById('startBtn').addEventListener('click', async () => {
    const val = document.getElementById('nameInput').value;
    if(!val.trim()){ document.getElementById('gateErr').style.display='block'; return; }
    document.getElementById('gateErr').style.display='none';
    gate.style.display='none';
    await loadProfile(val);
  });
  document.getElementById('nameInput').addEventListener('keydown', e => { if(e.key==='Enter') document.getElementById('startBtn').click(); });
  document.getElementById('switchProfileBtn').addEventListener('click', () => {
    document.getElementById('nameInput').value='';
    gate.style.display='flex';
  });
})();
</script>
</body>
</html></div>]]></turbo:content>
    </item>
  </channel>
</rss>
