No al cierre de webs
ShareCode
Permalink: http://www.treeweb.es/u/974/ 01/02/2011

ShareCode

1 <!DOCTYPE html>2 <html lang="es">3 <head>4 <meta charset="UTF-8">5 <meta name="viewport" content="width=device-width, initial-scale=1.0">6 <title>Contador — +2 / −3</title>7 <link rel="preconnect" href="https://fonts.googleapis.com">8 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>9 <link href="https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Space+Grotesk:wght@400;500;600;700&display=swap" rel="stylesheet">10 <style>11  :root{12  --bg:#071311; --line:rgba(214,238,228,.12);13  --ink:#e9f5ef; --mut:#7fa49a;14  --grn:#35e88c; --red:#ff4b3a; --gold:#ffd54a;15  }16  *{margin:0;padding:0;box-sizing:border-box}17 18  body{19  font-family:'Space Grotesk',sans-serif; background:var(--bg); color:var(--ink);20  min-height:100vh; display:flex; flex-direction:column; overflow-x:hidden;21  }22 23  /* ── fondo vivo: rejilla + halos que respiran y siguen al ratón ───────── */24  .grid-bg{position:fixed; inset:0; z-index:-2; pointer-events:none;25  background-image:linear-gradient(var(--line) 1px,transparent 1px),26  linear-gradient(90deg,var(--line) 1px,transparent 1px);27  background-size:46px 46px;}28  .glow{position:fixed; z-index:-1; pointer-events:none; border-radius:50%; opacity:.28}29  .g-g{width:75vmin;height:75vmin;left:-18vmin;top:-20vmin;30  background:radial-gradient(circle,var(--grn),transparent 66%);animation:breathe 9s ease-in-out infinite alternate}31  .g-r{width:70vmin;height:70vmin;right:-15vmin;bottom:-22vmin;32  background:radial-gradient(circle,var(--red),transparent 66%);animation:breathe 11s ease-in-out infinite alternate-reverse}33  @keyframes breathe{from{transform:scale(1)}to{transform:scale(1.18)}}34 35  /* ── barra superior tipo marcador ─────────────────────────────────────── */36  .topbar{display:flex; justify-content:space-between; align-items:center; gap:16px;37  padding:12px 20px; border-bottom:1px solid var(--line); background:#0a1714f2}38  .brand{font-family:'Bebas Neue'; font-size:1.3rem; letter-spacing:.1em}39  .live{display:flex; align-items:center; gap:8px; font-size:.68rem; font-weight:700; letter-spacing:.22em; color:var(--mut)}40  .dot{width:9px;height:9px;border-radius:50%;animation:blink 1.4s ease-in-out infinite}41  .dot.g{background:var(--grn);box-shadow:0 0 10px var(--grn)}42  .dot.r{background:var(--red);box-shadow:0 0 10px var(--red);animation-delay:.7s}43  @keyframes blink{50%{opacity:.2}}44 45  /* ── zona principal ───────────────────────────────────────────────────── */46  .arena{width:min(980px,100% - 40px); margin:auto; display:grid;47  grid-template-columns:1.35fr .95fr; gap:26px; padding:26px 0}48 49  .board{background:#0b1a17; border:1px solid var(--line);50  box-shadow:8px 8px 0 rgba(0,0,0,.35)}51  .state-row{display:flex; align-items:center; gap:12px; padding:14px 18px; border-bottom:1px solid var(--line)}52  .chip{font-size:.62rem; font-weight:700; letter-spacing:.24em; color:#5f8a7d}53  #stateTag{font-family:'Bebas Neue'; font-size:1.35rem; letter-spacing:.08em; transition:color .3s, text-shadow .3s}54  #stateTag.pos{color:var(--grn);text-shadow:0 0 24px rgba(53,232,140,.5)}55  #stateTag.neg{color:var(--red);text-shadow:0 0 24px rgba(255,75,58,.5)}56  #stateTag.zero{color:var(--gold)}57 58  .num-wrap{min-height:236px; display:flex; align-items:center; justify-content:center}59  .value{font-family:'Bebas Neue'; font-size:clamp(108px,24vw,192px); line-height:.95; transition:color .3s}60  #num.pos{color:var(--grn)} #num.neg{color:var(--red)} #num.zero{color:var(--gold)}61  .value.pop{animation:pop .45s cubic-bezier(.2,.85,.3,1.35)}62  @keyframes pop{0%{transform:translateY(26px) scale(.9);opacity:.2}100%{transform:none;opacity:1}}63 64  .board-foot{display:flex; justify-content:center; gap:18px; padding:13px 18px;65  border-top:1px solid var(--line); color:#6f9a8d; font-size:.7rem}66  kbd{border:1px solid #4c7265; background:#0e2b1f; color:var(--ink); padding:2px 7px; margin-right:5px; border-radius:3px}67 68  /* ── panel lateral: registro + estadísticas ───────────────────────────── */69  .panel{background:#0a1814; border:1px solid var(--line)}70  .p-head{display:flex; justify-content:space-between; align-items:center; padding:13px 16px; border-bottom:1px solid var(--line)}71  .count-badge{font-size:.65rem; font-weight:700; letter-spacing:.2em; color:#08241b; background:var(--grn); padding:3px 9px}72  #histWrap{max-height:296px; overflow-y:auto; scroll-behavior:smooth}73  .empty{padding:26px 18px; text-align:center; font-size:.75rem; color:#5f8a7d}74  .log-item{display:flex; justify-content:space-between; align-items:center; gap:10px; padding:9px 14px;75  border-bottom:1px solid rgba(214,238,228,.06); animation:slideIn .35s cubic-bezier(.2,.7,.3,1.2)}76  @keyframes slideIn{from{transform:translateX(-26px);opacity:0}to{transform:none;opacity:1}}77  .tag{font-family:'Bebas Neue'; font-size:.95rem; letter-spacing:.05em}78  .log-item.add .tag{color:var(--grn)} .log-item.sub .tag{color:var(--red)}79  .res{color:#6f9a8d; font-size:.72rem}80 81  .stats{display:grid; grid-template-columns:repeat(3,1fr); border-top:1px solid var(--line)}82  .stat{padding:12px 8px; text-align:center}83  .stat + .stat{border-left:1px solid rgba(214,238,228,.06)}84  .s-n{font-family:'Bebas Neue'; font-size:1.7rem}85  .s-l{font-size:.58rem; font-weight:700; letter-spacing:.18em; color:#5f8a7d}86 87  /* ── botones grandes con sombra dura que se hunde al pulsar ───────────── */88  .btn-row{display:flex; justify-content:center; align-items:center; gap:26px; flex-wrap:wrap; padding-bottom:34px}89  .op-btn{position:relative; width:190px; padding:26px 0 20px; border:none; cursor:pointer; user-select:none;90  font-family:'Space Grotesk',sans-serif; transition:transform .18s cubic-bezier(.3,.7,.4,1.25), box-shadow .18s}91  .op-btn .big{display:block; font-family:'Bebas Neue'; font-size:2.9rem; letter-spacing:.04em}92  .op-btn .lbl{font-size:.62rem; font-weight:700; text-transform:uppercase; letter-spacing:.3em}93  .b-add{background:var(--grn); color:#052e1c; box-shadow:9px 9px 0 #0f4d2f}94  .b-sub{background:var(--red); color:#fff; box-shadow:9px 9px 0 #6b1a11}95  .op-btn:hover{transform:translate(-3px,-3px)}96  .b-add:hover{box-shadow:12px 12px 0 #0f4d2f} .b-sub:hover{box-shadow:12px 12px 0 #6b1a11}97  .op-btn:active{transform:translate(7px,7px); box-shadow:0 0 0 rgba(0,0,0,0)}98  .op-btn:focus-visible,.reset:focus-visible{outline:3px solid var(--gold); outline-offset:4px}99 100  /* ── partículas y ondas al pulsar ─────────────────────────────────────── */101  .pop-txt{position:absolute; left:50%; top:12%; transform:translateX(-50%); font-family:'Bebas Neue';102  font-size:1.7rem; pointer-events:none; animation:rise .8s ease-out forwards}103  @keyframes rise{to{transform:translate(-50%,-48px); opacity:0}}104  .wave{position:absolute; left:50%; top:50%; width:26px;height:26px; margin:-13px 0 0 -13px; border-radius:50%;105  pointer-events:none; animation:rip .45s ease-out forwards}106  @keyframes rip{to{transform:scale(7); opacity:0}}107 108  /* ── reset con confirmación en dos pasos ──────────────────────────────── */109  .reset{padding:13px 26px; border:2px solid #4c7265; background:#10281f; color:var(--ink); cursor:pointer;110  font-family:'Space Grotesk'; font-size:.7rem; font-weight:700; letter-spacing:.2em; text-transform:uppercase; transition:.2s}111  .reset:hover{border-color:#6fa491; transform:translateY(-2px)}112  .reset.armed{background:var(--red); border-color:var(--red); color:#fff; animation:armPulse 1.3s ease-in-out infinite}113  @keyframes armPulse{50%{box-shadow:0 0 0 9px rgba(255,75,58,.16)}}114 115  /* ── flash de cambio de signo y avisos ─────────────────────────────────── */116  #flash{position:fixed; inset:0; z-index:50; pointer-events:none; opacity:0}117  #flash.go{animation:fgo .5s ease-out}118  @keyframes fgo{from{opacity:.45}to{opacity:0}}119  .toast{position:fixed; left:50%; bottom:26px; transform:translate(-50%,18px); opacity:0; z-index:60; pointer-events:none;120  background:#0d2b20; border:1px solid #4c7265; padding:10px 20px; font-size:.7rem; letter-spacing:.1em}121  .toast.show{animation:tst 1.8s ease forwards}122  @keyframes tst{from{opacity:0;transform:translate(-50%,18px)}14%{opacity:1;transform:translate(-50%,0)}72%{opacity:1}to{opacity:0}}123 124  /* ── entrada escalonada ───────────────────────────────────────────────── */125  .topbar,.board,.panel,.btn-row{animation:enter .6s cubic-bezier(.2,.8,.3,1) both}126  .board{animation-delay:.1s}.panel{animation-delay:.2s}.btn-row{animation-delay:.32s}127  @keyframes enter{from{opacity:0;transform:translateY(24px)}to{opacity:1;transform:none}}128 129  /* ── responsive y accesibilidad ───────────────────────────────────────── */130  @media (max-width:760px){ .arena{grid-template-columns:1fr} }131  @media (prefers-reduced-motion:reduce){132  *{animation-duration:.001s!important; transition:none!important} #histWrap{scroll-behavior:auto}133  }134 </style>135 </head>136 <body>137 138 <div class="grid-bg"></div><i class="glow g-g" id="gg"></i><i class="glow g-r" id="gr"></i>139 140 <header class="topbar">141  <span class="brand">SUMA / RESTA — 01</span>142  <span class="live"><i class="dot g"></i>EN VIVO<i class="dot r"></i></span>143  <span id="clock" style="font-size:.68rem;color:var(--mut);letter-spacing:.15em">—</span>144 </header>145 146 <main class="arena">147  <!-- marcador -->148  <section class="board">149  <div class="state-row"><span class="chip">ESTADO DEL MARCADOR</span><b id="stateTag" class="zero">NEUTRO</b></div>150  <div class="num-wrap"><div id="num" class="value zero" aria-live="polite">0</div></div>151  <footer class="board-foot">152  <span><kbd>A</kbd>suma 2</span><span><kbd>Z</kbd>resta 3</span><span><kbd>Borrar</kbd>reinicia</span>153  </footer>154  </section>155 156  <!-- registro -->157  <aside class="panel">158  <div class="p-head"><b style="letter-spacing:.24em;font-size:.68rem;color:#7fa49a">REGISTRO</b><span id="countBadge" class="count-badge">0 MOV.</span></div>159  <div id="histWrap"><p id="emptyHint" class="empty">Aún no hay movimientos.<br>Pulsa un botón para empezar →</p><ol id="log"></ol></div>160  <div class="stats">161  <div class="stat"><div class="s-n" id="stAdd">0</div><div class="s-l">SUMAS +2</div></div>162  <div class="stat"><div class="s-n" id="stSub">0</div><div class="s-l">RESTAS −3</div></div>163  <div class="stat"><div class="s-n" id="stTot">0</div><div class="s-l">TOTAL MOV.</div></div>164  </div>165  </aside>166 </main>167 168 <div class="btn-row">169  <button id="bAdd" class="op-btn b-add"><span class="big">+2</span><span class="lbl">sumar dos</span></button>170  <button id="bReset" class="reset">reiniciar</button>171  <button id="bSub" class="op-btn b-sub"><span class="big">−3</span><span class="lbl">restar tres</span></button>172 </div>173 174 <div id="flash"></div>175 <div id="toast" class="toast" role="status"></div>176 177 <script>178 const $ = s => document.querySelector(s);179 let value=0, adds=0, subs=0, moves=0;180 let resetArmed=false, armTimer=null; const logEls=[];181 182 function stateOf(v){ return v>0?'pos':v<0?'neg':'zero'; }183 const stateTxt = {pos:'POSITIVO', neg:'NEGATIVO', zero:'NEUTRO'};184 185 function render(animate=true){186  const st=stateOf(value);187  $('#num').className='value '+st;188  $('#num').textContent=(value<0?'−':'')+Math.abs(value);189  if(animate){const n=$('#num');n.classList.remove('pop');void n.offsetWidth;n.classList.add('pop');}190  const tag=$('#stateTag'); tag.textContent=stateTxt[st]; tag.className=st;191  $('#clock').textContent=new Date().toLocaleTimeString('es-ES',{hour12:false});192  if(value===0 && moves>0) flash('#ffd54a','¡VUELVE A CERO!');193 }194 195 function flash(color,msg){196  const f=$('#flash');197  f.style.background=`radial-gradient(60% 60% at 50% 38%, ${color}, transparent 72%)`;198  if(msg){const t=$('#toast');t.textContent=msg;t.classList.remove('show');void t.offsetWidth;t.classList.add('show');}199  f.classList.remove('go');void f.offsetWidth;f.classList.add('go');200 }201 202 function change(delta,btn,label){203  const prev=value; value+=delta; moves++; delta>0?adds++:subs++;204  $('#stAdd').textContent=adds; $('#stSub').textContent=subs; $('#stTot').textContent=moves;205  $('#countBadge').textContent=moves+' MOV.';206 207  // partícula "+2"/"−3" que vuela desde el botón + onda de impacto208  const p=document.createElement('span'); p.className='pop-txt'; p.textContent=label;209  p.style.color=delta>0?'var(--grn)':'var(--red)'; btn.appendChild(p); setTimeout(()=>p.remove(),820);210  const w=document.createElement('i'); w.className='wave';211  w.style.border=`3px solid ${delta>0?'var(--grn)':'var(--red)'}`; btn.appendChild(w); setTimeout(()=>w.remove(),500);212 213  // tarjeta nueva en el registro (máx. 12, con scroll automático)214  $('#emptyHint').style.display='none';215  const li=document.createElement('li'); li.className='log-item '+(delta>0?'add':'sub');216  li.innerHTML=`<b class="tag">${label}</b><span class="res">→ ${value<0?'−':''}${Math.abs(value)}</span>`;217  $('#log').append(li); logEls.push(li);218  while(logEls.length>12) logEls.shift().remove();219  $('#histWrap').scrollTo({top:$('#histWrap').scrollHeight});220 221  if(stateOf(prev)!==stateOf(value)) flash(delta>0?'#35e88c':'#ff4b3a', value<0?'ENTRA EN NEGATIVO':value===0?'A CERO!':'VOLVEMOS A POSITIVOS');222  render();223 }224 225 // botones226 $('#bAdd').addEventListener('click',()=>change(2, $('#bAdd'),'+2'));227 $('#bSub').addEventListener('click',()=>change(-3,$('#bSub'),'−3'));228 229 // reset con confirmación (2º clic confirma; se desarma solo a los 4 s)230 $('#bReset').addEventListener('click',e=>{231  if(!resetArmed){232  resetArmed=true; e.currentTarget.classList.add('armed'); e.currentTarget.textContent='¿seguro?';233  clearTimeout(armTimer); armTimer=setTimeout(disarm,4000); return;234  }235  disarm(); value=adds=subs=moves=0; logEls.length=0; $('#log').innerHTML='';236  $('#emptyHint').style.display='block'; $('#stAdd').textContent=$('#stSub').textContent=$('#stTot').textContent='#countBadge'.replace('#','')&&'0';237  render(false); flash('#ffd54a','RESET COMPLETO');238 });239 function disarm(){resetArmed=false; clearTimeout(armTimer); const b=$('#bReset');b.classList.remove('armed');b.textContent='reiniciar';}240 241 // atajos de teclado: A suma, Z resta, Backspace pide reset (Enter confirma)242 window.addEventListener('keydown',e=>{243  if(e.repeat)return; const k=e.key.toLowerCase();244  if(k==='a') $('#bAdd').click(); else if(k==='z') $('#bSub').click();245  else if(e.key==='Backspace'){e.preventDefault();$('#bReset').click();}246 });247 248 // los halos de fondo siguen al ratón con un ligero parallax249 window.addEventListener('pointermove',e=>{250  const dx=(e.clientX/innerWidth-.5)*36, dy=(e.clientY/innerHeight-.5)*28;251  $('#gg').style.translate=`${dx}px ${dy}px`; $('#gr').style.translate=`${-dx}px ${-dy}px`;252 });253 254 render(false);255 </script>256 </body>257 </html>258 
Enlace
El enlace para compartir es: