#if os(macOS)
let openAIDashboardScrapeScript = """

    (() => {
      const textOf = el => {
        const raw = el && (el.innerText || el.textContent) ? String(el.innerText || el.textContent) : '';
        return raw.trim();
      };
      const parseHexColor = (color) => {
        if (!color) return null;
        const c = String(color).trim().toLowerCase();
        if (c.startsWith('#')) {
          if (c.length === 4) {
            return '#' + c[1] + c[1] + c[2] + c[2] + c[3] + c[3];
          }
          if (c.length === 7) return c;
          return c;
        }
        const m = c.match(/^rgba?\\(([^)]+)\\)$/);
        if (m) {
          const parts = m[1].split(',').map(x => parseFloat(x.trim())).filter(x => Number.isFinite(x));
          if (parts.length >= 3) {
            const r = Math.max(0, Math.min(255, Math.round(parts[0])));
            const g = Math.max(0, Math.min(255, Math.round(parts[1])));
            const b = Math.max(0, Math.min(255, Math.round(parts[2])));
            const toHex = n => n.toString(16).padStart(2, '0');
            return '#' + toHex(r) + toHex(g) + toHex(b);
          }
        }
        return c;
      };
      const reactPropsOf = (el) => {
        if (!el) return null;
        try {
          const keys = Object.keys(el);
          const propsKey = keys.find(k => k.startsWith('__reactProps$'));
          if (propsKey) return el[propsKey] || null;
          const fiberKey = keys.find(k => k.startsWith('__reactFiber$'));
          if (fiberKey) {
            const fiber = el[fiberKey];
            return (fiber && (fiber.memoizedProps || fiber.pendingProps)) || null;
          }
        } catch {}
        return null;
      };
      const reactFiberOf = (el) => {
        if (!el) return null;
        try {
          const keys = Object.keys(el);
          const fiberKey = keys.find(k => k.startsWith('__reactFiber$'));
          return fiberKey ? (el[fiberKey] || null) : null;
        } catch {
          return null;
        }
      };
      const nestedBarMetaOf = (root) => {
        if (!root || typeof root !== 'object') return null;
        const queue = [root];
        const seen = typeof WeakSet !== 'undefined' ? new WeakSet() : null;
        let steps = 0;
        while (queue.length && steps < 250) {
          const cur = queue.shift();
          steps++;
          if (!cur || typeof cur !== 'object') continue;
          if (seen) {
            if (seen.has(cur)) continue;
            seen.add(cur);
          }
          if (cur.payload && (cur.dataKey || cur.name || cur.value !== undefined)) return cur;
          const values = Array.isArray(cur) ? cur : Object.values(cur);
          for (const v of values) {
            if (v && typeof v === 'object') queue.push(v);
          }
        }
        return null;
      };
      const barMetaFromElement = (el) => {
        const direct = reactPropsOf(el);
        if (direct && direct.payload && (direct.dataKey || direct.name || direct.value !== undefined)) return direct;

        const fiber = reactFiberOf(el);
        if (fiber) {
          let cur = fiber;
          for (let i = 0; i < 10 && cur; i++) {
            const props = (cur.memoizedProps || cur.pendingProps) || null;
            if (props && props.payload && (props.dataKey || props.name || props.value !== undefined)) return props;
            const nested = props ? nestedBarMetaOf(props) : null;
            if (nested) return nested;
            cur = cur.return || null;
          }
        }

        if (direct) {
          const nested = nestedBarMetaOf(direct);
          if (nested) return nested;
        }
        return null;
      };
      const normalizeHref = (raw) => {
        if (!raw) return null;
        const href = String(raw).trim();
        if (!href) return null;
        if (href.startsWith('http://') || href.startsWith('https://')) return href;
        if (href.startsWith('//')) return window.location.protocol + href;
        if (href.startsWith('/')) return window.location.origin + href;
        return window.location.origin + '/' + href;
      };
      const isLikelyCreditsURL = (raw) => {
        if (!raw) return false;
        try {
          const url = new URL(raw, window.location.origin);
          if (!url.host || !url.host.includes('chatgpt.com')) return false;
          const path = url.pathname.toLowerCase();
          return (
            path.includes('settings') ||
            path.includes('usage') ||
            path.includes('billing') ||
            path.includes('credits')
          );
        } catch {
          return false;
        }
      };
      const purchaseTextMatches = (text) => {
        const lower = String(text || '').trim().toLowerCase();
        if (!lower) return false;
        if (lower.includes('add more')) return true;
        if (!lower.includes('credit')) return false;
        return (
          lower.includes('buy') ||
          lower.includes('add') ||
          lower.includes('purchase') ||
          lower.includes('top up') ||
          lower.includes('top-up')
        );
      };
      const elementLabel = (el) => {
        if (!el) return '';
        return (
          textOf(el) ||
          el.getAttribute('aria-label') ||
          el.getAttribute('title') ||
          ''
        );
      };
      const urlFromProps = (props) => {
        if (!props || typeof props !== 'object') return null;
        const candidates = [
          props.href,
          props.to,
          props.url,
          props.link,
          props.destination,
          props.navigateTo
        ];
        for (const candidate of candidates) {
          if (typeof candidate === 'string' && candidate.trim()) {
            return normalizeHref(candidate);
          }
        }
        return null;
      };
      const purchaseURLFromElement = (el) => {
        if (!el) return null;
        const isAnchor = el.tagName && el.tagName.toLowerCase() === 'a';
        const anchor = isAnchor ? el : (el.closest ? el.closest('a') : null);
        const anchorHref = anchor ? anchor.getAttribute('href') : null;
        const dataHref = el.getAttribute
          ? (el.getAttribute('data-href') ||
            el.getAttribute('data-url') ||
            el.getAttribute('data-link') ||
            el.getAttribute('data-destination'))
          : null;
        const propHref = urlFromProps(reactPropsOf(el)) || urlFromProps(reactPropsOf(anchor));
        const normalized = normalizeHref(anchorHref || dataHref || propHref);
        return normalized && isLikelyCreditsURL(normalized) ? normalized : null;
      };
      const cleanPlanName = (raw) => String(raw || '')
        .replace(/\\b(claude|codex|account|plan)\\b/gi, ' ')
        .replace(/_/g, ' ')
        .replace(/-/g, ' ')
        .replace(/\\s+/g, ' ')
        .trim();
      const codexPlanDisplayName = (raw) => {
        const trimmed = String(raw || '').trim();
        if (!trimmed) return null;
        const lower = trimmed.toLowerCase();
        const exact = {
          pro: 'Pro 20x',
          prolite: 'Pro 5x',
          'pro_lite': 'Pro 5x',
          'pro-lite': 'Pro 5x',
          'pro lite': 'Pro 5x'
        };
        if (exact[lower]) return exact[lower];
        const cleaned = cleanPlanName(trimmed);
        if (!cleaned) return trimmed;
        if (exact[cleaned.toLowerCase()]) return exact[cleaned.toLowerCase()];
        return cleaned.split(' ')
          .filter(Boolean)
          .map(word => {
            const wordLower = word.toLowerCase();
            if (wordLower === 'cbp' || wordLower === 'k12') return wordLower.toUpperCase();
            if (word === word.toUpperCase() && /[a-z]/i.test(word)) return word;
            return word.charAt(0).toUpperCase() + word.slice(1);
          })
          .join(' ') || cleaned;
      };
      const normalizePlanValue = (value) => {
        const trimmed = String(value || '').trim();
        if (!trimmed) return null;
        const lower = trimmed.toLowerCase();
        const allowed = [
          'free',
          'plus',
          'pro',
          'team',
          'enterprise',
          'business',
          'edu',
          'education',
          'gov',
          'premium',
          'essential'
        ];
        if (!allowed.some(token => lower.includes(token))) return null;
        return codexPlanDisplayName(trimmed) || cleanPlanName(trimmed);
      };
      const planCandidate = (key, value) => {
        const lower = String(key || '').toLowerCase();
        if (!lower.includes('plan') && !lower.includes('tier') && !lower.includes('subscription')) return null;
        if (typeof value === 'string') return normalizePlanValue(value);
        if (value && typeof value === 'object' && !Array.isArray(value)) {
          return normalizePlanValue(value.name) ||
            normalizePlanValue(value.displayName) ||
            normalizePlanValue(value.tier);
        }
        return null;
      };
      const findPlan = (root) => {
        if (!root || typeof root !== 'object') return null;
        const queue = [root];
        const seenObjects = typeof WeakSet !== 'undefined' ? new WeakSet() : null;
        let index = 0;
        let seen = 0;
        while (index < queue.length && seen < 6000) {
          const cur = queue[index++];
          seen++;
          if (!cur || typeof cur !== 'object') continue;
          if (seenObjects) {
            if (seenObjects.has(cur)) continue;
            seenObjects.add(cur);
          }
          if (Array.isArray(cur)) {
            for (const v of cur) {
              if (v && typeof v === 'object') queue.push(v);
            }
            continue;
          }
          for (const [k, v] of Object.entries(cur)) {
            const plan = planCandidate(k, v);
            if (plan) return plan;
            if (v && typeof v === 'object') queue.push(v);
          }
        }
        return null;
      };
      const parseJSONScript = (id) => {
        try {
          const node = document.getElementById(id);
          const raw = node && node.textContent ? String(node.textContent) : '';
          return raw ? JSON.parse(raw) : null;
        } catch {
          return null;
        }
      };
      const pickLikelyPurchaseButton = (buttons) => {
        if (!buttons || buttons.length === 0) return null;
        const labeled = buttons.find(btn => {
          const label = elementLabel(btn);
          if (purchaseTextMatches(label)) return true;
          const aria = String(btn.getAttribute('aria-label') || '').toLowerCase();
          return aria.includes('credit') || aria.includes('buy') || aria.includes('add');
        });
        return labeled || buttons[0];
      };
      const findCreditsPurchaseButton = () => {
        const nodes = Array.from(document.querySelectorAll('h1,h2,h3,div,span,p'));
        const labelMatch = nodes.find(node => {
          const lower = textOf(node).toLowerCase();
          return lower === 'credits remaining' || (lower.includes('credits') && lower.includes('remaining'));
        });
        if (!labelMatch) return null;
        let cur = labelMatch;
        for (let i = 0; i < 6 && cur; i++) {
          const buttons = Array.from(cur.querySelectorAll('button, a'));
          const picked = pickLikelyPurchaseButton(buttons);
          if (picked) return picked;
          cur = cur.parentElement;
        }
        return null;
      };
      const dayKeyFromPayload = (payload) => {
        if (!payload || typeof payload !== 'object') return null;
        const localDayKeyForDate = (date) => {
          const year = date.getFullYear();
          const month = String(date.getMonth() + 1).padStart(2, '0');
          const day = String(date.getDate()).padStart(2, '0');
          return `${year}-${month}-${day}`;
        };
        const keys = ['day', 'date', 'name', 'label', 'x', 'time', 'timestamp'];
        for (const k of keys) {
          const v = payload[k];
          if (typeof v === 'string') {
            const s = v.trim();
            if (/^\\d{4}-\\d{2}-\\d{2}$/.test(s)) return s;
            const iso = s.match(/^(\\d{4}-\\d{2}-\\d{2})/);
            if (iso) return iso[1];
          }
          if (typeof v === 'number' && Number.isFinite(v) && (k === 'timestamp' || k === 'time' || k === 'x')) {
            try {
              const d = new Date(v);
              if (!isNaN(d.getTime())) return localDayKeyForDate(d);
            } catch {}
          }
        }
        return null;
      };
      const isSkillUsageServiceKey = (raw) => {
        const key = raw === null || raw === undefined ? '' : String(raw).trim().toLowerCase();
        return key.startsWith('skillusage:');
      };
      const displayNameForUsageServiceKey = (raw) => {
        const key = raw === null || raw === undefined ? '' : String(raw).trim();
        if (!key) return key;
        if (isSkillUsageServiceKey(key)) return null;
        if (key.toUpperCase() === key && key.length <= 6) return key;
        const lower = key.toLowerCase();
        if (lower === 'cli') return 'CLI';
        if (lower.includes('github') && lower.includes('review')) return 'GitHub Code Review';
        const words = lower.replace(/[_-]+/g, ' ').split(' ').filter(Boolean);
        return words.map(w => w.length <= 2 ? w.toUpperCase() : w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
      };
      const isLikelyCodexUsageService = (raw) => {
        const service = raw === null || raw === undefined ? '' : String(raw).trim().toLowerCase();
        return (
          service === 'cli' ||
          service === 'desktop' ||
          service === 'desktop app' ||
          service === 'vscode' ||
          service === 'vs code' ||
          service === 'unknown' ||
          (service.includes('github') && service.includes('review'))
        );
      };
      const usageChartRootForPath = (path) => {
        if (!path || !path.closest) return null;
        return (
          path.closest('.recharts-wrapper') ||
          path.closest('svg.recharts-surface') ||
          path.closest('section') ||
          path.parentElement ||
          null
        );
      };
      const uniqueUsageChartRoots = (paths) => {
        const roots = [];
        for (const path of paths) {
          const root = usageChartRootForPath(path);
          if (root && !roots.includes(root)) roots.push(root);
        }
        return roots;
      };
      const usageBreakdownTitleScore = (title) => {
        const lower = String(title || '').trim().toLowerCase().replace(/\\s+/g, ' ');
        if (!lower) return 0;
        if (lower === 'usage breakdown') return 1000000;
        if (lower.includes('usage breakdown')) return 900000;
        if (lower === 'personal usage') return 800000;
        if (lower.includes('threads') ||
          lower.includes('turns') ||
          lower.includes('client') ||
          lower.includes('skill') ||
          lower.includes('invocation')) return -1000000;
        return 0;
      };
      const titleLikeElements = (scope) => {
        try {
          return Array.from(scope.querySelectorAll('h1,h2,h3,[role=\"heading\"],div,span,p'))
            .filter(el => {
              const title = textOf(el);
              const lower = title.toLowerCase();
              const tag = el.tagName ? el.tagName.toLowerCase() : '';
              const isHeading = tag === 'h1' ||
                tag === 'h2' ||
                tag === 'h3' ||
                String(el.getAttribute('role') || '').toLowerCase() === 'heading';
              return title.length > 0 &&
                title.length <= 80 &&
                (
                  isHeading ||
                  usageBreakdownTitleScore(title) !== 0 ||
                  lower.includes('usage breakdown') ||
                  lower.includes('threads') ||
                  lower.includes('turns') ||
                  lower.includes('client') ||
                  lower.includes('skill') ||
                  lower.includes('invocation')
                );
            });
        } catch {
          return [];
        }
      };
      const titleNodePrecedesRoot = (titleNode, root) => {
        if (!titleNode || titleNode === root || root.contains(titleNode) || titleNode.contains(root)) return false;
        const relation = titleNode.compareDocumentPosition(root);
        return Boolean(relation & Node.DOCUMENT_POSITION_FOLLOWING);
      };
      const nearestScoredChartTitleInScope = (scope, root) => {
        let best = null;
        for (const titleNode of titleLikeElements(scope)) {
          if (!titleNodePrecedesRoot(titleNode, root)) continue;
          const title = textOf(titleNode);
          const score = usageBreakdownTitleScore(title);
          if (score === 0) continue;
          if (!best || score >= best.score) best = { title, score };
        }
        return best ? best.title : '';
      };
      const chartTitleBoundaryForRoot = (root) => {
        if (!root) return null;
        try {
          return root.closest('section,[role=\"region\"],article') || root.parentElement || null;
        } catch {
          return root.parentElement || null;
        }
      };
      const nearestTitleTextInScope = (scope, root) => {
        if (!scope) return '';
        let nearest = null;
        for (const titleNode of titleLikeElements(scope)) {
          if (titleNodePrecedesRoot(titleNode, root)) nearest = titleNode;
        }
        return textOf(nearest);
      };
      const nearestChartTitleTextForRoot = (root) => {
        if (!root) return '';
        try {
          const boundary = chartTitleBoundaryForRoot(root) || root.parentElement || null;
          let ancestor = root.parentElement || null;
          for (let i = 0; i < 8 && ancestor; i++) {
            const scoredTitle = nearestScoredChartTitleInScope(ancestor, root);
            if (scoredTitle) return scoredTitle;
            if (ancestor === boundary) break;
            ancestor = ancestor.parentElement || null;
          }

          return nearestTitleTextInScope(boundary, root);
        } catch {
          return '';
        }
      };
      const legendMapForUsageChartRoot = (root) => {
        const legendMap = {};
        const scopes = [
          root,
          root && root.parentElement,
          root && root.closest ? root.closest('section') : null
        ].filter(Boolean);
        for (const scope of scopes) {
          try {
            const legendItems = Array.from(scope.querySelectorAll('div[title]'));
            for (const item of legendItems) {
              const title = item.getAttribute('title') ? String(item.getAttribute('title')).trim() : '';
              const square = item.querySelector('div[style*=\"background-color\"]');
              const color = (square && square.style && square.style.backgroundColor)
                ? square.style.backgroundColor
                : null;
              const hex = parseHexColor(color);
              if (title && hex) legendMap[hex] = title;
            }
          } catch {}
          if (Object.keys(legendMap).length > 0) break;
        }
        return legendMap;
      };
      const parseUsageBreakdownFromChartPaths = (paths, legendMap) => {
        const totalsByDay = {}; // day -> service -> value
        const addValue = (day, service, value) => {
          if (!day || !service || isSkillUsageServiceKey(service)) return false;
          if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) return false;
          if (!totalsByDay[day]) totalsByDay[day] = {};
          totalsByDay[day][service] = (totalsByDay[day][service] || 0) + value;
          return true;
        };
        let pointCount = 0;
        for (const path of paths) {
          const meta = barMetaFromElement(path) || barMetaFromElement(path.parentElement) || null;
          if (!meta) continue;

          const payload = meta.payload || null;
          const day = dayKeyFromPayload(payload);
          if (!day) continue;

          const valuesObj = (payload && payload.values && typeof payload.values === 'object') ? payload.values : null;
          if (valuesObj) {
            for (const [k, v] of Object.entries(valuesObj)) {
              const service = displayNameForUsageServiceKey(k);
              if (addValue(day, service, v)) pointCount++;
            }
            continue;
          }

          let value = null;
          if (typeof meta.value === 'number' && Number.isFinite(meta.value)) value = meta.value;
          if (value === null && typeof meta.value === 'string') {
            const v = parseFloat(meta.value.replace(/,/g, ''));
            if (Number.isFinite(v)) value = v;
          }
          if (value === null) continue;

          const fill = parseHexColor(meta.fill || path.getAttribute('fill'));
          const service =
            (fill && legendMap[fill]) ||
            (typeof meta.name === 'string' && meta.name) ||
            null;
          if (addValue(day, service, value)) pointCount++;
        }

        const dayKeys = Object.keys(totalsByDay)
          .filter(day => Object.keys(totalsByDay[day] || {}).length > 0)
          .sort((a, b) => b.localeCompare(a))
          .slice(0, 30);
        const breakdown = dayKeys.map(day => {
          const servicesMap = totalsByDay[day] || {};
          const services = Object.keys(servicesMap).map(service => ({
            service,
            creditsUsed: servicesMap[service]
          })).sort((a, b) => {
            if (a.creditsUsed === b.creditsUsed) return a.service.localeCompare(b.service);
            return b.creditsUsed - a.creditsUsed;
          });
          const totalCreditsUsed = services.reduce((sum, s) => sum + (Number(s.creditsUsed) || 0), 0);
          return { day, services, totalCreditsUsed };
        });
        const services = Array.from(new Set(breakdown.flatMap(day => day.services.map(service => service.service))));
        const totalCreditsUsed = breakdown.reduce((sum, day) => sum + (Number(day.totalCreditsUsed) || 0), 0);
        const likelyCodexServiceCount = services.filter(isLikelyCodexUsageService).length;
        return {
          breakdown,
          pointCount,
          services,
          totalCreditsUsed,
          likelyCodexServiceCount,
          score: likelyCodexServiceCount * 1000 + services.length * 100 + pointCount + totalCreditsUsed / 1000
        };
      };
      const usageBreakdownJSON = (() => {
        try {
          if (window.__codexbarUsageBreakdownJSON) return window.__codexbarUsageBreakdownJSON;

          const paths = Array.from(document.querySelectorAll('g.recharts-bar-rectangle path.recharts-rectangle'));
          let debug = {
            pathCount: paths.length,
            chartCount: 0,
            eligibleCandidateCount: 0,
            selectedCandidateTitle: null,
            candidateSummaries: [],
            sampleReactKeys: null,
            sampleMetaKeys: null,
            samplePayloadKeys: null,
            sampleValuesKeys: null,
            sampleDayKey: null
          };
          try {
            const sample = paths[0] || null;
            if (sample) {
              const names = Object.getOwnPropertyNames(sample);
              debug.sampleReactKeys = names.filter(k => k.includes('react')).slice(0, 10);
              const metaSample = barMetaFromElement(sample) || barMetaFromElement(sample.parentElement) || null;
              if (metaSample) {
                debug.sampleMetaKeys = Object.keys(metaSample).slice(0, 12);
                const payload = metaSample.payload || null;
                if (payload && typeof payload === 'object') {
                  debug.samplePayloadKeys = Object.keys(payload).slice(0, 12);
                  debug.sampleDayKey = dayKeyFromPayload(payload);
                  const values = payload.values || null;
                  if (values && typeof values === 'object') {
                    debug.sampleValuesKeys = Object.keys(values).slice(0, 12);
                  }
                }
              }
            }
          } catch {}

          const roots = uniqueUsageChartRoots(paths);
          debug.chartCount = roots.length;
          const candidates = roots.map(root => {
            const chartPaths = paths.filter(path => usageChartRootForPath(path) === root);
            const title = nearestChartTitleTextForRoot(root);
            const titleScore = usageBreakdownTitleScore(title);
            const parsed = parseUsageBreakdownFromChartPaths(chartPaths, legendMapForUsageChartRoot(root));
            return {
              root,
              title,
              titleScore,
              pathCount: chartPaths.length,
              ...parsed,
              score: titleScore + parsed.score
            };
          }).filter(candidate => candidate.breakdown.length > 0);
          const rejectedTitleCandidates = candidates.filter(candidate => candidate.titleScore < 0);
          const titledCandidates = candidates.filter(candidate => candidate.titleScore > 0);
          const unknownTitleCandidates = candidates.filter(candidate => candidate.titleScore === 0);
          const eligibleCandidates = titledCandidates;
          eligibleCandidates.sort((a, b) => b.score - a.score);
          debug.eligibleCandidateCount = eligibleCandidates.length;
          debug.selectedCandidateTitle = eligibleCandidates[0] ? eligibleCandidates[0].title : null;
          if (eligibleCandidates.length === 0 && candidates.length > 0) {
            if (unknownTitleCandidates.length > 0) {
              debug.error = 'No English usage breakdown chart title found. Candidate titles: ' +
                candidates.map(candidate => candidate.title || 'Untitled chart').join(', ');
            } else if (rejectedTitleCandidates.length > 0) {
              debug.error = 'Only non-usage chart candidates found: ' +
                rejectedTitleCandidates.map(candidate => candidate.title || 'Untitled chart').join(', ');
            }
          }
          debug.candidateSummaries = candidates.slice(0, 6).map(candidate => ({
            title: candidate.title,
            titleScore: candidate.titleScore,
            pathCount: candidate.pathCount,
            dayCount: candidate.breakdown.length,
            pointCount: candidate.pointCount,
            serviceCount: candidate.services.length,
            likelyCodexServiceCount: candidate.likelyCodexServiceCount,
            services: candidate.services.slice(0, 8)
          }));

          const breakdown = eligibleCandidates[0] ? eligibleCandidates[0].breakdown : [];
          const json = (breakdown.length > 0) ? JSON.stringify(breakdown) : null;
          window.__codexbarUsageBreakdownJSON = json;
          window.__codexbarUsageBreakdownDebug = json ? null : JSON.stringify(debug);
          return json;
        } catch {
          return null;
        }
      })();
      const usageBreakdownDebug = (() => {
        try {
          return window.__codexbarUsageBreakdownDebug || null;
        } catch {
          return null;
        }
      })();
      const usageBreakdownError = (() => {
        try {
          if (!usageBreakdownDebug) return null;
          const parsed = JSON.parse(usageBreakdownDebug);
          return parsed && parsed.error ? String(parsed.error) : null;
        } catch {
          return null;
        }
      })();
      const bodyText = document.body ? String(document.body.innerText || '').trim() : '';
      const href = window.location ? String(window.location.href || '') : '';
      const workspacePicker = bodyText.includes('Select a workspace');
      const title = document.title ? String(document.title || '') : '';
      const cloudflareInterstitial =
        title.toLowerCase().includes('just a moment') ||
        bodyText.toLowerCase().includes('checking your browser') ||
        bodyText.toLowerCase().includes('cloudflare');
      const authSelector = [
        'input[type="email"]',
        'input[type="password"]',
        'input[name="username"]'
      ].join(', ');
      const hasAuthInputs = !!document.querySelector(authSelector);
      const lower = bodyText.toLowerCase();
      const loginCTA =
        lower.includes('sign in') ||
        lower.includes('log in') ||
        lower.includes('continue with google') ||
        lower.includes('continue with apple') ||
        lower.includes('continue with microsoft');
      const loginRequired =
        href.includes('/auth/') ||
        href.includes('/login') ||
        (hasAuthInputs && loginCTA) ||
        (!hasAuthInputs && loginCTA && href.includes('chatgpt.com'));
      const scrollY = (typeof window.scrollY === 'number') ? window.scrollY : 0;
      const scrollHeight = document.documentElement ? (document.documentElement.scrollHeight || 0) : 0;
      const viewportHeight = (typeof window.innerHeight === 'number') ? window.innerHeight : 0;

      let creditsHeaderPresent = false;
      let creditsHeaderInViewport = false;
      let didScrollToCredits = false;
      let rows = [];
      try {
        const looksLikeCreditsEventRow = (cells) => {
          if (!cells || cells.length < 3) return false;
          const first = String(cells[0] || '');
          const amount = String(cells[2] || '');
          return /\\d{4}|\\d{1,2}[\\/.\\-]\\d{1,2}/.test(first) && /\\d/.test(amount);
        };
        const allTableRows = () => Array.from(document.querySelectorAll('tbody tr')).map(tr => {
          const cells = Array.from(tr.querySelectorAll('td')).map(td => textOf(td));
          return cells;
        }).filter(looksLikeCreditsEventRow);
        const headings = Array.from(document.querySelectorAll('h1,h2,h3'));
        const header = headings.find(h => textOf(h).toLowerCase() === 'credits usage history');
        if (header) {
          creditsHeaderPresent = true;
          const rect = header.getBoundingClientRect();
          creditsHeaderInViewport = rect.top >= 0 && rect.top <= viewportHeight;

          // Only scrape rows from the *credits usage history* table. The page can contain other tables,
          // and treating any <table> as credits history can prevent our scroll-to-load logic from running.
          const container = header.closest('section') || header.parentElement || document;
          const table = container.querySelector('table') || null;
          const scope = table || container;
          rows = Array.from(scope.querySelectorAll('tbody tr')).map(tr => {
            const cells = Array.from(tr.querySelectorAll('td')).map(td => textOf(td));
            return cells;
          }).filter(r => r.length >= 3);
          if (rows.length === 0) {
            rows = allTableRows();
          }
          if (rows.length === 0 && !window.__codexbarDidScrollToCredits) {
            window.__codexbarDidScrollToCredits = true;
            // If the table is virtualized/lazy-loaded, we need to scroll to trigger rendering even if the
            // header is already in view.
            header.scrollIntoView({ block: 'start', inline: 'nearest' });
            if (creditsHeaderInViewport) {
              window.scrollBy(0, Math.max(220, viewportHeight * 0.6));
            }
            didScrollToCredits = true;
          }
        } else if (rows.length === 0 && !window.__codexbarDidScrollToCredits && scrollHeight > viewportHeight * 1.5) {
          rows = allTableRows();
          if (rows.length > 0) {
            creditsHeaderPresent = true;
            creditsHeaderInViewport = true;
          }
        }
        if (rows.length === 0 && !window.__codexbarDidScrollToCredits && scrollHeight > viewportHeight * 1.5) {
          // The credits history section often isn't part of the DOM until you scroll down. Nudge the page
          // once so subsequent scrapes can find the header and rows.
          window.__codexbarDidScrollToCredits = true;
          window.scrollTo(0, Math.max(0, scrollHeight - viewportHeight - 40));
          didScrollToCredits = true;
        }
      } catch {}

      let creditsPurchaseURL = null;
      try {
        const creditsButton = findCreditsPurchaseButton();
        if (creditsButton) {
          const url = purchaseURLFromElement(creditsButton);
          if (url) creditsPurchaseURL = url;
        }
        const candidates = Array.from(document.querySelectorAll('a, button'));
        for (const node of candidates) {
          const label = elementLabel(node);
          if (!purchaseTextMatches(label)) continue;
          const url = purchaseURLFromElement(node);
          if (url) {
            creditsPurchaseURL = url;
            break;
          }
        }
        if (!creditsPurchaseURL) {
          const anchors = Array.from(document.querySelectorAll('a[href]'));
          for (const anchor of anchors) {
            const label = elementLabel(anchor);
            const href = anchor.getAttribute('href') || '';
            const hrefLooksRelevant = /credits|billing/i.test(href);
            if (!hrefLooksRelevant && !purchaseTextMatches(label)) continue;
            const url = normalizeHref(href);
            if (url) {
              creditsPurchaseURL = url;
              break;
            }
          }
        }
      } catch {}

      let signedInEmail = null;
      let authStatus = null;
      let accountPlan = null;
      try {
        const next = window.__NEXT_DATA__ || null;
        const props = (next && next.props && next.props.pageProps) ? next.props.pageProps : null;
        const userEmail = (props && props.user) ? props.user.email : null;
        const sessionEmail = (props && props.session && props.session.user) ? props.session.user.email : null;
        signedInEmail = userEmail || sessionEmail || null;
      } catch {}

      const clientBootstrap = parseJSONScript('client-bootstrap');
      if (clientBootstrap) {
        try {
          authStatus = typeof clientBootstrap.authStatus === 'string' ? clientBootstrap.authStatus : null;
          if (!signedInEmail) {
            const session = clientBootstrap.session || null;
            const user = (session && session.user) || clientBootstrap.user || null;
            const email = user && typeof user.email === 'string' ? user.email : null;
            if (email && email.includes('@')) signedInEmail = email;
          }
          if (!accountPlan) accountPlan = findPlan(clientBootstrap);
        } catch {}
      }
      if (!accountPlan) {
        try {
          accountPlan = findPlan(window.__NEXT_DATA__ || parseJSONScript('__NEXT_DATA__'));
        } catch {}
      }

      if (!signedInEmail) {
        try {
          const obj = parseJSONScript('__NEXT_DATA__');
          if (obj) {
            const queue = [obj];
            let seen = 0;
            while (queue.length && seen < 2000 && !signedInEmail) {
              const cur = queue.shift();
              seen++;
              if (!cur) continue;
              if (typeof cur === 'string') {
                if (cur.includes('@')) signedInEmail = cur;
                continue;
              }
              if (typeof cur !== 'object') continue;
              for (const [k, v] of Object.entries(cur)) {
                if (signedInEmail) break;
                if (k === 'email' && typeof v === 'string' && v.includes('@')) {
                  signedInEmail = v;
                  break;
                }
                if (typeof v === 'object' && v) queue.push(v);
              }
            }
          }
        } catch {}
      }

      if (!signedInEmail) {
        try {
          const emailRe = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}/ig;
          const found = (bodyText.match(emailRe) || []).map(x => String(x).trim().toLowerCase());
          const unique = Array.from(new Set(found));
          if (unique.length === 1) {
            signedInEmail = unique[0];
          } else if (unique.length > 1) {
            signedInEmail = unique[0];
          }
        } catch {}
      }

      if (!signedInEmail) {
        // Last resort: open the account menu so the email becomes part of the DOM text.
        try {
          const emailRe = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}/ig;
          const hasMenu = Boolean(document.querySelector('[role="menu"]'));
          if (!hasMenu) {
            const button =
              document.querySelector('button[aria-haspopup="menu"]') ||
              document.querySelector('button[aria-expanded]');
            if (button && !button.disabled) {
              button.click();
            }
          }
          const afterText = document.body ? String(document.body.innerText || '').trim() : '';
          const found = (afterText.match(emailRe) || []).map(x => String(x).trim().toLowerCase());
          const unique = Array.from(new Set(found));
          if (unique.length === 1) {
            signedInEmail = unique[0];
          } else if (unique.length > 1) {
            signedInEmail = unique[0];
          }
        } catch {}
      }

      return {
        loginRequired,
        workspacePicker,
        cloudflareInterstitial,
        href,
        bodyText,
        signedInEmail,
        authStatus,
        accountPlan,
        creditsPurchaseURL,
        rows,
        usageBreakdownJSON,
        usageBreakdownDebug,
        usageBreakdownError,
        scrollY,
        scrollHeight,
        viewportHeight,
        creditsHeaderPresent,
        creditsHeaderInViewport,
        didScrollToCredits
      };
    })();

"""
#endif
