It looks like this is a web page, not a feed. I looked for a feed associated with this page, but couldn't find one. Please enter the address of your feed to validate.

Source: https://www.autoselection.xyz

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>AutoSelection Directory - Automobile Listings</title>
  6. <meta name="viewport" content="width=device-width,initial-scale=1">
  7. <style>
  8.    /* ====== Base ====== */
  9.    :root{
  10.        --brand:#004080;
  11.        --accent:#0073e6;
  12.        --muted:#6b7280;
  13.        --card-bg:#fafafa;
  14.        --featured-bg:#fff7e6;
  15.        --max-width:1100px;
  16.        --radius:8px;
  17.    }
  18.    *{box-sizing:border-box}
  19.    body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial; margin: 0; background: #fff; color: #222; }
  20.    a { color: var(--accent); text-decoration: none; }
  21.    a:hover { text-decoration: underline; }
  22.  
  23.    /* ====== Header ====== */
  24.    header { background: var(--brand); color:#fff; padding:18px 24px; }
  25.    header .inner { max-width: var(--max-width); margin: 0 auto; display:flex; align-items:center; justify-content:space-between; gap:20px; }
  26.    header h1 { margin:0; font-size:20px; letter-spacing:0.2px; }
  27.    nav { display:flex; gap:12px; align-items:center; }
  28.    nav a { color:#fff; font-weight:600; font-size:14px; }
  29.  
  30.    /* ====== Layout container ====== */
  31.    .container { max-width: var(--max-width); margin: 26px auto; padding: 0 16px; }
  32.  
  33.    /* ====== Section headings ====== */
  34.    section + section { margin-top: 28px; }
  35.    h2 { margin: 0 0 12px 0; font-size:18px; color:var(--brand); border-bottom:1px solid #eee; padding-bottom:10px; }
  36.  
  37.    /* ====== Cards ====== */
  38.    .listing-card {
  39.        border: 1px solid #e6e6e6;
  40.        border-radius: var(--radius);
  41.        padding: 16px;
  42.        margin: 12px 0;
  43.        background: var(--card-bg);
  44.    }
  45.    .listing-card h3 { margin:0 0 8px 0; color:var(--brand); font-size:16px; }
  46.    .listing-card p { margin:0; color:var(--muted); font-size:14px; }
  47.  
  48.    .featured { background: var(--featured-bg); border: 1px solid #ffd59b; }
  49.  
  50.    /* ====== Submit button ====== */
  51.    .btn { display:inline-block; background:var(--accent); color:#fff; padding:10px 14px; border-radius:6px; border:none; cursor:pointer; font-weight:700; }
  52.    .btn:active{transform:translateY(1px)}
  53.    .muted { color:var(--muted); font-size:14px; }
  54.  
  55.    /* ====== Slider ====== */
  56.    .slider-wrap { position:relative; margin-top:10px; }
  57.    .slider-viewport { overflow:hidden; padding:6px 0; }
  58.    .slider-track {
  59.        display:flex;
  60.        gap:12px;
  61.        transition: transform 360ms cubic-bezier(.22,.9,.35,1);
  62.        will-change:transform;
  63.        padding-bottom:6px;
  64.    }
  65.    .card {
  66.        min-width: 260px;
  67.        max-width: 260px;
  68.        background:#fff;
  69.        border:1px solid #e6e6e6;
  70.        border-radius:8px;
  71.        padding:12px;
  72.        box-shadow: 0 2px 6px rgba(10,10,10,0.04);
  73.        flex-shrink:0;
  74.    }
  75.    .card h4 { margin:0 0 6px 0; font-size:15px; color:var(--brand); }
  76.    .card p { margin:6px 0; color:var(--muted); font-size:13px; }
  77.  
  78.    /* ====== slider controls ====== */
  79.    .slider-btn {
  80.        position:absolute; top:50%; transform:translateY(-50%); width:40px; height:40px; border-radius:50%; border:none; background:var(--brand); color:#fff; display:flex; align-items:center; justify-content:center; cursor:pointer;
  81.        box-shadow:0 6px 16px rgba(0,0,0,0.12);
  82.    }
  83.    .slider-btn:disabled { opacity:0.45; cursor:default; }
  84.    .slider-btn-left{ left: -10px; }
  85.    .slider-btn-right{ right: -10px; }
  86.  
  87.    /* ====== dots ====== */
  88.    .dots { display:flex; gap:8px; justify-content:center; margin-top:12px; }
  89.    .dot { width:10px; height:10px; border-radius:50%; background:#e4e4e4; cursor:pointer; }
  90.    .dot.active { background:var(--brand); }
  91.  
  92.    /* ====== responsive ====== */
  93.    @media (max-width: 900px) {
  94.        .card { min-width: 220px; max-width: 220px; }
  95.    }
  96.    @media (max-width: 700px) {
  97.        header .inner { flex-direction:column; align-items:flex-start; gap:8px; }
  98.        .slider-btn-left{ left: 6px; }
  99.        .slider-btn-right{ right: 6px; }
  100.    }
  101.  
  102.    /* ====== modal ====== */
  103.    .modal { display:none; position:fixed; inset:0; background:rgba(0,0,0,0.6); z-index:2000; align-items:center; justify-content:center; }
  104.    .modal .dialog { background:#fff; padding:18px; border-radius:10px; width:92%; max-width:640px; box-shadow:0 8px 40px rgba(0,0,0,0.2); position:relative; }
  105.    .modal .close { position:absolute; right:12px; top:10px; border:none; background:none; font-size:22px; cursor:pointer; color:#666; }
  106.    label{ display:block; margin-top:8px; font-size:13px; color:#333; }
  107.    input[type="text"], input[type="url"], input[type="email"], textarea, select { width:100%; padding:10px; border:1px solid #e6e6e6; border-radius:6px; margin-top:6px; font-size:14px; }
  108.    textarea{ min-height:100px; resize:vertical; }
  109.  
  110.    /* small helper */
  111.    .small { font-size:13px; color:#666; margin-top:6px; }
  112.    .grid-two { display:grid; grid-template-columns:1fr 1fr; gap:10px; }
  113.    @media(max-width:520px){ .grid-two{ grid-template-columns:1fr } }
  114. </style>
  115. </head>
  116. <body>
  117.  
  118. <header>
  119.    <div class="inner">
  120.        <h1>AutoSelection Directory</h1>
  121.        <nav>
  122.            <a href="#">Home</a>
  123.            <a href="#backlinks">Top Auto Sites</a>
  124.            <a href="#featured">Featured</a>
  125.            <a href="#listings">Listings</a>
  126.            <a href="#submit">Submit Website</a>
  127.        </nav>
  128.    </div>
  129. </header>
  130.  
  131. <div class="container">
  132.  
  133.    <!-- TOP SITES SLIDER -->
  134.    <section id="backlinks" aria-label="Top Automobile Websites">
  135.        <h2>🔗 Top Automobile Websites (High Domain Authority)</h2>
  136.        <p class="small">List your auto website with us. <br>High-authority automobile industry sites — their Domain Authority (DA) and estimated backlink counts. Use the arrows or swipe on mobile.</p>
  137.  
  138.        <div class="slider-wrap" id="sliderWrap">
  139.            <button class="slider-btn slider-btn-left" id="btnPrev" aria-label="Previous" title="Previous">&#10094;</button>
  140.  
  141.            <div class="slider-viewport" id="sliderViewport" tabindex="0" aria-roledescription="carousel">
  142.                <div class="slider-track" id="sliderTrack">
  143.                                            <article class="card" role="group" aria-label="Car and Driver">
  144.                            <h4>Car and Driver</h4>
  145.                            <p><a href="https://www.caranddriver.com" target="_blank" rel="noopener">https://www.caranddriver.com</a></p>
  146.                            <p>DA: <strong>90</strong></p>
  147.                            <p>Backlinks: <strong>1,200,000</strong></p>
  148.                        </article>
  149.                                            <article class="card" role="group" aria-label="Autoblog">
  150.                            <h4>Autoblog</h4>
  151.                            <p><a href="https://www.autoblog.com" target="_blank" rel="noopener">https://www.autoblog.com</a></p>
  152.                            <p>DA: <strong>85</strong></p>
  153.                            <p>Backlinks: <strong>950,000</strong></p>
  154.                        </article>
  155.                                            <article class="card" role="group" aria-label="MotorTrend">
  156.                            <h4>MotorTrend</h4>
  157.                            <p><a href="https://www.motortrend.com" target="_blank" rel="noopener">https://www.motortrend.com</a></p>
  158.                            <p>DA: <strong>88</strong></p>
  159.                            <p>Backlinks: <strong>800,000</strong></p>
  160.                        </article>
  161.                                            <article class="card" role="group" aria-label="AutoExpress">
  162.                            <h4>AutoExpress</h4>
  163.                            <p><a href="https://www.autoexpress.co.uk" target="_blank" rel="noopener">https://www.autoexpress.co.uk</a></p>
  164.                            <p>DA: <strong>70</strong></p>
  165.                            <p>Backlinks: <strong>450,000</strong></p>
  166.                        </article>
  167.                                            <article class="card" role="group" aria-label="Top Gear">
  168.                            <h4>Top Gear</h4>
  169.                            <p><a href="https://www.topgear.com" target="_blank" rel="noopener">https://www.topgear.com</a></p>
  170.                            <p>DA: <strong>89</strong></p>
  171.                            <p>Backlinks: <strong>780,000</strong></p>
  172.                        </article>
  173.                                            <article class="card" role="group" aria-label="Kelley Blue Book">
  174.                            <h4>Kelley Blue Book</h4>
  175.                            <p><a href="https://www.kbb.com" target="_blank" rel="noopener">https://www.kbb.com</a></p>
  176.                            <p>DA: <strong>86</strong></p>
  177.                            <p>Backlinks: <strong>720,000</strong></p>
  178.                        </article>
  179.                                            <article class="card" role="group" aria-label="Edmunds">
  180.                            <h4>Edmunds</h4>
  181.                            <p><a href="https://www.edmunds.com" target="_blank" rel="noopener">https://www.edmunds.com</a></p>
  182.                            <p>DA: <strong>84</strong></p>
  183.                            <p>Backlinks: <strong>680,000</strong></p>
  184.                        </article>
  185.                                            <article class="card" role="group" aria-label="AutoTrader">
  186.                            <h4>AutoTrader</h4>
  187.                            <p><a href="https://www.autotrader.com" target="_blank" rel="noopener">https://www.autotrader.com</a></p>
  188.                            <p>DA: <strong>91</strong></p>
  189.                            <p>Backlinks: <strong>1,000,000</strong></p>
  190.                        </article>
  191.                                            <article class="card" role="group" aria-label="Cars.com">
  192.                            <h4>Cars.com</h4>
  193.                            <p><a href="https://www.cars.com" target="_blank" rel="noopener">https://www.cars.com</a></p>
  194.                            <p>DA: <strong>88</strong></p>
  195.                            <p>Backlinks: <strong>950,000</strong></p>
  196.                        </article>
  197.                                            <article class="card" role="group" aria-label="Road &amp; Track">
  198.                            <h4>Road &amp; Track</h4>
  199.                            <p><a href="https://www.roadandtrack.com" target="_blank" rel="noopener">https://www.roadandtrack.com</a></p>
  200.                            <p>DA: <strong>82</strong></p>
  201.                            <p>Backlinks: <strong>610,000</strong></p>
  202.                        </article>
  203.                                            <article class="card" role="group" aria-label="The Drive">
  204.                            <h4>The Drive</h4>
  205.                            <p><a href="https://www.thedrive.com" target="_blank" rel="noopener">https://www.thedrive.com</a></p>
  206.                            <p>DA: <strong>78</strong></p>
  207.                            <p>Backlinks: <strong>540,000</strong></p>
  208.                        </article>
  209.                                            <article class="card" role="group" aria-label="AutoWeek">
  210.                            <h4>AutoWeek</h4>
  211.                            <p><a href="https://www.autoweek.com" target="_blank" rel="noopener">https://www.autoweek.com</a></p>
  212.                            <p>DA: <strong>76</strong></p>
  213.                            <p>Backlinks: <strong>500,000</strong></p>
  214.                        </article>
  215.                                            <article class="card" role="group" aria-label="Motor Authority">
  216.                            <h4>Motor Authority</h4>
  217.                            <p><a href="https://www.motorauthority.com" target="_blank" rel="noopener">https://www.motorauthority.com</a></p>
  218.                            <p>DA: <strong>75</strong></p>
  219.                            <p>Backlinks: <strong>480,000</strong></p>
  220.                        </article>
  221.                                            <article class="card" role="group" aria-label="Jalopnik">
  222.                            <h4>Jalopnik</h4>
  223.                            <p><a href="https://jalopnik.com" target="_blank" rel="noopener">https://jalopnik.com</a></p>
  224.                            <p>DA: <strong>83</strong></p>
  225.                            <p>Backlinks: <strong>620,000</strong></p>
  226.                        </article>
  227.                                            <article class="card" role="group" aria-label="CarBuzz">
  228.                            <h4>CarBuzz</h4>
  229.                            <p><a href="https://carbuzz.com" target="_blank" rel="noopener">https://carbuzz.com</a></p>
  230.                            <p>DA: <strong>72</strong></p>
  231.                            <p>Backlinks: <strong>400,000</strong></p>
  232.                        </article>
  233.                                            <article class="card" role="group" aria-label="CarsGuide">
  234.                            <h4>CarsGuide</h4>
  235.                            <p><a href="https://www.carsguide.com.au" target="_blank" rel="noopener">https://www.carsguide.com.au</a></p>
  236.                            <p>DA: <strong>74</strong></p>
  237.                            <p>Backlinks: <strong>420,000</strong></p>
  238.                        </article>
  239.                                            <article class="card" role="group" aria-label="AutoTrader UK">
  240.                            <h4>AutoTrader UK</h4>
  241.                            <p><a href="https://www.autotrader.co.uk" target="_blank" rel="noopener">https://www.autotrader.co.uk</a></p>
  242.                            <p>DA: <strong>89</strong></p>
  243.                            <p>Backlinks: <strong>900,000</strong></p>
  244.                        </article>
  245.                                            <article class="card" role="group" aria-label="Parkers">
  246.                            <h4>Parkers</h4>
  247.                            <p><a href="https://www.parkers.co.uk" target="_blank" rel="noopener">https://www.parkers.co.uk</a></p>
  248.                            <p>DA: <strong>77</strong></p>
  249.                            <p>Backlinks: <strong>470,000</strong></p>
  250.                        </article>
  251.                                            <article class="card" role="group" aria-label="Motor1">
  252.                            <h4>Motor1</h4>
  253.                            <p><a href="https://www.motor1.com" target="_blank" rel="noopener">https://www.motor1.com</a></p>
  254.                            <p>DA: <strong>87</strong></p>
  255.                            <p>Backlinks: <strong>750,000</strong></p>
  256.                        </article>
  257.                                            <article class="card" role="group" aria-label="Auto Evolution">
  258.                            <h4>Auto Evolution</h4>
  259.                            <p><a href="https://www.autoevolution.com" target="_blank" rel="noopener">https://www.autoevolution.com</a></p>
  260.                            <p>DA: <strong>82</strong></p>
  261.                            <p>Backlinks: <strong>620,000</strong></p>
  262.                        </article>
  263.                                            <article class="card" role="group" aria-label="Carwow">
  264.                            <h4>Carwow</h4>
  265.                            <p><a href="https://www.carwow.co.uk" target="_blank" rel="noopener">https://www.carwow.co.uk</a></p>
  266.                            <p>DA: <strong>80</strong></p>
  267.                            <p>Backlinks: <strong>600,000</strong></p>
  268.                        </article>
  269.                                            <article class="card" role="group" aria-label="Classic Driver">
  270.                            <h4>Classic Driver</h4>
  271.                            <p><a href="https://www.classicdriver.com" target="_blank" rel="noopener">https://www.classicdriver.com</a></p>
  272.                            <p>DA: <strong>71</strong></p>
  273.                            <p>Backlinks: <strong>390,000</strong></p>
  274.                        </article>
  275.                                            <article class="card" role="group" aria-label="Auto123">
  276.                            <h4>Auto123</h4>
  277.                            <p><a href="https://www.auto123.com" target="_blank" rel="noopener">https://www.auto123.com</a></p>
  278.                            <p>DA: <strong>67</strong></p>
  279.                            <p>Backlinks: <strong>350,000</strong></p>
  280.                        </article>
  281.                                            <article class="card" role="group" aria-label="Supercars.net">
  282.                            <h4>Supercars.net</h4>
  283.                            <p><a href="https://www.supercars.net" target="_blank" rel="noopener">https://www.supercars.net</a></p>
  284.                            <p>DA: <strong>79</strong></p>
  285.                            <p>Backlinks: <strong>580,000</strong></p>
  286.                        </article>
  287.                                            <article class="card" role="group" aria-label="CarAdvice">
  288.                            <h4>CarAdvice</h4>
  289.                            <p><a href="https://www.caradvice.com.au" target="_blank" rel="noopener">https://www.caradvice.com.au</a></p>
  290.                            <p>DA: <strong>73</strong></p>
  291.                            <p>Backlinks: <strong>410,000</strong></p>
  292.                        </article>
  293.                                            <article class="card" role="group" aria-label="Automobile Magazine">
  294.                            <h4>Automobile Magazine</h4>
  295.                            <p><a href="https://www.automobilemag.com" target="_blank" rel="noopener">https://www.automobilemag.com</a></p>
  296.                            <p>DA: <strong>77</strong></p>
  297.                            <p>Backlinks: <strong>500,000</strong></p>
  298.                        </article>
  299.                                            <article class="card" role="group" aria-label="Inside EVs">
  300.                            <h4>Inside EVs</h4>
  301.                            <p><a href="https://insideevs.com" target="_blank" rel="noopener">https://insideevs.com</a></p>
  302.                            <p>DA: <strong>81</strong></p>
  303.                            <p>Backlinks: <strong>610,000</strong></p>
  304.                        </article>
  305.                                            <article class="card" role="group" aria-label="DriveTribe">
  306.                            <h4>DriveTribe</h4>
  307.                            <p><a href="https://drivetribe.com" target="_blank" rel="noopener">https://drivetribe.com</a></p>
  308.                            <p>DA: <strong>66</strong></p>
  309.                            <p>Backlinks: <strong>320,000</strong></p>
  310.                        </article>
  311.                                            <article class="card" role="group" aria-label="Autocar">
  312.                            <h4>Autocar</h4>
  313.                            <p><a href="https://www.autocar.co.uk" target="_blank" rel="noopener">https://www.autocar.co.uk</a></p>
  314.                            <p>DA: <strong>83</strong></p>
  315.                            <p>Backlinks: <strong>610,000</strong></p>
  316.                        </article>
  317.                                            <article class="card" role="group" aria-label="Motor1 (FR)">
  318.                            <h4>Motor1 (FR)</h4>
  319.                            <p><a href="https://fr.motor1.com" target="_blank" rel="noopener">https://fr.motor1.com</a></p>
  320.                            <p>DA: <strong>68</strong></p>
  321.                            <p>Backlinks: <strong>340,000</strong></p>
  322.                        </article>
  323.                                    </div>
  324.            </div>
  325.  
  326.            <button class="slider-btn slider-btn-right" id="btnNext" aria-label="Next" title="Next">&#10095;</button>
  327.        </div>
  328.  
  329.        <div class="dots" id="dots"></div>
  330.    </section>
  331.  
  332.    <!-- FEATURED -->
  333.    <section id="featured">
  334.        <h2>🚗 Featured Automobile Websites</h2>
  335.                    <p class="muted">No featured websites available yet.</p>
  336.            </section>
  337.  
  338.    <!-- LISTINGS -->
  339.    <section id="listings">
  340.        <h2>Automobile Website Directory</h2>
  341.                    <p class="muted">No listings found yet. Be the first to <a href="#submit">add your website</a>!</p>
  342.            </section>
  343.  
  344.    <!-- SUBMIT -->
  345.    <section id="submit">
  346.        <h2>List Your Automobile Website</h2>
  347.        <p class="small">Submit your automobile website to appear in our directory. Featured listings require a paid plan.</p>
  348.        <button class="btn" id="openModal">Submit Your Website</button>
  349.    </section>
  350.  
  351. </div>
  352.  
  353. <!-- MODAL FORM -->
  354. <div class="modal" id="modal" role="dialog" aria-modal="true" aria-labelledby="modalTitle">
  355.    <div class="dialog">
  356.        <button class="close" id="closeModal" aria-label="Close">&times;</button>
  357.        <h2 id="modalTitle">Submit Your Website</h2>
  358.  
  359.        <form method="POST" action="process_submission.php" id="submitForm">
  360.            <div class="grid-two">
  361.                <div>
  362.                    <label>Website Name</label>
  363.                    <input type="text" name="name" required placeholder="Example: John's Auto Sales">
  364.                </div>
  365.                <div>
  366.                    <label>Contact Email</label>
  367.                    <input type="email" name="email" required placeholder="owner@example.com">
  368.                </div>
  369.            </div>
  370.  
  371.            <label>Website URL</label>
  372.            <input type="url" name="url" required placeholder="https://example.com">
  373.  
  374.            <label>Category</label>
  375.            <select name="category_id" required>
  376.                <option value="">-- Select Category --</option>
  377.                            </select>
  378.  
  379.            <label>Description</label>
  380.            <textarea name="description" placeholder="Short description of the website" required></textarea>
  381.  
  382.            <div class="grid-two">
  383.                <div>
  384.                    <label>Payment Method</label>
  385.                    <select name="payment_method" required>
  386.                        <option value="crypto">Crypto</option>
  387.                        <option value="paypal">PayPal</option>
  388.                        <option value="bank_transfer">Bank Transfer</option>
  389.                        <option value="moneygram">MoneyGram</option>
  390.                    </select>
  391.                </div>
  392.                <div>
  393.                    <label>Subscription Plan</label>
  394.                    <select name="plan" required>
  395.                        <option value="monthly">Monthly - $5</option>
  396.                        <option value="half_year">6 Months - $25</option>
  397.                        <option value="yearly">1 Year - $45</option>
  398.                    </select>
  399.                </div>
  400.            </div>
  401.  
  402.            <label>Transaction ID / Reference</label>
  403.            <input type="text" name="txid" required placeholder="Transaction ID, PayPal txn id, or bank reference">
  404.  
  405.            <p class="small">After submission, admin will verify payment and approve the listing.</p>
  406.  
  407.            <div style="margin-top:12px; display:flex; gap:8px; justify-content:flex-end;">
  408.                <button type="button" class="btn" id="cancelBtn">Cancel</button>
  409.                <button type="submit" class="btn">Submit</button>
  410.            </div>
  411.        </form>
  412.    </div>
  413. </div>
  414.  
  415. <footer>
  416.    <div style="max-width:var(--max-width); margin:18px auto; padding:0 16px; text-align:center; color:#666;">
  417.        <small>&copy; 2025 AutoSelection Directory. All rights reserved.</small>
  418.    </div>
  419. </footer>
  420.  
  421. <script>
  422. /* ====== Modal logic ====== */
  423. (function(){
  424.    const open = document.getElementById('openModal');
  425.    const modal = document.getElementById('modal');
  426.    const close = document.getElementById('closeModal');
  427.    const cancel = document.getElementById('cancelBtn');
  428.  
  429.    function openModal(){ modal.style.display = 'flex'; document.body.style.overflow='hidden'; }
  430.    function closeModal(){ modal.style.display = 'none'; document.body.style.overflow=''; }
  431.  
  432.    open.addEventListener('click', openModal);
  433.    close.addEventListener('click', closeModal);
  434.    cancel.addEventListener('click', closeModal);
  435.    window.addEventListener('keydown', function(e){ if(e.key === 'Escape') closeModal(); });
  436.    modal.addEventListener('click', function(e){ if(e.target === modal) closeModal(); });
  437. })();
  438.  
  439. /* ====== Slider logic with swipe + responsive behavior ====== */
  440. (function(){
  441.    const track = document.getElementById('sliderTrack');
  442.    const viewport = document.getElementById('sliderViewport');
  443.    const prevBtn = document.getElementById('btnPrev');
  444.    const nextBtn = document.getElementById('btnNext');
  445.    const dotsContainer = document.getElementById('dots');
  446.  
  447.    let cardWidth = 260; // default card width (keeps in sync with CSS)
  448.    const gap = 12;
  449.    let cards; // NodeList of cards
  450.    let cardsPerView = calculateCardsPerView();
  451.    let totalCards = 0;
  452.    let currentIndex = 0; // index of first visible card
  453.    let isDragging = false, startX = 0, currentTranslate = 0, prevTranslate = 0, animationID = 0;
  454.  
  455.    function init() {
  456.        cards = track.querySelectorAll('.card');
  457.        totalCards = cards.length;
  458.        cardsPerView = calculateCardsPerView();
  459.        updateCardWidth();
  460.        createDots();
  461.        goTo(0);
  462.        updateButtons();
  463.        addEvents();
  464.        window.addEventListener('resize', onResize);
  465.        document.addEventListener('keydown', onKey);
  466.    }
  467.  
  468.    function calculateCardsPerView(){
  469.        const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
  470.        if(vw >= 1100) return 3;
  471.        if(vw >= 800) return 2;
  472.        return 1;
  473.    }
  474.  
  475.    function updateCardWidth(){
  476.        // compute card width based on actual DOM width to accommodate responsive sizes
  477.        if(cards.length > 0){
  478.            const style = getComputedStyle(cards[0]);
  479.            const w = cards[0].getBoundingClientRect().width;
  480.            cardWidth = Math.round(w + gap);
  481.        }
  482.    }
  483.  
  484.    function createDots(){
  485.        dotsContainer.innerHTML = '';
  486.        const pageCount = Math.max(1, Math.ceil(totalCards / cardsPerView));
  487.        for(let i=0;i<pageCount;i++){
  488.            const dot = document.createElement('button');
  489.            dot.className = 'dot' + (i===0? ' active':'');
  490.            dot.setAttribute('data-page', i);
  491.            dot.addEventListener('click', () => { goTo(i * cardsPerView); });
  492.            dotsContainer.appendChild(dot);
  493.        }
  494.    }
  495.  
  496.    function updateDots(){
  497.        const dots = dotsContainer.querySelectorAll('.dot');
  498.        const pageIndex = Math.floor(currentIndex / cardsPerView);
  499.        dots.forEach((d, i) => d.classList.toggle('active', i === pageIndex));
  500.    }
  501.  
  502.    function goTo(index){
  503.        // clamp
  504.        if(index < 0) index = 0;
  505.        if(index > totalCards - cardsPerView) index = Math.max(0, totalCards - cardsPerView);
  506.        currentIndex = index;
  507.        const translateX = - index * (cards[0].getBoundingClientRect().width + gap);
  508.        track.style.transform = `translateX(${translateX}px)`;
  509.        updateButtons();
  510.        updateDots();
  511.    }
  512.  
  513.    function next(){
  514.        goTo(currentIndex + cardsPerView);
  515.    }
  516.    function prev(){
  517.        goTo(currentIndex - cardsPerView);
  518.    }
  519.  
  520.    function updateButtons(){
  521.        prevBtn.disabled = (currentIndex === 0);
  522.        nextBtn.disabled = (currentIndex >= totalCards - cardsPerView);
  523.    }
  524.  
  525.    function onResize(){
  526.        const newCardsPerView = calculateCardsPerView();
  527.        if(newCardsPerView !== cardsPerView){
  528.            cardsPerView = newCardsPerView;
  529.            createDots();
  530.        }
  531.        updateCardWidth();
  532.        goTo(Math.floor(currentIndex/cardsPerView)*cardsPerView);
  533.    }
  534.  
  535.    function onKey(e){
  536.        if(e.key === 'ArrowRight') next();
  537.        if(e.key === 'ArrowLeft') prev();
  538.    }
  539.  
  540.    /* ----- Drag / Swipe support ----- */
  541.    function addEvents(){
  542.        // pointer events on track for drag
  543.        track.addEventListener('pointerdown', startDrag);
  544.        track.addEventListener('pointerup', endDrag);
  545.        track.addEventListener('pointercancel', endDrag);
  546.        track.addEventListener('pointermove', onDrag);
  547.  
  548.        // buttons
  549.        prevBtn.addEventListener('click', prev);
  550.        nextBtn.addEventListener('click', next);
  551.  
  552.        // touch support fallback (pointer covers most)
  553.        track.style.touchAction = 'pan-y';
  554.    }
  555.  
  556.    function startDrag(event){
  557.        isDragging = true;
  558.        startX = event.clientX;
  559.        track.style.transition = 'none';
  560.        prevTranslate = getCurrentTranslate();
  561.        event.target.setPointerCapture(event.pointerId);
  562.    }
  563.    function onDrag(event){
  564.        if(!isDragging) return;
  565.        const dx = event.clientX - startX;
  566.        const nextTranslate = prevTranslate + dx;
  567.        track.style.transform = `translateX(${nextTranslate}px)`;
  568.    }
  569.    function endDrag(event){
  570.        if(!isDragging) return;
  571.        isDragging = false;
  572.        const dx = event.clientX - startX;
  573.        const threshold = (cards[0].getBoundingClientRect().width) / 4;
  574.        if(dx < -threshold){
  575.            // swipe left -> next
  576.            next();
  577.        } else if(dx > threshold){
  578.            // swipe right -> prev
  579.            prev();
  580.        } else {
  581.            // snap back to current
  582.            goTo(currentIndex);
  583.        }
  584.        track.style.transition = 'transform 360ms cubic-bezier(.22,.9,.35,1)';
  585.    }
  586.  
  587.    function getCurrentTranslate(){
  588.        const style = window.getComputedStyle(track);
  589.        const matrix = new DOMMatrixReadOnly(style.transform);
  590.        return matrix.m41; // translateX
  591.    }
  592.  
  593.    // initialize slider
  594.    init();
  595. })();
  596. </script>
  597.  
  598. </body>
  599. </html>
  600.  
Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda