<!doctype html>

<html lang="en">

<head>

  <meta charset="utf-8" />

  <meta name="viewport" content="width=device-width, initial-scale=1" />

  <title>PEH Hair Product Analyzer</title>

  <style>

    body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; margin: 24px; background:#fafafa; color:#111; }

    h1 { margin: 0 0 12px; font-size: 1.6rem; }

    .card { background:#fff; border:1px solid #e5e7eb; border-radius:12px; padding:16px; box-shadow:0 1px 4px rgba(0,0,0,.04); }

    textarea { width:100%; min-height:140px; padding:12px; border:1px solid #e5e7eb; border-radius:8px; font-size:14px; }

    button { padding:10px 14px; border-radius:8px; border:1px solid #111; background:#111; color:#fff; cursor:pointer; }

    button.secondary { background:#fff; color:#111; border:1px solid #d1d5db; }

    .flex { display:flex; gap:8px; flex-wrap:wrap; align-items:center; }

    .stats { display:grid; grid-template-columns:repeat(auto-fit,minmax(160px,1fr)); gap:12px; margin:16px 0; }

    .stat { padding:12px; border:1px solid #e5e7eb; border-radius:10px; background:#fff; }

    table { width:100%; border-collapse:collapse; }

    th, td { padding:10px; border-bottom:1px solid #eee; text-align:left; font-size:14px; }

    .badge { display:inline-block; padding:2px 8px; border-radius:999px; border:1px solid #e5e7eb; font-size:12px; }

    .b-h { background:#eef6ff; border-color:#b6dcff; }

    .b-e { background:#eefcf1; border-color:#b7f0c4; }

    .b-p { background:#fff5ef; border-color:#ffd3b6; }

    .b-u { background:#f4f4f5; border-color:#e4e4e7; }

    .muted { color:#6b7280; font-size:12px; }

  </style>

</head>

<body>

  <h1>PEH Hair Product Analyzer</h1>

  <div class="card" style="margin-bottom:16px;">

    <p class="muted">Paste ingredients (comma, semicolon, or new lines). Click “Analyse”.</p>

    <textarea id="inp" placeholder="Aqua (Water), Glycerin, Cetearyl Alcohol, Hydrolyzed Wheat Protein, Dimethicone, Argania Spinosa Kernel Oil, Panthenol, Parfum, Phenoxyethanol, Sodium Hyaluronate"></textarea>

    <div class="flex" style="margin-top:10px;">

      <button id="btn">Analyse</button>

      <button class="secondary" id="btnClear">Clear</button>

      <button class="secondary" id="btnExample">Load example</button>

      <span class="muted">No data leaves your browser.</span>

    </div>

  </div>


  <div class="stats" id="stats"></div>


  <div class="card">

    <div class="flex" style="justify-content:space-between;">

      <strong>Results</strong>

      <div class="flex">

        <button class="secondary" data-filter="all">all</button>

        <button class="secondary" data-filter="humectant">humectant</button>

        <button class="secondary" data-filter="emollient">emollient</button>

        <button class="secondary" data-filter="protein">protein</button>

        <button class="secondary" data-filter="unknown">unknown</button>

      </div>

    </div>

    <div style="overflow:auto; margin-top:8px;">

      <table id="tbl">

        <thead>

          <tr><th>Ingredient</th><th>Category</th><th>Confidence</th><th>Why</th></tr>

        </thead>

        <tbody></tbody>

      </table>

    </div>

    <p class="muted" style="margin-top:8px;">

      Heuristic only. Always consider full formula and how your hair actually responds.

    </p>

  </div>


<script>

const BASE = {

  humectant: [

    "glycerin","propylene glycol","butylene glycol","pentylene glycol","sorbitol","xylitol",

    "honey","aloe barbadensis","aloe vera","hyaluronic acid","sodium hyaluronate",

    "sodium pca","pyrrolidone carboxylic acid","lactic acid","sodium lactate","betaine","urea","panthenol"

  ],

  protein: [

    "hydrolyzed silk","hydrolyzed keratin","hydrolyzed wheat protein","hydrolyzed soy protein",

    "hydrolyzed rice protein","hydrolyzed oat protein","hydrolyzed quinoa","hydrolyzed collagen",

    "arginine","lysine","glycine","serine","proline","cysteine","methionine","peptide","tripeptide","oligopeptide",

    "keratin","collagen"

  ],

  emollient: [

    "argania spinosa kernel oil","argan oil","cocos nucifera oil","coconut oil","olea europaea fruit oil","olive oil",

    "prunus amygdalus dulcis oil","sweet almond oil","butyrospermum parkii butter","shea butter",

    "theobroma cacao seed butter","cocoa butter","mangifera indica seed butter","mango butter",

    "cetearyl alcohol","cetyl alcohol","stearyl alcohol","isopropyl myristate","isopropyl palmitate",

    "caprylic/capric triglyceride","c12-15 alkyl benzoate","dimethicone","amodimethicone","cyclomethicone",

    "cyclopentasiloxane","phenyl trimethicone","petrolatum","mineral oil","paraffinum liquidum","beeswax","cera alba","lanolin"

  ]

};


const RX = {

  protein: [

    /\bhydroly(sed|z(ed)?)\b.*\b(protein|silk|keratin|rice|wheat|soy|oat|quinoa|collagen)\b/i,

    /\b(amino acid|oligopeptide|tripeptide|peptide)s?\b/i,

    /\bkeratin\b/i, /\bcollagen\b/i

  ],

  humectant: [/\b(hyaluronic|hyaluronate)\b/i, /\b(panthenol|betaine|urea|pca|lactate)\b/i],

  emollient: [

    /\b(dimethicone|amodimethicone|cyclo(penta)?siloxane|trimethicone)\b/i,

    /\b(cetearyl|cetyl|stearyl) alcohol\b/i,

    /\b(isopropyl (myristate|palmitate))\b/i,

    /\b(caprylic\/?capric triglyceride)\b/i,

    /\b(\w+\s)?(oil|butter|wax)\b/i,

    /\b(petrolatum|mineral oil|paraffinum liquidum|lanolin|cera alba|beeswax)\b/i

  ]

};


const $ = (s, r=document) => r.querySelector(s);

const $$ = (s, r=document) => Array.from(r.querySelectorAll(s));

const norm = t => t.toLowerCase().replace(/\s+/g,' ').replace(/\s*,\s*/g,', ').trim();

const split = raw => norm(raw).split(/[,;\n]/).map(s=>s.trim()).filter(Boolean);


const SETS = {

  humectant: new Set(BASE.humectant.map(norm)),

  protein:   new Set(BASE.protein.map(norm)),

  emollient: new Set(BASE.emollient.map(norm))

};


function classify(ing) {

  const text = norm(ing);

  const score = { humectant:0, protein:0, emollient:0 };

  const reasons = [];


  for (const cat of Object.keys(SETS)) {

    if (SETS[cat].has(text)) { score[cat]+=2; reasons.push(`${cat}: exact match`); }

  }

  for (const cat of Object.keys(RX)) {

    for (const r of RX[cat]) {

      if (r.test(ing)) { score[cat]+=1; reasons.push(`${cat}: heuristic`); break; }

    }

  }

  const sorted = Object.entries(score).sort((a,b)=>b[1]-a[1]);

  const [label, pts] = sorted[0];

  const conf = pts ? (pts>=2?0.9:0.6) : 0;

  return { label: pts?label:"unknown", confidence: conf, reasons };

}


function renderStats(rows) {

  const total = rows.length || 1;

  const c = { humectant:0, emollient:0, protein:0, unknown:0 };

  rows.forEach(r => c[r.result.label]++);

  const pct = k => Math.round((c[k]/total)*100);


  $('#stats').innerHTML = `

    <div class="stat"><div><strong>Humectants</strong></div><div>${pct('humectant')}% <span class="muted">(${c.humectant})</span></div></div>

    <div class="stat"><div><strong>Emollients</strong></div><div>${pct('emollient')}% <span class="muted">(${c.emollient})</span></div></div>

    <div class="stat"><div><strong>Proteins</strong></div><div>${pct('protein')}% <span class="muted">(${c.protein})</span></div></div>

    <div class="stat"><div><strong>Unknown</strong></div><div>${pct('unknown')}% <span class="muted">(${c.unknown})</span></div></div>

  `;

}


function renderTable(rows) {

  const tbody = $('#tbl tbody');

  tbody.innerHTML = rows.map(r => `

    <tr>

      <td><strong>${r.ingredient}</strong></td>

      <td>

        ${

          r.result.label==='humectant' ? '<span class="badge b-h">humectant</span>' :

          r.result.label==='emollient'  ? '<span class="badge b-e">emollient</span>' :

          r.result.label==='protein'    ? '<span class="badge b-p">protein</span>' :

                                           '<span class="badge b-u">unknown</span>'

        }

      </td>

      <td>${Math.round(r.result.confidence*100)}%</td>

      <td>${r.result.reasons.map(x=>`<span class="badge">${x}</span>`).join(' ')}</td>

    </tr>

  `).join('');

}


let current = [];

let filter = 'all';


function run() {

  const tokens = split($('#inp').value);

  current = tokens.map(ing => ({ ingredient: ing, result: classify(ing) }));

  applyFilter();

  renderStats(current);

}


function applyFilter() {

  const rows = filter==='all' ? current : current.filter(r => r.result.label===filter);

  renderTable(rows);

}


$('#btn').addEventListener('click', run);

$('#btnClear').addEventListener('click', () => { $('#inp').value=''; current=[]; renderTable([]); renderStats([]); });

$('#btnExample').addEventListener('click', () => {

  $('#inp').value = 'Aqua (Water), Glycerin, Cetearyl Alcohol, Behentrimonium Chloride, Hydrolyzed Wheat Protein, Dimethicone, Argania Spinosa Kernel Oil, Panthenol, Parfum, Phenoxyethanol, Sodium Hyaluronate';

});

$$('button[data-filter]').forEach(b=>{

  b.addEventListener('click', ()=>{ filter=b.dataset.filter; applyFilter(); });

});

</script>

</body>

</html>