console.log('[ENL] THEME JS LOADED');
$(() => {
  console.log('[ENL] router start');  
  // 1) читаем флаг курса
  const course = ($('[data-enl-course]').attr('data-enl-course') || '').trim();
  console.log('[ENL] course =', course);  
  if (!course) return;

  // 2) защита от повторного запуска
  window.__ENL_ONCE = window.__ENL_ONCE || {};
  const onceKey = 'course:' + course;
  if (window.__ENL_ONCE[onceKey]) return;
  window.__ENL_ONCE[onceKey] = true;

  // 3) роутер
  switch (course) {
    case 'year':
      runPack_YEAR();
      break;
    case 'half1':
      console.log('[ENL] switch → half1');
      runPack_HALF1();
      break;
    case 'half2':
      runPack_HALF2();
      break;  
    case 'intensive':
      runPack_INTENSIVE();
      break;
  }
});

// ===== ПАКЕТЫ КУРСОВ =====
function runPack_YEAR() {
  console.log('[ENL] runPack_YEAR');  
  
  runZachetka_YEAR_HIST();
  runZachetka_YEAR_SOC();

  runProbes_YEAR();
}

function runPack_HALF1() {
  runZachetka_HALF1();
  runProbes_HALF1();
  
}

function runPack_HALF2() {
  console.log('[ENL] runPack_HALF2');  
  runZachetka_HALF2();
  runProbes_HALF2();
  
}

function runPack_INTENSIVE() {
  runZachetka_INTENSIVE();
  runProbes_INTENSIVE();
  
}

