750	      Learning Analytics
751

752	      Udemy Platform
753

754

755

756

757	        Live data
758

759

760	        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
761	          <rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/>
762	          <line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/>
763	        </svg>
764	        Q2 2025 Cohort
765

766

767

768
769
770
771
772	    <svg class="hero-pattern" viewBox="0 0 480 200" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMaxYMid slice">
773	      <defs>
774	        <pattern id="dotgrid" x="0" y="0" width="24" height="24" patternUnits="userSpaceOnUse">
775	          <circle cx="1" cy="1" r="1" fill="#b8822a" opacity="0.18"/>
776	        </pattern>
777	        <linearGradient id="fade" x1="0" x2="1" y1="0" y2="0">
778	          <stop offset="0%" stop-color="white" stop-opacity="1"/>
779	          <stop offset="100%" stop-color="white" stop-opacity="0"/>
780	        </linearGradient>
781	        <mask id="fadeMask">
782	          <rect width="480" height="200" fill="url(#fade)"/>
783	        </mask>
784	      </defs>
785	      <rect width="480" height="200" fill="url(#dotgrid)" mask="url(#fadeMask)"/>
786
787	      <polygon points="420,20 460,42 460,86 420,108 380,86 380,42" stroke="#b8822a" stroke-width="1" fill="none" opacity="0.15"/>
788	      <polygon points="420,36 448,51 448,80 420,95 392,80 392,51" stroke="#b8822a" stroke-width="0.75" fill="none" opacity="0.12"/>
789	    </svg>
790
791

792

793

794	          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
795	            <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/>
796	            <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>
797	          </svg>
798	          Course Utilization Report
799

800

801	          AI Coder: Vibe Coder
to Agentic Engineer
802

803

804

805	            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
806	              <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
807	              <circle cx="9" cy="7" r="4"/>
808	              <path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
809	              <path d="M16 3.13a4 4 0 0 1 0 7.75"/>
810	            </svg>
811	            15 learners enrolled
812

813

814	            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
815	              <circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>
816	            </svg>
817	            93 total sessions
818

819

820	            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
821	              <rect x="3" y="4" width="18" height="18" rx="2"/>
822	              <line x1="16" y1="2" x2="16" y2="6"/>
823	              <line x1="8" y1="2" x2="8" y2="6"/>
824	              <line x1="3" y1="10" x2="21" y2="10"/>
825	            </svg>
826	            3 week program
827

828

829	            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
830	              <line x1="18" y1="20" x2="18" y2="10"/>
831	              <line x1="12" y1="20" x2="12" y2="4"/>
832	              <line x1="6" y1="20" x2="6" y2="14"/>
833	            </svg>
834	            Avg. 0% complete
835

836

837

838
839

840

841

842	            <svg class="trophy-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
843	              <path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"/>
844	              <path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"/>
845	              <path d="M4 22h16"/>
846	              <path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"/>
847	              <path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"/>
848	              <path d="M18 2H6v7a6 6 0 0 0 12 0V2z"/>
849	            </svg>
850	            Top Performer
851

852
—

853
Loading...

854

855

856

857

858
—

859
sessions

860

861

862

863

864
865
866
867
868
869
870

871
872

873

874

875	          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#2d6fe8" stroke-width="2" stroke-linecap="round">
876	            <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
877	            <circle cx="9" cy="7" r="4"/>
878	            <path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
879	            <path d="M16 3.13a4 4 0 0 1 0 7.75"/>
880	          </svg>
881

882
15

883
Total Enrolled

884

885	          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
886	            <polyline points="18 15 12 9 6 15"/>
887	          </svg>
888	          Active cohort
889

890

891
892

893

894

895	          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#b8822a" stroke-width="2" stroke-linecap="round">
896	            <line x1="18" y1="20" x2="18" y2="10"/>
897	            <line x1="12" y1="20" x2="12" y2="4"/>
898	            <line x1="6" y1="20" x2="6" y2="14"/>
899	          </svg>
900

901
0%

902
Average Progress

903

904	          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
905	            <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
906	          </svg>
907	          Across all learners
908

909

910
911

912

913

914	          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#16a362" stroke-width="2" stroke-linecap="round">
915	            <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
916	            <polyline points="22 4 12 14.01 9 11.01"/>
917	          </svg>
918

919
0

920
Completions

921

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

Learning Analytics

      Udemy Platform

        Live data

        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
          <rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/>
          <line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/>
        </svg>
        Q2 2025 Cohort

    <svg class="hero-pattern" viewBox="0 0 480 200" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMaxYMid slice">
      <defs>
        <pattern id="dotgrid" x="0" y="0" width="24" height="24" patternUnits="userSpaceOnUse">
          <circle cx="1" cy="1" r="1" fill="#b8822a" opacity="0.18"/>
        </pattern>
        <linearGradient id="fade" x1="0" x2="1" y1="0" y2="0">
          <stop offset="0%" stop-color="white" stop-opacity="1"/>
          <stop offset="100%" stop-color="white" stop-opacity="0"/>
        </linearGradient>
        <mask id="fadeMask">
          <rect width="480" height="200" fill="url(#fade)"/>
        </mask>
      </defs>
      <rect width="480" height="200" fill="url(#dotgrid)" mask="url(#fadeMask)"/>

      <polygon points="420,20 460,42 460,86 420,108 380,86 380,42" stroke="#b8822a" stroke-width="1" fill="none" opacity="0.15"/>
      <polygon points="420,36 448,51 448,80 420,95 392,80 392,51" stroke="#b8822a" stroke-width="0.75" fill="none" opacity="0.12"/>
    </svg>

          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
            <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/>
            <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>
          </svg>
          Course Utilization Report

          AI Coder: Vibe Coder
to Agentic Engineer

            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
              <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
              <circle cx="9" cy="7" r="4"/>
              <path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
              <path d="M16 3.13a4 4 0 0 1 0 7.75"/>
            </svg>
            15 learners enrolled

            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
              <circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>
            </svg>
            93 total sessions

            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
              <rect x="3" y="4" width="18" height="18" rx="2"/>
              <line x1="16" y1="2" x2="16" y2="6"/>
              <line x1="8" y1="2" x2="8" y2="6"/>
              <line x1="3" y1="10" x2="21" y2="10"/>
            </svg>
            3 week program

            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
              <line x1="18" y1="20" x2="18" y2="10"/>
              <line x1="12" y1="20" x2="12" y2="4"/>
              <line x1="6" y1="20" x2="6" y2="14"/>
            </svg>
            Avg. 0% complete

            <svg class="trophy-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
              <path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"/>
              <path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"/>
              <path d="M4 22h16"/>
              <path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"/>
              <path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"/>
              <path d="M18 2H6v7a6 6 0 0 0 12 0V2z"/>
            </svg>
            Top Performer

—

Loading...

—

sessions

          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#2d6fe8" stroke-width="2" stroke-linecap="round">
            <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
            <circle cx="9" cy="7" r="4"/>
            <path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
            <path d="M16 3.13a4 4 0 0 1 0 7.75"/>
          </svg>

15

Total Enrolled

          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
            <polyline points="18 15 12 9 6 15"/>
          </svg>
          Active cohort

          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#b8822a" stroke-width="2" stroke-linecap="round">
            <line x1="18" y1="20" x2="18" y2="10"/>
            <line x1="12" y1="20" x2="12" y2="4"/>
            <line x1="6" y1="20" x2="6" y2="14"/>
          </svg>

0%

Average Progress

          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
            <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
          </svg>
          Across all learners

          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#16a362" stroke-width="2" stroke-linecap="round">
            <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
            <polyline points="22 4 12 14.01 9 11.01"/>
          </svg>

0

Completions


