← Mike Higgins Home
Custom Code Experiment •

The Color API

Source Code View HTML / CSS / JavaScript
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Color API Tool</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
        }

        body {
            background: #000000;
            color: #ffffff;
            min-height: 100vh;
            padding: 0.75rem;
            line-height: 1.4;
            font-size: 0.875rem;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
        }

        .main-grid {
            display: grid;
            grid-template-columns: 1fr;
            gap: 1rem;
        }

        @media (min-width: 768px) {
            .main-grid {
                grid-template-columns: 1fr 1fr;
            }
        }

        .card {
            background: #111111;
            border-radius: 6px;
            padding: 1.25rem;
            border: 1px solid #222222;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
            transition: all 0.2s ease;
        }

        .card:hover {
            border-color: #333333;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
        }

        .card h2 {
            font-size: 1rem;
            margin-bottom: 1rem;
            display: flex;
            align-items: center;
            gap: 0.5rem;
            color: #ffffff;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            padding-bottom: 0.75rem;
            border-bottom: 1px solid #222222;
        }

        .card h2 i {
            color: #0066ff;
        }

        .input-group {
            margin-bottom: 0.75rem;
        }

        .input-group label {
            display: block;
            margin-bottom: 0.375rem;
            font-size: 0.8rem;
            color: #888888;
            font-weight: 500;
        }

        .input-row {
            display: flex;
            gap: 0.5rem;
        }

        input, select, button {
            padding: 0.5rem 0.75rem;
            border-radius: 4px;
            border: 1px solid #333333;
            background: #1a1a1a;
            color: #ffffff;
            font-size: 0.85rem;
            transition: all 0.2s;
        }

        input:focus, select:focus {
            outline: none;
            border-color: #0066ff;
            box-shadow: 0 0 0 1px rgba(0, 102, 255, 0.2);
        }

        input {
            flex: 1;
        }

        button {
            background: #0066ff;
            border: none;
            color: white;
            font-weight: 500;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 0.5rem;
            transition: all 0.2s;
        }

        button:hover {
            background: #0052d4;
            transform: translateY(-1px);
        }

        button:active {
            transform: translateY(0);
        }

        button:disabled {
            opacity: 0.5;
            cursor: not-allowed;
            transform: none;
        }

        .color-preview {
            width: 100%;
            height: 40px;
            border-radius: 4px;
            margin: 0.75rem 0;
            border: 1px solid #333333;
            overflow: hidden;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: 600;
            color: white;
            text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
            font-family: 'Monaco', 'Courier New', monospace;
            font-size: 0.8rem;
        }

        .results {
            margin-top: 1rem;
            max-height: 250px;
            overflow-y: auto;
        }

        .results h3 {
            font-size: 0.9rem;
            margin-bottom: 0.75rem;
            color: #ffffff;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }

        .results h3 span {
            font-size: 0.75rem;
            color: #888888;
            font-weight: normal;
        }

        .color-info {
            background: #0a0a0a;
            border-radius: 4px;
            padding: 0.75rem;
            margin-bottom: 1rem;
            border: 1px solid #222222;
        }

        .info-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 0.5rem;
            font-size: 0.85rem;
        }

        .info-row:last-child {
            margin-bottom: 0;
        }

        .info-label {
            color: #888888;
            width: 50px;
            flex-shrink: 0;
            font-weight: 500;
            text-transform: uppercase;
            font-size: 0.75rem;
        }

        .info-value {
            font-weight: 500;
            color: #ffffff;
            display: flex;
            justify-content: space-between;
            align-items: center;
            flex-grow: 1;
            margin-left: 0.75rem;
        }

        .color-text {
            font-family: 'Monaco', 'Courier New', monospace;
            font-size: 0.8rem;
            color: #e0e0e0;
        }

        .scheme-colors {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(50px, 1fr));
            gap: 0.375rem;
            margin-top: 0.75rem;
        }

        .scheme-color {
            height: 50px;
            border-radius: 4px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 0.65rem;
            font-weight: 600;
            color: white;
            text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
            cursor: pointer;
            transition: transform 0.2s, filter 0.2s;
            border: 1px solid rgba(255, 255, 255, 0.1);
            font-family: 'Monaco', 'Courier New', monospace;
        }

        .scheme-color:hover {
            transform: scale(1.05);
            filter: brightness(1.1);
        }

        .loading {
            display: none;
            text-align: center;
            padding: 0.75rem;
            color: #888888;
            font-size: 0.8rem;
        }

        .loading i {
            margin-right: 0.5rem;
            animation: spin 1s linear infinite;
        }

        @keyframes spin {
            from { transform: rotate(0deg); }
            to { transform: rotate(360deg); }
        }

        .error {
            background: rgba(255, 50, 50, 0.1);
            border: 1px solid #ff3333;
            color: #ff6666;
            padding: 0.75rem;
            border-radius: 4px;
            margin-top: 0.75rem;
            display: none;
            font-size: 0.8rem;
        }

        .footer {
            text-align: center;
            margin-top: 1.5rem;
            padding-top: 1rem;
            border-top: 1px solid #222222;
            color: #666666;
            font-size: 0.75rem;
        }

        .footer a {
            color: #0066ff;
            text-decoration: none;
            transition: color 0.2s;
        }

        .footer a:hover {
            color: #0052d4;
            text-decoration: underline;
        }

        .copy-btn {
            background: #222222;
            padding: 0.2rem 0.6rem;
            font-size: 0.7rem;
            border-radius: 3px;
            cursor: pointer;
            border: 1px solid #333333;
            color: #ffffff;
            transition: all 0.2s;
            flex-shrink: 0;
            width: 55px;
            text-align: center;
            font-weight: 500;
        }

        .copy-btn:hover {
            background: #333333;
            border-color: #444444;
        }

        .color-inputs {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 0.5rem;
            margin-bottom: 0.75rem;
        }

        .color-inputs input {
            text-align: center;
        }

        .color-format {
            display: flex;
            gap: 0.375rem;
            margin-bottom: 0.75rem;
        }

        .format-btn {
            flex: 1;
            background: #1a1a1a;
            text-align: center;
            padding: 0.5rem;
            border-radius: 4px;
            cursor: pointer;
            transition: all 0.2s;
            font-size: 0.8rem;
            border: 1px solid #333333;
            color: #888888;
            font-weight: 500;
        }

        .format-btn.active {
            background: #0066ff;
            color: white;
            border-color: #0066ff;
        }

        .format-btn:hover:not(.active) {
            background: #222222;
            color: #ffffff;
        }

        .color-value-display {
            text-align: center;
            font-weight: 600;
            margin: 0.5rem 0;
            font-size: 0.9rem;
            color: #ffffff;
            font-family: 'Monaco', 'Courier New', monospace;
            background: #1a1a1a;
            padding: 0.5rem;
            border-radius: 4px;
            border: 1px solid #222222;
        }

        .api-info {
            font-size: 0.75rem;
            color: #666666;
            margin-top: 0.5rem;
            line-height: 1.3;
        }

        .header {
            text-align: center;
            margin-bottom: 1.25rem;
            padding-bottom: 1rem;
            border-bottom: 1px solid #222222;
        }

        .header h1 {
            font-size: 1.25rem;
            background: linear-gradient(90deg, #0066ff, #00ccff);
            -webkit-background-clip: text;
            background-clip: text;
            color: transparent;
            margin-bottom: 0.25rem;
            font-weight: 700;
            letter-spacing: -0.5px;
        }

        .header .subtitle {
            color: #888888;
            font-size: 0.8rem;
            font-weight: 400;
        }

        ::-webkit-scrollbar {
            width: 6px;
            height: 6px;
        }

        ::-webkit-scrollbar-track {
            background: #1a1a1a;
            border-radius: 3px;
        }

        ::-webkit-scrollbar-thumb {
            background: #333333;
            border-radius: 3px;
        }

        ::-webkit-scrollbar-thumb:hover {
            background: #444444;
        }

        /* Compact utility classes */
        .compact-text {
            font-size: 0.85rem;
        }

        .compact-padding {
            padding: 0.5rem;
        }

        .compact-margin {
            margin-bottom: 0.5rem;
        }

        /* Status indicators */
        .status-dot {
            display: inline-block;
            width: 8px;
            height: 8px;
            border-radius: 50%;
            background: #00cc00;
            margin-right: 6px;
            animation: pulse 2s infinite;
        }

        @keyframes pulse {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.5; }
        }

        /* Badges */
        .badge {
            display: inline-block;
            padding: 0.15rem 0.4rem;
            border-radius: 3px;
            font-size: 0.7rem;
            font-weight: 600;
            background: #222222;
            color: #888888;
            margin-left: 0.5rem;
        }

        .badge.api {
            background: #0066ff;
            color: white;
        }

        /* Tooltip */
        .tooltip {
            position: relative;
            cursor: help;
        }

        .tooltip:hover:after {
            content: attr(data-tooltip);
            position: absolute;
            bottom: 100%;
            left: 50%;
            transform: translateX(-50%);
            background: #222222;
            color: #ffffff;
            padding: 0.5rem;
            border-radius: 4px;
            font-size: 0.75rem;
            white-space: nowrap;
            z-index: 100;
            border: 1px solid #333333;
            margin-bottom: 5px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="main-grid">
            <div class="card">
                <h2><i class="fas fa-eye-dropper"></i> Colour Analysis <span class="badge">ID</span></h2>

                <div class="color-format">
                    <div class="format-btn active" data-format="hex" data-tooltip="Hex color code">HEX</div>
                    <div class="format-btn" data-format="rgb" data-tooltip="Red, Green, Blue">RGB</div>
                    <div class="format-btn" data-format="hsl" data-tooltip="Hue, Saturation, Lightness">HSL</div>
                    <div class="format-btn" data-format="cmyk" data-tooltip="Cyan, Magenta, Yellow, Black">CMYK</div>
                </div>

                <div class="input-group">
                    <div class="color-inputs" id="colorInputs">
                        <div class="input-row">
                            <input type="text" id="hexInput" placeholder="e.g., 0047AB or #0047AB" value="0047AB">
                        </div>
                    </div>
                </div>

                <button id="identifyBtn">
                    <i class="fas fa-search"></i> Analyse Colour
                </button>

                <div class="color-preview" id="colorPreview" style="background-color: #0047AB;">
                    #0047AB
                </div>

                <div class="loading" id="identifyLoading">
                    <i class="fas fa-circle-notch"></i> Querying API...
                </div>

                <div class="error" id="identifyError"></div>

                <div class="results" id="identifyResults">
                    <h3>Color Data <span id="colorName">Cobalt Blue</span></h3>
                    <div class="color-info">
                        <div class="info-row">
                            <span class="info-label">HEX</span>
                            <div class="info-value">
                                <span class="color-text">#0047AB</span>
                                <button class="copy-btn" data-value="#0047AB">Copy</button>
                            </div>
                        </div>
                        <div class="info-row">
                            <span class="info-label">RGB</span>
                            <div class="info-value">
                                <span class="color-text">rgb(0, 71, 171)</span>
                                <button class="copy-btn" data-value="rgb(0, 71, 171)">Copy</button>
                            </div>
                        </div>
                        <div class="info-row">
                            <span class="info-label">HSL</span>
                            <div class="info-value">
                                <span class="color-text">hsl(215, 100%, 34%)</span>
                                <button class="copy-btn" data-value="hsl(215, 100%, 34%)">Copy</button>
                            </div>
                        </div>
                        <div class="info-row">
                            <span class="info-label">CMYK</span>
                            <div class="info-value">
                                <span class="color-text">cmyk(100, 58, 0, 33)</span>
                                <button class="copy-btn" data-value="cmyk(100, 58, 0, 33)">Copy</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="card">
                <h2><i class="fas fa-swatchbook"></i> Scheme Generator <span class="badge api">API</span></h2>

                <div class="input-group">
                    <label for="seedColor">Base Colour</label>
                    <div class="input-row">
                        <input type="text" id="seedColor" placeholder="e.g., 0047AB or #0047AB" value="0047AB">
                    </div>
                </div>

                <div class="input-group">
                    <div class="input-row">
                        <div style="flex: 1;">
                            <label for="schemeMode">Scheme Type</label>
                            <select id="schemeMode">
                                <option value="monochrome">Monochrome</option>
                                <option value="monochrome-dark">Monochrome Dark</option>
                                <option value="monochrome-light">Monochrome Light</option>
                                <option value="analogic">Analogic</option>
                                <option value="complement">Complement</option>
                                <option value="analogic-complement">Analogic Complement</option>
                                <option value="triad">Triad</option>
                                <option value="quad">Quad</option>
                            </select>
                        </div>
                        <div style="flex: 1;">
                            <label for="schemeCount">Colors</label>
                            <select id="schemeCount">
                                <option value="2">2</option>
                                <option value="3">3</option>
                                <option value="4">4</option>
                                <option value="5" selected>5</option>
                                <option value="6">6</option>
                                <option value="7">7</option>
                                <option value="8">8</option>
                            </select>
                        </div>
                    </div>
                </div>

                <button id="generateSchemeBtn">
                    <i class="fas fa-bolt"></i> Generate
                </button>

                <div class="loading" id="schemeLoading">
                    <i class="fas fa-circle-notch"></i> Processing...
                </div>

                <div class="error" id="schemeError"></div>

                <div class="results" id="schemeResults">
                    <h3>Colour Palette <span id="schemeInfo">Analogic • 5 colors</span></h3>
                    <div class="color-value-display" id="schemeColorsDisplay">
                        #0047AB • #005CE0 • #267AFF • #669DFF • #A3C4FF
                    </div>
                    <div class="scheme-colors" id="schemeColors">
                        <div class="scheme-color" style="background-color: #0047AB;" data-value="#0047AB">#0047AB</div>
                        <div class="scheme-color" style="background-color: #005CE0;" data-value="#005CE0">#005CE0</div>
                        <div class="scheme-color" style="background-color: #267AFF;" data-value="#267AFF">#267AFF</div>
                        <div class="scheme-color" style="background-color: #669DFF;" data-value="#669DFF">#669DFF</div>
                        <div class="scheme-color" style="background-color: #A3C4FF;" data-value="#A3C4FF">#A3C4FF</div>
                    </div>
                    <p class="api-info">
                        <i class="fas fa-info-circle"></i> Color schemes generated via The Color API based on color theory relationships.
                    </p>
                </div>
            </div>
        </div>

        <div class="footer">
            <p><i class="fas fa-code"></i> Built with <a href="https://www.thecolorapi.com" target="_blank">The Color API</a> • Created by <a href="https://github.com/andjosh" target="_blank">Josh Beckman</a></p>
        </div>
    </div>

    <script>
        const formatButtons = document.querySelectorAll('.format-btn');
        const colorInputsContainer = document.getElementById('colorInputs');
        const hexInput = document.getElementById('hexInput');
        const identifyBtn = document.getElementById('identifyBtn');
        const identifyLoading = document.getElementById('identifyLoading');
        const identifyError = document.getElementById('identifyError');
        const identifyResults = document.getElementById('identifyResults');
        const colorPreview = document.getElementById('colorPreview');
        const colorName = document.getElementById('colorName');
        const colorInfo = document.querySelector('.color-info');
        const seedColorInput = document.getElementById('seedColor');
        const schemeMode = document.getElementById('schemeMode');
        const schemeCount = document.getElementById('schemeCount');
        const generateSchemeBtn = document.getElementById('generateSchemeBtn');
        const schemeLoading = document.getElementById('schemeLoading');
        const schemeError = document.getElementById('schemeError');
        const schemeResults = document.getElementById('schemeResults');
        const schemeColorsDisplay = document.getElementById('schemeColorsDisplay');
        const schemeColorsContainer = document.getElementById('schemeColors');
        const schemeInfo = document.getElementById('schemeInfo');

        let currentFormat = 'hex';
        let currentColor = '#0047AB';

        document.addEventListener('DOMContentLoaded', function() {
            updateColorPreview();

            fetchColorData('hex=0047AB');

            fetchColorScheme('hex=0047AB', 'analogic', 5);

            setupEventListeners();

            setupCopyButtons();

            setupTooltips();
        });

        function setupEventListeners() {
            formatButtons.forEach(btn => {
                btn.addEventListener('click', function() {
                    const format = this.getAttribute('data-format');
                    switchColorFormat(format);
                });
            });

            hexInput.addEventListener('input', updateColorPreview);
            identifyBtn.addEventListener('click', identifyColor);

            seedColorInput.addEventListener('input', function() {
                const color = this.value.trim();
                if (isValidColor(color, 'hex')) {
                    currentColor = normalizeHex(color);
                    updateColorPreview();
                }
            });

            generateSchemeBtn.addEventListener('click', generateScheme);
        }

        function setupCopyButtons() {
            document.addEventListener('click', function(e) {
                // Check if the clicked element is a copy button or inside one
                let copyBtn = e.target.closest('.copy-btn');
                if (copyBtn) {
                    e.preventDefault();
                    const value = copyBtn.getAttribute('data-value');
                    if (value) {
                        copyToClipboard(value);

                        const originalText = copyBtn.textContent;
                        copyBtn.textContent = '✓';
                        copyBtn.style.background = '#00cc00';
                        copyBtn.style.borderColor = '#00cc00';

                        setTimeout(() => {
                            copyBtn.textContent = originalText;
                            copyBtn.style.background = '';
                            copyBtn.style.borderColor = '';
                        }, 1500);
                    }
                }

                let schemeColor = e.target.closest('.scheme-color');
                if (schemeColor) {
                    e.preventDefault();
                    const colorValue = schemeColor.getAttribute('data-value');
                    if (colorValue) {
                        copyToClipboard(colorValue);

                        const originalText = schemeColor.textContent;
                        const originalBg = schemeColor.style.backgroundColor;
                        schemeColor.textContent = '✓';
                        schemeColor.style.backgroundColor = '#00cc00';

                        setTimeout(() => {
                            schemeColor.textContent = originalText;
                            schemeColor.style.backgroundColor = originalBg;
                        }, 1500);
                    }
                }
            });
        }

        function setupTooltips() {
            const tooltipElements = document.querySelectorAll('[data-tooltip]');
            tooltipElements.forEach(el => {
                el.addEventListener('mouseenter', function() {
                    // Tooltip is handled by CSS
                });
            });
        }

        function switchColorFormat(format) {
            if (format === currentFormat) return;

            formatButtons.forEach(btn => {
                if (btn.getAttribute('data-format') === format) {
                    btn.classList.add('active');
                } else {
                    btn.classList.remove('active');
                }
            });

            let hexValue, rgbValue, hslValue, cmykValue;

            const infoRows = document.querySelectorAll('.info-row');
            infoRows.forEach(row => {
                const label = row.querySelector('.info-label').textContent;
                const valueSpan = row.querySelector('.info-value');
                const copyBtn = valueSpan.querySelector('.copy-btn');
                const value = copyBtn ? copyBtn.getAttribute('data-value') : '';

                if (label.includes('HEX')) hexValue = value;
                if (label.includes('RGB')) rgbValue = value;
                if (label.includes('HSL')) hslValue = value;
                if (label.includes('CMYK')) cmykValue = value;
            });

            colorInputsContainer.innerHTML = '';

            if (format === 'hex') {
                const inputRow = document.createElement('div');
                inputRow.className = 'input-row';
                inputRow.innerHTML = `
                    <input type="text" id="hexInput" placeholder="e.g., 0047AB or #0047AB" value="${hexValue ? hexValue.replace('#', '') : '0047AB'}">
                `;
                colorInputsContainer.appendChild(inputRow);

                // Add event listener
                const newHexInput = document.getElementById('hexInput');
                newHexInput.addEventListener('input', updateColorPreview);
            }
            else if (format === 'rgb') {
                let r = '0', g = '71', b = '171';
                if (rgbValue) {
                    const rgbValues = rgbValue.replace('rgb(', '').replace(')', '').split(',');
                    r = rgbValues[0].trim();
                    g = rgbValues[1].trim();
                    b = rgbValues[2].trim();
                }

                const inputRow = document.createElement('div');
                inputRow.className = 'input-row';
                inputRow.innerHTML = `
                    <input type="number" min="0" max="255" placeholder="R" value="${r}" class="rgb-input">
                    <input type="number" min="0" max="255" placeholder="G" value="${g}" class="rgb-input">
                    <input type="number" min="0" max="255" placeholder="B" value="${b}" class="rgb-input">
                `;
                colorInputsContainer.appendChild(inputRow);

                const rgbInputs = document.querySelectorAll('.rgb-input');
                rgbInputs.forEach(input => {
                    input.addEventListener('input', updateColorPreviewFromRGB);
                });
            }
            else if (format === 'hsl') {
                let h = '215', s = '100', l = '34';
                if (hslValue) {
                    const hslValues = hslValue.replace('hsl(', '').replace(')', '').replace(/%/g, '').split(',');
                    h = hslValues[0].trim();
                    s = hslValues[1].trim();
                    l = hslValues[2].trim();
                }

                const inputRow = document.createElement('div');
                inputRow.className = 'input-row';
                inputRow.innerHTML = `
                    <input type="number" min="0" max="360" placeholder="H" value="${h}" class="hsl-input">
                    <input type="number" min="0" max="100" placeholder="S%" value="${s}" class="hsl-input">
                    <input type="number" min="0" max="100" placeholder="L%" value="${l}" class="hsl-input">
                `;
                colorInputsContainer.appendChild(inputRow);

                const hslInputs = document.querySelectorAll('.hsl-input');
                hslInputs.forEach(input => {
                    input.addEventListener('input', updateColorPreviewFromHSL);
                });
            }
            else if (format === 'cmyk') {
                let c = '100', m = '58', y = '0', k = '33';
                if (cmykValue) {
                    const cmykValues = cmykValue.replace('cmyk(', '').replace(')', '').split(',');
                    c = cmykValues[0].trim();
                    m = cmykValues[1].trim();
                    y = cmykValues[2].trim();
                    k = cmykValues[3].trim();
                }

                const inputRow = document.createElement('div');
                inputRow.className = 'input-row';
                inputRow.innerHTML = `
                    <input type="number" min="0" max="100" placeholder="C%" value="${c}" class="cmyk-input">
                    <input type="number" min="0" max="100" placeholder="M%" value="${m}" class="cmyk-input">
                    <input type="number" min="0" max="100" placeholder="Y%" value="${y}" class="cmyk-input">
                    <input type="number" min="0" max="100" placeholder="K%" value="${k}" class="cmyk-input">
                `;
                colorInputsContainer.appendChild(inputRow);

                const cmykInputs = document.querySelectorAll('.cmyk-input');
                cmykInputs.forEach(input => {
                    input.addEventListener('input', updateColorPreviewFromCMYK);
                });
            }

            currentFormat = format;
        }

        function updateColorPreview() {
            const hexInput = document.getElementById('hexInput');
            if (!hexInput) return;

            let hex = hexInput.value.trim();
            hex = normalizeHex(hex);

            if (isValidColor(hex, 'hex')) {
                colorPreview.style.backgroundColor = hex;
                colorPreview.textContent = hex;
                currentColor = hex;
            }
        }

        function updateColorPreviewFromRGB() {
            const rgbInputs = document.querySelectorAll('.rgb-input');
            const r = parseInt(rgbInputs[0].value) || 0;
            const g = parseInt(rgbInputs[1].value) || 0;
            const b = parseInt(rgbInputs[2].value) || 0;

            if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {
                const hex = rgbToHex(r, g, b);
                colorPreview.style.backgroundColor = hex;
                colorPreview.textContent = hex;
                currentColor = hex;
            }
        }

        function updateColorPreviewFromHSL() {
            const hslInputs = document.querySelectorAll('.hsl-input');
            const h = parseInt(hslInputs[0].value) || 0;
            const s = parseInt(hslInputs[1].value) || 0;
            const l = parseInt(hslInputs[2].value) || 0;

            if (h >= 0 && h <= 360 && s >= 0 && s <= 100 && l >= 0 && l <= 100) {
                const hex = hslToHex(h, s, l);
                colorPreview.style.backgroundColor = hex;
                colorPreview.textContent = hex;
                currentColor = hex;
            }
        }

        function updateColorPreviewFromCMYK() {
            const cmykInputs = document.querySelectorAll('.cmyk-input');
            const c = parseInt(cmykInputs[0].value) || 0;
            const m = parseInt(cmykInputs[1].value) || 0;
            const y = parseInt(cmykInputs[2].value) || 0;
            const k = parseInt(cmykInputs[3].value) || 0;

            if (c >= 0 && c <= 100 && m >= 0 && m <= 100 && y >= 0 && y <= 100 && k >= 0 && k <= 100) {
                const hex = cmykToHex(c, m, y, k);
                colorPreview.style.backgroundColor = hex;
                colorPreview.textContent = hex;
                currentColor = hex;
            }
        }

        function identifyColor() {
            let apiParam = '';

            if (currentFormat === 'hex') {
                const hexInput = document.getElementById('hexInput');
                const hex = hexInput.value.trim();
                if (!isValidColor(hex, 'hex')) {
                    showError(identifyError, 'Please enter a valid HEX color (e.g., 0047AB or #0047AB)');
                    return;
                }
                apiParam = `hex=${normalizeHex(hex).replace('#', '')}`;
            }
            else if (currentFormat === 'rgb') {
                const rgbInputs = document.querySelectorAll('.rgb-input');
                const r = parseInt(rgbInputs[0].value) || 0;
                const g = parseInt(rgbInputs[1].value) || 0;
                const b = parseInt(rgbInputs[2].value) || 0;

                if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) {
                    showError(identifyError, 'RGB values must be between 0 and 255');
                    return;
                }
                apiParam = `rgb=${r},${g},${b}`;
            }
            else if (currentFormat === 'hsl') {
                const hslInputs = document.querySelectorAll('.hsl-input');
                const h = parseInt(hslInputs[0].value) || 0;
                const s = parseInt(hslInputs[1].value) || 0;
                const l = parseInt(hslInputs[2].value) || 0;

                if (h < 0 || h > 360 || s < 0 || s > 100 || l < 0 || l > 100) {
                    showError(identifyError, 'H must be 0-360, S and L must be 0-100');
                    return;
                }
                apiParam = `hsl=${h},${s}%,${l}%`;
            }
            else if (currentFormat === 'cmyk') {
                const cmykInputs = document.querySelectorAll('.cmyk-input');
                const c = parseInt(cmykInputs[0].value) || 0;
                const m = parseInt(cmykInputs[1].value) || 0;
                const y = parseInt(cmykInputs[2].value) || 0;
                const k = parseInt(cmykInputs[3].value) || 0;

                if (c < 0 || c > 100 || m < 0 || m > 100 || y < 0 || y > 100 || k < 0 || k > 100) {
                    showError(identifyError, 'CMYK values must be between 0 and 100');
                    return;
                }
                apiParam = `cmyk=${c},${m},${y},${k}`;
            }

            fetchColorData(apiParam);
        }

        function generateScheme() {
            const seedColor = seedColorInput.value.trim();
            const mode = schemeMode.value;
            const count = parseInt(schemeCount.value);

            if (!isValidColor(seedColor, 'hex')) {
                showError(schemeError, 'Please enter a valid HEX color for the base color');
                return;
            }

            const hex = normalizeHex(seedColor).replace('#', '');
            fetchColorScheme(`hex=${hex}`, mode, count);
        }

        async function fetchColorData(apiParam) {
            identifyLoading.style.display = 'block';
            identifyError.style.display = 'none';
            identifyResults.style.display = 'none';

            try {
                const response = await fetch(`https://www.thecolorapi.com/id?${apiParam}&format=json`);
                if (!response.ok) throw new Error('Failed to fetch color data');

                const data = await response.json();
                displayColorData(data);
            } catch (error) {
                showError(identifyError, `Error: ${error.message}`);
            } finally {
                identifyLoading.style.display = 'none';
            }
        }

        async function fetchColorScheme(apiParam, mode, count) {
            schemeLoading.style.display = 'block';
            schemeError.style.display = 'none';

            try {
                const response = await fetch(`https://www.thecolorapi.com/scheme?${apiParam}&mode=${mode}&count=${count}&format=json`);
                if (!response.ok) throw new Error('Failed to fetch color scheme');

                const data = await response.json();
                displayColorScheme(data, mode, count);
            } catch (error) {
                showError(schemeError, `Error: ${error.message}`);
            } finally {
                schemeLoading.style.display = 'none';
            }
        }

        function displayColorData(data) {
            colorName.textContent = data.name.value || 'Unknown Color';

            // Update color preview
            const hex = data.hex.value;
            colorPreview.style.backgroundColor = hex;
            colorPreview.textContent = hex;
            currentColor = hex;

            // Update info rows
            const colorInfoHTML = `
                <div class="info-row">
                    <span class="info-label">HEX</span>
                    <div class="info-value">
                        <span class="color-text">${data.hex.value}</span>
                        <button class="copy-btn" data-value="${data.hex.value}">Copy</button>
                    </div>
                </div>
                <div class="info-row">
                    <span class="info-label">RGB</span>
                    <div class="info-value">
                        <span class="color-text">rgb(${data.rgb.r}, ${data.rgb.g}, ${data.rgb.b})</span>
                        <button class="copy-btn" data-value="rgb(${data.rgb.r}, ${data.rgb.g}, ${data.rgb.b})">Copy</button>
                    </div>
                </div>
                <div class="info-row">
                    <span class="info-label">HSL</span>
                    <div class="info-value">
                        <span class="color-text">hsl(${data.hsl.h}, ${data.hsl.s}%, ${data.hsl.l}%)</span>
                        <button class="copy-btn" data-value="hsl(${data.hsl.h}, ${data.hsl.s}%, ${data.hsl.l}%)">Copy</button>
                    </div>
                </div>
                <div class="info-row">
                    <span class="info-label">CMYK</span>
                    <div class="info-value">
                        <span class="color-text">cmyk(${data.cmyk.c}%, ${data.cmyk.m}%, ${data.cmyk.y}%, ${data.cmyk.k}%)</span>
                        <button class="copy-btn" data-value="cmyk(${data.cmyk.c}%, ${data.cmyk.m}%, ${data.cmyk.y}%, ${data.cmyk.k}%)">Copy</button>
                    </div>
                </div>
            `;

            colorInfo.innerHTML = colorInfoHTML;
            identifyResults.style.display = 'block';
        }

        function displayColorScheme(data, mode, count) {
            schemeInfo.textContent = `${formatModeName(mode)} • ${count} colors`;

            schemeColorsContainer.innerHTML = '';
            schemeColorsDisplay.textContent = '';

            const colors = data.colors;
            const colorHexValues = colors.map(color => color.hex.value);

            schemeColorsDisplay.textContent = colorHexValues.join(' • ');

            colors.forEach(color => {
                const colorDiv = document.createElement('div');
                colorDiv.className = 'scheme-color';
                colorDiv.style.backgroundColor = color.hex.value;
                colorDiv.textContent = color.hex.value;
                colorDiv.setAttribute('data-value', color.hex.value);
                schemeColorsContainer.appendChild(colorDiv);
            });

            schemeResults.style.display = 'block';
        }

        function showError(element, message) {
            element.textContent = message;
            element.style.display = 'block';
        }

        function isValidColor(color, format) {
            if (format === 'hex') {
                const hexRegex = /^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;
                return hexRegex.test(color);
            }
            return true;
        }

        function normalizeHex(hex) {
            hex = hex.replace('#', '');
            if (hex.length === 3) {
                hex = hex.split('').map(c => c + c).join('');
            }
            return `#${hex.toUpperCase()}`;
        }

        function copyToClipboard(text) {
            // Create a temporary textarea element
            const textarea = document.createElement('textarea');
            textarea.value = text;
            textarea.style.position = 'fixed';
            textarea.style.left = '-999999px';
            textarea.style.top = '-999999px';
            document.body.appendChild(textarea);

            // Select and copy the text
            textarea.select();
            textarea.setSelectionRange(0, 99999); // For mobile devices

            try {
                const successful = document.execCommand('copy');
                console.log('Copied to clipboard:', text, successful ? 'successfully' : 'unsuccessfully');
            } catch (err) {
                console.error('Failed to copy text:', err);
            }

            // Clean up
            document.body.removeChild(textarea);
        }

        function formatModeName(mode) {
            const names = {
                'monochrome': 'Monochrome',
                'monochrome-dark': 'Monochrome Dark',
                'monochrome-light': 'Monochrome Light',
                'analogic': 'Analogic',
                'complement': 'Complement',
                'analogic-complement': 'Analogic Complement',
                'triad': 'Triad',
                'quad': 'Quad'
            };
            return names[mode] || mode;
        }

        function rgbToHex(r, g, b) {
            return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase();
        }

        function hslToHex(h, s, l) {
            s /= 100;
            l /= 100;

            const c = (1 - Math.abs(2 * l - 1)) * s;
            const x = c * (1 - Math.abs((h / 60) % 2 - 1));
            const m = l - c / 2;

            let r = 0, g = 0, b = 0;

            if (0 <= h && h < 60) {
                r = c; g = x; b = 0;
            } else if (60 <= h && h < 120) {
                r = x; g = c; b = 0;
            } else if (120 <= h && h < 180) {
                r = 0; g = c; b = x;
            } else if (180 <= h && h < 240) {
                r = 0; g = x; b = c;
            } else if (240 <= h && h < 300) {
                r = x; g = 0; b = c;
            } else if (300 <= h && h < 360) {
                r = c; g = 0; b = x;
            }

            r = Math.round((r + m) * 255);
            g = Math.round((g + m) * 255);
            b = Math.round((b + m) * 255);

            return rgbToHex(r, g, b);
        }

        function cmykToHex(c, m, y, k) {
            c /= 100;
            m /= 100;
            y /= 100;
            k /= 100;

            const r = Math.round(255 * (1 - c) * (1 - k));
            const g = Math.round(255 * (1 - m) * (1 - k));
            const b = Math.round(255 * (1 - y) * (1 - k));

            return rgbToHex(r, g, b);
        }
    </script>
</body>
</html>