Skip to content
TheAIDirector.Win ClaudeJoomla.com ClaudeTemplates.NET

You see something wrong on your site. A button's the wrong colour, a heading's too big, a layout's broken. You need Claude to fix it — but Claude can't see your screen.

So you screenshot it. Or you open the browser's developer tools, try to find the right panel, copy some CSS rules, paste them to Claude. Claude asks for more. You go back, copy something else, paste again. Five minutes of back-and-forth and you still haven't fixed anything.

This is the bottleneck nobody talks about. Not prompting. Not Claude's ability. It's getting what Claude needs from your browser — the technical data behind what you see on screen — without spending ages hunting for it yourself.

You don't need to understand what that data means. Claude does. You just need to get it there.

Not a developer? There's a step-by-step version of this guide that walks you through every click from scratch — no experience needed.

The fix: one script, full context

It's a JavaScript snippet you paste into your browser's DevTools Console. It grabs everything about the selected element — every CSS rule hitting it, which file each rule comes from, the computed styles, the parent chain, the selector path — and copies it straight to your clipboard.

Then you paste it to Claude. Claude has the full picture. No follow-up questions about "what rules are matching" or "what's the parent element." It's all there.

What Claude actually sees

Here's a trimmed snippet of real output from running the script on the Download button shown in the beginner guide's screenshots:

=== SELECTED ELEMENT ===
=== OUTER HTML ===
<a href="/media/templates/site/theaidirector/downloads/signal-dark-joomla5.zip"
   download="" class="taid-btn-gradient">Download Signal Dark — Joomla 5 Template</a>

=== CSS SELECTOR ===
main#taid-main > div.taid-container > div.taid-content-wrap:nth-child(3) >
  div.taid-content-primary > div.taid-component-panel > ...
  > a.taid-btn-gradient

=== COMPUTED STYLES (key properties) ===
  display: inline-block;
  width: 424.333px;
  padding: 14.4px 36px;
  border-radius: 8px;
  background: linear-gradient(135deg, rgb(124, 58, 237) 0%, rgb(6, 182, 212) 100%);
  color: rgb(255, 255, 255);
  font-family: "Space Grotesk", system-ui, sans-serif;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: 0.48px;
  box-shadow: rgba(124, 58, 237, 0.4) 0px 0px 28px 0px,
              rgba(0, 0, 0, 0.4) 0px 2px 8px 0px;

=== MATCHED CSS RULES ===
/* template.css */
.taid-btn-gradient {
  display: inline-block;
  background-image: linear-gradient(135deg, rgb(124, 58, 237) 0%,
                    rgb(6, 182, 212) 100%);
  color: rgb(255, 255, 255);
  font-weight: 600;
  padding-top: 0.9rem;
  padding-right: 2.25rem;
  padding-bottom: 0.9rem;
  padding-left: 2.25rem;
  border-radius: 8px;
  letter-spacing: 0.03em;
  box-shadow: rgba(124, 58, 237, 0.4) 0px 0px 28px,
              rgba(0, 0, 0, 0.4) 0px 2px 8px;
}
/* template.css */
.taid-component-panel a.taid-btn-gradient {
  color: rgb(255, 255, 255);
  text-decoration-line: none;
}

=== PARENT CHAIN ===
a.taid-btn-gradient
  div.taid-demo-hub-cta
    div.taid-demo-hub
      div.com-content-article__body
        div.com-content-article.item-page
          div.taid-component-panel
            div.taid-content-primary
              div.taid-content-wrap
                div.taid-container
                  main#taid-main.taid-main

The HTML. The exact CSS rules matching, with the source file. The computed values. The full DOM context. Claude can diagnose any CSS issue from this output alone.

How to use it

  1. Open DevTools (F12 in any browser) and click the element you want to debug in the Inspector tab.
  2. Switch to the Console tab. Paste the entire script from below and press Enter.
  3. Done. The debug info is on your clipboard. Ctrl+V to Claude.

One paste in, one paste out. Five seconds instead of five minutes.

Firefox users: Firefox blocks pasting into the Console by default. If you see a "Scam Warning" or nothing happens when you paste, type about:config in the address bar, search for devtools.selfxss.count, and change the value from 1 to 100. This only needs to be done once — after that, pasting works permanently. Chrome and Edge allow pasting by default.

Do this often? You can bind the script to a single key. Hit Super+D — the script loads to your clipboard. Ctrl+V in Console, Enter — the debug output replaces the script on your clipboard. Ctrl+V to Claude. You never open a file, never copy anything manually. The clipboard does all the work.

The script

Copy this entire block. No installation, no extension, no dependencies. Works in Firefox, Chrome, and Edge.

function debug(el) {
  if (!el) { el = $0; }
  if (!el) { console.log('No element selected. Pick one in Inspector first.'); return; }

  const lines = [];

  const outer = el.outerHTML;
  lines.push('=== SELECTED ELEMENT ===');
  lines.push('=== OUTER HTML ===');
  lines.push(outer.length > 3000 ? outer.slice(0, 3000) + '\n... (truncated)' : outer);

  lines.push('\n=== CSS SELECTOR ===');
  lines.push(cssPath(el));

  lines.push('\n=== XPATH ===');
  lines.push(xPath(el));

  lines.push('\n=== COMPUTED STYLES (key properties) ===');
  const comp = getComputedStyle(el);
  const props = [
    'display', 'position', 'float', 'clear',
    'width', 'height', 'min-width', 'max-width', 'min-height', 'max-height',
    'margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
    'padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left',
    'border', 'border-top', 'border-right', 'border-bottom', 'border-left',
    'border-color', 'border-width', 'border-style', 'border-radius',
    'background', 'background-color', 'background-image',
    'color', 'font-family', 'font-size', 'font-weight', 'line-height',
    'text-decoration', 'text-transform', 'letter-spacing',
    'overflow', 'z-index', 'opacity',
    'flex', 'flex-direction', 'flex-wrap', 'align-items', 'justify-content', 'gap',
    'grid-template-columns', 'grid-template-rows',
    'box-shadow', 'outline',
    'appearance', '-webkit-appearance',
  ];
  for (const p of props) {
    const v = comp.getPropertyValue(p);
    if (v && v !== '' && v !== 'none' && v !== 'normal' && v !== 'auto'
        && v !== '0px' && v !== 'rgba(0, 0, 0, 0)' && v !== 'start'
        && v !== 'visible' && v !== 'baseline' && v !== 'stretch') {
      lines.push('  ' + p + ': ' + v + ';');
    }
  }

  lines.push('\n=== MATCHED CSS RULES ===');
  try {
    const sheets = [...document.styleSheets];
    for (const sheet of sheets) {
      try {
        const rules = [...sheet.cssRules];
        for (const rule of rules) {
          if (rule.selectorText && el.matches(rule.selectorText)) {
            const src = sheet.href ? sheet.href.split('/').pop().split('?')[0] : 'inline';
            lines.push('/* ' + src + ' */');
            lines.push(rule.selectorText + ' {');
            for (let i = 0; i < rule.style.length; i++) {
              const prop = rule.style[i];
              const val = rule.style.getPropertyValue(prop);
              const pri = rule.style.getPropertyPriority(prop);
              lines.push('  ' + prop + ': ' + val + (pri ? ' !important' : '') + ';');
            }
            lines.push('}');
          }
        }
      } catch (e) {}
    }
  } catch (e) {
    lines.push('(Could not read stylesheets: ' + e.message + ')');
  }

  if (el.style.cssText) {
    lines.push('\n=== INLINE STYLES ===');
    lines.push(el.style.cssText);
  }

  lines.push('\n=== PARENT CHAIN ===');
  let node = el;
  let depth = 0;
  while (node && node !== document.documentElement && depth < 12) {
    const tag = node.tagName.toLowerCase();
    const id = node.id ? '#' + node.id : '';
    const cls = node.className && typeof node.className === 'string'
      ? '.' + node.className.trim().split(/\s+/).join('.') : '';
    lines.push('  '.repeat(depth) + tag + id + cls);
    node = node.parentElement;
    depth++;
  }

  const result = '\n\n\n\n\n' + lines.join('\n') + '\n\n\n\n\n# Next batch: ';
  copy(result);
  console.log('Copied ' + result.length + ' chars to clipboard.');
  return result;
}

function cssPath(el) {
  const parts = [];
  while (el && el.nodeType === 1) {
    let sel = el.tagName.toLowerCase();
    if (el.id) { parts.unshift(sel + '#' + el.id); break; }
    if (el.className && typeof el.className === 'string') {
      sel += '.' + el.className.trim().split(/\s+/).join('.');
    }
    const parent = el.parentElement;
    if (parent) {
      const siblings = [...parent.children].filter(c => c.tagName === el.tagName);
      if (siblings.length > 1) {
        sel += ':nth-child(' + ([...parent.children].indexOf(el) + 1) + ')';
      }
    }
    parts.unshift(sel);
    el = parent;
  }
  return parts.join(' > ');
}

