templates/website/page/indexes/support.html.twig line 1

  1. <!DOCTYPE html>
  2. <html lang="en" data-theme="dark">
  3. <head>
  4.     <meta charset="UTF-8" />
  5.     <meta name="viewport" content="width=device-width, initial-scale=1" />
  6.     <title>Vrshikyans — Support</title>
  7.     <meta name="description"
  8.           content="Support for Vrshikyans TOEFL, SAT, IELTS, ACT. Tutors, tests, subscriptions. Ask and track your requests." />
  9.     <link rel="preconnect" href="https://fonts.googleapis.com">
  10.     <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  11.     <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800;900&display=swap" rel="stylesheet">
  12.     <link rel="icon" href="{{ asset('students/Vrshikyan_logo.ico') }}" />
  13.     <meta name="color-scheme" content="dark light">
  14.     <style>
  15.         :root {
  16.             --bg: #0e1220;
  17.             --bg-2: #0c152b;
  18.             --surface: rgba(255, 255, 255, .07);
  19.             --surface-strong: rgba(12, 18, 40, .72);
  20.             --card: rgba(20, 26, 52, .85);
  21.             --border: rgba(140, 170, 255, .18);
  22.             --text: #f5f8ff;
  23.             --muted: #c7d1f2;
  24.             --accent: #78a6ff;
  25.             --accent-2: #66e6d2;
  26.             --green: #35d49f;
  27.             --violet: #a06bff;
  28.             --shadow-1: 0 10px 24px rgba(0, 0, 0, .28);
  29.             --shadow-2: 0 22px 60px rgba(0, 0, 0, .40);
  30.             --radius: 18px;
  31.             --blur: 14px;
  32.             --speed: .25s;
  33.             --fast: .15s;
  34.             --g1: #1c2550;
  35.             --g2: #142762;
  36.             --nav-h: 64px;
  37.         }
  38.         html[data-theme="light"] {
  39.             --bg: #f7f8fd;
  40.             --bg-2: #eef2ff;
  41.             --surface: rgba(255, 255, 255, .65);
  42.             --surface-strong: rgba(255, 255, 255, .92);
  43.             --card: rgba(255, 255, 255, .95);
  44.             --border: rgba(23, 32, 58, .12);
  45.             --text: #0f1428;
  46.             --muted: #3e4a74;
  47.             --shadow-1: 0 8px 20px rgba(23, 32, 58, .10);
  48.             --shadow-2: 0 24px 60px rgba(23, 32, 58, .16);
  49.             --g1: #dfe7ff;
  50.             --g2: #cfe0ff;
  51.         }
  52.         * {
  53.             box-sizing: border-box
  54.         }
  55.         html,
  56.         body {
  57.             height: 100%;
  58.             margin: 0
  59.         }
  60.         body {
  61.             font-family: Inter, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans";
  62.             color: var(--text);
  63.             line-height: 1.65;
  64.             overflow-x: hidden;
  65.             background:
  66.                     radial-gradient(160vw 120vh at -20vw -20vh, var(--g1) 0%, rgba(0, 0, 0, 0) 60%),
  67.                     radial-gradient(160vw 120vh at 120vw -10vh, var(--g2) 0%, rgba(0, 0, 0, 0) 55%),
  68.                     linear-gradient(180deg, var(--bg) 0%, var(--bg-2) 100%);
  69.             background-attachment: fixed, fixed, fixed;
  70.             -webkit-font-smoothing: antialiased;
  71.             -moz-osx-font-smoothing: grayscale;
  72.         }
  73.         body::before {
  74.             content: "";
  75.             position: fixed;
  76.             inset: 0;
  77.             z-index: 0;
  78.             pointer-events: none;
  79.             opacity: .05;
  80.             background-image: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0nNjQnIGhlaWdodD0nNjQnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Zyc+PGZpbHRlciBpZD0nbi1uJz48ZmVUdXJidWxlbmNlIHR5cGU9J2ZyYWN0YWxOb2lzZScgYmFzZUZyZXF1ZW5jeT0nMC44JyBudW1PY3RhdmVzPScyJy8+PC9maWx0ZXI+PHJlY3Qgd2lkdGg9JzEwMCUnIGhlaWdodD0nMTAwJScgZmlsbD0nd2hpdGUnIGZpbHRlcj0ndXJsKCMnKyc+PC9yZWN0Pjwvc3ZnPg==");
  81.             background-size: 240px 240px;
  82.             z-index: 0;
  83.         }
  84.         /* Nav */
  85.         .nav {
  86.             position: sticky;
  87.             top: 0;
  88.             z-index: 10;
  89.             height: var(--nav-h);
  90.             background: var(--surface-strong);
  91.             border-bottom: 1px solid var(--border);
  92.             backdrop-filter: blur(var(--blur)) saturate(140%);
  93.         }
  94.         .nav-inner {
  95.             width: min(1120px, 92%);
  96.             margin: 0 auto;
  97.             height: 100%;
  98.             display: flex;
  99.             align-items: center;
  100.             gap: 14px;
  101.         }
  102.         .brand {
  103.             display: flex;
  104.             gap: 12px;
  105.             align-items: center;
  106.             text-decoration: none;
  107.             color: var(--text);
  108.             font-weight: 900;
  109.             letter-spacing: .2px;
  110.         }
  111.         .logo {
  112.             width: 38px;
  113.             height: 38px;
  114.             border-radius: 12px;
  115.             background: linear-gradient(180deg, #6ea3ff, #4b82ff);
  116.             box-shadow: 0 10px 22px rgba(76, 130, 255, .22);
  117.             overflow: hidden;
  118.         }
  119.         .logo img {
  120.             width: 100%;
  121.             height: 100%;
  122.             object-fit: cover;
  123.             display: block
  124.         }
  125.         .spacer {
  126.             flex: 1
  127.         }
  128.         .theme-btn,
  129.         .cta {
  130.             display: inline-flex;
  131.             align-items: center;
  132.             justify-content: center;
  133.             height: 40px;
  134.             border-radius: 12px;
  135.         }
  136.         .theme-btn {
  137.             width: 40px;
  138.             border: 1px solid var(--border);
  139.             background: rgba(255, 255, 255, .08);
  140.             color: var(--text);
  141.             cursor: pointer;
  142.         }
  143.         .cta {
  144.             padding: 0 22px;
  145.             background: linear-gradient(180deg, #35d49f, #18b98a);
  146.             color: #061a11;
  147.             font-weight: 900;
  148.             text-decoration: none;
  149.             border: 0;
  150.             box-shadow: 0 10px 24px rgba(24, 185, 138, .22);
  151.         }
  152.         .inner {
  153.             width: min(1120px, 92%);
  154.             margin: 28px auto;
  155.             position: relative;
  156.             z-index: 1;
  157.         }
  158.         .h1 {
  159.             margin: 10px 0 4px;
  160.             font-size: clamp(34px, 4.8vw, 58px);
  161.             font-weight: 900;
  162.             text-shadow: 0 2px 16px rgba(0, 0, 0, .28);
  163.         }
  164.         .lead {
  165.             margin: 0;
  166.             color: var(--muted);
  167.         }
  168.         /*  layout */
  169.         .support-band {
  170.             margin-top: 18px;
  171.             border: 1px solid var(--border);
  172.             border-radius: var(--radius);
  173.             background: linear-gradient(180deg, rgba(255, 255, 255, .08), rgba(255, 255, 255, .04));
  174.             padding: 16px;
  175.             display: flex;
  176.             align-items: center;
  177.             justify-content: space-between;
  178.             gap: 14px;
  179.             flex-wrap: wrap;
  180.         }
  181.         .support-layout {
  182.             margin-top: 18px;
  183.             display: grid;
  184.             grid-template-columns: minmax(0, 320px) minmax(0, 1fr);
  185.             gap: 16px;
  186.         }
  187.         @media (max-width:900px) {
  188.             .support-layout {
  189.                 grid-template-columns: 1fr;
  190.             }
  191.         }
  192.         .card {
  193.             padding: 16px;
  194.             border-radius: var(--radius);
  195.             border: 1px solid var(--border);
  196.             background: var(--card);
  197.             box-shadow: var(--shadow-1);
  198.             width: 100%;
  199.         }
  200.         .card h3 {
  201.             margin: 0 0 6px;
  202.         }
  203.         .btn {
  204.             height: 40px;
  205.             padding: 0 16px;
  206.             border-radius: 12px;
  207.             border: 0;
  208.             font-weight: 900;
  209.             cursor: pointer;
  210.             display: inline-flex;
  211.             align-items: center;
  212.             justify-content: center;
  213.             gap: 6px;
  214.         }
  215.         .btn.primary {
  216.             background: linear-gradient(180deg, #78a6ff, #4b82ff);
  217.             color: #08152c;
  218.             box-shadow: 0 10px 26px rgba(120, 166, 255, .26);
  219.         }
  220.         .btn.ghost {
  221.             background: rgba(255, 255, 255, .06);
  222.             border: 1px solid var(--border);
  223.             color: var(--text);
  224.         }
  225.         .btn.subtle {
  226.             background: transparent;
  227.             border: 0;
  228.             color: var(--muted);
  229.             font-size: 13px;
  230.             padding: 0 6px;
  231.             height: auto;
  232.         }
  233.         label {
  234.             font-weight: 800;
  235.             display: block;
  236.             margin: 10px 0 4px;
  237.             font-size: 14px;
  238.         }
  239.         input[type="text"],
  240.         select,
  241.         textarea {
  242.             width: 100%;
  243.             border: 1px solid var(--border);
  244.             background: rgba(255, 255, 255, .06);
  245.             padding: 9px 11px;
  246.             color: var(--text);
  247.             border-radius: 12px;
  248.             outline: none;
  249.             font: inherit;
  250.         }
  251.         textarea {
  252.             resize: vertical;
  253.             min-height: 130px;
  254.         }
  255.         /* bigger */
  256.         option {
  257.             color: navy;
  258.         }
  259.         .row {
  260.             display: grid;
  261.             grid-template-columns: 1fr 1fr;
  262.             gap: 10px;
  263.         }
  264.         @media (max-width:640px) {
  265.             .row {
  266.                 grid-template-columns: 1fr;
  267.             }
  268.         }
  269.         /* History panel */
  270.         .history-header {
  271.             display: flex;
  272.             align-items: center;
  273.             justify-content: space-between;
  274.             gap: 8px;
  275.             margin-bottom: 8px;
  276.         }
  277.         .history-list {
  278.             display: flex;
  279.             flex-direction: column;
  280.             gap: 8px;
  281.             max-height: 420px;
  282.             overflow: auto;
  283.             padding-right: 4px;
  284.         }
  285.         .ticket-row {
  286.             border-radius: 14px;
  287.             border: 1px solid var(--border);
  288.             background: rgba(255, 255, 255, .04);
  289.             padding: 10px 10px;
  290.             text-align: left;
  291.             width: 100%;
  292.             cursor: pointer;
  293.             display: flex;
  294.             flex-direction: column;
  295.             gap: 4px;
  296.             position: relative;
  297.         }
  298.         .ticket-row:hover {
  299.             background: rgba(255, 255, 255, .07);
  300.         }
  301.         .ticket-row.active {
  302.             border-color: var(--accent);
  303.             box-shadow: 0 0 0 1px rgba(120, 166, 255, .35);
  304.         }
  305.         .ticket-title {
  306.             font-weight: 800;
  307.             font-size: 14px;
  308.         }
  309.         .ticket-meta {
  310.             font-size: 13px;
  311.             color: var(--muted);
  312.         }
  313.         .ticket-badges {
  314.             display: flex;
  315.             flex-wrap: wrap;
  316.             gap: 6px;
  317.             margin-top: 2px;
  318.             font-size: 12px;
  319.         }
  320.         .ticket-badge {
  321.             padding: 3px 8px;
  322.             border-radius: 999px;
  323.             border: 1px solid var(--border);
  324.             background: rgba(255, 255, 255, .06);
  325.             color: var(--muted);
  326.             font-weight: 700;
  327.         }
  328.         .ticket-status {
  329.             position: absolute;
  330.             right: 10px;
  331.             top: 10px;
  332.             padding: 3px 8px;
  333.             border-radius: 999px;
  334.             font-size: 11px;
  335.             font-weight: 800;
  336.             letter-spacing: .03em;
  337.             text-transform: uppercase;
  338.             border: 1px solid rgba(210, 255, 230, .28);
  339.             color: #0f2016;
  340.             background: rgba(53, 212, 159, .86);
  341.         }
  342.         .ticket-status.closed {
  343.             background: rgba(160, 107, 255, .82);
  344.             border-color: rgba(230, 210, 255, .4);
  345.             color: #100621;
  346.         }
  347.         /* Chat card */
  348.         .chat-card {
  349.             display: flex;
  350.             flex-direction: column;
  351.             gap: 10px;
  352.             min-height: 360px;
  353.         }
  354.         .chat-header {
  355.             display: flex;
  356.             align-items: center;
  357.             justify-content: space-between;
  358.             gap: 8px;
  359.             flex-wrap: wrap;
  360.         }
  361.         .chat-header-main {
  362.             display: flex;
  363.             flex-direction: column;
  364.             gap: 2px;
  365.         }
  366.         .chat-title {
  367.             font-weight: 900;
  368.             font-size: 18px;
  369.         }
  370.         .chat-sub {
  371.             font-size: 13px;
  372.             color: var(--muted);
  373.         }
  374.         .chat-chips {
  375.             display: flex;
  376.             flex-wrap: wrap;
  377.             gap: 6px;
  378.             font-size: 12px;
  379.         }
  380.         .chip {
  381.             padding: 4px 9px;
  382.             border-radius: 999px;
  383.             border: 1px solid var(--border);
  384.             background: rgba(255, 255, 255, .08);
  385.             font-weight: 800;
  386.             color: var(--muted);
  387.         }
  388.         .back-btn {
  389.             display: none;
  390.         }
  391.         body.creating .back-btn {
  392.             display: inline-flex;
  393.         }
  394.         .chat-body {
  395.             flex: 1;
  396.             min-height: 260px;
  397.             border-radius: 16px;
  398.             border: 1px solid var(--border);
  399.             background: linear-gradient(160deg, rgba(255, 255, 255, .06), rgba(15, 19, 32, .6));
  400.             padding: 12px;
  401.             overflow: auto;
  402.             max-height: 420px;
  403.             width: 100%;
  404.         }
  405.         .chat-empty {
  406.             height: 100%;
  407.             display: flex;
  408.             align-items: center;
  409.             justify-content: center;
  410.             text-align: center;
  411.             color: var(--muted);
  412.             font-size: 14px;
  413.             padding: 12px;
  414.         }
  415.         /* Messages */
  416.         .msg {
  417.             max-width: min(80%, 480px);
  418.             display: flex;
  419.             flex-direction: column;
  420.             gap: 3px;
  421.             margin-bottom: 10px;
  422.         }
  423.         .msg-user {
  424.             margin-left: auto;
  425.             align-items: flex-end;
  426.         }
  427.         .msg-admin {
  428.             margin-right: auto;
  429.             align-items: flex-start;
  430.         }
  431.         .msg-meta {
  432.             font-size: 11px;
  433.             color: var(--muted);
  434.             opacity: .9;
  435.         }
  436.         .msg-bubble {
  437.             padding: 9px 11px;
  438.             border-radius: 16px;
  439.             background: rgba(255, 255, 255, .10);
  440.             border: 1px solid rgba(255, 255, 255, .18);
  441.             font-size: 14px;
  442.             position: relative;
  443.         }
  444.         .msg-user .msg-bubble {
  445.             background: linear-gradient(180deg, #78a6ff, #4b82ff);
  446.             color: #050c1a;
  447.             border-color: rgba(24, 185, 138, .0);
  448.         }
  449.         .msg-admin .msg-bubble {
  450.             background: rgba(8, 14, 36, .9);
  451.             border-color: rgba(140, 170, 255, .35);
  452.         }
  453.         .msg-photos {
  454.             display: flex;
  455.             flex-wrap: wrap;
  456.             gap: 6px;
  457.             margin-top: 6px;
  458.         }
  459.         .msg-photos img {
  460.             width: 90px;
  461.             height: 90px;
  462.             border-radius: 10px;
  463.             object-fit: cover;
  464.             border: 1px solid rgba(255, 255, 255, .25);
  465.         }
  466.         /* Category step */
  467.         .category-step {
  468.             border-radius: 16px;
  469.             border: 1px dashed var(--border);
  470.             padding: 10px 10px 4px 10px;
  471.             background: rgba(255, 255, 255, .03);
  472.             font-size: 14px;
  473.             width: 100%;
  474.         }
  475.         .category-grid {
  476.             display: grid;
  477.             grid-template-columns: 1.1fr 1fr;
  478.             gap: 10px;
  479.         }
  480.         @media (max-width:640px) {
  481.             .category-grid {
  482.                 grid-template-columns: 1fr;
  483.             }
  484.         }
  485.         .subscription-extra {
  486.             margin-top: 6px;
  487.             display: none;
  488.         }
  489.         .topic-row {
  490.             margin-top: 2px;
  491.         }
  492.         /* Uploader for composer */
  493.         .composer {
  494.             margin-top: 8px;
  495.             border-radius: 16px;
  496.             border: 1px solid var(--border);
  497.             background: rgba(0, 0, 0, .18);
  498.             padding: 10px;
  499.             display: flex;
  500.             flex-direction: column;
  501.             gap: 8px;
  502.             width: 100%;
  503.         }
  504.         .composer-top {
  505.             display: flex;
  506.             gap: 10px;
  507.             align-items: flex-start;
  508.             flex-wrap: wrap;
  509.         }
  510.         .composer-top textarea {
  511.             flex: 1;
  512.         }
  513.         .composer-actions {
  514.             display: flex;
  515.             align-items: center;
  516.             justify-content: space-between;
  517.             gap: 10px;
  518.             flex-wrap: wrap;
  519.         }
  520.         .uploader {
  521.             border: 1px dashed var(--border);
  522.             border-radius: 12px;
  523.             padding: 8px;
  524.             text-align: center;
  525.             background: rgba(255, 255, 255, .04);
  526.             font-size: 13px;
  527.             flex: 1;
  528.         }
  529.         .uploader input {
  530.             display: none;
  531.         }
  532.         .uploader .hint {
  533.             color: var(--muted);
  534.             font-size: 12px;
  535.             margin-top: 2px;
  536.         }
  537.         .thumbs {
  538.             display: flex;
  539.             flex-wrap: wrap;
  540.             gap: 6px;
  541.             margin-top: 6px;
  542.         }
  543.         .thumb {
  544.             position: relative;
  545.             width: 80px;
  546.             height: 80px;
  547.             border-radius: 10px;
  548.             overflow: hidden;
  549.             border: 1px solid var(--border);
  550.             background: rgba(255, 255, 255, .08);
  551.             display: grid;
  552.             place-items: center;
  553.         }
  554.         .thumb img {
  555.             width: 100%;
  556.             height: 100%;
  557.             object-fit: cover;
  558.         }
  559.         .thumb button {
  560.             position: absolute;
  561.             top: 4px;
  562.             right: 4px;
  563.             border-radius: 999px;
  564.             border: 1px solid var(--border);
  565.             background: rgba(0, 0, 0, .5);
  566.             color: #fff;
  567.             font-size: 11px;
  568.             padding: 1px 6px;
  569.             cursor: pointer;
  570.         }
  571.         .category-step,
  572.         .composer {
  573.             display: none;
  574.         }
  575.         body.can-write .category-step,
  576.         body.can-write .composer {
  577.             display: block;
  578.         }
  579.         /* Mobile safety */
  580.         img,
  581.         video {
  582.             max-width: 100%;
  583.             height: auto;
  584.         }
  585.         .chat-body,
  586.         .card,
  587.         .support-layout {
  588.             max-width: 100%;
  589.             overflow-x: hidden;
  590.         }
  591.         /* Footer */
  592.         footer {
  593.             margin: 34px 0 18px;
  594.             position: relative;
  595.             z-index: 1;
  596.         }
  597.         .foot {
  598.             width: min(1120px, 92%);
  599.             margin: 0 auto;
  600.             border: 1px solid var(--border);
  601.             border-radius: var(--radius);
  602.             background: linear-gradient(180deg, rgba(255, 255, 255, .08), rgba(255, 255, 255, .04));
  603.             padding: 16px;
  604.             display: grid;
  605.             grid-template-columns: 1fr 1fr;
  606.             gap: 14px;
  607.         }
  608.         @media (max-width:640px) {
  609.             .foot {
  610.                 grid-template-columns: 1fr;
  611.             }
  612.         }
  613.         body.creating .history-panel {
  614.             display: none;
  615.         }
  616.         body.creating .support-layout {
  617.             grid-template-columns: 1fr;
  618.         }
  619.     </style>
  620.     <link rel="stylesheet" href="{{ asset('css/navbar.css') }}" />
  621.     <script>
  622.   (() => {
  623.     const saved = localStorage.getItem('theme');
  624.     if (saved) {
  625.       document.documentElement.setAttribute('data-theme', saved);
  626.     } else {
  627.       document.documentElement.setAttribute(
  628.         'data-theme',
  629.         matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
  630.       );
  631.     }
  632.   })();
  633. </script>
  634. </head>
  635. <body>
  636.   <nav class="nav" role="navigation" aria-label="Primary">
  637.   <div class="nav-inner">
  638.     <a class="brand" href="/" aria-label="Exam-hub">
  639.       <span class="logo" aria-hidden="true" style="overflow: hidden;">
  640.         <img src="../students/Vrshikyan_logo.ico" width="39px" alt="Vrshikyans logo">
  641.       </span>
  642.       <span>Vrshikyans</span>&nbsp;&nbsp;
  643.     </a>
  644.     <div class="nav-links">
  645.       <a class="nav-link" data-section="toefl" href="./test-selection?type=toefl" id="toeflNav">TOEFL</a>
  646.       <a class="nav-link" data-section="sat" href="./test-sat-selection#sat" >SAT</a>
  647.       <a class="nav-link" data-section="act" href="./test-sat-selection#act">ACT</a>
  648.       <a class="nav-link" data-section="reading" href="./test-selection?type=readingPractice" id="readingPrNav">Reading Practice</a>
  649.       <a class="nav-link active" data-section="support" href="./support">Support</a>
  650.       <a class="nav-link" data-section="reviews" href="./reviews">Reviews</a>
  651.     </div>
  652.     <button class="mobile-menu-btn" id="mobileMenuBtn">☰</button>
  653.     <div class="spacer"></div>
  654.     <button id="themeToggle" class="theme-btn" aria-label="Toggle theme">🌑</button>
  655.     <a class="cta" id="startTop" href="../indexes/account" aria-label="Account"
  656.       style="width: 40px; height: 40px; background: whitesmoke;">👤</a>
  657.   </div>
  658. </nav>
  659. <div class="mobile-menu" id="mobileMenu">
  660.   <div class="mobile-nav-links">
  661.     <a class="mobile-nav-link" href="./test-selection?type=toefl">TOEFL</a>
  662.     <a class="mobile-nav-link" href="./test-sat-selection#sat">SAT</a>
  663.     <a class="mobile-nav-link" href="./test-sat-selection#act">ACT</a>
  664.     <a class="mobile-nav-link" href="./test-selection?type=readingPractice">Reading Practice</a>
  665.     <a class="mobile-nav-link" href="./support">Support</a>
  666.     <a class="mobile-nav-link" href="./reviews">Reviews</a>
  667.   </div>
  668. </div>
  669. <header class="inner">
  670.     <h1 class="h1">Support</h1>
  671.     <p class="lead">Tutors, tests, subscriptions — ask anything and keep all your requests in one place.</p>
  672.     <div class="support-band">
  673.         <div>
  674.             <strong>Need help fast?</strong>
  675.             <p class="lead" style="margin:.2rem 0 0 0; font-size:14px;">
  676.                 Open a new request and we’ll reply in the same chat, just like a messenger.
  677.             </p>
  678.         </div>
  679.         <button class="btn primary" id="newRequestBandBtn">
  680.             ✨ New request
  681.         </button>
  682.     </div>
  683.     <div class="support-layout" id="supportMain">
  684.         <aside class="card history-panel" aria-label="Support history">
  685.             <div class="history-header">
  686.                 <div>
  687.                     <h3>Your requests</h3>
  688.                     <p class="lead" style="margin:.1rem 0 0 0; font-size:13px;">
  689.                         Tap any request to reopen the chat.
  690.                     </p>
  691.                 </div>
  692.                 <button class="btn ghost" id="newRequestBtn">+ New</button>
  693.             </div>
  694.             <div class="history-list" id="historyList"></div>
  695.         </aside>
  696.         <section class="card chat-card" aria-label="Support conversation">
  697.             <div class="chat-header">
  698.                 <div class="chat-header-main">
  699.                     <div class="chat-title" id="chatTitle">Support inbox</div>
  700.                     <div class="chat-sub" id="chatSubtitle">
  701.                         Choose a request on the left or start a new one.
  702.                     </div>
  703.                 </div>
  704.                 <div style="display:flex; gap:6px; align-items:center; flex-wrap:wrap;">
  705.                     <div class="chat-chips" id="chatChips"></div>
  706.                     <button class="btn ghost back-btn" id="backToList">← Back to requests</button>
  707.                 </div>
  708.             </div>
  709.             <div class="category-step" id="categoryStep">
  710.                 <div style="display:flex; justify-content:space-between; align-items:center; gap:8px;">
  711.                         <span
  712.                                 style="font-size:12px; text-transform:uppercase; letter-spacing:.08em; color:var(--muted); font-weight:800;">
  713.                             Request details
  714.                         </span>
  715.                     <span id="categoryHint" style="font-size:12px; color:var(--muted);">
  716.                             Pick a category to unlock the message box.
  717.                         </span>
  718.                 </div>
  719.                 <div class="category-grid" style="margin-top:4px;">
  720.                     <div>
  721.                         <label for="categorySelect">I need help with</label>
  722.                         <select id="categorySelect">
  723.                             <option value="">Choose a category</option>
  724.                             <option value="Tutors">Tutors</option>
  725.                             <option value="Info">Information about tests</option>
  726.                             <option value="Subscriptions">Subscriptions</option>
  727.                         </select>
  728.                     </div>
  729.                     <div id="categorySecondaryWrapper" style="display:none;">
  730.                         <label id="secondaryLabel" for="secondarySelect">Exam</label>
  731.                         <select id="secondarySelect"></select>
  732.                     </div>
  733.                 </div>
  734.                 <div class="subscription-extra" id="subscriptionExtra">
  735.                     <p class="lead" style="font-size:13px; margin:.4rem 0 0 0;">
  736.                         Billing questions, upgrades, cancellations — you can also check your plan here:
  737.                     </p>
  738.                     <a href="/#pricing" id="subscriptionLink" class="btn primary"
  739.                        style="margin-top:6px; font-size:13px;">
  740.                         ↗ Open subscription page
  741.                     </a>
  742.                 </div>
  743.                 <div class="row topic-row">
  744.                     <div>
  745.                         <label for="topicInput">Topic (optional)</label>
  746.                         <input id="topicInput" type="text"
  747.                                placeholder="e.g., SAT tutor, TOEFL test date, Subscription plan">
  748.                         <div class="lead" style="font-size:12px; margin:.2rem 0 0 0;">
  749.                             This short title will appear in your history.
  750.                         </div>
  751.                     </div>
  752.                 </div>
  753.             </div>
  754.             <div class="chat-body" id="chatBody">
  755.                 <div class="chat-empty" id="chatEmpty">
  756.                     <div>
  757.                         <p style="margin:0 0 4px 0;"><strong>No request selected</strong></p>
  758.                         <p style="margin:0; font-size:13px;">
  759.                             Start a new request or choose one from the left.
  760.                         </p>
  761.                     </div>
  762.                 </div>
  763.             </div>
  764.             <form class="composer" id="composerForm" autocomplete="off">
  765.                 <div class="composer-top">
  766.                         <textarea id="messageInput"
  767.                                   placeholder="Type your message… (at least a few characters)"></textarea>
  768.                     <div class="uploader" id="uploader">
  769.                         <p style="margin:0 0 2px 0;">
  770.                             <strong>Attach images</strong> or
  771.                             <label style="text-decoration:underline; cursor:pointer;">
  772.                                 <input type="file" id="photosInput" accept="image/*" multiple>
  773.                                 browse
  774.                             </label>
  775.                         </p>
  776.                         <div class="hint">Screenshots of tasks, scores, billing pages, etc. (~1MB each is ideal).
  777.                         </div>
  778.                         <div class="thumbs" id="thumbs"></div>
  779.                     </div>
  780.                 </div>
  781.                 <div class="composer-actions">
  782.                     <div style="display:flex; flex-direction:column; gap:2px;">
  783.                             <span style="font-size:11px; color:var(--muted);" id="composerStatus">
  784.                                 Choose a category above to send your first message.
  785.                             </span>
  786.                     </div>
  787.                     <button type="submit" class="btn primary" id="sendBtn">Send</button>
  788.                 </div>
  789.             </form>
  790.         </section>
  791.     </div>
  792. </header>
  793. <footer>
  794.     <div class="foot">
  795.         <div>
  796.             <b>Contact</b>
  797.             <p class="lead" style="margin:.4rem 0 0 0">examHubYerevan@gmail.com</p>
  798.             <p class="lead" style="margin:.2rem 0 0 0">+374 96 361 236</p>
  799.         </div>
  800.         <div>
  801.             <b>Vrshikyans</b>
  802.             <p class="lead" style="margin:.4rem 0 0 0">Yerevan • Since 2025</p>
  803.             <small>© <span id="year"></span> Vrshikyans — All rights reserved.</small>
  804.         </div>
  805.     </div>
  806. </footer>
  807. <script src="{{ asset('js/navbar.js') }}"></script>
  808. <script>
  809.     document.getElementById('year').textContent = new Date().getFullYear();
  810.     const supportApi = {
  811.         KEY: 'vrshikyans_support_v1',
  812.         async _request(url, method = 'GET', params = {}) {
  813.             const reqParams = {
  814.                 method: method,
  815.             }
  816.             if (Object.keys(params).length) {
  817.                 reqParams.body = JSON.stringify(params)
  818.             }
  819.             if (params instanceof FormData) {
  820.                 reqParams.body = params
  821.             }
  822.             const response = await fetch(url, reqParams);
  823.             return await response.json();
  824.         },
  825.         async _loadAll() {
  826.             return await this._request("/support/list");
  827.         },
  828.         async _saveAll(list) {
  829.             localStorage.setItem(this.KEY, JSON.stringify(list));
  830.         },
  831.         async list() {
  832.             const all = await this._loadAll();
  833.             all.sort((a, b) => (b.lastUpdated || b.createdAt) - (a.lastUpdated || a.createdAt));
  834.             return all;
  835.         },
  836.         async get(id) {
  837.             return await this._request(`/support/list/${id}`);
  838.         },
  839.         async create(ticket) {
  840.             return await this._request(`/support/create`, 'POST', ticket);
  841.         },
  842.         async createMsg(msg) {
  843.             const fileInput = document.querySelector('#photosInput')
  844.             const files = fileInput.files; // get selected files
  845.             const formData = new FormData();
  846.             for (const key in msg) {
  847.                 const value = msg[key];
  848.                 formData.append(key, value);
  849.             }
  850.             // Append all files
  851.             for (let i = 0; i < files.length; i++) {
  852.                 formData.append('photos[]', files[i]);
  853.             }
  854.             return await this._request(`/support/${uiState.activeTicketId}/create-msg`, 'POST', formData);
  855.         },
  856.         async update(ticket) {
  857.             const all = await this._loadAll();
  858.             const idx = all.findIndex(t => t.id === ticket.id);
  859.             if (idx !== -1) {
  860.                 all[idx] = ticket;
  861.                 await this._saveAll(all);
  862.                 return { ok: true };
  863.             }
  864.             return { ok: false };
  865.         }
  866.     };
  867.     const uiState = {
  868.         creating: false,
  869.         activeTicketId: null,
  870.         files: []
  871.     };
  872.     const historyList = document.getElementById('historyList');
  873.     const newRequestBtn = document.getElementById('newRequestBtn');
  874.     const newRequestBandBtn = document.getElementById('newRequestBandBtn');
  875.     const backToList = document.getElementById('backToList');
  876.     const chatTitle = document.getElementById('chatTitle');
  877.     const chatSubtitle = document.getElementById('chatSubtitle');
  878.     const chatChips = document.getElementById('chatChips');
  879.     const chatBody = document.getElementById('chatBody');
  880.     const chatEmpty = document.getElementById('chatEmpty');
  881.     const categorySelect = document.getElementById('categorySelect');
  882.     const categorySecondaryWrapper = document.getElementById('categorySecondaryWrapper');
  883.     const secondarySelect = document.getElementById('secondarySelect');
  884.     const secondaryLabel = document.getElementById('secondaryLabel');
  885.     const subscriptionExtra = document.getElementById('subscriptionExtra');
  886.     const topicInput = document.getElementById('topicInput');
  887.     const composerStatus = document.getElementById('composerStatus');
  888.     const composerForm = document.getElementById('composerForm');
  889.     const messageInput = document.getElementById('messageInput');
  890.     const sendBtn = document.getElementById('sendBtn');
  891.     const uploader = document.getElementById('uploader');
  892.     const photosInput = document.getElementById('photosInput');
  893.     const thumbs = document.getElementById('thumbs');
  894.     function escapeHtml(s) {
  895.         return String(s)
  896.             .replaceAll('&', '&amp;')
  897.             .replaceAll('<', '&lt;')
  898.             .replaceAll('>', '&gt;')
  899.             .replaceAll('"', '&quot;')
  900.             .replaceAll("'", "&#39;");
  901.     }
  902.     function formatDate(ts) {
  903.         const d = new Date(ts);
  904.         return d.toLocaleDateString(undefined, {
  905.             year: 'numeric', month: 'short', day: 'numeric'
  906.         });
  907.     }
  908.     function formatTime(ts) {
  909.         const d = new Date(ts);
  910.         return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });
  911.     }
  912.     function shortCategory(main, sub) {
  913.         if (!main && !sub) return '';
  914.         if (main === 'Tutors') return 'Tutors' + (sub ? ' • ' + sub : '');
  915.         if (main === 'Info') return 'Information • ' + (sub || 'Tests');
  916.         if (main === 'Subscriptions') return 'Subscriptions';
  917.         return [main, sub].filter(Boolean).join(' • ');
  918.     }
  919.     function isCategoryValidForNew() {
  920.         const main = categorySelect.value;
  921.         if (!main) return false;
  922.         if (main === 'Tutors' || main === 'Info') {
  923.             return !!secondarySelect.value;
  924.         }
  925.         return true;
  926.     }
  927.     function updateComposerStatus() {
  928.         const hasTicket = !!uiState.activeTicketId;
  929.         const main = categorySelect.value;
  930.         const sec = secondarySelect.value;
  931.         if (hasTicket) {
  932.             composerStatus.textContent = 'You can continue writing in this chat.';
  933.             messageInput.disabled = false;
  934.             sendBtn.disabled = false;
  935.             messageInput.placeholder = 'Type your message…';
  936.             return;
  937.         }
  938.         if (!main) {
  939.             composerStatus.textContent = 'Choose a category above to send your first message.';
  940.             messageInput.disabled = true;
  941.             sendBtn.disabled = true;
  942.             messageInput.placeholder = 'Select a category to start typing…';
  943.             messageInput.style.border = "1px solid red"
  944.         } else if ((main === 'Tutors' || main === 'Info') && !sec) {
  945.             composerStatus.textContent = 'Pick the exam to unlock the message box.';
  946.             messageInput.disabled = true;
  947.             sendBtn.disabled = true;
  948.             messageInput.style.border = "1px solid red"
  949.             messageInput.placeholder = 'Choose the exam first…';
  950.         } else {
  951.             composerStatus.textContent = 'Ready. Your first message will create a new support request.';
  952.             messageInput.disabled = false;
  953.             sendBtn.disabled = false;
  954.             messageInput.style.border = ''
  955.             messageInput.placeholder = 'Type your message… (at least a few characters)';
  956.         }
  957.     }
  958.     function populateSecondary(main) {
  959.         secondarySelect.innerHTML = '';
  960.         const optEmpty = document.createElement('option');
  961.         optEmpty.value = '';
  962.         optEmpty.textContent = 'Choose an exam';
  963.         secondarySelect.appendChild(optEmpty);
  964.         const examsTutors = ['SAT', 'TOEFL', 'ACT', 'IELTS'];
  965.         const examsInfo = ['SAT', 'TOEFL', 'ACT', 'IELTS', 'Overall information about all tests'];
  966.         let list = [];
  967.         if (main === 'Tutors') list = examsTutors;
  968.         if (main === 'Info') list = examsInfo;
  969.         list.forEach((name, idx) => {
  970.             const o = document.createElement('option');
  971.             o.value = (idx + 1);
  972.             o.textContent = name;
  973.             secondarySelect.appendChild(o);
  974.         });
  975.     }
  976.     categorySelect.addEventListener('change', () => {
  977.         const main = categorySelect.value;
  978.         secondarySelect.value = '';
  979.         subscriptionExtra.style.display = 'none';
  980.         categorySecondaryWrapper.style.display = 'none';
  981.         if (main === 'Tutors') {
  982.             secondaryLabel.textContent = 'Which exam?';
  983.             populateSecondary(main);
  984.             categorySecondaryWrapper.style.display = '';
  985.         } else if (main === 'Info') {
  986.             secondaryLabel.textContent = 'About which test?';
  987.             populateSecondary(main);
  988.             categorySecondaryWrapper.style.display = '';
  989.         } else if (main === 'Subscriptions') {
  990.             subscriptionExtra.style.display = "block";
  991.         }
  992.         updateComposerStatus();
  993.     });
  994.     secondarySelect.addEventListener('change', updateComposerStatus);
  995.     function addFiles(list) {
  996.         const arr = [...list];
  997.         arr.forEach(file => {
  998.             if (!file.type.startsWith('image/')) return;
  999.             const reader = new FileReader();
  1000.             reader.onload = () => {
  1001.                 uiState.files.push({ file, dataUrl: reader.result });
  1002.                 renderThumbs();
  1003.             };
  1004.             reader.readAsDataURL(file);
  1005.         });
  1006.     }
  1007.     photosInput.addEventListener('change', e => addFiles(e.target.files));
  1008.     uploader.addEventListener('dragover', e => {
  1009.         e.preventDefault();
  1010.         uploader.style.borderColor = 'var(--accent)';
  1011.     });
  1012.     uploader.addEventListener('dragleave', () => {
  1013.         uploader.style.borderColor = 'var(--border)';
  1014.     });
  1015.     uploader.addEventListener('drop', e => {
  1016.         e.preventDefault();
  1017.         uploader.style.borderColor = 'var(--border)';
  1018.         addFiles(e.dataTransfer.files);
  1019.     });
  1020.     function renderThumbs() {
  1021.         thumbs.innerHTML = '';
  1022.         uiState.files.forEach((f, idx) => {
  1023.             const el = document.createElement('div');
  1024.             el.className = 'thumb';
  1025.             el.innerHTML = `
  1026.           <img alt="preview ${idx + 1}">
  1027.           <button type="button">✕</button>
  1028.         `;
  1029.             el.querySelector('img').src = f.dataUrl;
  1030.             el.querySelector('button').addEventListener('click', () => {
  1031.                 uiState.files.splice(idx, 1);
  1032.                 renderThumbs();
  1033.             });
  1034.             thumbs.appendChild(el);
  1035.         });
  1036.     }
  1037.     function clearComposer() {
  1038.         messageInput.value = '';
  1039.         uiState.files = [];
  1040.         renderThumbs();
  1041.     }
  1042.     let cachedTickets = [];
  1043.     async function loadHistory() {
  1044.         cachedTickets = await supportApi.list();
  1045.         renderHistory();
  1046.     }
  1047.     function renderHistory() {
  1048.         historyList.innerHTML = '';
  1049.         if (!cachedTickets.length) {
  1050.             const p = document.createElement('p');
  1051.             p.className = 'lead';
  1052.             p.style.fontSize = '13px';
  1053.             p.style.margin = '0';
  1054.             p.textContent = 'No requests yet. Start with “New”.';
  1055.             historyList.appendChild(p);
  1056.             return;
  1057.         }
  1058.         cachedTickets.forEach(t => {
  1059.             const btn = document.createElement('button');
  1060.             btn.className = 'ticket-row' + (t.id === uiState.activeTicketId ? ' active' : '');
  1061.             btn.dataset.id = t.id;
  1062.             const subject = t.subject || shortCategory(t.categoryMain, t.categorySub) || 'Support request';
  1063.             const created = formatDate(t.createdAt);
  1064.             const statusClass = t.status === 'closed' ? 'ticket-status closed' : 'ticket-status';
  1065.             btn.innerHTML = `
  1066.           <div class="ticket-title">${escapeHtml(subject)}</div>
  1067.           <div class="ticket-meta">${escapeHtml(created)}</div>
  1068.           <div class="ticket-badges">
  1069.             ${t.categoryMain ? `<span class="ticket-badge">${escapeHtml(t.categoryMain === 'Info' ? 'Information about tests' : t.categoryMain)}</span>` : ''}
  1070.             ${t.categorySub ? `<span class="ticket-badge">${escapeHtml(t.categorySub)}</span>` : ''}
  1071.           </div>
  1072.           <span class="${statusClass}">${t.status === 'closed' ? 'Closed' : 'Open'}</span>
  1073.         `;
  1074.             btn.addEventListener('click', () => openExistingTicket(t.id));
  1075.             historyList.appendChild(btn);
  1076.         });
  1077.     }
  1078.     function renderChat(ticket) {
  1079.         chatBody.innerHTML = '';
  1080.         chatEmpty.style.display = 'none';
  1081.         if (!ticket || !ticket.messages || !ticket.messages.length) {
  1082.             const empty = document.createElement('div');
  1083.             empty.className = 'chat-empty';
  1084.             empty.innerHTML = `
  1085.           <div>
  1086.             <p style="margin:0 0 4px 0;"><strong>No messages yet</strong></p>
  1087.             <p style="margin:0; font-size:13px;">Write your first message below to start the conversation.</p>
  1088.           </div>
  1089.         `;
  1090.             chatBody.appendChild(empty);
  1091.             return;
  1092.         }
  1093.         ticket.messages.forEach(m => {
  1094.             const el = document.createElement('div');
  1095.             const isUser = m.from === 'user';
  1096.             el.className = 'msg ' + (isUser ? 'msg-user' : 'msg-admin');
  1097.             const fromLabel = isUser ? 'You' : 'Vrshikyans support';
  1098.             el.innerHTML = `
  1099.           <div class="msg-meta">${escapeHtml(fromLabel)} · ${escapeHtml(formatTime(m.createdAt))}</div>
  1100.           <div class="msg-bubble">
  1101.             ${m.text ? `<div>${escapeHtml(m.text)}</div>` : ''}
  1102.             ${m.photos && m.photos.length ? `
  1103.               <div class="msg-photos">
  1104.                 ${m.photos.map((p, idx) => `<img src="${p.url}" alt="attachment ${idx + 1}">`).join('')}
  1105.               </div>
  1106.             `: ''}
  1107.           </div>
  1108.         `;
  1109.             chatBody.appendChild(el);
  1110.         });
  1111.         chatBody.scrollTop = chatBody.scrollHeight;
  1112.     }
  1113.     function updateChatHeader(ticket) {
  1114.         chatChips.innerHTML = '';
  1115.         if (!ticket) {
  1116.             chatTitle.textContent = 'New support request';
  1117.             chatSubtitle.textContent = 'Pick a category and send your first message.';
  1118.             return;
  1119.         }
  1120.         const subject = ticket.subject || shortCategory(ticket.categoryMain, ticket.categorySub) || 'Support request';
  1121.         chatTitle.textContent = subject;
  1122.         const created = formatDate(ticket.createdAt);
  1123.         chatSubtitle.textContent = `Created ${created} • ${ticket.status === 'closed' ? 'Closed' : 'Open'}`;
  1124.         if (ticket.categoryMain) {
  1125.             const chipMain = document.createElement('span');
  1126.             chipMain.className = 'chip';
  1127.             chipMain.textContent = ticket.categoryMain === 'Info' ? 'Information about tests' : ticket.categoryMain;
  1128.             chatChips.appendChild(chipMain);
  1129.         }
  1130.         if (ticket.categorySub) {
  1131.             const chipSub = document.createElement('span');
  1132.             chipSub.className = 'chip';
  1133.             chipSub.textContent = ticket.categorySub;
  1134.             chatChips.appendChild(chipSub);
  1135.         }
  1136.     }
  1137.     function syncCategoryUI(ticket) {
  1138.         if (!ticket) {
  1139.             categorySelect.disabled = false;
  1140.             secondarySelect.disabled = false;
  1141.             topicInput.disabled = false;
  1142.             categorySelect.value = '';
  1143.             secondarySelect.innerHTML = '';
  1144.             categorySecondaryWrapper.style.display = 'none';
  1145.             subscriptionExtra.style.display = 'none';
  1146.             topicInput.value = '';
  1147.         } else {
  1148.             categorySelect.disabled = true;
  1149.             secondarySelect.disabled = true;
  1150.             topicInput.disabled = true;
  1151.             categorySelect.value = ticket.categoryMain || '';
  1152.             if (ticket.categoryMain === 'Tutors') {
  1153.                 populateSecondary('Tutors');
  1154.                 categorySecondaryWrapper.style.display = '';
  1155.             } else if (ticket.categoryMain === 'Info') {
  1156.                 populateSecondary('Info');
  1157.                 categorySecondaryWrapper.style.display = '';
  1158.             } else {
  1159.                 categorySecondaryWrapper.style.display = 'none';
  1160.             }
  1161.             if (ticket.categoryMain === 'Subscriptions') {
  1162.                 subscriptionExtra.style.display = '';
  1163.             } else {
  1164.                 subscriptionExtra.style.display = 'none';
  1165.             }
  1166.             if (ticket.categorySub) {
  1167.                 secondarySelect.value = ticket.categorySub;
  1168.             }
  1169.             topicInput.value = ticket.subject || '';
  1170.         }
  1171.         updateComposerStatus();
  1172.     }
  1173.     function startNewRequest() {
  1174.         uiState.creating = true;
  1175.         uiState.activeTicketId = null;
  1176.         document.body.classList.add('creating', 'can-write');
  1177.         chatTitle.textContent = 'New support request';
  1178.         chatSubtitle.textContent = 'Pick a category and send your first message.';
  1179.         chatChips.innerHTML = '';
  1180.         chatBody.innerHTML = '';
  1181.         chatEmpty.style.display = 'block';
  1182.         chatEmpty.innerHTML = `
  1183.         <div>
  1184.           <p style="margin:0 0 4px 0;"><strong>Describe your issue</strong></p>
  1185.           <p style="margin:0; font-size:13px;">Once you send the first message, this will turn into a chat thread.</p>
  1186.         </div>
  1187.       `;
  1188.         syncCategoryUI(null);
  1189.         clearComposer();
  1190.         renderHistory();
  1191.     }
  1192.     async function openExistingTicket(id) {
  1193.         uiState.creating = false;
  1194.         uiState.activeTicketId = id;
  1195.         document.body.classList.remove('creating');
  1196.         document.body.classList.add('can-write');
  1197.         const ticket = await supportApi.get(id);
  1198.         if (!ticket) return;
  1199.         updateChatHeader(ticket);
  1200.         syncCategoryUI(ticket);
  1201.         renderChat(ticket);
  1202.         renderHistory();
  1203.     }
  1204.     composerForm.addEventListener('submit', async (e) => {
  1205.         e.preventDefault();
  1206.         const text = messageInput.value.trim();
  1207.         const hasText = text.length >= 3;
  1208.         const hasPhotos = uiState.files.length > 0;
  1209.         if (!uiState.activeTicketId) {
  1210.             if (!isCategoryValidForNew()) {
  1211.                 updateComposerStatus();
  1212.                 messageInput.focus();
  1213.                 return;
  1214.             }
  1215.             if (!hasText && !hasPhotos) {
  1216.                 messageInput.focus();
  1217.                 return;
  1218.             }
  1219.         } else {
  1220.             if (!hasText && !hasPhotos) return;
  1221.         }
  1222.         const photos = uiState.files.map(f => ({ url: f.dataUrl }));
  1223.         clearComposer();
  1224.         let ticket;
  1225.         if (!uiState.activeTicketId) {
  1226.             const id = 't_' + Math.random().toString(36).slice(2);
  1227.             const now = Date.now();
  1228.             const main = categorySelect.value || '';
  1229.             const sub = (main === 'Tutors' || main === 'Info') ? (secondarySelect.value || '') : '';
  1230.             const subject = topicInput.value.trim() || shortCategory(main, sub) || 'Support request';
  1231.             ticket = {
  1232.                 subject,
  1233.                 categoryMain: main,
  1234.                 categorySub: sub,
  1235.                 status: 'open',
  1236.                 createdAt: now,
  1237.                 lastUpdated: now,
  1238.                 messages: []
  1239.             };
  1240.             const res = await supportApi.create(ticket);
  1241.             uiState.activeTicketId = res.id;
  1242.             uiState.creating = false;
  1243.             document.body.classList.remove('creating');
  1244.             document.body.classList.add('can-write');
  1245.         }
  1246.         ticket = await supportApi.get(uiState.activeTicketId);
  1247.         if (!ticket) return;
  1248.         const msg = {
  1249.             id: 'm_' + Math.random().toString(36).slice(2),
  1250.             from: 'user',
  1251.             text: text,
  1252.             photos: photos,
  1253.             createdAt: Date.now()
  1254.         };
  1255.         ticket.messages.push(msg);
  1256.         ticket.lastUpdated = msg.createdAt;
  1257.         await supportApi.createMsg(msg);
  1258.         updateChatHeader(ticket);
  1259.         syncCategoryUI(ticket);
  1260.         renderChat(ticket);
  1261.         await loadHistory();
  1262.     });
  1263.     newRequestBtn.addEventListener('click', startNewRequest);
  1264.     newRequestBandBtn.addEventListener('click', startNewRequest);
  1265.     backToList.addEventListener('click', () => {
  1266.         uiState.creating = false;
  1267.         document.body.classList.remove('creating', 'can-write');
  1268.         uiState.activeTicketId = null;
  1269.         chatTitle.textContent = 'Support inbox';
  1270.         chatSubtitle.textContent = 'Choose a request on the left or start a new one.';
  1271.         chatChips.innerHTML = '';
  1272.         chatBody.innerHTML = '';
  1273.         chatEmpty.style.display = 'block';
  1274.         chatEmpty.innerHTML = `
  1275.         <div>
  1276.           <p style="margin:0 0 4px 0;"><strong>No request selected</strong></p>
  1277.           <p style="margin:0; font-size:13px;">Pick a request from your history or create a new one.</p>
  1278.         </div>
  1279.       `;
  1280.         syncCategoryUI(null);
  1281.         clearComposer();
  1282.         renderHistory();
  1283.     });
  1284.     (async () => {
  1285.         const existing = await supportApi.list();
  1286.         if (!existing.length) {
  1287.             const seed = [
  1288.                 {
  1289.                     id: 't_seed1',
  1290.                     subject: 'SAT tutor',
  1291.                     categoryMain: 'Tutors',
  1292.                     categorySub: 'SAT',
  1293.                     status: 'closed',
  1294.                     createdAt: new Date('2024-12-22T10:00:00').getTime(),
  1295.                     lastUpdated: new Date('2024-12-22T11:05:00').getTime(),
  1296.                     messages: [
  1297.                         {
  1298.                             id: 'm1',
  1299.                             from: 'user',
  1300.                             text: 'Hi! I need a SAT tutor for March 2025. Can you recommend someone from Vrshikyans?',
  1301.                             photos: [],
  1302.                             createdAt: new Date('2024-12-22T10:00:00').getTime()
  1303.                         },
  1304.                         {
  1305.                             id: 'm2',
  1306.                             from: 'admin',
  1307.                             text: 'Of course! We can connect you with a tutor who focuses on the math section and one for Reading/English. We’ll email you the options today.',
  1308.                             photos: [],
  1309.                             createdAt: new Date('2024-12-22T10:20:00').getTime()
  1310.                         },
  1311.                         {
  1312.                             id: 'm3',
  1313.                             from: 'user',
  1314.                             text: 'Perfect, thank you so much!',
  1315.                             photos: [],
  1316.                             createdAt: new Date('2024-12-22T11:05:00').getTime()
  1317.                         }
  1318.                     ]
  1319.                 },
  1320.                 {
  1321.                     id: 't_seed2',
  1322.                     subject: 'TOEFL practice tests',
  1323.                     categoryMain: 'Info',
  1324.                     categorySub: 'TOEFL',
  1325.                     status: 'open',
  1326.                     createdAt: new Date('2023-11-14T15:00:00').getTime(),
  1327.                     lastUpdated: new Date('2023-11-14T15:35:00').getTime(),
  1328.                     messages: [
  1329.                         {
  1330.                             id: 'm1',
  1331.                             from: 'user',
  1332.                             text: 'Hi, are your TOEFL tests updated to the new format?',
  1333.                             photos: [],
  1334.                             createdAt: new Date('2023-11-14T15:00:00').getTime()
  1335.                         },
  1336.                         {
  1337.                             id: 'm2',
  1338.                             from: 'admin',
  1339.                             text: 'Yes! Our TOEFL Practice 2026 set follows the short reading + new speaking timing. Let us know which sections you care about most.',
  1340.                             photos: [],
  1341.                             createdAt: new Date('2023-11-14T15:20:00').getTime()
  1342.                         },
  1343.                         {
  1344.                             id: 'm3',
  1345.                             from: 'user',
  1346.                             text: 'I need more listening practice sets. How many do you have?',
  1347.                             photos: [],
  1348.                             createdAt: new Date('2023-11-14T15:35:00').getTime()
  1349.                         }
  1350.                     ]
  1351.                 }
  1352.             ];
  1353.             localStorage.setItem(supportApi.KEY, JSON.stringify(seed));
  1354.         }
  1355.         await loadHistory();
  1356.         updateComposerStatus();
  1357.     })();
  1358. </script>
  1359. </body>
  1360. </html>