Line sheet template: one page of styles and prices, sent as a link

A line sheet is the page a stockist uses to decide what to order. Here is one you can copy, an AI prompt to fill it with your styles, and a way to send it so a price change reaches everyone.

If you searched for how to create a brochure online, the version a stockist wants is a line sheet. It is one page listing each style with its style number, wholesale price and suggested retail price, plus your minimums and dates.

You can build it as a web page and send one link instead of a file.

Below is a line sheet for a made-up brand. Filter by category, enter some quantities, and watch the total and the opening-order check change. The button at the bottom turns the order into text.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Fernlake Goods line sheet</title>
<style>
  * { box-sizing: border-box; }
  body { margin: 0; font-family: system-ui, sans-serif; background: #f6f4ef; color: #23262d; line-height: 1.45; padding-bottom: 84px; }
  .wrap { max-width: 980px; margin: 0 auto; padding: 0 14px; }
  header { background: #2f4a3c; color: #fff; padding: 22px 0 18px; }
  header h1 { margin: 0 0 2px; font-size: 24px; }
  header p { margin: 0; font-size: 14px; opacity: .92; }
  .terms { background: #fff; border: 1px solid #e3ded2; border-radius: 12px; margin: 14px 0; padding: 12px 14px; display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px 14px; }
  .terms dt { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: #6a6f78; }
  .terms dd { margin: 0 0 2px; font-size: 14px; font-weight: 600; overflow-wrap: anywhere; }
  .chips { display: flex; gap: 6px; flex-wrap: wrap; margin: 0 0 12px; }
  .chip { border: 1px solid #c9c3b3; background: #fff; border-radius: 999px; padding: 7px 14px; font: inherit; font-size: 14px; cursor: pointer; }
  .chip[aria-pressed="true"] { background: #2f4a3c; color: #fff; border-color: #2f4a3c; }
  .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); gap: 12px; }
  .card { background: #fff; border: 1px solid #e3ded2; border-radius: 12px; overflow: hidden; display: flex; flex-direction: column; }
  .card.warn { border-color: #d98a3d; }
  .art { background: #ece8dc; height: 130px; display: flex; align-items: center; justify-content: center; position: relative; }
  .art svg { height: 100px; width: auto; }
  .tag { position: absolute; top: 8px; left: 8px; font-size: 12px; font-weight: 700; padding: 2px 8px; border-radius: 999px; background: #ffe9a8; color: #6b4a00; }
  .tag.out { background: #e6e6e6; color: #555; }
  .body { padding: 10px 12px 12px; display: flex; flex-direction: column; gap: 4px; flex: 1; }
  .sku { font-size: 12px; font-weight: 700; color: #6a6f78; letter-spacing: .03em; }
  .name { font-size: 16px; font-weight: 700; margin: 0; }
  .desc, .meta { font-size: 13px; color: #4a4f58; margin: 0; }
  .sw { display: inline-block; width: 12px; height: 12px; border-radius: 50%; border: 1px solid #0003; vertical-align: -1px; margin-right: 3px; }
  .prices { display: flex; gap: 14px; margin: 6px 0 2px; }
  .prices div { font-size: 12px; color: #6a6f78; }
  .prices b { display: block; font-size: 19px; color: #23262d; }
  .prices .w b { color: #2f4a3c; }
  .order { margin-top: auto; padding-top: 8px; display: flex; align-items: center; gap: 8px; font-size: 13px; }
  .order input { width: 76px; padding: 7px 8px; font: inherit; font-size: 15px; border: 1px solid #b9b3a3; border-radius: 8px; }
  .order .note { color: #b4470c; font-weight: 600; }
  .bar { position: fixed; left: 0; right: 0; bottom: 0; background: #fff; border-top: 1px solid #d9d3c4; padding: 10px 0; box-shadow: 0 -2px 10px #0001; }
  .bar .wrap { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
  .tot { font-size: 18px; font-weight: 700; }
  .min { font-size: 13px; font-weight: 600; }
  .min.ok { color: #0f6b3a; } .min.no { color: #b4470c; }
  .btn { background: #2f4a3c; color: #fff; border: 0; border-radius: 8px; padding: 10px 14px; font: inherit; font-size: 14px; font-weight: 600; cursor: pointer; }
  #summary { display: none; margin: 14px 0; }
  #summary.on { display: block; }
  #summary textarea { width: 100%; min-height: 130px; font: 13px/1.4 ui-monospace, Consolas, monospace; padding: 8px; border: 1px solid #b9b3a3; border-radius: 8px; }
  footer { font-size: 13px; color: #6a6f78; padding: 14px 0 0; }
  @media print { .bar, .chips, .order, #summary { display: none; } body { background: #fff; padding: 0; } .card { break-inside: avoid; } }
</style>
</head>
<body>
<header><div class="wrap">
  <h1>Fernlake Goods</h1>
  <p>Spring 2027 line sheet &middot; prices in USD &middot; updated 1 Oct 2026 (fictional brand)</p>
</div></header>

<div class="wrap">
  <dl class="terms">
    <div><dt>Opening order</dt><dd>$300 minimum</dd></div>
    <div><dt>Per style</dt><dd>Sold in packs (see card)</dd></div>
    <div><dt>Order by</dt><dd>10 Jan 2027</dd></div>
    <div><dt>Ships from</dt><dd>15 Feb 2027</dd></div>
    <div><dt>Orders to</dt><dd>orders@fernlake.example</dd></div>
  </dl>

  <div class="chips" id="chips"></div>
  <div class="grid" id="grid"></div>

  <section id="summary">
    <h2 style="font-size:16px;margin:0 0 6px">Your order, as text</h2>
    <textarea id="text" readonly></textarea>
    <p style="font-size:13px;margin:6px 0 0">Select the text, copy it, and paste it into your email to orders@fernlake.example. Nothing is sent from this page.</p>
  </section>
  <footer>Wholesale prices exclude shipping. Retail prices are suggested.</footer>
</div>

<div class="bar"><div class="wrap">
  <div><div class="tot" id="total">Order total $0</div><div class="min no" id="min">$300 to reach the opening order</div></div>
  <button class="btn" id="show" type="button">Show order as text</button>
</div></div>

<script>
  // Edit this list to change the page. One object per style.
  const OPENING_MIN = 300;
  const COLORS = { Oat: '#d8c9a8', Moss: '#5d7a54', Ink: '#27324a', Rust: '#b0583a', Cream: '#efe7d3', Slate: '#5f6b73', Pine: '#2f5a45', Fig: '#6d3b52', Heather: '#a59cb0', Plum: '#5a2d4f', Sand: '#cdb88f' };
  const STYLES = [
    { sku: 'FL-101', name: 'Market tote', cat: 'Bags', art: 'tote', desc: 'Heavy cotton canvas with an inside pocket.', colors: ['Oat', 'Moss', 'Ink'], size: 'One size, 38 x 40 cm', w: 14, r: 32, pack: 6 },
    { sku: 'FL-102', name: 'Linen napkins, set of 4', cat: 'Home', art: 'napkin', desc: 'Stonewashed linen, hemmed edges.', colors: ['Oat', 'Rust'], size: '45 x 45 cm', w: 18, r: 40, pack: 4 },
    { sku: 'FL-201', name: 'Stoneware mug', cat: 'Kitchen', art: 'mug', desc: 'Hand-glazed, dishwasher safe.', colors: ['Slate', 'Cream'], size: '350 ml', w: 9, r: 22, pack: 12 },
    { sku: 'FL-202', name: 'Soy candle', cat: 'Home', art: 'candle', desc: 'Poured in small batches. About 40 hours.', colors: ['Pine', 'Fig'], size: '180 g', w: 11, r: 26, pack: 6 },
    { sku: 'FL-301', name: 'Wool scarf', cat: 'Accessories', art: 'scarf', desc: 'Soft lambswool with a fringed end.', colors: ['Heather', 'Plum'], size: '180 x 30 cm', w: 22, r: 52, pack: 4, status: 'New' },
    { sku: 'FL-302', name: 'Bucket hat', cat: 'Accessories', art: 'hat', desc: 'Washed cotton twill.', colors: ['Moss', 'Sand'], size: 'S/M and M/L', w: 12, r: 30, pack: 6, status: 'Sold out' }
  ];

  const ART = {
    tote: (c) => '<svg viewBox="0 0 100 100"><path d="M34 38 C34 10 66 10 66 38" fill="none" stroke="#0007" stroke-width="4"/><rect x="18" y="38" width="64" height="54" rx="4" fill="' + c + '" stroke="#0004"/></svg>',
    napkin: (c) => '<svg viewBox="0 0 100 100"><rect x="26" y="26" width="52" height="52" fill="#0002" transform="rotate(8 52 52)"/><rect x="22" y="22" width="52" height="52" fill="' + c + '" stroke="#0004" transform="rotate(-6 48 48)"/></svg>',
    mug: (c) => '<svg viewBox="0 0 100 100"><path d="M72 40 h8 a10 10 0 0 1 0 24 h-8" fill="none" stroke="' + c + '" stroke-width="6"/><rect x="22" y="28" width="52" height="60" rx="8" fill="' + c + '" stroke="#0004"/></svg>',
    candle: (c) => '<svg viewBox="0 0 100 100"><path d="M50 8 C58 20 56 28 50 32 C44 28 42 20 50 8Z" fill="#f2a93b"/><rect x="48" y="30" width="4" height="10" fill="#333"/><rect x="26" y="40" width="48" height="50" rx="6" fill="' + c + '" stroke="#0004"/></svg>',
    scarf: (c) => '<svg viewBox="0 0 100 100"><path d="M14 30 Q50 10 86 30 L86 48 Q50 28 14 48Z" fill="' + c + '" stroke="#0004"/><rect x="62" y="40" width="20" height="46" fill="' + c + '" stroke="#0004"/></svg>',
    hat: (c) => '<svg viewBox="0 0 100 100"><path d="M30 60 C30 20 70 20 70 60Z" fill="' + c + '" stroke="#0004"/><ellipse cx="50" cy="62" rx="40" ry="10" fill="' + c + '" stroke="#0004"/></svg>'
  };

  const grid = document.getElementById('grid');
  const chips = document.getElementById('chips');
  let filter = 'All';

  function money(n) { return '$' + n.toLocaleString('en-US'); }

  function render() {
    grid.innerHTML = '';
    STYLES.filter((s) => filter === 'All' || s.cat === filter).forEach((s) => {
      const out = s.status === 'Sold out';
      const margin = Math.round(((s.r - s.w) / s.r) * 100);
      const card = document.createElement('article');
      card.className = 'card';
      card.dataset.sku = s.sku;
      card.innerHTML =
        '<div class="art">' + ART[s.art](COLORS[s.colors[0]]) + (s.status ? '<span class="tag' + (out ? ' out' : '') + '">' + s.status + '</span>' : '') + '</div>' +
        '<div class="body">' +
        '<div class="sku">' + s.sku + '</div><h3 class="name">' + s.name + '</h3>' +
        '<p class="desc">' + s.desc + '</p>' +
        '<p class="meta">' + s.colors.map((c) => '<span class="sw" style="background:' + COLORS[c] + '"></span>' + c).join(' &nbsp; ') + '</p>' +
        '<p class="meta">' + s.size + ' &middot; packs of ' + s.pack + '</p>' +
        '<div class="prices"><div class="w">Wholesale<b>' + money(s.w) + '</b></div><div>Suggested retail<b>' + money(s.r) + '</b></div><div>Margin<b>' + margin + '%</b></div></div>' +
        '<div class="order">' + (out ? '<span class="meta">Not available this season</span>' :
          '<label>Units <input type="number" min="0" step="' + s.pack + '" value="' + (qty[s.sku] || 0) + '" inputmode="numeric"></label><span class="note"></span>') + '</div>' +
        '</div>';
      grid.appendChild(card);
      const input = card.querySelector('input');
      if (input) input.addEventListener('input', () => { qty[s.sku] = Math.max(0, parseInt(input.value, 10) || 0); update(); });
    });
    update();
  }

  const qty = {};
  function update() {
    let total = 0;
    document.querySelectorAll('.card').forEach((card) => {
      const s = STYLES.find((x) => x.sku === card.dataset.sku);
      const q = qty[s.sku] || 0;
      const bad = q > 0 && q % s.pack !== 0;
      card.classList.toggle('warn', bad);
      const note = card.querySelector('.note');
      if (note) note.textContent = bad ? 'Multiples of ' + s.pack : '';
    });
    STYLES.forEach((s) => { total += (qty[s.sku] || 0) * s.w; });
    document.getElementById('total').textContent = 'Order total ' + money(total);
    const min = document.getElementById('min');
    const ok = total >= OPENING_MIN;
    min.className = 'min ' + (ok ? 'ok' : 'no');
    min.textContent = ok ? 'Opening order minimum met' : money(OPENING_MIN - total) + ' to reach the opening order';
    return total;
  }

  document.getElementById('show').addEventListener('click', () => {
    const lines = STYLES.filter((s) => qty[s.sku] > 0).map((s) => s.sku + '  ' + s.name + '  x ' + qty[s.sku] + '  = ' + money(qty[s.sku] * s.w));
    document.getElementById('text').value = lines.length ? lines.join('\n') + '\nTotal: ' + money(update()) : 'No units entered yet.';
    const box = document.getElementById('summary');
    box.classList.add('on');
    box.scrollIntoView({ behavior: 'smooth', block: 'center' });
  });

  ['All', 'Bags', 'Home', 'Kitchen', 'Accessories'].forEach((c) => {
    const b = document.createElement('button');
    b.type = 'button'; b.className = 'chip'; b.textContent = c;
    b.setAttribute('aria-pressed', c === 'All');
    b.addEventListener('click', () => {
      filter = c;
      chips.querySelectorAll('.chip').forEach((x) => x.setAttribute('aria-pressed', x === b));
      render();
    });
    chips.appendChild(b);
  });
  render();
</script>
</body>
</html>
A line sheet with six styles. The styles live in one list near the bottom of the code.

A stockist sees prices, margin and terms together, and can try an order without writing to you first. Your own changes are a one-line edit in the list. A visitor's quantities are not saved.

Make it with AI

You do not have to write the page yourself. Paste your product list into ChatGPT, Claude or Gemini with this prompt.

Make one HTML page that works as a wholesale line sheet.
Header with brand name, season and an "updated" date. Under it,
a terms box: opening order minimum, order-by date, ship date,
contact email. Then one card per style with style number, name,
colours, size, pack size, wholesale price and suggested retail
price. Put the styles in one JavaScript list near the bottom.
Category filter buttons at the top. Large text, works on a phone.
No outside libraries, images or fonts. Do not save data.

[paste your styles here]

Then check the result before you send it:

  • Every price. Compare wholesale and retail for each style with your own sheet. An AI can swap two numbers without telling you.
  • Every minimum and date. Opening order, pack size, order-by and ship dates are the terms a stockist will hold you to.
  • Style numbers. Stockists order by them, so one typo costs you a wrong order.
  • Pictures. The example draws each product as a simple shape, because pictures loaded from other websites are blocked on a shared page.
  • Phone width. Make the browser window narrow and confirm the cards still read.
  1. Copy all of the code the AI returned.
  2. Paste it into a NOS document. The page renders and its scripts run, so test the filters and quantities yourself.
  3. Choose Create share link and copy the address. HTML to link walks through it.
  4. Put that address in your email to the stockist.
From a list of styles to one link, in four steps.
From a list of styles to one link, in four steps.

Anyone with the link can open the page in a browser, on a phone or a laptop, without an account. They cannot edit it, and the quantities they type are not saved.

If a phone shows a file you sent as plain text, see opening an HTML file on a phone.

What a stockist sees when the link is opened on a phone.
What a stockist sees when the link is opened on a phone.

Some stockists will still want a file for their records. As of October 2026, Chrome's help says to open the print preview with Ctrl+P and choose Save as PDF. Do that from the open page.

Email size is another reason to send a link. Gmail's help says the limit for a personal account is 25 MB, and that larger attachments are replaced by a Google Drive link. Work and school accounts have limits their administrators set.

For a trade-show table, print the link as a QR code. QR code link explains why a printed code stays useful when the page behind it changes.

What to put on each style

Two sources agree on the core fields. Maker's Row lists a photo or sketch, style number, description, sizes, colours and prices.

It also lists minimum order, case pack, delivery date and contact. RepSpark adds order deadlines and terms.

Field Why a stockist looks for it
Photo To judge the product at a glance
Style number To write the order and to reorder
Sizes and colours To pick what fits their shop
Wholesale price What they pay per unit
Suggested retail price What they would charge, so they can see their margin
Minimum and pack size To see whether your minimums fit their shop
Order-by and ship dates To plan their season

Maker's Row also advises stating minimums, case pack and delivery date plainly rather than writing "contact us". The example page works out each style's margin from your two prices, so you never type it.

PDF attachment Link to a page
What the stockist holds A copy An address
After a price change Send a new file Edit once, same link
Size in email Counts toward the mail limit A short address
Stock or sold-out tags Out of date once sent Update the page
Printing Prints as laid out Print from the browser

A PDF is not wrong. Maker's Row says a simple PDF or spreadsheet works for a first line sheet. A link helps when the numbers move.

Keep prices and stock current

RepSpark describes static line sheets as going stale as soon as inventory or prices change. A buyer holding last month's file orders from last month's numbers.

A price change as a new file compared with a change on a page.
A price change as a new file compared with a change on a page.

On a page, you fix the line in the list and paste the code again into the same NOS document. The address already in your stockists' emails shows the change.

Put an updated date at the top so they can see it is current. For a long range, this table version keeps one row per style and adds a status tag.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Lanternfly Paper line sheet</title>
<style>
  * { box-sizing: border-box; }
  body { margin: 0; font-family: system-ui, sans-serif; background: #f4f6fa; color: #1d2330; line-height: 1.45; }
  .wrap { max-width: 860px; margin: 0 auto; padding: 0 14px 24px; }
  header { padding: 20px 0 10px; }
  header h1 { margin: 0; font-size: 22px; }
  header p { margin: 2px 0 0; font-size: 14px; color: #5b6472; }
  .tools { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin: 10px 0; }
  .tab { border: 1px solid #c4cbd8; background: #fff; border-radius: 8px; padding: 8px 14px; font: inherit; font-size: 14px; font-weight: 600; cursor: pointer; }
  .tab[aria-pressed="true"] { background: #243b6b; border-color: #243b6b; color: #fff; }
  .tools input[type=search] { flex: 1; min-width: 140px; padding: 8px 10px; font: inherit; font-size: 14px; border: 1px solid #c4cbd8; border-radius: 8px; }
  .tools label { font-size: 14px; display: flex; gap: 6px; align-items: center; }
  table { width: 100%; border-collapse: collapse; background: #fff; border-radius: 10px; overflow: hidden; font-size: 14px; }
  th { text-align: left; background: #243b6b; color: #fff; font-size: 12px; text-transform: uppercase; letter-spacing: .04em; padding: 9px 8px; }
  td { padding: 9px 8px; border-bottom: 1px solid #e7eaf1; vertical-align: top; }
  td.n, th.n { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
  .sku { font-weight: 700; white-space: nowrap; }
  .st { display: inline-block; font-size: 12px; font-weight: 700; padding: 1px 8px; border-radius: 999px; }
  .st.in { background: #dff3e6; color: #0f5132; }
  .st.soon { background: #ffe9a8; color: #6b4a00; }
  .st.out { background: #e6e8ee; color: #4a5260; }
  .sold td { color: #7a8190; }
  .m { display: none; }
  .showm .m { display: table-cell; }
  .empty { padding: 16px; text-align: center; color: #5b6472; background: #fff; }
  .foot { font-size: 13px; color: #5b6472; margin-top: 10px; }
  @media (max-width: 560px) {
    thead { display: none; }
    table, tbody, tr, td { display: block; width: 100%; }
    tr { padding: 10px 12px; border-bottom: 1px solid #e7eaf1; }
    td { border: 0; padding: 1px 0; text-align: left !important; }
    td.n { display: inline-block; width: auto; margin-right: 14px; }
    td[data-l]::before { content: attr(data-l) ": "; color: #5b6472; font-size: 12px; }
    .m { display: none !important; }
    .showm td.m { display: inline-block !important; }
  }
</style>
</head>
<body>
<div class="wrap">
  <header>
    <h1>Lanternfly Paper Co.</h1>
    <p>Line sheet &middot; prices in USD &middot; updated 1 Oct 2026 (fictional brand)</p>
  </header>
  <div class="tools">
    <button class="tab" data-season="Autumn 2026" type="button" aria-pressed="true">Autumn 2026</button>
    <button class="tab" data-season="Spring 2027" type="button" aria-pressed="false">Spring 2027</button>
    <input id="q" type="search" placeholder="Search style or name" aria-label="Search styles">
    <label><input id="mg" type="checkbox"> Show margin</label>
  </div>
  <div id="wrap"></div>
  <p class="foot" id="foot"></p>
</div>

<script>
  // Edit this list to change the page. status: in, soon or out.
  const STYLES = [
    { season: 'Autumn 2026', sku: 'LP-A10', name: 'Pocket notebook, 3-pack', colors: 'Kraft, Sage, Dusk', min: 6, w: 8, r: 18, status: 'in' },
    { season: 'Autumn 2026', sku: 'LP-A11', name: 'Weekly planner pad', colors: 'Cream', min: 6, w: 7, r: 16, status: 'in' },
    { season: 'Autumn 2026', sku: 'LP-A20', name: 'Letterpress card, set of 6', colors: 'Mixed', min: 12, w: 9, r: 20, status: 'soon', note: 'Ships 20 Nov' },
    { season: 'Autumn 2026', sku: 'LP-A30', name: 'Brass bookmark', colors: 'Brass', min: 12, w: 4, r: 10, status: 'out' },
    { season: 'Autumn 2026', sku: 'LP-A40', name: 'Gift wrap, 3 sheets', colors: 'Moss, Ink', min: 10, w: 5, r: 12, status: 'in' },
    { season: 'Spring 2027', sku: 'LP-S10', name: 'Seed-paper card, set of 4', colors: 'Mixed', min: 12, w: 8, r: 18, status: 'soon', note: 'Ships 15 Feb' },
    { season: 'Spring 2027', sku: 'LP-S20', name: 'Garden journal', colors: 'Leaf, Clay', min: 6, w: 11, r: 24, status: 'soon', note: 'Ships 15 Feb' },
    { season: 'Spring 2027', sku: 'LP-S30', name: 'Sticker sheet, 5-pack', colors: 'Mixed', min: 20, w: 6, r: 14, status: 'soon', note: 'Ships 1 Mar' }
  ];
  const LABEL = { in: 'In stock', soon: 'Coming', out: 'Sold out' };
  let season = 'Autumn 2026';

  function money(n) { return '$' + n.toFixed(2); }
  function cell(text, label, cls) {
    const td = document.createElement('td');
    td.textContent = text;
    if (label) td.dataset.l = label;
    if (cls) td.className = cls;
    return td;
  }

  function render() {
    const q = document.getElementById('q').value.trim().toLowerCase();
    const rows = STYLES.filter((s) => s.season === season && (s.sku + ' ' + s.name).toLowerCase().includes(q));
    const host = document.getElementById('wrap');
    host.innerHTML = '';
    if (!rows.length) { host.innerHTML = '<div class="empty">No styles match.</div>'; return; }
    const table = document.createElement('table');
    table.innerHTML = '<thead><tr><th>Style</th><th>Item</th><th>Colours</th><th class="n">Min</th><th class="n">Wholesale</th><th class="n">Retail</th><th class="n m">Margin</th><th>Status</th></tr></thead>';
    const body = document.createElement('tbody');
    rows.forEach((s) => {
      const tr = document.createElement('tr');
      if (s.status === 'out') tr.className = 'sold';
      tr.appendChild(cell(s.sku, '', 'sku'));
      tr.appendChild(cell(s.name, ''));
      tr.appendChild(cell(s.colors, 'Colours'));
      tr.appendChild(cell(s.min, 'Min', 'n'));
      tr.appendChild(cell(money(s.w), 'Wholesale', 'n'));
      tr.appendChild(cell(money(s.r), 'Retail', 'n'));
      tr.appendChild(cell(Math.round(((s.r - s.w) / s.r) * 100) + '%', 'Margin', 'n m'));
      const st = document.createElement('td');
      const tag = document.createElement('span');
      tag.className = 'st ' + s.status;
      tag.textContent = LABEL[s.status] + (s.note ? ' - ' + s.note : '');
      st.appendChild(tag);
      tr.appendChild(st);
      body.appendChild(tr);
    });
    table.appendChild(body);
    host.appendChild(table);
    document.getElementById('foot').textContent = rows.length + ' styles. Min is the smallest order per style, in units.';
  }

  document.querySelectorAll('.tab').forEach((b) => b.addEventListener('click', () => {
    season = b.dataset.season;
    document.querySelectorAll('.tab').forEach((x) => x.setAttribute('aria-pressed', x === b));
    render();
  }));
  document.getElementById('q').addEventListener('input', render);
  document.getElementById('mg').addEventListener('change', (e) => document.body.classList.toggle('showm', e.target.checked));
  render();
</script>
</body>
</html>
Two seasons on one page, with search, a margin toggle and a status tag on every style.

If your prices are for one account only, see price list link. For a catalogue with photos, see catalogue as a link.

When it does not work

Symptom Cause Fix
The stockist sees code, not a page The file was sent as an attachment and opened as text Send the link, not the file
A price is wrong on the page The AI changed or swapped it Fix the line in the list, paste again
The category buttons do nothing A line was lost when copying Copy all of the AI's code again
Photos or fonts are missing They come from another website, which the page blocks Ask for a version with drawn shapes and no outside images
An order cannot be sent from the page NOS blocks forms that send to a server Use the order-as-text button and email it
You cannot see who opened it NOS does not record opens Ask the stockist to reply

For a deeper check before you send any page an AI wrote, read share AI-generated HTML. To change one price without touching code, see edit AI-generated HTML without code.

Questions people ask

What is a line sheet?

A line sheet is a sales document that lists your products with photos, style numbers, prices and ordering information, so a wholesale buyer can decide what to order without contacting you first. It is shorter and plainer than a catalogue.

What should a line sheet include?

Sources such as Maker's Row and RepSpark list the same core fields: a photo, a style number, a description, sizes and colours, the wholesale price and suggested retail price, the minimum order, delivery dates and your contact details.

Is a PDF line sheet still fine?

For a first line sheet, yes. Maker's Row says a simple, well-organised PDF or spreadsheet works. A link earns its place once prices, colours or stock change, because RepSpark notes that a static line sheet goes stale as soon as they do.

Can stockists place an order from this page?

The first example lets a stockist enter quantities and see a running total and the opening-order check. It then shows the order as text to paste into an email. The page sends nothing to a server, since NOS blocks forms that post elsewhere.

Can I see who opened the link?

No. NOS does not record who opens a link. If you need to know a stockist has seen it, ask them to reply to your email.

Keep reading