function xPath(el) {
  const parts = [];
  while (el && el.nodeType === 1) {
    let idx = 1;
    for (let sib = el.previousElementSibling; sib; sib = sib.previousElementSibling) {
      if (sib.tagName === el.tagName) idx++;
    }
    parts.unshift(el.tagName.toLowerCase() + '[' + idx + ']');
    el = el.parentElement;
  }
  return '/' + parts.join('/');
}

debug($0);

Make it even faster: one keyboard shortcut (Linux)

This is written for Linux — it's what I use. The script itself works in any browser on any OS. The keyboard shortcut below is for MATE desktop, but the AI prompt at the end will adapt it to whatever you're running.

On Linux with MATE desktop, here's how to bind it to Super+D:

  1. Install xsel if you don't have it:

    sudo apt install xsel
  2. Save the script somewhere permanent (e.g. ~/tools/debug-element.js), then run:

    gsettings set org.mate.Marco.keybinding-commands command-9 \
      "/bin/sh -c 'cat ~/tools/debug-element.js | xsel --clipboard --input'"
    
    gsettings set org.mate.Marco.global-keybindings run-command-9 '<Super>d'

Now the workflow is:

  1. Click the broken element in Inspector
  2. Super+D — the script is now on your clipboard
  3. Ctrl+V in Console, Enter — the script runs, and the debug output replaces the script on your clipboard
  4. Ctrl+V to Claude — full debug context, pasted

Read that again. You never open a file. You never select text. You never copy anything. Your clipboard gets written to twice — first with the script, then with the debug output — and each time you just paste. Three keystrokes from "I see a problem" to "Claude has full context." That's the floor. You physically cannot get the information to Claude any faster without a browser extension.

Other Linux desktops: The gsettings commands above are specific to MATE (Marco window manager). If you're on a different desktop environment, paste this into Microsoft Copilot (free) or any AI assistant:

Make this keyboard shortcut work on my Linux setup.
I want Super+D to copy ~/tools/debug-element.js to my clipboard.

Here's the MATE version — adapt it for my desktop environment:

gsettings set org.mate.Marco.keybinding-commands command-9 
  "/bin/sh -c 'cat ~/tools/debug-element.js | xsel --clipboard --input'"
gsettings set org.mate.Marco.global-keybindings run-command-9 '<Super>d'

My setup: [tell it your distro and desktop environment]

macOS

Paste this into Copilot or any AI assistant:

I'm on macOS. I have a JavaScript file at ~/tools/debug-element.js.
I want a keyboard shortcut (Cmd+Shift+D) that copies the file contents
to my clipboard. Give me step-by-step instructions.

Windows

Paste this into Copilot or any AI assistant:

I'm on Windows. I have a JavaScript file at %USERPROFILE%\tools\debug-element.js.
I want a keyboard shortcut (Win+D or similar) that copies the file contents
to my clipboard. Give me step-by-step instructions.

Three scripts, three depths

The single-element script above is great for quick checks. But CSS bugs often come from parent elements — a flex container, a grid wrapper, or a panel with overflow hidden. You need to see the full chain, not just the leaf node.

I use three scripts, bound to three keyboard shortcuts:

ShortcutScriptWhat it does
Super+Ddebug-element.jsSingle element — outer HTML, computed styles, matched CSS rules, parent chain
Super+Fdeep-debug-5.jsWalks 5 levels up from the selected element — each level gets full debug output
Super+Gdeep-debug-10.jsWalks 10 levels up — from the element all the way to the component panel or body
Download the scripts:
debug-element.js (Super+D — single element)
deep-debug-5.js (Super+F — 5 levels)
deep-debug-10.js (Super+G — 10 levels)
Right-click → Save Link As, or click to download. Save to ~/tools/ and bind the keyboard shortcuts below.

When to use which:

  • Super+D — "Why is this text the wrong color?" or "Why doesn't this button have padding?"
  • Super+F — "Why is this card misaligned?" or "Why is the sidebar pushing content?" — you need the card, its wrapper, and the grid container
  • Super+G — "Why is the whole page layout broken?" — you need everything from the broken element up to the body class

Setup — all three shortcuts (Linux/MATE)

Save each script to ~/tools/, then:

# Super+D — single element
gsettings set org.mate.Marco.keybinding-commands command-9 \
  "/bin/sh -c 'cat ~/tools/debug-element.js | xsel --clipboard --input'"
gsettings set org.mate.Marco.global-keybindings run-command-9 '<Super>d'