590	    }
591
592	    .progress-cell { padding-right: 20px; }
593
594	    .progress-track {
595	      height: 7px;
596	      background: var(--bg-alt);
597	      border-radius: 99px;
598	      overflow: hidden;
599	      border: 1px solid var(--border);
600	    }
601
602	    .progress-fill {
603	      height: 100%;
604	      border-radius: 99px;
605	      width: 0%;
606	      transition: width 1.3s cubic-bezier(0.16, 1, 0.3, 1);
607	    }
608
609	    .progress-label {
610	      font-size: 11px;
611	      color: var(--ink-muted);
612	      margin-top: 5px;
613	    }
614
615	    .pct-cell {
616	      text-align: right;
617	      font-family: 'Fraunces', serif;
618	      font-size: 22px;
619	      font-weight: 700;
620	      line-height: 1;
621	      color: var(--ink);
622	    }
623
624	    .pct-cell small {
625	      font-family: 'DM Sans', sans-serif;
626	      font-size: 12px;
627	      font-weight: 400;
628	      color: var(--ink-muted);
629	    }
630
631	    .week-badge {
632	      display: inline-flex;
633	      align-items: center;
634	      justify-content: center;
635	      padding: 4px 11px;
636	      border-radius: 99px;
637	      font-size: 11px;
638	      font-weight: 600;
639	      letter-spacing: 0.02em;
640	    }
641
642	    .week-badge.w0 {
643	      background: var(--slate-bg);
644	      color: var(--ink-muted);
645	      border: 1px solid var(--slate-border);
646	    }
647	    .week-badge.w1 {
648	      background: var(--blue-bg);
649	      color: var(--blue);
650	      border: 1px solid var(--blue-border);
651	    }
652	    .week-badge.w2 {
653	      background: var(--amber-bg);
654	      color: var(--amber);
655	      border: 1px solid var(--amber-border);
656	    }
657	    .week-badge.w3 {
658	      background: var(--green-bg);
659	      color: var(--green);
660	      border: 1px solid var(--green-border);
661	    }
662
663	    .status-badge {
664	      display: inline-flex;
665	      align-items: center;
666	      gap: 5px;
667	      padding: 5px 11px;
668	      border-radius: 99px;
669	      font-size: 11px;
670	      font-weight: 600;
671	    }
672
673	    .status-badge.not-started {
674	      background: var(--slate-bg);
675	      color: var(--ink-muted);
676	      border: 1px solid var(--slate-border);
677	    }
678
679	    .status-badge.in-progress {
680	      background: var(--amber-bg);
681	      color: var(--amber);
682	      border: 1px solid var(--amber-border);
683	    }
684
685	    .status-badge.completed {
686	      background: var(--green-bg);
687	      color: var(--green);
688	      border: 1px solid var(--green-border);
689	    }
690
691	    /* ─── EMPTY STATE ───────────────────────────────── */
692	    .empty-state {
693	      padding: 56px 24px;
694	      text-align: center;
695	      color: var(--ink-muted);
696	      font-size: 13px;
697	      display: none;
698	    }
699
700	    .empty-state svg { margin: 0 auto 12px; display: block; }
701
702	    /* ─── FOOTER ────────────────────────────────────── */
703	    .footer {
704	      text-align: center;
705	      padding: 22px 56px;
706	      font-size: 11px;
707	      color: var(--ink-muted);
708	      border-top: 1px solid var(--border);
709	      background: var(--white);
710	      letter-spacing: 0.05em;
711	    }
712
713	    .footer strong { color: var(--gold); font-weight: 600; }
714
715	    /* ─── RESPONSIVE ────────────────────────────────── */
716	    @media (max-width: 1140px) {
717	      .stats-grid { grid-template-columns: repeat(2, 1fr); }
718	      .table-head, .learner-row { grid-template-columns: 2fr 88px 88px 180px 70px 90px 100px; }
719	    }
720
721	    @media (max-width: 860px) {
722	      .topbar, .hero, .main { padding-left: 20px; padding-right: 20px; }
723	      .hero-inner { flex-direction: column; }
724	      .hero-right { align-self: stretch; }
725	      .performer-card { min-width: unset; }
726	      .table-card { overflow-x: auto; }
727	      .table-head, .learner-row { min-width: 760px; }
728	      .controls-row { flex-wrap: wrap; }
729	    }
730
731	    /* ─── ANIMATIONS ────────────────────────────────── */
732	    @keyframes slideDown {
733	      from { opacity: 0; transform: translateY(-8px); }
734	      to   { opacity: 1; transform: translateY(0); }
735	    }
736
737	    .hero { animation: slideDown 0.5s ease both; }
738	  </style>
739
740
741
742
743

744

745

746	        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.2" stroke-linecap="round">
747	          <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
748	        </svg>
749

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

}

    .progress-cell { padding-right: 20px; }

    .progress-track {
      height: 7px;
      background: var(--bg-alt);
      border-radius: 99px;
      overflow: hidden;
      border: 1px solid var(--border);
    }

    .progress-fill {
      height: 100%;
      border-radius: 99px;
      width: 0%;
      transition: width 1.3s cubic-bezier(0.16, 1, 0.3, 1);
    }

    .progress-label {
      font-size: 11px;
      color: var(--ink-muted);
      margin-top: 5px;
    }

    .pct-cell {
      text-align: right;
      font-family: 'Fraunces', serif;
      font-size: 22px;
      font-weight: 700;
      line-height: 1;
      color: var(--ink);
    }

    .pct-cell small {
      font-family: 'DM Sans', sans-serif;
      font-size: 12px;
      font-weight: 400;
      color: var(--ink-muted);
    }

    .week-badge {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      padding: 4px 11px;
      border-radius: 99px;
      font-size: 11px;
      font-weight: 600;
      letter-spacing: 0.02em;
    }

    .week-badge.w0 {
      background: var(--slate-bg);
      color: var(--ink-muted);
      border: 1px solid var(--slate-border);
    }
    .week-badge.w1 {
      background: var(--blue-bg);
      color: var(--blue);
      border: 1px solid var(--blue-border);
    }
    .week-badge.w2 {
      background: var(--amber-bg);
      color: var(--amber);
      border: 1px solid var(--amber-border);
    }
    .week-badge.w3 {
      background: var(--green-bg);
      color: var(--green);
      border: 1px solid var(--green-border);
    }

    .status-badge {
      display: inline-flex;
      align-items: center;
      gap: 5px;
      padding: 5px 11px;
      border-radius: 99px;
      font-size: 11px;
      font-weight: 600;
    }

    .status-badge.not-started {
      background: var(--slate-bg);
      color: var(--ink-muted);
      border: 1px solid var(--slate-border);
    }

    .status-badge.in-progress {
      background: var(--amber-bg);
      color: var(--amber);
      border: 1px solid var(--amber-border);
    }

    .status-badge.completed {
      background: var(--green-bg);
      color: var(--green);
      border: 1px solid var(--green-border);
    }

    /* ─── EMPTY STATE ───────────────────────────────── */
    .empty-state {
      padding: 56px 24px;
      text-align: center;
      color: var(--ink-muted);
      font-size: 13px;
      display: none;
    }

    .empty-state svg { margin: 0 auto 12px; display: block; }

    /* ─── FOOTER ────────────────────────────────────── */
    .footer {
      text-align: center;
      padding: 22px 56px;
      font-size: 11px;
      color: var(--ink-muted);
      border-top: 1px solid var(--border);
      background: var(--white);
      letter-spacing: 0.05em;
    }

    .footer strong { color: var(--gold); font-weight: 600; }

    /* ─── RESPONSIVE ────────────────────────────────── */
    @media (max-width: 1140px) {
      .stats-grid { grid-template-columns: repeat(2, 1fr); }
      .table-head, .learner-row { grid-template-columns: 2fr 88px 88px 180px 70px 90px 100px; }
    }

    @media (max-width: 860px) {
      .topbar, .hero, .main { padding-left: 20px; padding-right: 20px; }
      .hero-inner { flex-direction: column; }
      .hero-right { align-self: stretch; }
      .performer-card { min-width: unset; }
      .table-card { overflow-x: auto; }
      .table-head, .learner-row { min-width: 760px; }
      .controls-row { flex-wrap: wrap; }
    }

    /* ─── ANIMATIONS ────────────────────────────────── */
    @keyframes slideDown {
      from { opacity: 0; transform: translateY(-8px); }
      to   { opacity: 1; transform: translateY(0); }
    }

    .hero { animation: slideDown 0.5s ease both; }
  </style>

        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.2" stroke-linecap="round">
          <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
        </svg>


Let me open the file in the browser directly to verify how it renders.


Bash

Open dashboard in default browser


(Bash completed with no output)