// ===== НИЖЕ: тут наши СКРИПТЫ, НО БЕЗ $(() => {...}) =====
function runZachetka_YEAR_HIST() {
  // СЧАСТЛИВАЯ ЗАЧЕТКА ГК ИСТ   // Работаем только внутри контейнера с месячным рейтингом
    console.log('[ENL] YEAR zachetka code loaded')
   $('.hist-stat').each((_, cont) => {
    const $c   = $(cont);
    const $ach = $('.achv-source.xdget-trainingAchievements').first();
if (!$ach.length) return;

    // === НАСТРОЙКИ ===
    const MONTHS_ORDER = [
      'баллы за сентябрь'
    ];

    const MONTH_MAX = {
      'баллы за сентябрь': 600
    };

    // текущий месяц для печатей
    const CURRENT_MONTH_TITLE  = 'баллы за сентябрь';
    const CURRENT_STAMP_PREFIX = 'сентябрь: печать'; // подпись бейджа начинается с...

    // правила выдачи печатей
    const THRESHOLD_PCT = 60; // после достижения 60%…
    const STEP_POINTS   = 30; // …каждые +30 баллов = 1 печать

    // === 1) Берём только месячные строки из таблицы ===
    let $rows = $ach.find('tbody tr').filter((i, tr) => {
      const title = $(tr).find('a').text().trim();
      return MONTHS_ORDER.includes(title);
    });
    if (!$rows.length) return;

    // 2) Убираем дубли
    const seen = new Set();
    $rows = $rows.filter((i, tr) => {
      const t = $(tr).find('a').text().trim();
      if (seen.has(t)) return false;
      seen.add(t);
      return true;
    });

    // 3) Сортируем по MONTHS_ORDER
    $rows = $rows.sort((a, b) => {
      const ta = $(a).find('a').text().trim();
      const tb = $(b).find('a').text().trim();
      return MONTHS_ORDER.indexOf(ta) - MONTHS_ORDER.indexOf(tb);
    });

    // 4) Рендер «зачётки»
    // на всякий: если перезапуск — уберём предыдущий рендер
$c.find('.monthProgress, .stamps-wrap').remove();

const $mp = $('<div class="monthProgress"></div>');
$c.append($mp); // <-- ВАЖНО: рисуем в tr-stat, а не рядом с источником

    let currentMonthGot   = 0;
    let currentMonthTotal = Number(MONTH_MAX[CURRENT_MONTH_TITLE]) || 0;

    $rows.each((i, tr) => {
      const $tr   = $(tr);
      const title = $tr.find('a').text().trim();
      const raw   = $tr.find('.badge').text();
      const got   = parseInt(String(raw).replace(/[^\d]/g, ''), 10) || 0;

      if (title === CURRENT_MONTH_TITLE) currentMonthGot = got;

      const total   = Number(MONTH_MAX[title]) || 0;
      const percent = total > 0 ? Math.min(100, Math.floor((got * 100) / total)) : 0;
      const width   = total > 0 ? `${percent}%` : '35px';

      $mp.append(`
        <div class="st-top">
          <div class="stt-block">
            <div class="stt-header">${title}</div>
            <div class="stt-value">
              <span class="stv-1">${got}</span> из <span class="stv-2">${total}</span>
            </div>
          </div>
        </div>
        <div class="st-bottom">
          <div class="stb-bar">
            <div class="stb-complete" style="width:${width};">
              <span class="stv-3">${percent}%</span>
            </div>
          </div>
        </div>
      `);
    });

    // === 5) Собираем печати текущего месяца ===
    const $allBadgeChips = $ach.find("div:has(img[src*='fileservice/file/thumbnail'])");
    const $stamps = $allBadgeChips.filter((_, el) => {
      const text = $(el).find('span').text().trim();
      return text.startsWith(CURRENT_STAMP_PREFIX);
    });

    const realEarned = $stamps.length;

    const threshold = Math.floor(currentMonthTotal * THRESHOLD_PCT / 100);
    const maxStamps = currentMonthTotal > 0 && currentMonthTotal > threshold
      ? Math.max(0, Math.floor((currentMonthTotal - threshold) / STEP_POINTS))
      : 0;

    const $stampsWrap = $(`
      <div class="stamps-wrap">
        <div class="stamps-title">печати в твоей зачетке</div>
        <div class="stamps-row"></div>
      </div>
    `);
    const $row = $stampsWrap.find('.stamps-row');

// Хелпер: из превью-URL сделать ссылку на оригинал
function toOriginalGC(url) {
  if (!url) return url;

  // унифицируем протокол относительные ссылки
  let out = url;

  // 1) fs-thb -> fs (домен превью -> домен оригиналов)
  out = out.replace(/\/\/fs-thb(\d*)\.getcourse\.ru/i, '//fs$1.getcourse.ru');

  // 2) thumbnail -> download (путь к файлу)
  out = out.replace(/\/file\/thumbnail\//i, '/file/download/');

  // 3) убрать размер превью /s/xNN или /s/xNNN
  out = out.replace(/\/s\/x\d+(?=\/|$)/i, '');

  // 4) иногда порядок сегментов иной: .../thumbnail/.../s/x50/a/123/sc/456
  // после п.2 п.3 останется валидный download-путь; ничего больше не нужно

  return out;
}

// 5.1 добавляем выданные печати (только картинки, без подписей)
$stamps.each((_, el) => {
  const $img = $(el).find('img').first().clone();

  // вычищаем «ограничители» качества
  $img.removeAttr('style width height srcset sizes');

  // переписываем src с превью на оригинал
  const fixedSrc = toOriginalGC($img.attr('src'));
  if (fixedSrc) $img.attr('src', fixedSrc);

  $row.append($('<span class="stamp got"></span>').append($img));
});

// На всякий случай пройдёмся и по уже вставленным (если появятся позже динамически)
$row.find('.stamp.got img').each(function(){
  const fixedSrc = toOriginalGC(this.getAttribute('src'));
  if (fixedSrc) this.setAttribute('src', fixedSrc);
  this.removeAttribute('srcset');
  this.removeAttribute('sizes');
});
    // 5.2 «пустые» до максимума
    const placeholders = Math.max(0, maxStamps - realEarned);
    for (let i = 0; i < placeholders; i++) {
      $row.append('<span class="stamp empty" aria-hidden="true"></span>');
    }

    // 5.3 показать блок печатей
    if (maxStamps > 0) $mp.append($stampsWrap);

// === 5.4 Двухрядная раскладка + равномерное растяжение ===
const $allStampsPlaced = $row.children('.stamp');
const totalSlots = $allStampsPlaced.length;

if (totalSlots) {
  const topCount = Math.ceil(totalSlots / 2);   // верхний ряд — большее
  const botCount = Math.floor(totalSlots / 2);  // нижний — меньшее
  const isOdd    = (totalSlots % 2 === 1);

  // передаём количество колонок в CSS
  $row.get(0).style.setProperty('--cols', topCount);

  // размечаем, какие элементы в каком ряду (нужно для .shift)
  $allStampsPlaced.each((idx, el) => {
    $(el).addClass(idx < topCount ? 'r1' : 'r2');
  });

  // включаем шахматное смещение только при нечётном количестве
  if (isOdd) {
    $row.addClass('shift');
  } else {
    $row.removeClass('shift');
  }
}
    
  });
}

function runProbes_YEAR() {
  // ПРОБНИКИ ГК
     const MAX = 58;
  const N   = 12;
  const GAP_DEG = 2;
  const SIZE = 420;
  const R = SIZE/2 - 10;
  const OFFSET = -Math.PI/2;
  const PALETTE = ['#C9DD93','#D2E4FF','#FDC7EF','#FFE296','#C6C9FF','#FED2FF','#C9DD93','#D2E4FF','#FDC7EF','#FFE296','#C6C9FF','#FED2FF'];

  // 1) Контейнер, куда рисуем колесо
  const $host = $('.probes-wheel').first();
  if (!$host.length) return;

  // 2) ЕДИНЫЙ источник достижений
  let $ach = $('.achv-source.xdget-trainingAchievements').first();
if (!$ach.length) return;

  // 3) Парсим баллы только по строкам «Пробник №N|Пробник N»
  const scores = Array.from({length:N}, () => 0);
  $ach.find('tbody tr, tr').each((_, tr) => {
    const $tr = $(tr);
    const t = ($tr.find('a,.title,td:first').text().trim() || $tr.text().trim()).replace(/\s+/g,' ');
    const m = t.match(/Пробник\s*(?:№|N)?\s*(\d+)/i);
    if (!m) return;
    const n = +m[1]; if (!n || n > N) return;
    const slab = $tr.find('.badge,.label,.gc-badge,.progress,.score,td,span').text();
    const mBall = String(slab).match(/(\d+)\s*бал/i) || String(slab).match(/\b(\d+)\b/);
    scores[n-1] = mBall ? +mBall[1] : 0;
  });

  // 4) Вставляем каркас колеса ВНУТРЬ .probes-wheel (источник не трогаем, не скрываем)
  const $wrap = $(`
    <div class="gc-wheel">
      <h4>Прогресс по пробникам</h4>
      <div class="svg-wrap"></div>
    </div>
  `);
  $host.empty().append($wrap);

  const cx=SIZE/2, cy=SIZE/2;
  const gap = GAP_DEG*Math.PI/180;
  const step = (Math.PI*2)/N;

  const svg = document.createElementNS('http://www.w3.org/2000/svg','svg');
  svg.setAttribute('viewBox', `0 0 ${SIZE} ${SIZE}`);
  svg.setAttribute('width','100%');
  svg.setAttribute('height','100%');

  const path = (d)=>{const p=document.createElementNS(svg.namespaceURI,'path'); p.setAttribute('d',d); return p;};
  const hexA = (hex,a)=>{const h=hex.replace('#',''); const r=parseInt(h.substr(0,2),16), g=parseInt(h.substr(2,2),16), b=parseInt(h.substr(4,2),16); return `rgba(${r},${g},${b},${a})`;};
  function sectorPath(cx,cy,r,a0,a1){const x0=cx+r*Math.cos(a0), y0=cy+r*Math.sin(a0); const x1=cx+r*Math.cos(a1), y1=cy+r*Math.sin(a1); const large=(a1-a0)>Math.PI?1:0; return `M ${cx} ${cy} L ${x0} ${y0} A ${r} ${r} 0 ${large} 1 ${x1} ${y1} Z`;}
  function arcPath(cx,cy,r,a0,a1){const x0=cx+r*Math.cos(a0), y0=cy+r*Math.sin(a0); const x1=cx+r*Math.cos(a1), y1=cy+r*Math.sin(a1); const large=(a1-a0)>Math.PI?1:0; return `M ${x0} ${y0} A ${r} ${r} 0 ${large} 1 ${x1} ${y1}`;}

  for(let i=0;i<N;i++){
    const aStart = OFFSET + i*step + gap/2;
    const aEnd   = OFFSET + (i+1)*step - gap/2;
    const color  = PALETTE[i % PALETTE.length];

    const bg = path(sectorPath(cx,cy,R,aStart,aEnd));
    bg.setAttribute('fill', hexA(color, .28));
    bg.setAttribute('stroke','rgba(0,0,0,.05)');
    bg.setAttribute('stroke-linejoin','round');
    svg.appendChild(bg);

    const got = Math.max(0, Math.min(MAX, scores[i]||0));
    const rf = Math.max(6, R * (got/MAX));
    if (got>0){
      const fill = path(sectorPath(cx,cy,rf,aStart,aEnd));
      fill.setAttribute('fill', hexA(color, .95));
      fill.setAttribute('stroke','rgba(0,0,0,.06)');
      fill.setAttribute('stroke-linejoin','round');
      svg.appendChild(fill);
    }

    // подпись по дуге
    const baseLabelR = R * 0.83;
    const needFlip   = (i + 1 >= 5 && i + 1 <= 9);
    const labelR     = needFlip ? baseLabelR + 24 : baseLabelR;
    const arcId = `arc-${i}-${Date.now()}`;
    const arc = path(needFlip ? arcPath(cx,cy,labelR,aEnd,aStart) : arcPath(cx,cy,labelR,aStart,aEnd));
    arc.setAttribute('id', arcId); arc.setAttribute('fill','none'); arc.setAttribute('stroke','none'); svg.appendChild(arc);

    const txtArc = document.createElementNS(svg.namespaceURI,'text');
    txtArc.setAttribute('class','label-arc');
    const tp = document.createElementNS(svg.namespaceURI,'textPath');
    tp.setAttributeNS('http://www.w3.org/1999/xlink','xlink:href',`#${arcId}`);
    tp.setAttribute('startOffset','50%'); tp.setAttribute('text-anchor','middle');
    tp.setAttribute('side', needFlip ? 'right' : 'left');
    tp.textContent = `№${i+1}`;
    txtArc.appendChild(tp); svg.appendChild(txtArc);

    // центральная подпись
    function pluralBallov(n){const mod10=n%10, mod100=n%100; if(mod10===1 && mod100!==11) return 'балл'; if([2,3,4].includes(mod10) && !(mod100>=12 && mod100<=14)) return 'балла'; return 'баллов';}
    const mid = (aStart + aEnd)/2;
    const centerR = Math.max(28, R*0.55);
    const cxLabel = cx + centerR*Math.cos(mid);
    const cyLabel = cy + centerR*Math.sin(mid);

    const txtCenter = document.createElementNS(svg.namespaceURI,'text');
    txtCenter.setAttribute('class','label-center');
    txtCenter.setAttribute('x', cxLabel.toFixed(2));
    txtCenter.setAttribute('y', cyLabel.toFixed(2));
    txtCenter.setAttribute('text-anchor','middle');

    const t1 = document.createElementNS(svg.namespaceURI,'tspan');
    t1.textContent = `${got}`; t1.setAttribute('x', cxLabel.toFixed(2)); t1.setAttribute('dy','-0.15em');
    const t2 = document.createElementNS(svg.namespaceURI,'tspan');
    t2.textContent = pluralBallov(got); t2.setAttribute('class','sub'); t2.setAttribute('x', cxLabel.toFixed(2)); t2.setAttribute('dy','1.2em');

    txtCenter.appendChild(t1); txtCenter.appendChild(t2); svg.appendChild(txtCenter);
  }

  $wrap.find('.svg-wrap').append(svg);
}


function runZachetka_YEAR_SOC() {
  // СЧАСТЛИВАЯ ЗАЧЕТКА ГК ОБЩ   // Работаем только внутри контейнера с месячным рейтингом
    console.log('[ENL] YEAR zachetka code loaded')
   $('.soc-stat').each((_, cont) => {
    const $c   = $(cont);
    const $ach = $('.achv-source.xdget-trainingAchievements').first();
if (!$ach.length) return;

    // === НАСТРОЙКИ ===
    const MONTHS_ORDER = [
      'баллы за сентябрь'
    ];

    const MONTH_MAX = {
      'баллы за сентябрь': 410
    };

    // текущий месяц для печатей
    const CURRENT_MONTH_TITLE  = 'баллы за сентябрь';
    const CURRENT_STAMP_PREFIX = 'сентябрь: печать'; // подпись бейджа начинается с...

    // правила выдачи печатей
    const THRESHOLD_PCT = 60; // после достижения 60%…
    const STEP_POINTS   = 30; // …каждые +30 баллов = 1 печать

    // === 1) Берём только месячные строки из таблицы ===
    let $rows = $ach.find('tbody tr').filter((i, tr) => {
      const title = $(tr).find('a').text().trim();
      return MONTHS_ORDER.includes(title);
    });
    if (!$rows.length) return;

    // 2) Убираем дубли
    const seen = new Set();
    $rows = $rows.filter((i, tr) => {
      const t = $(tr).find('a').text().trim();
      if (seen.has(t)) return false;
      seen.add(t);
      return true;
    });

    // 3) Сортируем по MONTHS_ORDER
    $rows = $rows.sort((a, b) => {
      const ta = $(a).find('a').text().trim();
      const tb = $(b).find('a').text().trim();
      return MONTHS_ORDER.indexOf(ta) - MONTHS_ORDER.indexOf(tb);
    });

    // 4) Рендер «зачётки»
    // на всякий: если перезапуск — уберём предыдущий рендер
$c.find('.monthProgress, .stamps-wrap').remove();

const $mp = $('<div class="monthProgress"></div>');
$c.append($mp); // <-- ВАЖНО: рисуем в tr-stat, а не рядом с источником

    let currentMonthGot   = 0;
    let currentMonthTotal = Number(MONTH_MAX[CURRENT_MONTH_TITLE]) || 0;

    $rows.each((i, tr) => {
      const $tr   = $(tr);
      const title = $tr.find('a').text().trim();
      const raw   = $tr.find('.badge').text();
      const got   = parseInt(String(raw).replace(/[^\d]/g, ''), 10) || 0;

      if (title === CURRENT_MONTH_TITLE) currentMonthGot = got;

      const total   = Number(MONTH_MAX[title]) || 0;
      const percent = total > 0 ? Math.min(100, Math.floor((got * 100) / total)) : 0;
      const width   = total > 0 ? `${percent}%` : '35px';

      $mp.append(`
        <div class="st-top">
          <div class="stt-block">
            <div class="stt-header">${title}</div>
            <div class="stt-value">
              <span class="stv-1">${got}</span> из <span class="stv-2">${total}</span>
            </div>
          </div>
        </div>
        <div class="st-bottom">
          <div class="stb-bar">
            <div class="stb-complete" style="width:${width};">
              <span class="stv-3">${percent}%</span>
            </div>
          </div>
        </div>
      `);
    });

    // === 5) Собираем печати текущего месяца ===
    const $allBadgeChips = $ach.find("div:has(img[src*='fileservice/file/thumbnail'])");
    const $stamps = $allBadgeChips.filter((_, el) => {
      const text = $(el).find('span').text().trim();
      return text.startsWith(CURRENT_STAMP_PREFIX);
    });

    const realEarned = $stamps.length;

    const threshold = Math.floor(currentMonthTotal * THRESHOLD_PCT / 100);
    const maxStamps = currentMonthTotal > 0 && currentMonthTotal > threshold
      ? Math.max(0, Math.floor((currentMonthTotal - threshold) / STEP_POINTS))
      : 0;

    const $stampsWrap = $(`
      <div class="stamps-wrap">
        <div class="stamps-title">печати в твоей зачетке</div>
        <div class="stamps-row"></div>
      </div>
    `);
    const $row = $stampsWrap.find('.stamps-row');

// Хелпер: из превью-URL сделать ссылку на оригинал
function toOriginalGC(url) {
  if (!url) return url;

  // унифицируем протокол относительные ссылки
  let out = url;

  // 1) fs-thb -> fs (домен превью -> домен оригиналов)
  out = out.replace(/\/\/fs-thb(\d*)\.getcourse\.ru/i, '//fs$1.getcourse.ru');

  // 2) thumbnail -> download (путь к файлу)
  out = out.replace(/\/file\/thumbnail\//i, '/file/download/');

  // 3) убрать размер превью /s/xNN или /s/xNNN
  out = out.replace(/\/s\/x\d+(?=\/|$)/i, '');

  // 4) иногда порядок сегментов иной: .../thumbnail/.../s/x50/a/123/sc/456
  // после п.2 п.3 останется валидный download-путь; ничего больше не нужно

  return out;
}

// 5.1 добавляем выданные печати (только картинки, без подписей)
$stamps.each((_, el) => {
  const $img = $(el).find('img').first().clone();

  // вычищаем «ограничители» качества
  $img.removeAttr('style width height srcset sizes');

  // переписываем src с превью на оригинал
  const fixedSrc = toOriginalGC($img.attr('src'));
  if (fixedSrc) $img.attr('src', fixedSrc);

  $row.append($('<span class="stamp got"></span>').append($img));
});

// На всякий случай пройдёмся и по уже вставленным (если появятся позже динамически)
$row.find('.stamp.got img').each(function(){
  const fixedSrc = toOriginalGC(this.getAttribute('src'));
  if (fixedSrc) this.setAttribute('src', fixedSrc);
  this.removeAttribute('srcset');
  this.removeAttribute('sizes');
});
    // 5.2 «пустые» до максимума
    const placeholders = Math.max(0, maxStamps - realEarned);
    for (let i = 0; i < placeholders; i++) {
      $row.append('<span class="stamp empty" aria-hidden="true"></span>');
    }

    // 5.3 показать блок печатей
    if (maxStamps > 0) $mp.append($stampsWrap);

// === 5.4 Двухрядная раскладка + равномерное растяжение ===
const $allStampsPlaced = $row.children('.stamp');
const totalSlots = $allStampsPlaced.length;

if (totalSlots) {
  const topCount = Math.ceil(totalSlots / 2);   // верхний ряд — большее
  const botCount = Math.floor(totalSlots / 2);  // нижний — меньшее
  const isOdd    = (totalSlots % 2 === 1);

  // передаём количество колонок в CSS
  $row.get(0).style.setProperty('--cols', topCount);

  // размечаем, какие элементы в каком ряду (нужно для .shift)
  $allStampsPlaced.each((idx, el) => {
    $(el).addClass(idx < topCount ? 'r1' : 'r2');
  });

  // включаем шахматное смещение только при нечётном количестве
  if (isOdd) {
    $row.addClass('shift');
  } else {
    $row.removeClass('shift');
  }
}
    
  });
}

function runProbes_YEAR() {
  // ПРОБНИКИ ГК
     const MAX = 58;
  const N   = 12;
  const GAP_DEG = 2;
  const SIZE = 420;
  const R = SIZE/2 - 10;
  const OFFSET = -Math.PI/2;
  const PALETTE = ['#C9DD93','#D2E4FF','#FDC7EF','#FFE296','#C6C9FF','#FED2FF','#C9DD93','#D2E4FF','#FDC7EF','#FFE296','#C6C9FF','#FED2FF'];

  // 1) Контейнер, куда рисуем колесо
  const $host = $('.probes-wheel').first();
  if (!$host.length) return;

  // 2) ЕДИНЫЙ источник достижений
  let $ach = $('.achv-source.xdget-trainingAchievements').first();
if (!$ach.length) return;

  // 3) Парсим баллы только по строкам «Пробник №N|Пробник N»
  const scores = Array.from({length:N}, () => 0);
  $ach.find('tbody tr, tr').each((_, tr) => {
    const $tr = $(tr);
    const t = ($tr.find('a,.title,td:first').text().trim() || $tr.text().trim()).replace(/\s+/g,' ');
    const m = t.match(/Пробник\s*(?:№|N)?\s*(\d+)/i);
    if (!m) return;
    const n = +m[1]; if (!n || n > N) return;
    const slab = $tr.find('.badge,.label,.gc-badge,.progress,.score,td,span').text();
    const mBall = String(slab).match(/(\d+)\s*бал/i) || String(slab).match(/\b(\d+)\b/);
    scores[n-1] = mBall ? +mBall[1] : 0;
  });

  // 4) Вставляем каркас колеса ВНУТРЬ .probes-wheel (источник не трогаем, не скрываем)
  const $wrap = $(`
    <div class="gc-wheel">
      <h4>Прогресс по пробникам</h4>
      <div class="svg-wrap"></div>
    </div>
  `);
  $host.empty().append($wrap);

  const cx=SIZE/2, cy=SIZE/2;
  const gap = GAP_DEG*Math.PI/180;
  const step = (Math.PI*2)/N;

  const svg = document.createElementNS('http://www.w3.org/2000/svg','svg');
  svg.setAttribute('viewBox', `0 0 ${SIZE} ${SIZE}`);
  svg.setAttribute('width','100%');
  svg.setAttribute('height','100%');

  const path = (d)=>{const p=document.createElementNS(svg.namespaceURI,'path'); p.setAttribute('d',d); return p;};
  const hexA = (hex,a)=>{const h=hex.replace('#',''); const r=parseInt(h.substr(0,2),16), g=parseInt(h.substr(2,2),16), b=parseInt(h.substr(4,2),16); return `rgba(${r},${g},${b},${a})`;};
  function sectorPath(cx,cy,r,a0,a1){const x0=cx+r*Math.cos(a0), y0=cy+r*Math.sin(a0); const x1=cx+r*Math.cos(a1), y1=cy+r*Math.sin(a1); const large=(a1-a0)>Math.PI?1:0; return `M ${cx} ${cy} L ${x0} ${y0} A ${r} ${r} 0 ${large} 1 ${x1} ${y1} Z`;}
  function arcPath(cx,cy,r,a0,a1){const x0=cx+r*Math.cos(a0), y0=cy+r*Math.sin(a0); const x1=cx+r*Math.cos(a1), y1=cy+r*Math.sin(a1); const large=(a1-a0)>Math.PI?1:0; return `M ${x0} ${y0} A ${r} ${r} 0 ${large} 1 ${x1} ${y1}`;}

  for(let i=0;i<N;i++){
    const aStart = OFFSET + i*step + gap/2;
    const aEnd   = OFFSET + (i+1)*step - gap/2;
    const color  = PALETTE[i % PALETTE.length];

    const bg = path(sectorPath(cx,cy,R,aStart,aEnd));
    bg.setAttribute('fill', hexA(color, .28));
    bg.setAttribute('stroke','rgba(0,0,0,.05)');
    bg.setAttribute('stroke-linejoin','round');
    svg.appendChild(bg);

    const got = Math.max(0, Math.min(MAX, scores[i]||0));
    const rf = Math.max(6, R * (got/MAX));
    if (got>0){
      const fill = path(sectorPath(cx,cy,rf,aStart,aEnd));
      fill.setAttribute('fill', hexA(color, .95));
      fill.setAttribute('stroke','rgba(0,0,0,.06)');
      fill.setAttribute('stroke-linejoin','round');
      svg.appendChild(fill);
    }

    // подпись по дуге
    const baseLabelR = R * 0.83;
    const needFlip   = (i + 1 >= 5 && i + 1 <= 9);
    const labelR     = needFlip ? baseLabelR + 24 : baseLabelR;
    const arcId = `arc-${i}-${Date.now()}`;
    const arc = path(needFlip ? arcPath(cx,cy,labelR,aEnd,aStart) : arcPath(cx,cy,labelR,aStart,aEnd));
    arc.setAttribute('id', arcId); arc.setAttribute('fill','none'); arc.setAttribute('stroke','none'); svg.appendChild(arc);

    const txtArc = document.createElementNS(svg.namespaceURI,'text');
    txtArc.setAttribute('class','label-arc');
    const tp = document.createElementNS(svg.namespaceURI,'textPath');
    tp.setAttributeNS('http://www.w3.org/1999/xlink','xlink:href',`#${arcId}`);
    tp.setAttribute('startOffset','50%'); tp.setAttribute('text-anchor','middle');
    tp.setAttribute('side', needFlip ? 'right' : 'left');
    tp.textContent = `№${i+1}`;
    txtArc.appendChild(tp); svg.appendChild(txtArc);

    // центральная подпись
    function pluralBallov(n){const mod10=n%10, mod100=n%100; if(mod10===1 && mod100!==11) return 'балл'; if([2,3,4].includes(mod10) && !(mod100>=12 && mod100<=14)) return 'балла'; return 'баллов';}
    const mid = (aStart + aEnd)/2;
    const centerR = Math.max(28, R*0.55);
    const cxLabel = cx + centerR*Math.cos(mid);
    const cyLabel = cy + centerR*Math.sin(mid);

    const txtCenter = document.createElementNS(svg.namespaceURI,'text');
    txtCenter.setAttribute('class','label-center');
    txtCenter.setAttribute('x', cxLabel.toFixed(2));
    txtCenter.setAttribute('y', cyLabel.toFixed(2));
    txtCenter.setAttribute('text-anchor','middle');

    const t1 = document.createElementNS(svg.namespaceURI,'tspan');
    t1.textContent = `${got}`; t1.setAttribute('x', cxLabel.toFixed(2)); t1.setAttribute('dy','-0.15em');
    const t2 = document.createElementNS(svg.namespaceURI,'tspan');
    t2.textContent = pluralBallov(got); t2.setAttribute('class','sub'); t2.setAttribute('x', cxLabel.toFixed(2)); t2.setAttribute('dy','1.2em');

    txtCenter.appendChild(t1); txtCenter.appendChild(t2); svg.appendChild(txtCenter);
  }

  $wrap.find('.svg-wrap').append(svg);
}



// ДАЛЕЕ ИДУТ ОБЩИЕ АЧИВКИ ЕДИНЫЙ КОД ТВОИ НАГРАДЫ ГАЛЕРЕЯ АЧИВОК
(function(){

    setTimeout(function(){


    const $gallery = $('.achv-gallery').first();

if (!$gallery.length) return;


// защита от повторного запуска
if ($gallery.data('achvInited')) return;
$gallery.data('achvInited', true);


// источник достижений
const $source = $('.achv-source').first();

if (!$source.length) {
    console.log('Нет achv-source');
    return;
}

  // === 1. Заголовок ===
  if (!$gallery.find('.achv-head').length) {
    $gallery.prepend('<div class="achv-head"><span class="icon" aria-hidden="true"></span>твои награды</div>');
  }

  // === 2. Куда кладём список ===
  let $list = $gallery.find('.achv-list').first();
  if (!$list.length) $list = $('<div class="achv-list"></div>').appendTo($gallery);


  // === 4. Словарь ===
  const DICT_URL = 'https://script.google.com/macros/s/AKfycbwI_TfcoMrMlUkifsB26QIvwf80int-R9-v0Bc5GcwiYZ4PF7daslAVfVvCGay4WZ3b/exec';

  function loadDict(callback) {
    if (window.ACHV_DESCR_RAW && typeof window.ACHV_DESCR_RAW === 'object') {
      callback(window.ACHV_DESCR_RAW);
      return;
    }

    $.ajax({ url: DICT_URL, method: 'GET', dataType: 'json' })
      .done(function (data) {
        window.ACHV_DESCR_RAW = data || {};
        callback(window.ACHV_DESCR_RAW);
      })
      .fail(function (xhr, status, err) {
        console.error('[achv] не удалось загрузить словарь ачивок', status, err);
        callback({});
      });
  }

  // === 5. Основная логика ===
  loadDict((DESCR_RAW) => {
    const norm = s => String(s).toLowerCase().replace(/\s+/g, ' ').trim();
    const DESCR = {};
    Object.keys(DESCR_RAW || {}).forEach(k => DESCR[norm(k)] = String(DESCR_RAW[k]).trim());

    function toOriginalGC(url) {
      if (!url) return url;
      return url
        .replace(/\/\/fs-thb(\d*)\.getcourse\.ru/i, '//fs$1.getcourse.ru')
        .replace(/\/file\/thumbnail\//i, '/file/download/')
        .replace(/\/s\/x\d+(?=\/|$)/i, '');
    }

    const $chips = $source
      .find("div:has(img[src*='fileservice/file/thumbnail'])")
      .filter((_, el) => !/печать/i.test($(el).find('span').text()));

    if ($chips.length === 0) { $gallery.hide(); return; }

    // на всякий — очищаем прошлую отрисовку
    $gallery.find('.achv-tip').remove();
    $list.empty();

    let rendered = 0;
    const MISS_LOG = [];

    const $tip = $(`
      <div class="achv-tip" aria-hidden="true">
        <div class="t1"></div>
        <div class="t2"></div>
      </div>
    `).appendTo($gallery);

    $chips.each((_, el) => {
      const $chip = $(el);
      const title = $chip.find('span').text().trim();
      const key   = norm(title);
      const $img0 = $chip.find('img').first();
      if (!$img0.length) return;

      const src = toOriginalGC($img0.attr('src'));

      const $card = $(`
        <div class="achv-card" role="group" aria-label="${title}" tabindex="0">
          <div class="achv-thumb"><img alt="${title}"></div>
        </div>
      `);

      $card.find('.achv-thumb img').attr('src', src);
      $card.data('title', title);
      $card.data('desc', DESCR[key] || '');

      $list.append($card);
      if (!DESCR[key]) MISS_LOG.push(title);
      rendered++;
    });

    if (!rendered) { $gallery.hide(); return; }
    if (MISS_LOG.length) console.log('[Ачивки без описания]:', MISS_LOG);

    function placeTipFor($card) {
      const title = $card.data('title') || '';
      const desc  = ($card.data('desc') || '').trim();

      $tip.find('.t1').text(title);
      if (desc) {
        if (!$tip.find('.t2').length) $tip.append('<div class="t2"></div>');
        $tip.find('.t2').text(desc);
      } else {
        $tip.find('.t2').remove();
      }

      const g = $gallery.offset();
      const c = $card.offset();
      const cx = c.left - g.left + $card.outerWidth() / 2;
      const top = c.top - g.top + 4;
      $tip.css({ left: cx, top: top }).addClass('show');
    }

    function hideTip() { $tip.removeClass('show'); }

    // не плодим обработчики
    $gallery.off('mouseenter.achv focusin.achv mouseleave.achv focusout.achv');
    $gallery.on('mouseenter.achv focusin.achv', '.achv-card', function () { placeTipFor($(this)); });
    $gallery.on('mouseleave.achv focusout.achv', '.achv-card', hideTip);

    initAchvSlider($gallery, $list);
  });
}, 1500);

})();

/* ------------ Slider helpers (стрелки по бокам) ------------ */
function initAchvSlider($gallery, $list){
  // не оборачиваем повторно
  if (!$list.parent().hasClass('achv-viewport')) {
    $list.wrap('<div class="achv-viewport"></div>');
  }
  const $rail = $list.parent();
  const rail  = $rail.get(0);

  $gallery.find('.achv-btn.prev, .achv-btn.next').remove();

  const $prev = $(`
    <button type="button" class="achv-btn prev" aria-label="прокрутить влево">
      <svg viewBox="0 0 24 24"><path d="M15.5 4.5L8 12l7.5 7.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
    </button>
  `);
  const $next = $(`
    <button type="button" class="achv-btn next" aria-label="прокрутить вправо">
      <svg viewBox="0 0 24 24"><path d="M8.5 4.5L16 12l-7.5 7.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
    </button>
  `);

  $gallery.append($prev, $next);

  const step = () => Math.max(rail.clientWidth * 0.8, 1);

  function updateButtons(){
    const maxScroll = rail.scrollWidth - rail.clientWidth - 1;
    const x = rail.scrollLeft;
    $prev.prop('disabled', x <= 0);
    $next.prop('disabled', x >= maxScroll);
  }

  // чистим прошлые обработчики
  $prev.off('click.achv');
  $next.off('click.achv');
  $rail.off('scroll.achv wheel.achv');
  $(window).off('resize.achv');

  $prev.on('click.achv', () => rail.scrollBy({left: -step(), behavior:'smooth'}));
  $next.on('click.achv', () => rail.scrollBy({left:  step(), behavior:'smooth'}));
  $rail.on('scroll.achv', updateButtons);
  $(window).on('resize.achv', updateButtons);

  $rail.on('wheel.achv', (e) => {
    const dx = e.originalEvent.deltaX;
    const dy = e.originalEvent.deltaY;
    if (Math.abs(dx) > Math.abs(dy)) {
      e.preventDefault();
      rail.scrollBy({left: dx, behavior:'auto'});
    }
  }, {passive:false});

  updateButtons();
}

/* =========================================================
   КНОПКА ? РЯДОМ С «СЧАСТЛИВОЙ ЗАЧЁТКОЙ»
   ========================================================= */

$(function () {

  $('.tr-stat .al_trHeader').each(function () {

    const $title = $(this);

    // защита от повторного добавления
    if ($title.find('.zachetka-help-btn').length) return;

    const $btn = $(`
      <a
        class="zachetka-help-btn"
        href="https://egenalegke.getcourse.ru/zachetka"
        aria-label="Что такое Счастливая зачётка"
      >?</a>
    `);

    $title.append($btn);

  });

});