{"id":14,"date":"2026-09-12T20:53:42","date_gmt":"2026-09-12T20:53:42","guid":{"rendered":"https:\/\/turnerdesign.com\/?page_id=14"},"modified":"2026-09-12T21:50:16","modified_gmt":"2026-09-12T21:50:16","slug":"turner-design","status":"publish","type":"page","link":"https:\/\/turnerdesign.com\/","title":{"rendered":"Turner Design"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Turner Design<\/title>\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=BioRhyme+Expanded:wght@200;300;400;700;800&#038;display=swap\" rel=\"stylesheet\">\n<style>\n  :root {\n    --headline-color: #ffffff;\n    --cursor-color: #000000;\n    --font-size: clamp(22px, 6vw, 43px);\n  }\n\n  * {\n    box-sizing: border-box;\n  }\n\n  html, body {\n    height: 100%;\n    margin: 0;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    background: #0e1a2b url(\"https:\/\/turnerdesign.com\/wp-content\/uploads\/2026\/09\/flying-landscape-1.jpg\") center center \/ cover no-repeat fixed;\n    font-family: \"BioRhyme Expanded\", serif;\n    overflow-x: hidden;\n  }\n\n  .headline {\n    display: block;\n    font-size: var(--font-size);\n    font-weight: 400;\n    line-height: 1.2;\n    color: var(--headline-color);\n    text-align: center;\n    margin: 0;\n    padding: 0 20px;\n    max-width: 100%;\n  }\n\n  @media (max-width: 480px) {\n    html, body {\n      background-attachment: scroll;\n    }\n  }\n\n  .headline-outer {\n    position: relative;\n    display: inline-block;\n    vertical-align: bottom;\n  }\n\n  \/* The reveal wrapper is clipped \u2014 its width is animated by JS\n     from 0 up to the full text width (typing) and back to 0 (deleting).\n     Because the text itself is never added\/removed character by character,\n     letters can appear *partially* uncovered mid-sweep, matching the\n     smooth wipe seen in the real site. *\/\n  .reveal-wrapper {\n    display: inline-block;\n    overflow: hidden;\n    white-space: nowrap;\n    vertical-align: bottom;\n    width: 0;\n  }\n\n  .reveal-text {\n    display: inline-block;\n    white-space: nowrap;\n  }\n\n  \/* cursor rides the edge of the reveal wrapper, positioned via JS\n     to stay in sync every animation frame *\/\n  .cursor {\n    display: none;\n  }\n<\/style>\n<\/head>\n<body>\n\n<h1 class=\"headline\">\n  <span class=\"headline-outer\">\n    <span class=\"reveal-wrapper\" id=\"revealWrapper\"><span class=\"reveal-text\" id=\"revealText\"><\/span><\/span><span class=\"cursor\" id=\"cursor\"><\/span>\n  <\/span>\n<\/h1>\n\n<script>\n\/*\n  Recreates Elementor's Animated Headline \u2014 Rotating style, \"Typing\" animation\n  as a CLIP\/WIPE reveal, not a character-by-character typewriter.\n\n  Mechanism:\n  - The full phrase is rendered at all times inside #revealText (never\n    partially built up as a string).\n  - #revealWrapper clips it with overflow:hidden and an animated width.\n  - A requestAnimationFrame loop drives that width from 0 -> full text width\n    (typing) and full width -> 0 (deleting), so the sweep is continuous and\n    can reveal\/hide the middle of a letter mid-frame \u2014 matching the smooth\n    wipe seen in the real animation, not discrete per-character jumps.\n  - The cursor bar's `left` position is updated every frame to match the\n    wrapper's current width, so it always sits right at the reveal edge.\n*\/\n\nconst PHRASES = [\n  \"[ REBUILDING ]\",\n  \"> BACK SOON <\",\n  \"have a great day\"\n];\n\nconst MS_PER_CHAR_TYPE = 50;    \/\/ matches measured ~50ms\/char typing speed\nconst MS_PER_CHAR_DELETE = 55;  \/\/ matches measured ~55ms\/char deleting speed\nconst MIN_DURATION = 300;       \/\/ floor so short phrases don't snap instantly\nconst PAUSE_AFTER_TYPE = 2500;  \/\/ hold on full phrase\nconst PAUSE_AFTER_DELETE = 400; \/\/ pause on empty before next phrase\nconst INFINITE_LOOP = true;\n\nconst wrapperEl = document.getElementById('revealWrapper');\nconst textEl = document.getElementById('revealText');\nconst cursorEl = document.getElementById('cursor');\n\nlet phraseIndex = 0;\n\nfunction animateWidth(fromWidth, toWidth, duration) {\n  return new Promise(resolve => {\n    const start = performance.now();\n    function step(now) {\n      const t = Math.min((now - start) \/ duration, 1);\n      const eased = t; \/\/ linear sweep, matches the observed constant-speed wipe\n      const val = fromWidth + (toWidth - fromWidth) * eased;\n      wrapperEl.style.width = val + 'px';\n      cursorEl.style.left = val + 'px';\n      if (t < 1) {\n        requestAnimationFrame(step);\n      } else {\n        resolve();\n      }\n    }\n    requestAnimationFrame(step);\n  });\n}\n\nfunction wait(ms) {\n  return new Promise(resolve => setTimeout(resolve, ms));\n}\n\nasync function runCycle() {\n  while (true) {\n    const phrase = PHRASES[phraseIndex];\n    textEl.textContent = phrase;\n\n    \/\/ measure the phrase's natural rendered width\n    const fullWidth = textEl.offsetWidth;\n\n    \/\/ type in: sweep open from 0 to fullWidth\n    const typeDuration = Math.max(MIN_DURATION, phrase.length * MS_PER_CHAR_TYPE);\n    await animateWidth(0, fullWidth, typeDuration);\n\n    \/\/ hold on the complete phrase\n    await wait(PAUSE_AFTER_TYPE);\n\n    \/\/ delete: sweep closed from fullWidth back to 0\n    const deleteDuration = Math.max(MIN_DURATION, phrase.length * MS_PER_CHAR_DELETE);\n    await animateWidth(fullWidth, 0, deleteDuration);\n\n    await wait(PAUSE_AFTER_DELETE);\n\n    phraseIndex++;\n    if (phraseIndex >= PHRASES.length) {\n      if (!INFINITE_LOOP) return;\n      phraseIndex = 0;\n    }\n  }\n}\n\ndocument.fonts.ready.then(runCycle);\n<\/script>\n\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>Turner Design<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-14","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/turnerdesign.com\/index.php?rest_route=\/wp\/v2\/pages\/14","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/turnerdesign.com\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/turnerdesign.com\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/turnerdesign.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/turnerdesign.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=14"}],"version-history":[{"count":4,"href":"https:\/\/turnerdesign.com\/index.php?rest_route=\/wp\/v2\/pages\/14\/revisions"}],"predecessor-version":[{"id":21,"href":"https:\/\/turnerdesign.com\/index.php?rest_route=\/wp\/v2\/pages\/14\/revisions\/21"}],"wp:attachment":[{"href":"https:\/\/turnerdesign.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=14"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}