[Image #1]


I've opened it in your browser. Can you describe what's broken — is it the learner table missing, the stat cards invisible, layout broken, or fonts not loading?

Meanwhile, let me check the JS for any potential issues:


<tool_use_error>InputValidationError: Grep failed due to the following issue:
An unexpected parameter `file_path` was provided</tool_use_error>

InputValidationError: [
  {
    "code": "unrecognized_keys",
    "keys": [
      "file_path"
    ],
    "path": [],
    "message": "Unrecognized key: \"file_path\""
  }
]


I can see the issues clearly from the screenshot — JS is not executing fully (stat cards invisible, learner rows empty, "Loading..." and "Avg. 0" stuck). Let me read the full JS block to find the bug.


832-              <line x1="6" y1="20" x2="6" y2="14"/>
833-            </svg>
834:            Avg. 0% complete
835-

836-

--
850-            Top Performer
851-

852:
—

853-
Loading...

854-

--
1043-    ];
1044-
1045:    const DATA = [
1046-      { name:'Mohammed Al Mansoori', done:78  },
1047-      { name:'Fatima Al Rashidi',    done:93  },
--
1075-    const top = [...DATA].sort((a,b)=>b.done-a.done)[0];
1076-
1077:    document.getElementById('hero-avg').textContent = avg;
1078-    document.getElementById('avg-num').textContent  = avg;
1079-    document.getElementById('completed-num').textContent = completions;
--
1124-    }
1125-
1126:    function render() {
1127-      let rows = DATA.filter(l => {
1128-        const fOk = filter === 'all' || l.status === filter;
--
1181-          requestAnimationFrame(() => r.classList.add('visible'));
1182-        });
1183:        setTimeout(() => {
1184-          document.querySelectorAll('.progress-fill').forEach(b => {
1185-            b.style.width = b.dataset.pct + '%';
--
1193-      document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
1194-      btn.classList.add('active');
1195:      render();
1196-    }
1197-
--
1199-      sortAsc = !sortAsc;
1200-      document.getElementById('sort-label').textContent = sortAsc ? 'Low to High' : 'High to Low';
1201:      render();
1202-    }
1203-
1204-    document.getElementById('search-input').addEventListener('input', e => {
1205-      query = e.target.value;
1206:      render();
1207-    });
1208-
1209-    // initial render
1210:    render();
1211-
1212-    // animate stat cards
1213-    ['sc-enrolled','sc-avg','sc-completed','sc-inprogress'].forEach((id, i) => {
1214:      setTimeout(() => document.getElementById(id).classList.add('visible'), 80 + i * 90);
1215-    });
1216-
1217-    // animate top performer bar
1218:    setTimeout(() => {
1219-      document.getElementById('top-bar').style.width = top.pct + '%';
1220-    }, 300);


1040	      { bg:'#edfaf4', border:'#a3dfc3', text:'#16a362' },
1041	      { bg:'#f5f0ff', border:'#c4a8f5', text:'#7c3aed' },
1042	      { bg:'#fff0ee', border:'#f5b5a8', text:'#d64828' },
1043	    ];
1044
1045	    const DATA = [
1046	      { name:'Mohammed Al Mansoori', done:78  },
1047	      { name:'Fatima Al Rashidi',    done:93  },
1048	      { name:'Ahmed Al Mazrouei',    done:45  },
1049	      { name:'Mariam Al Suwaidi',    done:12  },
1050	      { name:'Khalid Al Nuaimi',     done:67  },
1051	      { name:'Noura Al Hameli',      done:0   },
1052	      { name:'Sultan Al Kaabi',      done:88  },
1053	      { name:'Aisha Al Dhaheri',     done:31  },
1054	      { name:'Omar Al Muhairi',      done:55  },
1055	      { name:'Latifa Al Shamsi',     done:72  },
1056	      { name:'Saeed Al Falasi',      done:19  },
1057	      { name:'Hessa Al Ketbi',       done:93  },
1058	      { name:'Zayed Al Ameri',       done:38  },
1059	      { name:'Maitha Al Jabri',      done:62  },
1060	      { name:'Rashid Al Tenaiji',    done:84  },
1061	    ].map((l, i) => {
1062	      const pct    = Math.round((l.done / TOTAL) * 100);
1063	      const status = l.done === 0 ? 'not-started' : l.done >= TOTAL ? 'completed' : 'in-progress';
1064	      const week   = l.done === 0 ? 0 : l.done <= 31 ? 1 : l.done <= 62 ? 2 : 3;
1065	      return { ...l, pct, status, week,
1066	               remaining: TOTAL - l.done,
1067	               pal: AVATARS[i % AVATARS.length],
1068	               initials: l.name.split(' ').slice(0,2).map(p=>p[0]).join('') };
1069	    });
1070
1071	    // header stats
1072	    const avg = Math.round(DATA.reduce((s,l)=>s+l.pct,0)/DATA.length);
1073	    const completions = DATA.filter(l=>l.status==='completed').length;
1074	    const inProgress  = DATA.filter(l=>l.status==='in-progress').length;
1075	    const top = [...DATA].sort((a,b)=>b.done-a.done)[0];
1076
1077	    document.getElementById('hero-avg').textContent = avg;
1078	    document.getElementById('avg-num').textContent  = avg;
1079	    document.getElementById('completed-num').textContent = completions;
1080	    document.getElementById('inprogress-num').textContent = inProgress;
1081
1082	    document.getElementById('top-name').textContent     = top.name;
1083	    document.getElementById('top-score').textContent    = top.done + ' of ' + TOTAL + ' sessions';
1084	    document.getElementById('top-pct').textContent      = top.pct + '%';
1085	    document.getElementById('top-sessions').textContent = top.done + ' sessions done';
1086
1087	    // state
1088	    let filter = 'all', sortAsc = false, query = '';
1089
1090	    function weekInfo(w) {
1091	      const map = {
1092	        0: { cls:'w0', label:'Not yet' },
1093	        1: { cls:'w1', label:'Week 1'  },
1094	        2: { cls:'w2', label:'Week 2'  },
1095	        3: { cls:'w3', label:'Week 3'  },
1096	      };
1097	      return map[w];
1098	    }
1099
1100	    function statusIcon(s) {
1101	      if (s==='completed')
1102	        return '<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><polyline points="20 6 9 17 4 12"/></svg>';
1103	      if (s==='in-progress')
1104	        return '<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>';
1105	      return '<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><line x1="8" y1="12" x2="16" y2="12"/></svg>';
1106	    }
1107
1108	    function statusLabel(s) {
1109	      return s === 'completed' ? 'Completed' : s === 'in-progress' ? 'In Progress' : 'Not Started';
1110	    }
1111
1112	    function pctColor(pct) {
1113	      if (pct >= 100) return 'linear-gradient(90deg,#16a362,#3fcf8e)';
1114	      if (pct >= 66)  return 'linear-gradient(90deg,#b8822a,#e6a93a)';
1115	      if (pct >= 33)  return 'linear-gradient(90deg,#2d6fe8,#6a9ff5)';
1116	      return 'linear-gradient(90deg,#9aa3b8,#c0cad9)';
1117	    }
1118
1119	    function pctTextColor(pct) {
1120	      if (pct >= 100) return 'var(--green)';
1121	      if (pct >= 66)  return 'var(--gold)';
1122	      if (pct >= 33)  return 'var(--blue)';
1123	      return 'var(--ink-muted)';
1124	    }
1125
1126	    function render() {
1127	      let rows = DATA.filter(l => {
1128	        const fOk = filter === 'all' || l.status === filter;
1129	        const sOk = l.name.toLowerCase().includes(query.toLowerCase());
1130	        return fOk && sOk;
1131	      }).sort((a,b) => sortAsc ? a.done - b.done : b.done - a.done);
1132
1133	      const list  = document.getElementById('learner-list');
1134	      const empty = document.getElementById('empty-state');
1135	      const badge = document.getElementById('count-badge');
1136
1137	      badge.textContent = rows.length + ' learner' + (rows.length !== 1 ? 's' : '');
1138
1139	      if (!rows.length) {
1140	        list.innerHTML = '';
1141	        empty.style.display = 'block';
1142	        return;
1143	      }
1144	      empty.style.display = 'none';
1145
1146	      list.innerHTML = rows.map((l, i) => {
1147	        const wk = weekInfo(l.week);
1148	        return `
1149

1150

1151

1152	                ${l.initials}
1153

1154
${l.name}

1155

1156
${l.done}

1157
${l.remaining}

1158

1159

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

{ bg:'#edfaf4', border:'#a3dfc3', text:'#16a362' },
      { bg:'#f5f0ff', border:'#c4a8f5', text:'#7c3aed' },
      { bg:'#fff0ee', border:'#f5b5a8', text:'#d64828' },
    ];

    const DATA = [
      { name:'Mohammed Al Mansoori', done:78  },
      { name:'Fatima Al Rashidi',    done:93  },
      { name:'Ahmed Al Mazrouei',    done:45  },
      { name:'Mariam Al Suwaidi',    done:12  },
      { name:'Khalid Al Nuaimi',     done:67  },
      { name:'Noura Al Hameli',      done:0   },
      { name:'Sultan Al Kaabi',      done:88  },
      { name:'Aisha Al Dhaheri',     done:31  },
      { name:'Omar Al Muhairi',      done:55  },
      { name:'Latifa Al Shamsi',     done:72  },
      { name:'Saeed Al Falasi',      done:19  },
      { name:'Hessa Al Ketbi',       done:93  },
      { name:'Zayed Al Ameri',       done:38  },
      { name:'Maitha Al Jabri',      done:62  },
      { name:'Rashid Al Tenaiji',    done:84  },
    ].map((l, i) => {
      const pct    = Math.round((l.done / TOTAL) * 100);
      const status = l.done === 0 ? 'not-started' : l.done >= TOTAL ? 'completed' : 'in-progress';
      const week   = l.done === 0 ? 0 : l.done <= 31 ? 1 : l.done <= 62 ? 2 : 3;
      return { ...l, pct, status, week,
               remaining: TOTAL - l.done,
               pal: AVATARS[i % AVATARS.length],
               initials: l.name.split(' ').slice(0,2).map(p=>p[0]).join('') };
    });

    // header stats
    const avg = Math.round(DATA.reduce((s,l)=>s+l.pct,0)/DATA.length);
    const completions = DATA.filter(l=>l.status==='completed').length;
    const inProgress  = DATA.filter(l=>l.status==='in-progress').length;
    const top = [...DATA].sort((a,b)=>b.done-a.done)[0];

    document.getElementById('hero-avg').textContent = avg;
    document.getElementById('avg-num').textContent  = avg;
    document.getElementById('completed-num').textContent = completions;
    document.getElementById('inprogress-num').textContent = inProgress;

    document.getElementById('top-name').textContent     = top.name;
    document.getElementById('top-score').textContent    = top.done + ' of ' + TOTAL + ' sessions';
    document.getElementById('top-pct').textContent      = top.pct + '%';
    document.getElementById('top-sessions').textContent = top.done + ' sessions done';

    // state
    let filter = 'all', sortAsc = false, query = '';

    function weekInfo(w) {
      const map = {
        0: { cls:'w0', label:'Not yet' },
        1: { cls:'w1', label:'Week 1'  },
        2: { cls:'w2', label:'Week 2'  },
        3: { cls:'w3', label:'Week 3'  },
      };
      return map[w];
    }

    function statusIcon(s) {
      if (s==='completed')
        return '<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><polyline points="20 6 9 17 4 12"/></svg>';
      if (s==='in-progress')
        return '<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>';
      return '<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><line x1="8" y1="12" x2="16" y2="12"/></svg>';
    }

    function statusLabel(s) {
      return s === 'completed' ? 'Completed' : s === 'in-progress' ? 'In Progress' : 'Not Started';
    }

    function pctColor(pct) {
      if (pct >= 100) return 'linear-gradient(90deg,#16a362,#3fcf8e)';
      if (pct >= 66)  return 'linear-gradient(90deg,#b8822a,#e6a93a)';
      if (pct >= 33)  return 'linear-gradient(90deg,#2d6fe8,#6a9ff5)';
      return 'linear-gradient(90deg,#9aa3b8,#c0cad9)';
    }

    function pctTextColor(pct) {
      if (pct >= 100) return 'var(--green)';
      if (pct >= 66)  return 'var(--gold)';
      if (pct >= 33)  return 'var(--blue)';
      return 'var(--ink-muted)';
    }

    function render() {
      let rows = DATA.filter(l => {
        const fOk = filter === 'all' || l.status === filter;
        const sOk = l.name.toLowerCase().includes(query.toLowerCase());
        return fOk && sOk;
      }).sort((a,b) => sortAsc ? a.done - b.done : b.done - a.done);

      const list  = document.getElementById('learner-list');
      const empty = document.getElementById('empty-state');
      const badge = document.getElementById('count-badge');

      badge.textContent = rows.length + ' learner' + (rows.length !== 1 ? 's' : '');

      if (!rows.length) {
        list.innerHTML = '';
        empty.style.display = 'block';
        return;
      }
      empty.style.display = 'none';

      list.innerHTML = rows.map((l, i) => {
        const wk = weekInfo(l.week);
        return `

                ${l.initials}

${l.name}

${l.done}

${l.remaining}


1020

1021	        <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="var(--ink-muted)" stroke-width="1.5" stroke-linecap="round">
1022	          <circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
1023	        </svg>
1024	        No learners match your search or filter.
1025

1026

1027
1028
1029
1030
1031	    AI Coder: Vibe Coder to Agentic Engineer  ·  93 Sessions  ·  3 Weeks  ·  Utilization Dashboard
1032
1033
1034

        <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="var(--ink-muted)" stroke-width="1.5" stroke-linecap="round">
          <circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
        </svg>
        No learners match your search or filter.

    AI Coder: Vibe Coder to Agentic Engineer  ·  93 Sessions  ·  3 Weeks  ·  Utilization Dashboard


1215	    });
1216
1217	    // animate top performer bar
1218	    setTimeout(() => {
1219	      document.getElementById('top-bar').style.width = top.pct + '%';
1220	    }, 300);
1221	  </script>
1222	</body>
1223	</html>
1224

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

    });

    // animate top performer bar
    setTimeout(() => {
      document.getElementById('top-bar').style.width = top.pct + '%';
    }, 300);
  </script>
</body>
</html>


1159

1160

1161

1162
${l.done} of ${TOTAL} sessions

1163

1164

1165	              ${l.pct}%
1166

1167

1168	              ${wk.label}
1169

1170

1171
1172	                ${statusIcon(l.status)}
1173	                ${statusLabel(l.status)}
1174
1175

1176
`;
1177	      }).join('');
1178
1179	      requestAnimationFrame(() => {
1180	        document.querySelectorAll('.learner-row').forEach(r => {
1181	          requestAnimationFrame(() => r.classList.add('visible'));
1182	        });
1183	        setTimeout(() => {
1184	          document.querySelectorAll('.progress-fill').forEach(b => {
1185	            b.style.width = b.dataset.pct + '%';
1186	          });
1187	        }, 60);
1188	      });

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

${l.done} of ${TOTAL} sessions

              ${l.pct}%

              ${wk.label}

                ${statusIcon(l.status)}
                ${statusLabel(l.status)}

`;
      }).join('');

      requestAnimationFrame(() => {
        document.querySelectorAll('.learner-row').forEach(r => {
          requestAnimationFrame(() => r.classList.add('visible'));
        });
        setTimeout(() => {
          document.querySelectorAll('.progress-fill').forEach(b => {
            b.style.width = b.dataset.pct + '%';
          });
        }, 60);
      });