# Super+F — 5 levels deep
gsettings set org.mate.Marco.keybinding-commands command-10 \
  "/bin/sh -c 'cat ~/tools/deep-debug-5.js | xsel --clipboard --input'"
gsettings set org.mate.Marco.global-keybindings run-command-10 '<Super>f'

# Super+G — 10 levels deep
gsettings set org.mate.Marco.keybinding-commands command-11 \
  "/bin/sh -c 'cat ~/tools/deep-debug-10.js | xsel --clipboard --input'"
gsettings set org.mate.Marco.global-keybindings run-command-11 '<Super>g'

Deep debug — 5 levels (Super+F)

This script walks up from the selected element through 5 parent levels. Each level gets full debug output — outer HTML, CSS selector, computed styles, and matched rules. Paste it in Console the same way as the single-element script.

// Firefox DevTools Console snippet — DEEP DEBUG
// Walks UP from selected element through 5 parent levels.
// Each level gets: outer HTML, CSS selector, computed styles, matched rules.
// Bind to Super+F (5 levels) for quick access.
//
// Usage: Select element in Inspector, paste this in Console.
// Or: debug($0)

function debug(el) {
  if (!el) { el = $0; }
  if (!el) { console.log('No element selected. Pick one in Inspector first.'); return; }

  const allLines = [];
  let node = el;
  let level = 0;
  const maxLevels = 5;

  while (node && node.nodeType === 1 && node !== document.documentElement && level < maxLevels) {
    const lines = [];

    // Outer HTML (truncated)
    const outer = node.outerHTML;
    lines.push(level === 0 ? '=== SELECTED ELEMENT ===' : '=== PARENT ' + level + ' ===');
    lines.push('=== OUTER HTML ===');
    lines.push(outer.length > 3000 ? outer.slice(0, 3000) + '\n... (truncated)' : outer);

    // CSS Selector
    lines.push('\n=== CSS SELECTOR ===');
    lines.push(cssPath(node));

    // XPath
    lines.push('\n=== XPATH ===');
    lines.push(xPath(node));

    // Computed styles
    lines.push('\n=== COMPUTED STYLES (key properties) ===');
    const comp = getComputedStyle(node);
    const props = [
      'display', 'position',
      'width', 'height', 'max-width',
      'margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
      'padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left',
      'border', 'border-top', 'border-right', 'border-bottom', 'border-left',
      'border-color', 'border-width', 'border-style', 'border-radius',
      'background', 'background-color',
      'color', 'font-family', 'font-size', 'font-weight', 'line-height',
      'text-transform', 'letter-spacing',
      'overflow', 'opacity',
      'flex', 'flex-direction', 'flex-wrap', 'align-items', 'justify-content', 'gap',
      'grid-template-columns', 'grid-template-rows',
      'outline',
    ];
    for (const p of props) {
      const v = comp.getPropertyValue(p);
      if (v && v !== '' && v !== 'none' && v !== 'normal' && v !== 'auto'
          && v !== '0px' && v !== 'rgba(0, 0, 0, 0)' && v !== 'start'
          && v !== 'visible' && v !== 'baseline' && v !== 'stretch') {
        lines.push(`  ${p}: ${v};`);
      }
    }

    // Matched CSS rules
    lines.push('\n=== MATCHED CSS RULES ===');
    try {
      for (const sheet of [...document.styleSheets]) {
        try {
          for (const rule of [...sheet.cssRules]) {
            if (rule.selectorText && node.matches(rule.selectorText)) {
              const src = sheet.href ? sheet.href.split('/').pop().split('?')[0] : 'inline';
              lines.push(`/* ${src} */`);
              lines.push(`${rule.selectorText} {`);
              for (let i = 0; i < rule.style.length; i++) {
                const prop = rule.style[i];
                const val = rule.style.getPropertyValue(prop);
                const pri = rule.style.getPropertyPriority(prop);
                lines.push(`  ${prop}: ${val}${pri ? ' !important' : ''};`);
              }
              lines.push('}');
            }
          }
        } catch (e) { /* cross-origin */ }
      }
    } catch (e) {
      lines.push('(Could not read stylesheets)');
    }

    // Parent chain (compact, just for this node)
    lines.push('\n=== PARENT CHAIN ===');
    let p = node; let d = 0;
    while (p && p !== document.documentElement && d < 12) {
      const tag = p.tagName.toLowerCase();
      const id = p.id ? `#${p.id}` : '';
      const cls = p.className && typeof p.className === 'string'
        ? '.' + p.className.trim().split(/\s+/).join('.') : '';
      lines.push(`${'  '.repeat(d)}${tag}${id}${cls}`);
      p = p.parentElement; d++;
    }

    allLines.push(lines.join('\n'));
    allLines.push('\n\n');

    node = node.parentElement;
    level++;
  }

  const result = '\n\n\n\n\n' + allLines.join('') + '\n\n\n# End of deep debug (' + level + ' levels)\n\n\n\n\n# Next batch: ';
  copy(result);
  console.log(`Deep debug: ${level} levels, ${result.length} chars copied to clipboard.`);
  return result;
}

