<html lang="es"><head><script>(function(firebaseConfig, initialAuthToken, appId) {
window.__firebase_config = firebaseConfig;
window.__initial_auth_token = initialAuthToken;
window.__app_id = appId;
})("\n{\n \"apiKey\": \"AIzaSyCqyCcs2R2e7AegGjvFAwG98wlamtbHvZY\",\n \"authDomain\": \"bard-frontend.firebaseapp.com\",\n \"projectId\": \"bard-frontend\",\n \"storageBucket\": \"bard-frontend.firebasestorage.app\",\n \"messagingSenderId\": \"175205271074\",\n \"appId\": \"1:175205271074:web:2b7bd4d34d33bf38e6ec7b\"\n}\n","eyJhbGciOiJSUzI1NiIsImtpZCI6ImUzOGIyZmQ4N2FiNjRlNWIzOGQzZjliYzA1MWQwMWRkOWE0NGEyMDAiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiJmaXJlYmFzZS1hZG1pbnNkay1mYnN2Y0BiYXJkLWZyb250ZW5kLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYXVkIjoiaHR0cHM6XC9cL2lkZW50aXR5dG9vbGtpdC5nb29nbGVhcGlzLmNvbVwvZ29vZ2xlLmlkZW50aXR5LmlkZW50aXR5dG9vbGtpdC52MS5JZGVudGl0eVRvb2xraXQiLCJ1aWQiOiIxODE2ODExMjIxOTUyNDI1OTE2MyIsImlzcyI6ImZpcmViYXNlLWFkbWluc2RrLWZic3ZjQGJhcmQtZnJvbnRlbmQuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJjbGFpbXMiOnsiYXBwSWQiOiJjX2FjOGQxYWM2NWY0ZTk3MTBfaW52aXRhY2lvbi05MHMtd2hhdHNhcHAtODI1In0sImV4cCI6MTc1NDUxNzAyMiwiaWF0IjoxNzU0NTEzNDIyLCJhbGciOiJSUzI1NiJ9.XuYnjR4NzL8D8UVbOq13Mi-tk6AukEKHTH7l28a9bOZlLZw7Ep0EukFuPXwytIIWxo69QQIBYvOZfuf51FgOKVts3-mjsjDV5lO5kqAJXhMpR93tTM15dPCDUixPYvkTahusmAqXRPe8ZZSvUF0wPDETVU_Hk5ll9WLtRwPQlUW2NBLnhdrHPduOsWS9m-4YbPae1ANJ3_GEuxzjirb_7hwSEZ3ARphdTgM9rSst8XardaGI2cem6Tmy9JRrFHczl9Cbz0GfmxMtjmjTgXCrjpjGpKp72mPKG_81vWs5BFVu_7IUmoy9giZw6F9xp9tNB9V47kXbbvAkq9HQuGkYpg","c_ac8d1ac65f4e9710_invitacion-90s-whatsapp-825")</script><script>(function() {
// Ensure this script is executed only once
if (window.firebaseAuthBridgeScriptLoaded) {
return;
}
window.firebaseAuthBridgeScriptLoaded = true;
let nextTokenPromiseId = 0;
// Stores { resolve, reject } for ongoing token requests
const pendingTokenPromises = {};
// Listen for messages from the Host Application
window.addEventListener('message', function(event) {
const messageData = event.data;
if (messageData && messageData.type === 'RESOLVE_NEW_FIREBASE_TOKEN') {
const { success, token, error, promiseId } = messageData ?? {};
if (pendingTokenPromises[promiseId]) {
if (success) {
pendingTokenPromises[promiseId].resolve(token);
} else {
pendingTokenPromises[promiseId].reject(new Error(error || 'Token refresh failed from host.'));
}
delete pendingTokenPromises[promiseId];
}
}
});
// Expose a function for the Generated App to request a new Firebase token
window.requestNewFirebaseToken = function() {
const currentPromiseId = nextTokenPromiseId++;
const promise = new Promise((resolve, reject) => {
pendingTokenPromises[currentPromiseId] = { resolve, reject };
});
if (window.parent && window.parent !== window) {
window.parent.postMessage({
type: 'REQUEST_NEW_FIREBASE_TOKEN',
promiseId: currentPromiseId
}, '*');
} else {
pendingTokenPromises[currentPromiseId].reject(new Error('No parent window to request token from.'));
delete pendingTokenPromises[currentPromiseId];
}
return promise;
};
})();</script><script>
let realOriginalGetUserMedia = null;
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
realOriginalGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
}
(function() {
if (navigator.mediaDevices && navigator.mediaDevices.__proto__) {
try {
Object.defineProperty(navigator.mediaDevices.__proto__, 'getUserMedia', {
get: function() {
return undefined; // Or throw an error
},
configurable: false
});
} catch (error) {
console.error("Error defining prototype getter:", error);
}
}
})();
(function() {
const pendingMediaResolvers = {};
let nextMediaPromiseId = 0;
function requestMediaPermissions(constraints) {
const mediaPromiseId = nextMediaPromiseId++;
const promise = new Promise((resolve, reject) => {
pendingMediaResolvers[mediaPromiseId] = (granted) => {
delete pendingMediaResolvers[mediaPromiseId];
resolve(granted);
};
});
window.parent.postMessage({
type: 'requestMediaPermission',
constraints: constraints,
promiseId: mediaPromiseId,
}, '*');
return promise;
}
let originalGetUserMedia = realOriginalGetUserMedia;
function interceptGetUserMedia() {
if (navigator.mediaDevices) {
Object.defineProperty(navigator.mediaDevices, 'getUserMedia', {
value: function(constraints) {
return requestMediaPermissions(constraints).then((granted) => {
if (granted) {
if (originalGetUserMedia) {
return originalGetUserMedia(constraints);
} else {
throw new Error("Original getUserMedia not available.");
}
} else {
throw new DOMException('Permission denied', 'NotAllowedError');
}
});
},
writable: false,
configurable: false
});
}
}
interceptGetUserMedia();
const observer = new MutationObserver(function(mutationsList, observer) {
for (const mutation of mutationsList) {
if (mutation.type === 'reconfigured' && mutation.name === 'getUserMedia' && mutation.object === navigator.mediaDevices) {
interceptGetUserMedia();
} else if (mutation.type === 'attributes' && mutation.attributeName === 'getUserMedia' && mutation.target === navigator.mediaDevices) {
interceptGetUserMedia();
} else if (mutation.type === 'childList' && mutation.addedNodes) {
mutation.addedNodes.forEach(node => {
if (node === navigator.mediaDevices) {
interceptGetUserMedia();
}
});
}
}
});
function interceptSpeechRecognition() {
if (!window.SpeechRecognition && !window.webkitSpeechRecognition) {
return;
}
const OriginalSpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
const SpeechRecognitionWrapper = function(...args) {
const recognizer = new OriginalSpeechRecognition(...args);
const originalStart = recognizer.start.bind(recognizer);
recognizer.start = function() {
requestMediaPermissions({ audio: true }).then(granted => {
if (granted) {
originalStart();
} else {
const errorEvent = new SpeechRecognitionErrorEvent('error');
errorEvent.error = 'not-allowed'; // This is the standard error for permission denial.
recognizer.dispatchEvent(errorEvent);
}
});
};
return recognizer;
};
SpeechRecognitionWrapper.prototype = OriginalSpeechRecognition.prototype;
SpeechRecognitionWrapper.prototype.constructor = SpeechRecognitionWrapper;
if (window.SpeechRecognition) {
window.SpeechRecognition = SpeechRecognitionWrapper;
}
if (window.webkitSpeechRecognition) {
window.webkitSpeechRecognition = SpeechRecognitionWrapper;
}
}
interceptSpeechRecognition();
window.addEventListener('message', function(event) {
if (event.data) {
if (event.data.type === 'resolveMediaPermission') {
const { promiseId, granted } = event.data;
if (pendingMediaResolvers[promiseId]) {
pendingMediaResolvers[promiseId](granted);
}
}
}
});
})();</script><script>((function(modelInformation) {
const originalFetch = window.fetch;
// TODO: b/421908508 - Move these out of the script and match all generative AI model calls.
let googleLlmBaseApiUrls = [
'https://generativelanguage.googleapis.com/v1beta/models/' + modelInformation.textModelName + ':streamGenerateContent',
'https://generativelanguage.googleapis.com/v1beta/models/' + modelInformation.textModelName + ':generateContent',
'https://generativelanguage.googleapis.com/v1beta/models/' + modelInformation.imageModelName + ':predict',
'https://generativelanguage.googleapis.com/v1beta/models/' + modelInformation.imageModelName + ':predictLongRunning',
'https://generativelanguage.googleapis.com/v1beta/models/' + modelInformation.imageEditModelName + ':generateContent',
'https://generativelanguage.googleapis.com/v1beta/models/' + modelInformation.videoModelName + ':predict',
'https://generativelanguage.googleapis.com/v1beta/models/' + modelInformation.videoModelName + ':predictLongRunning',
'https://generativelanguage.googleapis.com/v1beta/models/' + modelInformation.ttsModelName + ':generateContent',
];
modelInformation.deprecatedTextModelNames.forEach((modelName) => {
googleLlmBaseApiUrls.push(
'https://generativelanguage.googleapis.com/v1beta/models/' + modelName + ':streamGenerateContent',
'https://generativelanguage.googleapis.com/v1beta/models/' + modelName + ':generateContent',
);
});
const pendingFetchResolvers = {};
let nextPromiseId = 0;
function handleStringInput(input, optionsArgument) {
const actualUrl = input;
const fetchCallArgs = [actualUrl, optionsArgument];
const effectiveOptions = optionsArgument || {};
const bodyForApiKeyCheck = effectiveOptions.body;
const bodyForPostMessage = effectiveOptions.body;
return { actualUrl, fetchCallArgs, effectiveOptions, bodyForApiKeyCheck, bodyForPostMessage };
}
function handleRequestInput(input, optionsArgument) {
const actualUrl = input.url;
const fetchCallArgs = [input, optionsArgument];
const effectiveOptions = { method: input.method, headers: new Headers(input.headers) };
let bodyForApiKeyCheck;
let bodyForPostMessage;
if (optionsArgument) {
if (optionsArgument.method) effectiveOptions.method = optionsArgument.method;
if (optionsArgument.headers) effectiveOptions.headers = new Headers(optionsArgument.headers);
if ('body' in optionsArgument) {
bodyForApiKeyCheck = optionsArgument.body;
bodyForPostMessage = optionsArgument.body;
} else {
bodyForApiKeyCheck = undefined;
bodyForPostMessage = input.body;
}
} else {
bodyForApiKeyCheck = undefined;
bodyForPostMessage = input.body;
}
return { actualUrl, fetchCallArgs, effectiveOptions, bodyForApiKeyCheck, bodyForPostMessage };
}
window.fetch = function(input, optionsArgument) {
let actualUrl;
let fetchCallArgs;
let effectiveOptions = {};
let bodyForApiKeyCheck;
let bodyForPostMessage;
if (typeof input === 'string') {
({actualUrl, fetchCallArgs, effectiveOptions, bodyForApiKeyCheck, bodyForPostMessage} = handleStringInput(input, optionsArgument));
} else if (input instanceof Request) {
({actualUrl, fetchCallArgs, effectiveOptions, bodyForApiKeyCheck, bodyForPostMessage} = handleRequestInput(input, optionsArgument));
} else {
return originalFetch.apply(window, [input, optionsArgument]);
}
effectiveOptions.method = effectiveOptions.method || 'GET';
if (!effectiveOptions.headers) {
effectiveOptions.headers = new Headers();
}
if (typeof actualUrl === 'string' && googleLlmBaseApiUrls.some((url) => actualUrl.startsWith(url))) {
let apiKeyIsNull = true;
const regex = new RegExp("models/([^:]+)");
const modelNameMatch = actualUrl.match(regex);
const modelName = modelNameMatch ? modelNameMatch[1] : 'unspecified';
try {
const urlObject = new URL(actualUrl); // Use URL object for robust parsing
const apiKeyParam = urlObject.searchParams.get('key');
if (apiKeyParam) {
apiKeyIsNull = false;
}
} catch (e) {
// Continue checks even if URL parsing fails
}
if (apiKeyIsNull && effectiveOptions.headers) {
const h = new Headers(effectiveOptions.headers);
const apiKeyHeaderValue = h.get('X-API-Key') || h.get('x-api-key');
if (apiKeyHeaderValue) {
apiKeyIsNull = false;
return originalFetch.apply(window, fetchCallArgs);
}
}
if (apiKeyIsNull && effectiveOptions.method && ['POST', 'PUT', 'PATCH'].includes(effectiveOptions.method.toUpperCase()) && typeof bodyForApiKeyCheck === 'string') {
try {
const bodyData = JSON.parse(bodyForApiKeyCheck);
if (bodyData && bodyData.apiKey) {
apiKeyIsNull = false;
return originalFetch.apply(window, fetchCallArgs);
}
} catch (e) {
// Ignore JSON parsing errors
}
}
if(apiKeyIsNull) {
const promiseId = nextPromiseId++;
const promise = new Promise((resolve) => {
pendingFetchResolvers[promiseId] = (resolvedResponse) => {
delete pendingFetchResolvers[promiseId];
resolve(resolvedResponse);
};
});
let serializedBodyForPostMessage;
if (typeof bodyForPostMessage === 'string' || bodyForPostMessage == null) {
serializedBodyForPostMessage = bodyForPostMessage;
} else if (bodyForPostMessage instanceof ReadableStream) {
serializedBodyForPostMessage = null;
} else {
try {
serializedBodyForPostMessage = JSON.stringify(bodyForPostMessage);
} catch (e) {
serializedBodyForPostMessage = null;
}
}
const messageOptions = {
method: effectiveOptions.method,
headers: Object.fromEntries(new Headers(effectiveOptions.headers).entries()),
body: serializedBodyForPostMessage
};
window.parent.postMessage({
type: 'requestFetch',
url: actualUrl,
modelName: modelName,
options: messageOptions,
promiseId: promiseId,
}, '*');
return promise;
}
return originalFetch.apply(window, fetchCallArgs);
}
return originalFetch.apply(window, fetchCallArgs);
};
window.addEventListener('message', function(event) {
if (event.data && event.data.type === 'resolveFetch') {
const { promiseId, response } = event.data;
if (pendingFetchResolvers[promiseId]) {
try {
const reconstructedResponse = new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: new Headers(response.headers),
});
pendingFetchResolvers[promiseId](reconstructedResponse);
} catch (error) {
pendingFetchResolvers[promiseId](new Response(null, { status: 500, statusText: "Interceptor Response Reconstruction Error" }));
}
}
}
});
}))({"textModelName":"gemini-2.5-flash-preview-05-20","imageModelName":"imagen-3.0-generate-002","imageEditModelName":"gemini-2.0-flash-preview-image-generation","videoModelName":"veo-2.0-generate-001","ttsModelName":"gemini-2.5-flash-preview-tts","deprecatedTextModelNames":["gemini-2.0-flash","gemini-2.5-flash-preview-04-17"]})</script><script>(function() {
const originalConsoleLog = console.log;
const originalConsoleError = console.error;
/**
* Normalizes an error event or a promise rejection reason into a structured error object.
* @param {*} errorEventOrReason The error object or reason.
* @return {object} Structured error data { message, name, stack }.
*/
function getErrorObject(errorEventOrReason) {
if (errorEventOrReason instanceof Error) {
return {
message: errorEventOrReason.message,
name: errorEventOrReason.name,
stack: errorEventOrReason.stack,
};
}
// Fallback for non-Error objects.
try {
return {
message: JSON.stringify(errorEventOrReason),
name: 'UnknownErrorType',
stack: null,
};
} catch (e) {
return {
message: String(errorEventOrReason),
name: 'UnknownErrorTypeNonStringifiable',
stack: null,
};
}
}
/**
* Converts an array of arguments (from log/error) into a single string.
* Handles Error objects specially to include their message and stack.
* @param {Array<*>} args - Arguments passed to console methods.
* @return {string} A string representation of the arguments.
*/
function stringifyArgs(args) {
return args
.map((arg) => {
if (arg instanceof Error) {
const {message, stack} = arg;
return `Error: ${message}${stack ? ('\nStack: ' + stack) : ''}`;
}
if (typeof arg === 'object' && arg !== null) {
try {
return JSON.stringify(arg);
} catch (error) {
return '[Circular Object]';
}
} else {
return String(arg);
}
})
.join(' ');
}
console.log = function(...args) {
const logString = stringifyArgs(args);
window.parent.postMessage({ type: 'log', message: logString }, '*');
originalConsoleLog.apply(console, args);
};
console.error = function(...args) {
let errorData;
if (args.length > 0 && args[0] instanceof Error) {
const err = args[0];
// If the first arg is an Error, capture its details.
errorData = {
type: 'error',
source: 'CONSOLE_ERROR',
...getErrorObject(err),
rawArgsString: stringifyArgs(args.slice(1)),
timestamp: new Date().toISOString(),
};
} else {
// If not an Error object, treat all args as a general error message.
errorData = {
type: 'error',
source: 'CONSOLE_ERROR',
message: stringifyArgs(args),
name: 'ConsoleLoggedError',
stack: null,
timestamp: new Date().toISOString(),
};
}
window.parent.postMessage(errorData, '*');
originalConsoleError.apply(console, args);
};
// Listen for global unhandled synchronous errors.
window.addEventListener('error', function(event) {
const errorDetails = event.error ? getErrorObject(event.error) : {
message: event.message,
name: 'GlobalError',
stack: null,
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
};
window.parent.postMessage({
type: 'error',
source: 'global',
...errorDetails,
message: errorDetails.message || event.message,
timestamp: new Date().toISOString(),
}, '*');
});
// Listen for unhandled promise rejections (asynchronous errors).
window.addEventListener('unhandledrejection', function(event) {
const errorDetails = getErrorObject(event.reason);
window.parent.postMessage({
type: 'error',
source: 'unhandledrejection',
...errorDetails,
message: errorDetails.message || 'Unhandled Promise Rejection',
timestamp: new Date().toISOString(),
}, '*');
});
})();</script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Invitación Cumpleaños #40 de Juan Carlos</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&family=VT323&display=swap" rel="stylesheet">
<style>
/* Estilos personalizados para aplicar las fuentes y efectos */
body {
background-color: #1a1a2e;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E%3Cg fill-rule='evenodd'%3E%3Cg fill='%23e94560' fill-opacity='0.1'%3E%3Cpath d='M0 38.59l2.83-2.83 1.41 1.41L1.41 40H0v-1.41zM0 1.4l2.83 2.83 1.41-1.41L1.41 0H0v1.41zM38.59 40l-2.83-2.83 1.41-1.41L40 38.59V40h-1.41zM40 1.41l-2.83 2.83-1.41-1.41L38.59 0H40v1.41zM20 18.6l2.83-2.83 1.41 1.41L21.41 20l2.83 2.83-1.41 1.41L20 21.41l-2.83 2.83-1.41-1.41L18.59 20l-2.83-2.83 1.41-1.41L20 18.59z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
}
.font-press-start { font-family: 'Press Start 2P', cursive; }
.font-vt323 { font-family: 'VT323', monospace; }
.neon-glow-pink { text-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 20px #ff007f, 0 0 30px #ff007f, 0 0 40px #ff007f; }
.neon-glow-cyan { text-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 20px #00ffff, 0 0 30px #00ffff, 0 0 40px #00ffff; }
.card-border-animated {
border: 4px solid;
border-image: linear-gradient(45deg, #f0f, #0ff, #ff0, #f0f) 1;
animation: border-animation 4s linear infinite;
}
@keyframes border-animation {
0% { border-image: linear-gradient(45deg, #f0f, #0ff, #ff0, #f0f) 1; }
25% { border-image: linear-gradient(135deg, #f0f, #0ff, #ff0, #f0f) 1; }
50% { border-image: linear-gradient(225deg, #f0f, #0ff, #ff0, #f0f) 1; }
75% { border-image: linear-gradient(315deg, #f0f, #0ff, #ff0, #f0f) 1; }
100% { border-image: linear-gradient(405deg, #f0f, #0ff, #ff0, #f0f) 1; }
}
</style>
<style>*, ::before, ::after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/* ! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com */*,::after,::before{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}::after,::before{--tw-content:''}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;font-family:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.mb-6{margin-bottom:1.5rem}.mt-2{margin-top:0.5rem}.mt-4{margin-top:1rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.min-h-screen{min-height:100vh}.w-full{width:100%}.max-w-md{max-width:28rem}.transform{transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.space-x-4 > :not([hidden]) ~ :not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem * var(--tw-space-x-reverse));margin-left:calc(1rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-5 > :not([hidden]) ~ :not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.rounded-md{border-radius:0.375rem}.rounded-xl{border-radius:0.75rem}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.bg-purple-600{--tw-bg-opacity:1;background-color:rgb(147 51 234 / var(--tw-bg-opacity, 1))}.bg-yellow-400{--tw-bg-opacity:1;background-color:rgb(250 204 21 / var(--tw-bg-opacity, 1))}.bg-opacity-20{--tw-bg-opacity:0.2}.bg-opacity-80{--tw-bg-opacity:0.8}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-3{padding-top:0.75rem;padding-bottom:0.75rem}.pb-6{padding-bottom:1.5rem}.text-center{text-align:center}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:0.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:0.75rem;line-height:1rem}.text-cyan-300{--tw-text-opacity:1;color:rgb(103 232 249 / var(--tw-text-opacity, 1))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.text-pink-400{--tw-text-opacity:1;color:rgb(244 114 182 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-300{--tw-text-opacity:1;color:rgb(253 224 71 / var(--tw-text-opacity, 1))}.shadow-2xl{--tw-shadow:0 25px 50px -12px rgb(0 0 0 / 0.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms}.duration-300{transition-duration:300ms}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:bg-green-600:hover{--tw-bg-opacity:1;background-color:rgb(22 163 74 / var(--tw-bg-opacity, 1))}.hover\:bg-purple-700:hover{--tw-bg-opacity:1;background-color:rgb(126 34 206 / var(--tw-bg-opacity, 1))}.hover\:bg-yellow-300:hover{--tw-bg-opacity:1;background-color:rgb(253 224 71 / var(--tw-bg-opacity, 1))}@media (min-width: 768px){.md\:p-8{padding:2rem}.md\:px-8{padding-left:2rem;padding-right:2rem}.md\:text-2xl{font-size:1.5rem;line-height:2rem}}</style></head>
<body class="flex items-center justify-center min-h-screen p-4 flex-col">
<div class="bg-gray-900 bg-opacity-80 backdrop-blur-sm text-white rounded-xl max-w-md w-full card-border-animated shadow-2xl overflow-hidden mb-6">
<div class="p-6 md:p-8 text-center bg-black bg-opacity-20">
<h2 class="font-vt323 text-2xl text-yellow-300">¡Rebobina la cinta y prepárate!</h2>
<h1 class="font-press-start text-xl md:text-2xl mt-2 neon-glow-pink">CUMPLEAÑOS #40</h1>
<p class="font-vt323 text-3xl mt-2 text-cyan-300 neon-glow-cyan">de Juan Carlos</p>
</div>
<div class="p-6 md:p-8 space-y-5">
<div class="flex items-start space-x-4"><span class="font-press-start text-2xl text-pink-400">►</span><div><h3 class="font-vt323 text-2xl text-yellow-300">QUÉ:</h3><p class="font-vt323 text-xl">Un asado para celebrar al más puro estilo de los 90s.</p></div></div>
<div class="flex items-start space-x-4"><span class="font-press-start text-2xl text-pink-400">►</span><div><h3 class="font-vt323 text-2xl text-yellow-300">CUÁNDO:</h3><p class="font-vt323 text-xl">Sábado, 16 de Agosto</p><p class="font-vt323 text-xl">2:00 PM hasta las 8:00 PM</p></div></div>
<div class="flex items-start space-x-4"><span class="font-press-start text-2xl text-pink-400">►</span><div><h3 class="font-vt323 text-2xl text-yellow-300">PARA LA SED:</h3><p class="font-vt323 text-xl">Cada quien lleva el licor o bebida de su gusto para compartir (BYOB).</p></div></div>
</div>
<div class="px-6 md:px-8 pb-6 text-center">
<a href="https://wa.me/573504967140?text=¡Hola%20Juan%20Carlos!%20Aquí%20te%20comparto%20mis%20fotos%20de%20la%20fiesta.%20📸" target="_blank" class="block w-full bg-green-500 text-white font-press-start text-xs py-3 px-4 rounded-md hover:bg-green-600 transform hover:scale-105 transition-transform duration-300">
📸 Sube tus Fotos del Evento Aquí
</a>
<p class="font-vt323 text-base mt-2 text-gray-400">¡Haz clic para enviarme tus fotos por WhatsApp!</p>
</div>
<div class="p-6 md:p-8 text-center bg-black bg-opacity-20">
<a href="https://www.google.com/maps/search/?api=1&query=Finca+Villa+Melita" target="_blank" class="inline-block bg-yellow-400 text-gray-900 font-press-start text-sm py-3 px-6 rounded-md hover:bg-yellow-300 transform hover:scale-105 transition-transform duration-300 shadow-lg">
<span class="animate-pulse">📍 VER UBICACIÓN</span>
</a>
<p class="font-vt323 text-lg mt-4 text-gray-400">¡Confirma que la ubicación sea correcta!</p>
</div>
</div>
<button id="copyCodeBtn" class="bg-purple-600 text-white font-press-start text-sm py-3 px-6 rounded-md hover:bg-purple-700 transform hover:scale-105 transition-all duration-300">
Copiar Código HTML
</button>
<script>
const copyCodeBtn = document.getElementById('copyCodeBtn');
const copyFullCode = () => {
const originalButtonText = copyCodeBtn.textContent;
// Usamos el innerHTML del body para evitar copiar el script y el botón mismo.
const codeToCopy = document.documentElement.outerHTML;
const tempTextArea = document.createElement('textarea');
tempTextArea.value = codeToCopy;
document.body.appendChild(tempTextArea);
tempTextArea.select();
document.execCommand('copy');
document.body.removeChild(tempTextArea);
copyCodeBtn.textContent = '¡Copiado!';
setTimeout(() => {
copyCodeBtn.textContent = 'Copiar Código HTML';
}, 2000);
};
copyCodeBtn.addEventListener('click', copyFullCode);
</script>
</body></html><h1>👋 Hello World!</h1>