I can see exactly what's wrong from the screenshot:
1. **Stat cards invisible** — stuck at `opacity: 0`, JS timeouts may not be firing
2. **Learner rows missing** — same RAF timing issue
3. **"Avg. 0" / "Loading..."** — DOM updates not reaching the elements (likely a JS execution timing error)

The root cause is the JS-driven opacity animation approach is fragile. I'll fix it by replacing all `opacity: 0` + JS class toggling with CSS `@keyframes` (which always fire), and make the data binding more robust.


160	    .hero-left { flex: 1; }
161
162	    .hero-pill {
163	      display: inline-flex;
164	      align-items: center;
165	      gap: 7px;
166	      background: var(--gold-pale);
167	      border: 1px solid var(--gold-border);
168	      border-radius: 99px;
169	      padding: 5px 13px 5px 9px;
170	      font-size: 11px;
171	      font-weight: 600;
172	      color: var(--gold);
173	      letter-spacing: 0.04em;
174	      text-transform: uppercase;
175	      margin-bottom: 18px;
176	    }
177
178	    .hero-title {
179	      font-family: 'Fraunces', serif;

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

    .hero-left { flex: 1; }

    .hero-pill {
      display: inline-flex;
      align-items: center;
      gap: 7px;
      background: var(--gold-pale);
      border: 1px solid var(--gold-border);
      border-radius: 99px;
      padding: 5px 13px 5px 9px;
      font-size: 11px;
      font-weight: 600;
      color: var(--gold);
      letter-spacing: 0.04em;
      text-transform: uppercase;
      margin-bottom: 18px;
    }

    .hero-title {
      font-family: 'Fraunces', serif;


I have a full picture now. Let me rewrite the file with a clean fix — replace all JS-driven `opacity: 0` toggling with pure CSS `@keyframes`, and wrap DOM updates in `DOMContentLoaded` for reliability.


Write

<!DOCTYPE html>

  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>AI Coder — Utilization Dashboard</title>
  <link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,wght@0,300;0,600;0,700;1,300&family=DM+Sans:wght@300;400;500;600&display=swap" rel="stylesheet" />

        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.2" stroke-linecap="round">
          <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
        </svg>

      Learning Analytics

      Udemy Platform

        Live data

        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
          <rect x="3" y="4" width="18" height="18" rx="2"/>
          <line x1="16" y1="2" x2="16" y2="6"/>
          <line x1="8" y1="2" x2="8" y2="6"/>
          <line x1="3" y1="10" x2="21" y2="10"/>
        </svg>
        Q2 2025 Cohort

    <svg class="hero-pattern" viewBox="0 0 480 220" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMaxYMid slice">
      <defs>
        <pattern id="dots" x="0" y="0" width="24" height="24" patternUnits="userSpaceOnUse">
          <circle cx="1" cy="1" r="1" fill="#b8822a" opacity="0.15"/>
        </pattern>
        <linearGradient id="dfade" x1="0" x2="1" y1="0" y2="0">
          <stop offset="0%" stop-color="white"/>
          <stop offset="100%" stop-color="white" stop-opacity="0"/>
        </linearGradient>
        <mask id="dmask">
          <rect width="480" height="220" fill="url(#dfade)"/>
        </mask>
      </defs>
      <rect width="480" height="220" fill="url(#dots)" mask="url(#dmask)"/>
      <polygon points="420,18 462,42 462,90 420,114 378,90 378,42" stroke="#b8822a" stroke-width="1" fill="none" opacity="0.14"/>
      <polygon points="420,36 449,53 449,80 420,97 391,80 391,53" stroke="#b8822a" stroke-width="0.7" fill="none" opacity="0.1"/>
    </svg>

          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
            <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/>
            <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>
          </svg>
          Course Utilization Report

AI Coder: Vibe Coder
to Agentic Engineer

            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
              <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
              <circle cx="9" cy="7" r="4"/>
              <path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
              <path d="M16 3.13a4 4 0 0 1 0 7.75"/>
            </svg>
            15 learners enrolled

            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
              <circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>
            </svg>
            93 total sessions

            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
              <rect x="3" y="4" width="18" height="18" rx="2"/>
              <line x1="16" y1="2" x2="16" y2="6"/>
              <line x1="8" y1="2" x2="8" y2="6"/>
              <line x1="3" y1="10" x2="21" y2="10"/>
            </svg>
            3 week program

            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
              <line x1="18" y1="20" x2="18" y2="10"/>
              <line x1="12" y1="20" x2="12" y2="4"/>
              <line x1="6" y1="20" x2="6" y2="14"/>
            </svg>
            Avg. —% complete

          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#e6a93a" stroke-width="1.8" stroke-linecap="round">
            <path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"/>
            <path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"/>
            <path d="M4 22h16"/>
            <path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"/>
            <path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"/>
            <path d="M18 2H6v7a6 6 0 0 0 12 0V2z"/>
          </svg>
          Top Performer

—

—

sessions done

          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#2d6fe8" stroke-width="2" stroke-linecap="round">
            <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
            <circle cx="9" cy="7" r="4"/>
            <path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
            <path d="M16 3.13a4 4 0 0 1 0 7.75"/>
          </svg>

15

Total Enrolled

          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="18 15 12 9 6 15"/></svg>
          Active cohort

          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#b8822a" stroke-width="2" stroke-linecap="round">
            <line x1="18" y1="20" x2="18" y2="10"/>
            <line x1="12" y1="20" x2="12" y2="4"/>
            <line x1="6" y1="20" x2="6" y2="14"/>
          </svg>

—%

Average Progress

          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
          Across all learners

          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#16a362" stroke-width="2" stroke-linecap="round">
            <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
            <polyline points="22 4 12 14.01 9 11.01"/>
          </svg>

—

Completions

          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="20 6 9 17 4 12"/></svg>
          100% of sessions

          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#c47d0e" stroke-width="2" stroke-linecap="round">
            <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
          </svg>

—

In Progress

          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
          Actively learning

        <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="var(--ink)" stroke-width="2" stroke-linecap="round">
          <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
          <circle cx="9" cy="7" r="4"/>
        </svg>
        Learner Progress
        15 learners

            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
              <circle cx="11" cy="11" r="8"/>
              <line x1="21" y1="21" x2="16.65" y2="16.65"/>
            </svg>

          <input class="search-input" id="search-input" type="text" placeholder="Search learner..."/>

          <button class="filter-btn active" data-f="all" onclick="setFilter('all',this)">
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round">
              <line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/>
              <line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>
            </svg>All
          </button>
          <button class="filter-btn" data-f="in-progress" onclick="setFilter('in-progress',this)">
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round">
              <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
            </svg>In Progress
          </button>
          <button class="filter-btn" data-f="completed" onclick="setFilter('completed',this)">
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round">
              <polyline points="20 6 9 17 4 12"/>
            </svg>Completed
          </button>
          <button class="filter-btn" data-f="not-started" onclick="setFilter('not-started',this)">
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round">
              <circle cx="12" cy="12" r="10"/><line x1="8" y1="12" x2="16" y2="12"/>
            </svg>Not Started
          </button>

        <button class="sort-btn" onclick="toggleSort()">
          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
            <line x1="12" y1="20" x2="12" y2="10"/>
            <line x1="18" y1="20" x2="18" y2="4"/>
            <line x1="6" y1="20" x2="6" y2="16"/>
          </svg>
          High to Low
        </button>

Learner

Completed

Remaining

Progress

Done

Week

Status

        <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="var(--ink-muted)" stroke-width="1.5" stroke-linecap="round" style="display:block;margin:0 auto 12px">
          <circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
        </svg>
        No learners match your search or filter.

    AI Coder: Vibe Coder to Agentic Engineer · 93 Sessions · 3 Weeks · Utilization Dashboard


The file /Users/khalidbinkalban/course-dashboard.html has been updated successfully.

<!DOCTYPE html>

  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>AI Coder — Utilization Dashboard</title>
  <link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,wght@0,300;0,600;0,700;1,300&family=DM+Sans:wght@300;400;500;600&display=swap" rel="stylesheet" />

        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.2" stroke-linecap="round">
          <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
        </svg>

      Learning Analytics

      Udemy Platform

        Live data

        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
          <rect x="3" y="4" width="18" height="18" rx="2"/>
          <line x1="16" y1="2" x2="16" y2="6"/>
          <line x1="8" y1="2" x2="8" y2="6"/>
          <line x1="3" y1="10" x2="21" y2="10"/>
        </svg>
        Q2 2025 Cohort

    <svg class="hero-pattern" viewBox="0 0 480 220" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMaxYMid slice">
      <defs>
        <pattern id="dots" x="0" y="0" width="24" height="24" patternUnits="userSpaceOnUse">
          <circle cx="1" cy="1" r="1" fill="#b8822a" opacity="0.15"/>
        </pattern>
        <linearGradient id="dfade" x1="0" x2="1" y1="0" y2="0">
          <stop offset="0%" stop-color="white"/>
          <stop offset="100%" stop-color="white" stop-opacity="0"/>
        </linearGradient>
        <mask id="dmask">
          <rect width="480" height="220" fill="url(#dfade)"/>
        </mask>
      </defs>
      <rect width="480" height="220" fill="url(#dots)" mask="url(#dmask)"/>
      <polygon points="420,18 462,42 462,90 420,114 378,90 378,42" stroke="#b8822a" stroke-width="1" fill="none" opacity="0.14"/>
      <polygon points="420,36 449,53 449,80 420,97 391,80 391,53" stroke="#b8822a" stroke-width="0.7" fill="none" opacity="0.1"/>
    </svg>

          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
            <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/>
            <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>
          </svg>
          Course Utilization Report

AI Coder: Vibe Coder
to Agentic Engineer

            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
              <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
              <circle cx="9" cy="7" r="4"/>
              <path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
              <path d="M16 3.13a4 4 0 0 1 0 7.75"/>
            </svg>
            15 learners enrolled

            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
              <circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>
            </svg>
            93 total sessions

            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
              <rect x="3" y="4" width="18" height="18" rx="2"/>
              <line x1="16" y1="2" x2="16" y2="6"/>
              <line x1="8" y1="2" x2="8" y2="6"/>
              <line x1="3" y1="10" x2="21" y2="10"/>
            </svg>
            3 week program

            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
              <line x1="18" y1="20" x2="18" y2="10"/>
              <line x1="12" y1="20" x2="12" y2="4"/>
              <line x1="6" y1="20" x2="6" y2="14"/>
            </svg>
            Avg. —% complete

          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#e6a93a" stroke-width="1.8" stroke-linecap="round">
            <path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"/>
            <path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"/>
            <path d="M4 22h16"/>
            <path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"/>
            <path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"/>
            <path d="M18 2H6v7a6 6 0 0 0 12 0V2z"/>
          </svg>
          Top Performer

—

—

sessions done

          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#2d6fe8" stroke-width="2" stroke-linecap="round">
            <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
            <circle cx="9" cy="7" r="4"/>
            <path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
            <path d="M16 3.13a4 4 0 0 1 0 7.75"/>
          </svg>

15

Total Enrolled

          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="18 15 12 9 6 15"/></svg>
          Active cohort

          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#b8822a" stroke-width="2" stroke-linecap="round">
            <line x1="18" y1="20" x2="18" y2="10"/>
            <line x1="12" y1="20" x2="12" y2="4"/>
            <line x1="6" y1="20" x2="6" y2="14"/>
          </svg>

—%

Average Progress

          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
          Across all learners

          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#16a362" stroke-width="2" stroke-linecap="round">
            <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
            <polyline points="22 4 12 14.01 9 11.01"/>
          </svg>

—

Completions

          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="20 6 9 17 4 12"/></svg>
          100% of sessions

          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#c47d0e" stroke-width="2" stroke-linecap="round">
            <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
          </svg>

—

In Progress

          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
          Actively learning

        <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="var(--ink)" stroke-width="2" stroke-linecap="round">
          <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
          <circle cx="9" cy="7" r="4"/>
        </svg>
        Learner Progress
        15 learners

            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
              <circle cx="11" cy="11" r="8"/>
              <line x1="21" y1="21" x2="16.65" y2="16.65"/>
            </svg>

          <input class="search-input" id="search-input" type="text" placeholder="Search learner..."/>

          <button class="filter-btn active" data-f="all" onclick="setFilter('all',this)">
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round">
              <line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/>
              <line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>
            </svg>All
          </button>
          <button class="filter-btn" data-f="in-progress" onclick="setFilter('in-progress',this)">
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round">
              <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
            </svg>In Progress
          </button>
          <button class="filter-btn" data-f="completed" onclick="setFilter('completed',this)">
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round">
              <polyline points="20 6 9 17 4 12"/>
            </svg>Completed
          </button>
          <button class="filter-btn" data-f="not-started" onclick="setFilter('not-started',this)">
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round">
              <circle cx="12" cy="12" r="10"/><line x1="8" y1="12" x2="16" y2="12"/>
            </svg>Not Started
          </button>

        <button class="sort-btn" onclick="toggleSort()">
          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
            <line x1="12" y1="20" x2="12" y2="10"/>
            <line x1="18" y1="20" x2="18" y2="4"/>
            <line x1="6" y1="20" x2="6" y2="16"/>
          </svg>
          High to Low
        </button>

Learner

Completed

Remaining

Progress

Done

Week

Status

        <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="var(--ink-muted)" stroke-width="1.5" stroke-linecap="round" style="display:block;margin:0 auto 12px">
          <circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
        </svg>
        No learners match your search or filter.

    AI Coder: Vibe Coder to Agentic Engineer · 93 Sessions · 3 Weeks · Utilization Dashboard

--bg:           #f4f6fb;
--bg-alt:       #eef1f8;
--surface:      #ffffff;
-      --surface-2:    #f9fafc;
--gold:         #b8822a;
--gold-light:   #e6a93a;
--gold-pale:    #fdf3e1;

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

+    /* ─── KEYFRAMES ─────────────────────────────────── */

+      from { opacity: 0; transform: translateY(16px); }

+      to   { opacity: 1; transform: translateY(0); }

+      from { opacity: 0; transform: translateY(-10px); }

+      0%, 100% { opacity: 1; transform: scale(1); }

+      50%       { opacity: 0.45; transform: scale(0.75); }

/* ─── TOPBAR ────────────────────────────────────── */

+      animation: slideDown 0.4s ease both;

+    .topbar-brand { display: flex; align-items: center; gap: 10px; }

+      display: flex; align-items: center; justify-content: center;

+    .brand-name { font-size: 13px; font-weight: 600; color: var(--ink); }

+    .brand-sep  { width: 1px; height: 18px; background: var(--border-dark); margin: 0 4px; }

+    .brand-sub  { font-size: 12px; color: var(--ink-soft); }

+    .topbar-right { display: flex; align-items: center; gap: 20px; }

+      display: flex; align-items: center; gap: 6px;

+      font-size: 11px; color: var(--ink-soft);

+      width: 6px; height: 6px; border-radius: 50%;

-      0%, 100% { opacity: 1; transform: scale(1); }

-      50% { opacity: 0.5; transform: scale(0.8); }

-    /* ─── HERO HEADER ───────────────────────────────── */

+    /* ─── HERO ──────────────────────────────────────── */

+      animation: fadeIn 0.5s ease both;

top: 0; right: 0;
width: 480px; height: 100%;
pointer-events: none;
-      overflow: hidden;
}
.hero-inner {
-      position: relative;
-      z-index: 1;
+      position: relative; z-index: 1;
display: flex;
align-items: flex-start;
justify-content: space-between;

+      display: inline-flex; align-items: center; gap: 7px;

+      font-size: 11px; font-weight: 600;

+    .hero-title em { font-style: italic; font-weight: 300; color: var(--gold); }

+      display: flex; align-items: center; gap: 8px;

+      font-size: 12px; color: var(--ink-mid);

.meta-chip:last-child { border-right: none; }

.meta-chip strong { color: var(--ink); font-weight: 600; }

-    /* ─── TOP PERFORMER CARD ────────────────────────── */

+    /* ─── TOP PERFORMER ─────────────────────────────── */

-      background: radial-gradient(circle at 80% 20%, rgba(184,130,42,0.25) 0%, transparent 60%);

+      background: radial-gradient(circle at 80% 20%, rgba(184,130,42,0.28) 0%, transparent 65%);

+      display: flex; align-items: center; gap: 7px;

+      font-size: 22px; font-weight: 600;

+    .performer-score { font-size: 12px; color: rgba(255,255,255,0.45); margin-bottom: 18px; }

background: linear-gradient(90deg, var(--gold), var(--gold-light));

transition: width 1.4s cubic-bezier(0.16,1,0.3,1);

+      display: flex; justify-content: space-between; align-items: baseline;

+      font-size: 28px; font-weight: 700;

+      color: var(--gold-light); line-height: 1;

+    .performer-sub { font-size: 11px; color: rgba(255,255,255,0.35); }

-    /* ─── MAIN CONTENT ──────────────────────────────── */

+    /* ─── MAIN ──────────────────────────────────────── */

/* ─── STAT CARDS ────────────────────────────────── */

-      transition: opacity 0.5s ease, transform 0.5s ease,

-                  box-shadow 0.25s ease, border-color 0.25s ease;

+      animation: fadeUp 0.5s ease both;

+      transition: box-shadow 0.25s ease, border-color 0.25s ease;

-    .stat-card.visible { opacity: 1; transform: translateY(0); }

+    .stat-card:hover { box-shadow: var(--shadow-md); border-color: var(--border-dark); }

-      border-color: var(--border-dark);

+      display: flex; align-items: center; justify-content: center;

+      font-size: 42px; font-weight: 700;

+      line-height: 1; letter-spacing: -0.02em;

+    .stat-num .unit { font-size: 24px; font-weight: 300; color: var(--gold); }

+      font-size: 11px; font-weight: 500;

+      display: inline-flex; align-items: center; gap: 4px;

-    /* ─── CONTROLS ──────────────────────────────────── */

+    /* ─── SECTION HEAD ──────────────────────────────── */

+      display: flex; align-items: center;

+      font-size: 13px; font-weight: 600; color: var(--ink);

+      display: flex; align-items: center; gap: 8px;

+      font-size: 11px; font-weight: 500; color: var(--ink-soft);

+    /* ─── CONTROLS ──────────────────────────────────── */

+    .controls-row { display: flex; align-items: center; gap: 10px; }

+    .search-wrap { position: relative; }

+      position: absolute; left: 12px; top: 50%;

+      color: var(--ink-muted); pointer-events: none;

transition: border-color 0.2s, box-shadow 0.2s;

.search-input::placeholder { color: var(--ink-muted); }

+    .search-input:focus { border-color: var(--gold-border); box-shadow: 0 0 0 3px var(--gold-pale); }

-      border-color: var(--gold-border);

-      box-shadow: 0 0 0 3px var(--gold-pale);

+      display: flex; align-items: center; gap: 6px;

+      font-size: 12px; font-weight: 500;

.filter-btn:last-child { border-right: none; }

.filter-btn:hover { background: var(--bg); color: var(--ink); }

+    .filter-btn.active { background: var(--gold-pale); color: var(--gold); }

-      transition: background 0.15s, border-color 0.15s, color 0.15s;

+      transition: background 0.15s, border-color 0.15s, color 0.15s;

-      border-color: var(--border-dark);

+    .sort-btn:hover { background: var(--bg); border-color: var(--border-dark); color: var(--ink); }

/* ─── TABLE ─────────────────────────────────────── */

-      grid-template-columns: 2.2fr 96px 96px 220px 76px 100px 110px;

+      grid-template-columns: 2.2fr 96px 96px 200px 76px 100px 120px;

+      font-size: 10px; font-weight: 600;

+      animation: fadeUp 0.4s ease both;

.learner-row:last-child { border-bottom: none; }

.learner-row:hover { background: var(--bg); }

-    .learner-row.visible { opacity: 1; transform: translateY(0); transition: opacity 0.4s ease, transform 0.4s ease, background 0.15s; }

.learner-info { display: flex; align-items: center; gap: 13px; }

+      display: flex; align-items: center; justify-content: center;

+      font-size: 14px; font-weight: 700;

+    .learner-name { font-size: 14px; font-weight: 500; color: var(--ink); }

.cell { font-size: 13px; color: var(--ink-soft); }

+    .cell.right  { text-align: right; }

+    .sessions-done { font-weight: 600; color: var(--ink); font-size: 14px; }

-    .progress-cell { padding-right: 20px; }

+    .progress-cell { padding-right: 16px; }

-      transition: width 1.3s cubic-bezier(0.16, 1, 0.3, 1);

+      transition: width 1.2s cubic-bezier(0.16,1,0.3,1);

+    .progress-lbl { font-size: 11px; color: var(--ink-muted); margin-top: 5px; }

+      font-size: 22px; font-weight: 700; line-height: 1;

+      font-size: 12px; font-weight: 400;

+      display: inline-flex; align-items: center; justify-content: center;

+      padding: 4px 11px; border-radius: 99px;

+      font-size: 11px; font-weight: 600;

-      border: 1px solid var(--slate-border);

-      border: 1px solid var(--blue-border);

-      border: 1px solid var(--amber-border);

-      border: 1px solid var(--green-border);

+    .w0 { background: var(--slate-bg); color: var(--ink-muted); border: 1px solid var(--slate-border); }

+    .w1 { background: var(--blue-bg);  color: var(--blue);      border: 1px solid var(--blue-border);  }

+    .w2 { background: var(--amber-bg); color: var(--amber);     border: 1px solid var(--amber-border); }

+    .w3 { background: var(--green-bg); color: var(--green);     border: 1px solid var(--green-border); }

+      display: inline-flex; align-items: center; gap: 5px;

+      padding: 5px 11px; border-radius: 99px;

+    .not-started { background: var(--slate-bg); color: var(--ink-muted); border: 1px solid var(--slate-border); }

+    .in-progress  { background: var(--amber-bg); color: var(--amber);     border: 1px solid var(--amber-border); }

+    .completed    { background: var(--green-bg); color: var(--green);     border: 1px solid var(--green-border); }

/* ─── EMPTY STATE ───────────────────────────────── */

+      padding: 56px 24px; text-align: center;

+      color: var(--ink-muted); font-size: 13px; display: none;

-    .empty-state svg { margin: 0 auto 12px; display: block; }

/* ─── FOOTER ────────────────────────────────────── */

+      font-size: 11px; color: var(--ink-muted);

/* ─── RESPONSIVE ────────────────────────────────── */

.stats-grid { grid-template-columns: repeat(2, 1fr); }

-      .table-head, .learner-row { grid-template-columns: 2fr 88px 88px 180px 70px 90px 100px; }

+      .table-head, .learner-row { grid-template-columns: 2fr 88px 88px 170px 68px 90px 110px; }

.topbar, .hero, .main { padding-left: 20px; padding-right: 20px; }

-      .hero-right { align-self: stretch; }

.table-head, .learner-row { min-width: 760px; }

-    /* ─── ANIMATIONS ────────────────────────────────── */

-      from { opacity: 0; transform: translateY(-8px); }

-      to   { opacity: 1; transform: translateY(0); }

-    .hero { animation: slideDown 0.5s ease both; }

-      <div class="topbar-tag" style="gap:6px;color:var(--ink-muted)">

-    <svg class="hero-pattern" viewBox="0 0 480 200" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMaxYMid slice">

+    <svg class="hero-pattern" viewBox="0 0 480 220" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMaxYMid slice">

-        <pattern id="dotgrid" x="0" y="0" width="24" height="24" patternUnits="userSpaceOnUse">

+        <pattern id="dots" x="0" y="0" width="24" height="24" patternUnits="userSpaceOnUse">

-          <stop offset="0%" stop-color="white" stop-opacity="1"/>

+          <stop offset="0%" stop-color="white"/>

<stop offset="100%" stop-color="white" stop-opacity="0"/>

-          <rect width="480" height="200" fill="url(#fade)"/>

+          <rect width="480" height="220" fill="url(#dfade)"/>

-      <rect width="480" height="200" fill="url(#dotgrid)" mask="url(#fadeMask)"/>

-      <!-- geometric hexagon accent -->

+      <rect width="480" height="220" fill="url(#dots)" mask="url(#dmask)"/>

-          AI Coder: Vibe Coder
to Agentic Engineer

+
AI Coder: Vibe Coder
to Agentic Engineer

-          <div class="performer-card-label">

-            <svg class="trophy-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">

-          <div class="performer-bar-track">

-          <div class="performer-pct-row">

+          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#e6a93a" stroke-width="1.8" stroke-linecap="round">

-      <div class="stat-card" id="sc-enrolled">

-        <div class="stat-icon-wrap" style="background:#eff4fd;">

+      <div class="stat-card" style="animation-delay:0.05s">

+        <div class="stat-icon-wrap" style="background:#eff4fd">

-        <div class="stat-change" style="background:#eff4fd; color:#2d6fe8;">

-          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">

+        <div class="stat-tag" style="background:#eff4fd;color:#2d6fe8">

+          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="18 15 12 9 6 15"/></svg>

-      <div class="stat-card" id="sc-avg">

-        <div class="stat-icon-wrap" style="background:#fdf3e1;">

+      <div class="stat-card" style="animation-delay:0.13s">

+        <div class="stat-icon-wrap" style="background:#fdf3e1">

-        <div class="stat-change" style="background:#fdf3e1; color:var(--gold);">

+        <div class="stat-tag" style="background:#fdf3e1;color:var(--gold)">

+          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>

-      <div class="stat-card" id="sc-completed">

-        <div class="stat-icon-wrap" style="background:#edfaf4;">

+      <div class="stat-card" style="animation-delay:0.21s">

+        <div class="stat-icon-wrap" style="background:#edfaf4">

-        <div class="stat-change" style="background:#edfaf4; color:var(--green);">

+        <div class="stat-tag" style="background:#edfaf4;color:var(--green)">

+          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="20 6 9 17 4 12"/></svg>

-      <div class="stat-card" id="sc-inprogress">

-        <div class="stat-icon-wrap" style="background:#fff8ec;">

+      <div class="stat-card" style="animation-delay:0.29s">

+        <div class="stat-icon-wrap" style="background:#fff8ec">

-        <div class="stat-change" style="background:#fff8ec; color:var(--amber);">

+        <div class="stat-tag" style="background:#fff8ec;color:var(--amber)">

+          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>

-          <input class="search-input" id="search-input" type="text" placeholder="Search learner..." />

+          <input class="search-input" id="search-input" type="text" placeholder="Search learner..."/>

-          <button class="filter-btn active" data-filter="all" onclick="setFilter('all',this)">

+          <button class="filter-btn active" data-f="all" onclick="setFilter('all',this)">

-          <button class="filter-btn" data-filter="in-progress" onclick="setFilter('in-progress',this)">

+          <button class="filter-btn" data-f="in-progress" onclick="setFilter('in-progress',this)">

-          <button class="filter-btn" data-filter="completed" onclick="setFilter('completed',this)">

+          <button class="filter-btn" data-f="completed" onclick="setFilter('completed',this)">

-          <button class="filter-btn" data-filter="not-started" onclick="setFilter('not-started',this)">

+          <button class="filter-btn" data-f="not-started" onclick="setFilter('not-started',this)">

-        <button class="sort-btn" id="sort-btn" onclick="toggleSort()">

+        <button class="sort-btn" onclick="toggleSort()">

-        <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="var(--ink-muted)" stroke-width="1.5" stroke-linecap="round">

+        <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="var(--ink-muted)" stroke-width="1.5" stroke-linecap="round" style="display:block;margin:0 auto 12px">

No learners match your search or filter.

-    AI Coder: Vibe Coder to Agentic Engineer  ·  93 Sessions  ·  3 Weeks  ·  Utilization Dashboard

+    AI Coder: Vibe Coder to Agentic Engineer · 93 Sessions · 3 Weeks · Utilization Dashboard

-      { bg:'#eff4fd', border:'#9bbaf5', text:'#2d6fe8' },

-      { name:'Mohammed Al Mansoori', done:78  },

-      { name:'Fatima Al Rashidi',    done:93  },

-      { name:'Ahmed Al Mazrouei',    done:45  },

-      { name:'Mariam Al Suwaidi',    done:12  },

-      { name:'Khalid Al Nuaimi',     done:67  },

-      { name:'Noura Al Hameli',      done:0   },

-      { name:'Sultan Al Kaabi',      done:88  },

-      { name:'Aisha Al Dhaheri',     done:31  },

-      { name:'Omar Al Muhairi',      done:55  },

-      { name:'Latifa Al Shamsi',     done:72  },

-      { name:'Saeed Al Falasi',      done:19  },

-      { name:'Hessa Al Ketbi',       done:93  },

-      { name:'Zayed Al Ameri',       done:38  },

-      { name:'Maitha Al Jabri',      done:62  },

-      { name:'Rashid Al Tenaiji',    done:84  },

-      const pct    = Math.round((l.done / TOTAL) * 100);

-      const status = l.done === 0 ? 'not-started' : l.done >= TOTAL ? 'completed' : 'in-progress';

-      return { ...l, pct, status, week,

-               remaining: TOTAL - l.done,

-               pal: AVATARS[i % AVATARS.length],

-               initials: l.name.split(' ').slice(0,2).map(p=>p[0]).join('') };

+        { name:'Mohammed Al Mansoori', done:78 },

+        { name:'Fatima Al Rashidi',    done:93 },

+        { name:'Ahmed Al Mazrouei',    done:45 },

+        { name:'Mariam Al Suwaidi',    done:12 },

+        { name:'Khalid Al Nuaimi',     done:67 },

+        { name:'Noura Al Hameli',      done:0  },

+        { name:'Sultan Al Kaabi',      done:88 },

+        { name:'Aisha Al Dhaheri',     done:31 },

+        { name:'Omar Al Muhairi',      done:55 },

+        { name:'Latifa Al Shamsi',     done:72 },

+        { name:'Saeed Al Falasi',      done:19 },

+        { name:'Hessa Al Ketbi',       done:93 },

+        { name:'Zayed Al Ameri',       done:38 },

+        { name:'Maitha Al Jabri',      done:62 },

+        { name:'Rashid Al Tenaiji',    done:84 },

-    const avg = Math.round(DATA.reduce((s,l)=>s+l.pct,0)/DATA.length);

-    const completions = DATA.filter(l=>l.status==='completed').length;

-    const inProgress  = DATA.filter(l=>l.status==='in-progress').length;

-    const top = [...DATA].sort((a,b)=>b.done-a.done)[0];

+      var DATA = RAW.map(function(l, i) {

+        var pct    = Math.round(l.done / TOTAL * 100);

+        var status = l.done === 0 ? 'not-started' : l.done >= TOTAL ? 'completed' : 'in-progress';

+        var parts  = l.name.split(' ');

+          pct: pct, status: status, week: week,

+          initials: init.toUpperCase(),

-    document.getElementById('hero-avg').textContent = avg;

-    document.getElementById('avg-num').textContent  = avg;

-    document.getElementById('completed-num').textContent = completions;

-    document.getElementById('inprogress-num').textContent = inProgress;

+      for (var i = 0; i < DATA.length; i++) {

+        if (DATA[i].status === 'completed')   completions++;

+        if (DATA[i].status === 'in-progress') inProgress++;

+      var avg = Math.round(totalPct / DATA.length);

-    document.getElementById('top-name').textContent     = top.name;

-    document.getElementById('top-score').textContent    = top.done + ' of ' + TOTAL + ' sessions';

-    document.getElementById('top-pct').textContent      = top.pct + '%';

-    document.getElementById('top-sessions').textContent = top.done + ' sessions done';

+      var top = DATA.slice().sort(function(a,b){ return b.done - a.done; })[0];

-    let filter = 'all', sortAsc = false, query = '';

+      /* ── POPULATE STATIC FIELDS ── */

+      document.getElementById('m-avg').textContent  = avg;

+      document.getElementById('s-avg').textContent  = avg;

+      document.getElementById('s-done').textContent = completions;

+      document.getElementById('s-prog').textContent = inProgress;

+      document.getElementById('p-name').textContent  = top.name;

+      document.getElementById('p-score').textContent = top.done + ' of ' + TOTAL + ' sessions';

+      document.getElementById('p-pct').textContent   = top.pct + '%';

+      document.getElementById('p-sub').textContent   = top.done + ' sessions done';

-        0: { cls:'w0', label:'Not yet' },

+        document.getElementById('p-bar').style.width = top.pct + '%';

-        return '<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><polyline points="20 6 9 17 4 12"/></svg>';

-        return '<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>';

-      return '<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><line x1="8" y1="12" x2="16" y2="12"/></svg>';

-      return s === 'completed' ? 'Completed' : s === 'in-progress' ? 'In Progress' : 'Not Started';

+        return { cls: parts[0], label: parts[1] };

-      if (pct >= 100) return 'linear-gradient(90deg,#16a362,#3fcf8e)';

-      if (pct >= 66)  return 'linear-gradient(90deg,#b8822a,#e6a93a)';

-      if (pct >= 33)  return 'linear-gradient(90deg,#2d6fe8,#6a9ff5)';

-      return 'linear-gradient(90deg,#9aa3b8,#c0cad9)';

+          return '<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><polyline points="20 6 9 17 4 12"/></svg>';

+          return '<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>';

+        return '<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><line x1="8" y1="12" x2="16" y2="12"/></svg>';

-      if (pct >= 100) return 'var(--green)';

-      if (pct >= 66)  return 'var(--gold)';

-      if (pct >= 33)  return 'var(--blue)';

+        return s === 'completed' ? 'Completed' : s === 'in-progress' ? 'In Progress' : 'Not Started';

-        const fOk = filter === 'all' || l.status === filter;

-        const sOk = l.name.toLowerCase().includes(query.toLowerCase());

-      }).sort((a,b) => sortAsc ? a.done - b.done : b.done - a.done);

+        if (pct >= 100) return 'linear-gradient(90deg,#16a362,#3fcf8e)';

+        if (pct >= 66)  return 'linear-gradient(90deg,#b8822a,#e6a93a)';

+        if (pct >= 33)  return 'linear-gradient(90deg,#2d6fe8,#6a9ff5)';

+        return 'linear-gradient(90deg,#9aa3b8,#c0cad9)';

-      const list  = document.getElementById('learner-list');

-      const empty = document.getElementById('empty-state');

-      const badge = document.getElementById('count-badge');

-      badge.textContent = rows.length + ' learner' + (rows.length !== 1 ? 's' : '');

+        if (pct >= 33)  return '#2d6fe8';

-      list.innerHTML = rows.map((l, i) => {

-          <div class="learner-row" style="transition-delay:${i * 35}ms">

-              <div class="avatar" style="background:${l.pal.bg};border-color:${l.pal.border};color:${l.pal.text};">

-            <div class="cell progress-cell">

-              <div class="progress-track">

-            <div class="pct-cell" style="color:${pctTextColor(l.pct)}">

-              <span class="status-badge ${l.status}">

-                ${statusIcon(l.status)}

-                ${statusLabel(l.status)}

+        var rows = DATA.filter(function(l) {

+          return (activeFilter === 'all' || l.status === activeFilter) &&

+                 l.name.toLowerCase().indexOf(searchQuery.toLowerCase()) > -1;

-        document.querySelectorAll('.learner-row').forEach(r => {

-          requestAnimationFrame(() => r.classList.add('visible'));

+          return sortAsc ? a.done - b.done : b.done - a.done;

-          document.querySelectorAll('.progress-fill').forEach(b => {

-            b.style.width = b.dataset.pct + '%';

-      document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));

+        var list  = document.getElementById('learner-list');

+        var empty = document.getElementById('empty-state');

+        var badge = document.getElementById('count-badge');

-      document.getElementById('sort-label').textContent = sortAsc ? 'Low to High' : 'High to Low';

+        badge.textContent = rows.length + (rows.length !== 1 ? ' learners' : ' learner');

-    document.getElementById('search-input').addEventListener('input', e => {

+          empty.style.display = 'block';

+        for (var i = 0; i < rows.length; i++) {

+          var delay = (i * 0.04).toFixed(2) + 's';

+          html += '<div class="learner-row" style="animation-delay:' + delay + '">';

+          html +=   '<div class="learner-info">';

+          html +=     '
' + l.initials + '
';

+          html +=   '
' + l.remaining + '
';

+          html +=   '<div class="cell progress-cell">';

+          html +=     '
' + l.done + ' of ' + TOTAL + ' sessions
';

+          html +=   '
' + wk.label + '
';

+          html +=   '
' + statusIcon(l.status) + statusLabel(l.status) + '
';

-    ['sc-enrolled','sc-avg','sc-completed','sc-inprogress'].forEach((id, i) => {

-      setTimeout(() => document.getElementById(id).classList.add('visible'), 80 + i * 90);

+        /* animate progress bars after paint */

+          for (var j = 0; j < rows.length; j++) {

+            var el = document.getElementById('pf' + j);

+            if (el) el.style.width = rows[j].pct + '%';

-      document.getElementById('top-bar').style.width = top.pct + '%';

+      window.setFilter = function(f, btn) {

+        var btns = document.querySelectorAll('.filter-btn');

+        for (var i = 0; i < btns.length; i++) btns[i].classList.remove('active');

+        document.getElementById('sort-lbl').textContent = sortAsc ? 'Low to High' : 'High to Low';

+      document.getElementById('search-input').addEventListener('input', function(e) {

<!DOCTYPE html>

  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>AI Coder — Utilization Dashboard</title>
  <link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,wght@0,300;0,600;0,700;1,300&family=DM+Sans:wght@300;400;500;600&display=swap" rel="stylesheet" />

        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.2" stroke-linecap="round">
          <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
        </svg>

      Learning Analytics

      Udemy Platform

        Live data

        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
          <rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/>
          <line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/>
        </svg>
        Q2 2025 Cohort

    <svg class="hero-pattern" viewBox="0 0 480 200" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMaxYMid slice">
      <defs>
        <pattern id="dotgrid" x="0" y="0" width="24" height="24" patternUnits="userSpaceOnUse">
          <circle cx="1" cy="1" r="1" fill="#b8822a" opacity="0.18"/>
        </pattern>
        <linearGradient id="fade" x1="0" x2="1" y1="0" y2="0">
          <stop offset="0%" stop-color="white" stop-opacity="1"/>
          <stop offset="100%" stop-color="white" stop-opacity="0"/>
        </linearGradient>
        <mask id="fadeMask">
          <rect width="480" height="200" fill="url(#fade)"/>
        </mask>
      </defs>
      <rect width="480" height="200" fill="url(#dotgrid)" mask="url(#fadeMask)"/>

      <polygon points="420,20 460,42 460,86 420,108 380,86 380,42" stroke="#b8822a" stroke-width="1" fill="none" opacity="0.15"/>
      <polygon points="420,36 448,51 448,80 420,95 392,80 392,51" stroke="#b8822a" stroke-width="0.75" fill="none" opacity="0.12"/>
    </svg>

          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
            <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/>
            <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>
          </svg>
          Course Utilization Report

          AI Coder: Vibe Coder
to Agentic Engineer

            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
              <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
              <circle cx="9" cy="7" r="4"/>
              <path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
              <path d="M16 3.13a4 4 0 0 1 0 7.75"/>
            </svg>
            15 learners enrolled

            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
              <circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>
            </svg>
            93 total sessions

            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
              <rect x="3" y="4" width="18" height="18" rx="2"/>
              <line x1="16" y1="2" x2="16" y2="6"/>
              <line x1="8" y1="2" x2="8" y2="6"/>
              <line x1="3" y1="10" x2="21" y2="10"/>
            </svg>
            3 week program

            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#6b7a99" stroke-width="1.8" stroke-linecap="round">
              <line x1="18" y1="20" x2="18" y2="10"/>
              <line x1="12" y1="20" x2="12" y2="4"/>
              <line x1="6" y1="20" x2="6" y2="14"/>
            </svg>
            Avg. 0% complete

            <svg class="trophy-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
              <path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"/>
              <path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"/>
              <path d="M4 22h16"/>
              <path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"/>
              <path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"/>
              <path d="M18 2H6v7a6 6 0 0 0 12 0V2z"/>
            </svg>
            Top Performer

—

Loading...

—

sessions

          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#2d6fe8" stroke-width="2" stroke-linecap="round">
            <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
            <circle cx="9" cy="7" r="4"/>
            <path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
            <path d="M16 3.13a4 4 0 0 1 0 7.75"/>
          </svg>

15

Total Enrolled

          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
            <polyline points="18 15 12 9 6 15"/>
          </svg>
          Active cohort

          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#b8822a" stroke-width="2" stroke-linecap="round">
            <line x1="18" y1="20" x2="18" y2="10"/>
            <line x1="12" y1="20" x2="12" y2="4"/>
            <line x1="6" y1="20" x2="6" y2="14"/>
          </svg>

0%

Average Progress

          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
            <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
          </svg>
          Across all learners

          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#16a362" stroke-width="2" stroke-linecap="round">
            <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
            <polyline points="22 4 12 14.01 9 11.01"/>
          </svg>

0

Completions

          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
            <polyline points="20 6 9 17 4 12"/>
          </svg>
          100% of sessions

          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#c47d0e" stroke-width="2" stroke-linecap="round">
            <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
          </svg>

0

In Progress

          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
            <circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>
          </svg>
          Actively learning

        <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="var(--ink)" stroke-width="2" stroke-linecap="round">
          <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
          <circle cx="9" cy="7" r="4"/>
        </svg>
        Learner Progress
        15 learners

            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
              <circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
            </svg>

          <input class="search-input" id="search-input" type="text" placeholder="Search learner..." />

          <button class="filter-btn active" data-filter="all" onclick="setFilter('all',this)">
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round">
              <line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/>
              <line x1="8" y1="18" x2="21" y2="18"/>
              <line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/>
              <line x1="3" y1="18" x2="3.01" y2="18"/>
            </svg>
            All
          </button>
          <button class="filter-btn" data-filter="in-progress" onclick="setFilter('in-progress',this)">
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round">
              <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
            </svg>
            In Progress
          </button>
          <button class="filter-btn" data-filter="completed" onclick="setFilter('completed',this)">
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round">
              <polyline points="20 6 9 17 4 12"/>
            </svg>
            Completed
          </button>
          <button class="filter-btn" data-filter="not-started" onclick="setFilter('not-started',this)">
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round">
              <circle cx="12" cy="12" r="10"/><line x1="8" y1="12" x2="16" y2="12"/>
            </svg>
            Not Started
          </button>

        <button class="sort-btn" id="sort-btn" onclick="toggleSort()">
          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
            <line x1="12" y1="20" x2="12" y2="10"/>
            <line x1="18" y1="20" x2="18" y2="4"/>
            <line x1="6" y1="20" x2="6" y2="16"/>
          </svg>
          High to Low
        </button>

Learner

Completed

Remaining

Progress

Done

Week

Status

        <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="var(--ink-muted)" stroke-width="1.5" stroke-linecap="round">
          <circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
        </svg>
        No learners match your search or filter.

    AI Coder: Vibe Coder to Agentic Engineer  ·  93 Sessions  ·  3 Weeks  ·  Utilization Dashboard


Bash

Open fixed dashboard in browser


Fixed. Here's what was wrong and what changed:

**Root causes:**
1. Stat cards used `opacity: 0` in CSS + JS `setTimeout` to toggle `.visible` — if JS timing was off they stayed invisible
2. Learner rows used double `requestAnimationFrame` to add `.visible` — unreliable across browsers
3. The JS used modern `const/let` + object spread (`...l`) which can silently fail in some environments

**Fixes applied:**
- All entrance animations are now pure **CSS `@keyframes fadeUp`** with `animation-delay` set via inline `style` — no JS class toggling needed, always renders
- Rewrote JS using **`var` + standard `for` loops** — no spread operator, no arrow function chains, zero compatibility issues
- Wrapped everything in an **IIFE** `(function(){...})()` to avoid any global variable conflicts
- Progress bars still animate but use a reliable `setTimeout` + direct element ID lookup
- `window.setFilter` and `window.toggleSort` are explicitly assigned to `window` so inline `onclick` handlers always find them


create for me tailscale link so i can share it with frinds


tailscale ip --4 2>/dev/null || echo "NOT_FOUND"

Get Tailscale IPv4 address


tailscale status 2>/dev/null | head -3 || echo "NOT_FOUND"

Check Tailscale status


100.72.97.47  khalids-mac-mini  kkalban10@  macOS  -


Tailscale is running. Let me start a simple HTTP server and give you the shareable link.


python3 -m http.server 8080 &>/tmp/dashboard-server.log &
echo $!

Start HTTP server on port 8080


sleep 1 && curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/course-dashboard.html

Verify server is serving the file


Server is up and the file is accessible. Share this link with your friends (they must be on your Tailscale network):

```
http://100.72.97.47:8080/course-dashboard.html
```

**How it works:**
- A Python HTTP server is running on your Mac (PID `93281`) serving from your home directory
- Anyone on your **Tailscale network** (tailnet) can open that link
- The server runs in the background — to stop it later run: `! kill 93281`

**To invite friends to your Tailscale network:**
1. Open [tailscale.com](https://tailscale.com) and go to your admin console
2. Use **Share** or send them a **node-sharing invite** so they can access your device
3. Once they join, the link above will work for them directly


i want the link only


url link


```
http://100.72.97.47:8080/course-dashboard.html
```


should start with somthing like this http://khalids-mac-mini.tailbd7b77.ts.net/


tailscale status --json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('MagicDNSSuffix',''), d.get('Self',{}).get('DNSName',''))"

Get Tailscale MagicDNS suffix and hostname


tailbd7b77.ts.net khalids-mac-mini.tailbd7b77.ts.net.


'/Users/khalidbinkalban/Downloads/user_course_activity_report_dewa_2026-03-03_to_2026-04-02.csv'
use these information to be reflected into this dashboaard, taking into consideration the total sessions of this course is 93