function cssPath(el) {
  const parts = [];
  while (el && el.nodeType === 1) {
    let sel = el.tagName.toLowerCase();
    if (el.id) { parts.unshift(`${sel}#${el.id}`); break; }
    if (el.className && typeof el.className === 'string') {
      sel += '.' + el.className.trim().split(/\s+/).join('.');
    }
    const parent = el.parentElement;
    if (parent) {
      const siblings = [...parent.children].filter(c => c.tagName === el.tagName);
      if (siblings.length > 1) {
        sel += `:nth-child(${[...parent.children].indexOf(el) + 1})`;
      }
    }
    parts.unshift(sel);
    el = parent;
  }
  return parts.join(' > ');
}

function xPath(el) {
  const parts = [];
  while (el && el.nodeType === 1) {
    let idx = 1;
    for (let sib = el.previousElementSibling; sib; sib = sib.previousElementSibling) {
      if (sib.tagName === el.tagName) idx++;
    }
    parts.unshift(`${el.tagName.toLowerCase()}[${idx}]`);
    el = el.parentElement;
  }
  return '/' + parts.join('/');
}

debug($0);

Deep debug — 10 levels (Super+G)

Same script as above. Change line 16 from const maxLevels = 5; to const maxLevels = 10; — that's the only difference. Save it as ~/tools/deep-debug-10.js and bind it to Super+G using the gsettings command shown in the setup section above.

Level markers: The output starts with === SELECTED ELEMENT === for the element you clicked, then === PARENT 1 ===, === PARENT 2 ===, etc. as it walks up. Your AI knows exactly which element you were looking at and which containers surround it.

The workflow is the same for all three: click the element in Inspector, hit the shortcut, Ctrl+V in Console, Enter, then Ctrl+V to your AI. The deeper scripts just walk up the DOM tree and dump each parent level — so your AI sees not just the broken element, but every container that might be causing the problem.

Other desktop environments: The gsettings commands above are MATE-specific. Ask your AI to adapt them — paste the MATE version and tell it your desktop environment.

Why this matters more than you think

The quality of Claude's CSS fixes is directly proportional to the context you give it. A screenshot tells Claude what's wrong. The debug output tells Claude why it's wrong — which rule is winning the specificity war, which file it comes from, what the parent chain looks like, whether an inline style is overriding everything.

That's the difference between Claude saying "try adding !important" and Claude saying "your .nav-item a rule at specificity 0,1,1 is being overridden by .taid-menu a at 0,1,1 — same specificity, but it appears later in template.css. Move it below or increase the specificity."

Better context. Better fixes. Less back-and-forth.

The AI Director

Build Joomla Sites with AI

Drop one file into your project. VS Code + Claude Code reads it automatically — every Joomla gotcha, every silent failure, every fix. Describe what you want. AI builds it.

Browse the Shop →

The Shop

Briefing Doc $18

The AI Joomla Blueprint

One CLAUDE.md file. 300+ Joomla gotchas your AI already knows — silent failures, wrong defaults, invisible bugs, with the exact fix for each. Drop it in your project root.

  • 300+ gotchas across 14 sections
  • 70+ symptom → cause → fix entries
  • 120+ copy-paste code blocks
  • Works with Claude Code, Copilot, ChatGPT, Gemini
  • One file, works forever, instant download
Get the Blueprint — $18 →

Checkout via Gumroad · Instant download

Bundle
$54 $63

The Full Stack

The Blueprint that teaches your AI everything about Joomla, plus the kit that gets a site running before lunch. Everything you need — this afternoon and every project after.

  • The AI Joomla Blueprint ($18 value)
  • The AI Director Starter Kit ($45 value)
  • AI knows your entire stack from message one
  • Lifetime access — reuse on every project
Get the Full Stack — $54 →

Save $9 · Checkout via Gumroad

Stay Sharp on AI

New articles, prompt packs, and scripts — delivered when they're ready. No filler.

Newsletter coming soon — AI workflows, Joomla tips, and new Blueprint updates straight to your inbox.