ManyRoots WordPlay Studio

ManyRoots WordPlay Studio by TurknoyTravels100.world { “@context”:”https://schema.org”, “@type”:”WebApplication”, “name”:”ManyRoots WordPlay Studio”, “applicationCategory”:”LifestyleApplication”, “operatingSystem”:”Any”, “url”:”https://turknoytravels100.world/manyroots/”, “image”:”https://turknoytravels100.world/wp-content/uploads/2026/05/og-image.png”, “description”:”A free family language and wordplay studio for multicultural, multilingual, migrant, expat, and long-distance families. Create a family fusion word, a family language type, a motto, a caption, and a shareable card.”, “isAccessibleForFree”:true, “offers”:{“@type”:”Offer”,”price”:”0″,”priceCurrency”:”USD”}, “publisher”:{“@type”:”Organization”,”name”:”TurknoyTravels100.world”,”url”:”https://TurknoyTravels100.world”} } { “@context”:”https://schema.org”, “@type”:”FAQPage”, “mainEntity”:[ {“@type”:”Question”,”name”:”Is ManyRoots WordPlay Studio free?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Yes. It is completely free, with no login required, by TurknoyTravels100.world.”}}, {“@type”:”Question”,”name”:”Are the family words official cultural labels?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”No. The words are playful, editable, and personal. They are not definitive cultural labels. You can edit, regenerate, or reject any word.”}}, {“@type”:”Question”,”name”:”Where are my Word Wall entries stored?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Entries are saved only on your own device in your browser. They are not posted publicly.”}} ] } https://cdnjs.cloudflare.com/ajax/libs/html-to-image/1.11.11/html-to-image.min.js :root{ –paper:#FBF5E9; –paper-deep:#F4E9D4; –ink:#211E18; –ink-soft:#4A4439; –navy:#15263F; –terracotta:#C0512F; –terracotta-deep:#9C3C1C; –gold:#C8881F; –gold-bright:#E0A52E; –teal:#2A6F66; –teal-deep:#1C544C; –coral:#E8826B; –line:rgba(33,30,24,.16); –line-soft:rgba(33,30,24,.08); –shadow:0 18px 48px -22px rgba(33,30,24,.5); –radius:22px; –maxw:1180px; } *{box-sizing:border-box;margin:0;padding:0} html{scroll-behavior:smooth;-webkit-text-size-adjust:100%} body{ font-family:”Plus Jakarta Sans”,system-ui,-apple-system,Segoe UI,sans-serif; background:var(–paper);color:var(–ink);line-height:1.6;overflow-x:hidden; background-image: radial-gradient(circle at 8% 4%, rgba(200,136,31,.16), transparent 34%), radial-gradient(circle at 94% 10%, rgba(42,111,102,.15), transparent 38%), radial-gradient(circle at 50% 128%, rgba(192,81,47,.13), transparent 52%), url(“data:image/svg+xml,%3Csvg xmlns=’http://www.w3.org/2000/svg’ width=’140′ height=’140’%3E%3Cfilter id=’n’%3E%3CfeTurbulence type=’fractalNoise’ baseFrequency=’0.9′ numOctaves=’2’/%3E%3CfeColorMatrix type=’saturate’ values=’0’/%3E%3C/filter%3E%3Crect width=’100%25′ height=’100%25′ filter=’url(%23n)’ opacity=’0.035’/%3E%3C/svg%3E”); } .font-display{font-family:”Fraunces”,Georgia,”Times New Roman”,serif} .mono{font-family:”Space Mono”,ui-monospace,monospace;letter-spacing:.06em} .hand{font-family:”Caveat”,”Segoe Script”,cursive} .wrap{max-width:var(–maxw);margin:0 auto;padding:0 22px} section{position:relative} .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0} a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, [tabindex]:focus-visible{ outline:3px solid var(–teal);outline-offset:2px;border-radius:8px; } /* ———- reduced motion + user pause ———- */ @media (prefers-reduced-motion: reduce){ *{animation-duration:.001ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important;scroll-behavior:auto !important} .reveal{opacity:1 !important;transform:none !important} .drift,.routes-anim path,.tw-cursor,.pulse-dot{animation:none !important} } body.motion-paused .drift, body.motion-paused .routes-anim path, body.motion-paused .tw-cursor, body.motion-paused .pulse-dot, body.motion-paused .wom-rot{animation-play-state:paused !important} /* ———- decorative ———- */ .dotline{height:2px;width:100%;background-image:radial-gradient(circle,var(–line) 1.6px,transparent 1.6px);background-size:14px 2px;background-repeat:repeat-x;opacity:.7} .kicker{font-family:”Space Mono”,monospace;font-size:.72rem;letter-spacing:.22em;text-transform:uppercase;color:var(–teal-deep);font-weight:700} .stamp{display:inline-flex;align-items:center;gap:.5em;font-family:”Space Mono”,monospace;font-size:.66rem;letter-spacing:.16em;text-transform:uppercase;font-weight:700;border:2px solid var(–terracotta);color:var(–terracotta-deep);padding:.42em .8em;border-radius:999px;transform:rotate(-3deg);background:rgba(232,130,107,.08)} /* torn-paper section divider */ .tear{height:34px;width:100%;display:block;line-height:0} .tear svg{width:100%;height:100%;display:block} /* ———- dev banner ———- */ .devbanner{display:none;background:#7a1f0f;color:#ffe9d6;text-align:center;font-family:”Space Mono”,monospace;font-size:.8rem;letter-spacing:.04em;padding:10px 14px} .devbanner.show{display:block} /* ———- top bar ———- */ .topbar{position:sticky;top:0;z-index:80;backdrop-filter:saturate(1.2) blur(8px);background:rgba(251,245,233,.86);border-bottom:1px solid var(–line-soft)} .topbar .wrap{display:flex;align-items:center;justify-content:space-between;height:64px;gap:12px} .brandmark{display:flex;align-items:center;gap:10px;text-decoration:none;color:var(–ink)} .brandmark .globe{width:34px;height:34px;border-radius:50%;flex:0 0 auto;background:radial-gradient(circle at 32% 30%,var(–gold-bright),var(–terracotta) 70%);position:relative;box-shadow:inset 0 0 0 2px rgba(255,255,255,.35),var(–shadow)} .brandmark .globe:before{content:””;position:absolute;inset:6px;border-radius:50%;border:1.5px solid rgba(255,255,255,.6);border-right-color:transparent;border-bottom-color:transparent;transform:rotate(30deg)} .brandmark .bw{font-family:”Fraunces”;font-weight:600;font-size:1.04rem;line-height:1.05} .brandmark .bw b{font-weight:600} .brandmark .bw span{display:block;font-size:.6rem;letter-spacing:.1em;text-transform:uppercase;color:var(–teal-deep);font-weight:700;margin-top:2px} .nav{display:flex;align-items:center;gap:18px} .nav a{color:var(–ink);text-decoration:none;font-weight:600;font-size:.92rem;opacity:.8} .nav a:hover{opacity:1;color:var(–terracotta-deep)} .nav .powered{font-family:”Space Mono”,monospace;font-size:.64rem;letter-spacing:.06em;color:var(–teal-deep)} @media(max-width:860px){.nav a:not(.powered){display:none}} @media(max-width:520px){.nav .powered{display:none}} /* ———- buttons ———- */ .btn{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:.5em;font-family:”Plus Jakarta Sans”;font-weight:700;font-size:.96rem;padding:.85em 1.4em;border-radius:999px;border:none;cursor:pointer;text-decoration:none;transition:transform .15s ease,box-shadow .2s ease,background .2s ease,filter .2s;color:#fff} .btn:hover{transform:translateY(-2px)} .btn:active{transform:translateY(1px) scale(.99)} .btn-primary{background:var(–terracotta);box-shadow:0 12px 26px -12px rgba(192,81,47,.8)} .btn-primary:hover{background:var(–terracotta-deep);box-shadow:0 18px 34px -12px rgba(192,81,47,.9)} .btn-ghost{background:transparent;color:var(–navy);border:2px solid var(–navy)} .btn-ghost:hover{background:var(–navy);color:var(–paper)} .btn-soft{background:var(–paper-deep);color:var(–ink);border:1px solid var(–line)} .btn-soft:hover{background:#fff} .btn-teal{background:var(–teal)} .btn-teal:hover{background:var(–teal-deep)} .btn-gold{background:var(–gold);color:#1f1402} .btn-gold:hover{background:var(–gold-bright)} .btn-sm{padding:.6em 1em;font-size:.85rem} .btn[disabled]{opacity:.45;cursor:not-allowed;transform:none} .btn .ck{display:none} .btn.copied{background:var(–teal)} .btn.copied .ck{display:inline} .btn.copied .lb{display:none} /* ============================ HERO ============================ */ .hero{padding:40px 0 50px;position:relative;overflow:hidden} .hero-grid{display:grid;grid-template-columns:1.04fr .96fr;gap:40px;align-items:center} @media(max-width:920px){.hero-grid{grid-template-columns:1fr;gap:22px}} .hero h1{font-family:”Fraunces”;font-weight:600;line-height:1.03;font-size:clamp(2.1rem,4.7vw,3.6rem);letter-spacing:-.014em;color:var(–navy);max-width:18ch} .hero h1 em{font-style:italic;color:var(–terracotta-deep)} .hero .sub{margin-top:16px;font-size:clamp(1.02rem,1.5vw,1.18rem);color:var(–ink-soft);max-width:52ch} .hero .origin{margin-top:12px;font-family:”Space Mono”,monospace;font-size:.74rem;letter-spacing:.04em;color:var(–teal-deep)} .hero .origin b{color:var(–terracotta-deep)} /* morphing typewriter line */ .morph{margin-top:14px;font-family:”Space Mono”,monospace;font-size:.92rem;color:var(–ink-soft);display:flex;align-items:center;gap:.5ch;flex-wrap:wrap} .morph .mlbl{color:var(–teal-deep);font-weight:700} .morph .mword{font-family:”Fraunces”;font-weight:600;font-style:italic;font-size:1.5rem;color:var(–terracotta-deep);min-width:6ch} .tw-cursor{display:inline-block;width:2px;height:1.1em;background:var(–terracotta);margin-left:1px;animation:blink 1s steps(1) infinite;vertical-align:-2px} @keyframes blink{50%{opacity:0}} /* live examples strip */ .exstrip{margin-top:14px;display:flex;flex-wrap:wrap;gap:8px} .exstrip .ex2{font-family:”Space Mono”,monospace;font-size:.72rem;letter-spacing:.02em;background:#fff;border:1px solid var(–line);border-radius:999px;padding:.4em .8em;color:var(–ink-soft)} .exstrip .ex2 b{color:var(–terracotta-deep)} /* WORD FORGE mini generator */ .forge{margin-top:22px;background:linear-gradient(160deg,#ffffff,#fffaf0);border:1px solid var(–line);border-radius:20px;padding:18px;box-shadow:var(–shadow);position:relative;overflow:hidden} .forge:before{content:””;position:absolute;inset:0;background:radial-gradient(circle at 92% 0%,rgba(200,136,31,.12),transparent 40%);pointer-events:none} .forge .flabel{font-weight:700;font-size:.82rem;color:var(–navy);margin-bottom:12px;display:flex;align-items:center;gap:.5em} .forge .flabel .fkick{font-family:”Space Mono”,monospace;font-size:.6rem;letter-spacing:.16em;text-transform:uppercase;color:var(–teal-deep);background:rgba(42,111,102,.1);padding:.25em .6em;border-radius:999px} .forge-row{display:grid;grid-template-columns:1fr auto 1fr;gap:10px;align-items:stretch} @media(max-width:520px){.forge-row{grid-template-columns:1fr}} .rootcard{background:var(–paper);border:1.5px solid var(–line);border-radius:14px;padding:10px 12px;transition:border .15s,box-shadow .15s,transform .15s} .rootcard:focus-within{border-color:var(–terracotta);box-shadow:0 0 0 4px rgba(192,81,47,.14)} .rootcard .rc-k{font-family:”Space Mono”,monospace;font-size:.56rem;letter-spacing:.14em;text-transform:uppercase;color:var(–teal-deep);font-weight:700} .rootcard input{width:100%;border:none;background:transparent;font-family:”Fraunces”;font-weight:600;font-size:1.2rem;color:var(–navy);padding:2px 0;margin-top:2px} .rootcard input:focus{outline:none} .rootcard input::placeholder{color:rgba(33,30,24,.32)} .connector{display:flex;align-items:center;justify-content:center;width:42px;color:var(–terracotta);font-size:1.4rem;font-weight:800;position:relative} @media(max-width:520px){.connector{width:auto;height:26px;transform:rotate(90deg)}} .connector .thread{position:absolute;inset:0;display:flex;align-items:center;justify-content:center} .connector .thread svg{width:42px;height:24px;overflow:visible} .connector .knot{position:relative;z-index:2;width:30px;height:30px;border-radius:50%;background:#fff;border:2px solid var(–terracotta);display:flex;align-items:center;justify-content:center;box-shadow:0 6px 14px -6px rgba(192,81,47,.7)} .forge-preview{margin-top:13px;display:flex;align-items:center;gap:10px;flex-wrap:wrap;min-height:30px} .forge-preview .fp-eq{font-family:”Space Mono”,monospace;font-size:.74rem;color:var(–ink-soft)} .forge-preview .fp-word{font-family:”Fraunces”;font-weight:600;font-size:1.4rem;color:var(–terracotta-deep);transition:opacity .2s} .forge-preview .fp-word.flip{opacity:0} .forge-actions{margin-top:13px;display:flex;gap:10px;flex-wrap:wrap} .forge-actions .btn{flex:1;min-width:160px} .forge-chips{display:flex;flex-wrap:wrap;gap:7px;margin-top:13px;align-items:center} .forge-chips .lbl{font-size:.74rem;color:var(–ink-soft);font-weight:600;margin-right:2px} .ex{cursor:pointer;font-size:.78rem;font-weight:600;padding:.34em .7em;border-radius:999px;border:1.5px solid var(–line);background:var(–paper);color:var(–ink-soft);transition:all .14s;font-family:inherit} .ex:hover{border-color:var(–teal);color:var(–teal-deep)} .ex.sel{border-color:var(–terracotta);color:var(–terracotta-deep);background:rgba(232,130,107,.12);animation:chipPulse .4s ease} @keyframes chipPulse{0%{transform:scale(1)}45%{transform:scale(1.08)}100%{transform:scale(1)}} .forge-note{margin-top:12px;font-size:.74rem;color:var(–ink-soft)} .cta-cluster{display:flex;gap:12px;flex-wrap:wrap;margin-top:18px} .powered-pill{display:inline-flex;align-items:center;gap:.5em;margin-top:16px;font-family:”Space Mono”,monospace;font-size:.68rem;letter-spacing:.08em;text-transform:uppercase;color:var(–teal-deep)} .powered-pill a{color:var(–terracotta-deep);font-weight:700;text-decoration:none} .motion-toggle{margin-top:14px;background:none;border:1px solid var(–line);border-radius:999px;padding:.35em .8em;font-family:”Space Mono”,monospace;font-size:.64rem;letter-spacing:.08em;text-transform:uppercase;color:var(–ink-soft);cursor:pointer} .motion-toggle:hover{border-color:var(–teal);color:var(–teal-deep)} /* —- editorial collage —- */ .collage{position:relative;width:100%;aspect-ratio:1/1;max-width:520px;margin:0 auto;filter:drop-shadow(0 30px 50px rgba(33,30,24,.22))} @media(max-width:920px){.collage{max-width:420px}} .collage .map-bg{position:absolute;inset:0;border-radius:24px;background:linear-gradient(150deg,#1b2f4d,#16263F 60%,#0f1d31);overflow:hidden} .collage .map-bg:before{content:””;position:absolute;inset:0;opacity:.5;background-image:radial-gradient(circle,rgba(255,255,255,.35) 1px,transparent 1px);background-size:22px 22px} .collage svg.routes{position:absolute;inset:0;width:100%;height:100%} .routes-anim path{stroke-dasharray:3 4;animation:dash 7s linear infinite} .routes-anim .p2{animation-duration:9s} .routes-anim .p3{animation-duration:11s} @keyframes dash{to{stroke-dashoffset:-140}} .collage.firepulse .routes-anim path{animation:dashPulse 1.1s ease} @keyframes dashPulse{0%{stroke:var(–gold-bright);stroke-width:1.1}100%{stroke-width:.5}} .pulse-dot{animation:pdot 3.4s ease-in-out infinite} @keyframes pdot{0%,100%{r:1.4}50%{r:2.2}} .ccard{position:absolute;border-radius:14px;box-shadow:0 14px 30px -14px rgba(0,0,0,.55);overflow:hidden} .drift{animation:drift 9s ease-in-out infinite} .drift.d-b{animation-duration:11s;animation-delay:-3s} .drift.d-c{animation-duration:10s;animation-delay:-1.5s} .drift.d-d{animation-duration:12s;animation-delay:-4s} @keyframes drift{0%,100%{transform:translateY(0) rotate(var(–rot,0deg))}50%{transform:translateY(-9px) rotate(var(–rot,0deg))}} .c-passport{–rot:-7deg;width:42%;top:6%;left:5%;background:linear-gradient(160deg,#7a2f17,#9C3C1C);color:#f7e7c8;transform:rotate(-7deg);padding:12px 12px 14px} .c-passport .pp-top{font-family:”Space Mono”,monospace;font-size:.52rem;letter-spacing:.18em;opacity:.85;display:flex;justify-content:space-between} .c-passport .pp-seal{width:38px;height:38px;border-radius:50%;border:2px solid var(–gold-bright);color:var(–gold-bright);font-size:.46rem;display:flex;align-items:center;justify-content:center;text-align:center;font-family:”Space Mono”,monospace;margin:8px auto 6px;transform:rotate(-12deg);letter-spacing:.06em} .c-passport .pp-name{font-family:”Fraunces”;font-weight:600;font-size:.92rem;text-align:center} .c-passport .pp-line{height:1px;background:rgba(247,231,200,.4);margin:7px 0} .c-passport .pp-foot{font-family:”Space Mono”,monospace;font-size:.5rem;letter-spacing:.1em;opacity:.8} .c-call{–rot:4deg;width:40%;bottom:6%;left:3%;background:#0c1626;color:#e9eef6;transform:rotate(4deg);padding:10px} .c-call .vc-bar{display:flex;align-items:center;gap:5px;font-family:”Space Mono”,monospace;font-size:.5rem;letter-spacing:.1em;color:#9fd6cd} .c-call .dot{width:6px;height:6px;border-radius:50%;background:#48d39a;box-shadow:0 0 0 3px rgba(72,211,154,.25)} .c-call .vc-faces{display:flex;gap:6px;margin:8px 0 6px} .c-call .face{flex:1;aspect-ratio:1/1;border-radius:9px;background:linear-gradient(135deg,#2a6f66,#1c544c);display:flex;align-items:center;justify-content:center;font-size:1rem} .c-call .face.b{background:linear-gradient(135deg,#c0512f,#9C3C1C)} .c-call .vc-time{font-family:”Space Mono”,monospace;font-size:.5rem;color:#cdd7e6;letter-spacing:.04em;text-align:center} .c-note{–rot:5deg;width:46%;top:7%;right:4%;background:repeating-linear-gradient(#fffdf6,#fffdf6 17px,#cfe3ea 18px);transform:rotate(5deg);padding:12px 12px 14px 22px;color:#2a3340} .c-note:before{content:””;position:absolute;left:12px;top:0;bottom:0;width:1.5px;background:#e2897f} .c-note .nb-h{font-family:”Space Mono”,monospace;font-size:.5rem;letter-spacing:.14em;color:#7d8a95;text-transform:uppercase} .c-note .nb-words{font-family:”Caveat”,cursive;font-weight:600;line-height:1.5;font-size:1.02rem;color:#1d3a4d;margin-top:4px} .c-note .nb-words b{color:#9C3C1C;font-weight:700} .c-food{–rot:-5deg;width:30%;bottom:5%;right:6%;background:linear-gradient(150deg,#e7b34a,#C8881F);color:#3a2400;transform:rotate(-5deg);padding:10px;text-align:center} .c-food .fd-ic{font-size:1.5rem;line-height:1} .c-food .fd-t{font-family:”Space Mono”,monospace;font-size:.5rem;letter-spacing:.1em;margin-top:4px;text-transform:uppercase} /* central rotating word of the moment */ .c-word{width:52%;top:43%;left:50%;transform:translate(-50%,-50%) rotate(-2deg);background:linear-gradient(160deg,#fff,#fbeede);border:2px solid var(–gold);padding:14px 10px;text-align:center;box-shadow:0 18px 38px -12px rgba(0,0,0,.6)} .c-word .cw-k{font-family:”Space Mono”,monospace;font-size:.5rem;letter-spacing:.16em;color:var(–teal-deep);text-transform:uppercase} .c-word .cw-word{font-family:”Fraunces”;font-weight:600;font-size:clamp(1.5rem,5vw,2.1rem);color:var(–navy);line-height:1;transition:opacity .35s} .c-word .cw-word.wom-rot{} .c-word .cw-word.flip{opacity:0} .c-word .cw-sub{font-size:.56rem;color:var(–terracotta-deep);font-weight:700;margin-top:2px;transition:opacity .35s} .c-word .cw-sub.flip{opacity:0} .scrap{position:absolute;font-family:”Caveat”,cursive;font-weight:700;color:#fff;text-shadow:0 2px 6px rgba(0,0,0,.4);font-size:1.1rem} .scrap.s1{top:38%;left:8%;transform:rotate(-12deg);color:#ffd9a0} .scrap.s2{bottom:30%;right:2%;transform:rotate(10deg);color:#a9e7dd} /* staggered reveal */ .reveal{opacity:0;transform:translateY(14px);animation:rise .7s cubic-bezier(.2,.7,.2,1) forwards} @keyframes rise{to{opacity:1;transform:none}} .d1{animation-delay:.04s}.d2{animation-delay:.14s}.d3{animation-delay:.24s}.d4{animation-delay:.34s}.d5{animation-delay:.46s} /* ———- generic sections ———- */ .sec{padding:58px 0} .sec-head{max-width:64ch} .sec-head h2{font-family:”Fraunces”;font-weight:600;font-size:clamp(1.9rem,4vw,2.8rem);color:var(–navy);line-height:1.08;letter-spacing:-.01em;margin-top:10px} .sec-head p{margin-top:12px;color:var(–ink-soft);font-size:1.05rem;max-width:58ch} /* ===== instant result stage ===== */ .studio{background:var(–paper-deep);border-top:1px solid var(–line-soft);border-bottom:1px solid var(–line-soft)} .disclaimer{display:flex;gap:10px;align-items:flex-start;background:#fff;border:1px solid var(–line);border-left:4px solid var(–gold);border-radius:12px;padding:12px 14px;margin-top:18px;font-size:.9rem;color:var(–ink-soft)} .result-wrap{margin-top:8px} .result{background:#fff;border:1px solid var(–line);border-radius:var(–radius);overflow:hidden;box-shadow:var(–shadow)} .result-top{background:linear-gradient(135deg,var(–navy),#0e1b30);color:var(–paper);padding:30px 28px 28px;text-align:center;position:relative;overflow:hidden} .result-top:before{content:””;position:absolute;inset:0;opacity:.16;background-image:radial-gradient(circle,rgba(255,255,255,.6) 1px,transparent 1px);background-size:16px 16px} .belongs{position:relative;font-family:”Space Mono”,monospace;font-size:.7rem;letter-spacing:.18em;text-transform:uppercase;color:var(–gold-bright)} /* passport stamp reveal */ .stampfound{position:relative;display:inline-flex;align-items:center;gap:.5em;margin:2px auto 6px;font-family:”Space Mono”,monospace;font-size:.62rem;letter-spacing:.18em;text-transform:uppercase;font-weight:700;color:#ffd9a0;border:2px solid rgba(224,165,46,.7);border-radius:8px;padding:.3em .7em;transform:rotate(-4deg);opacity:0} .stampfound.go{animation:stampIn .5s cubic-bezier(.2,.9,.3,1.4) forwards} @keyframes stampIn{0%{opacity:0;transform:rotate(-4deg) scale(2.4)}60%{opacity:1}100%{opacity:1;transform:rotate(-4deg) scale(1)}} .word-edit{position:relative;display:flex;flex-direction:column;align-items:center;gap:4px;margin-top:6px} .word-edit input{font-family:”Fraunces”;font-weight:600;font-size:clamp(2.4rem,8vw,4.2rem);line-height:1;letter-spacing:-.01em;color:#fff;background:transparent;border:none;text-align:center;width:100%;max-width:12ch;padding:2px 6px;border-bottom:2px dashed transparent;transition:border-color .15s} .word-edit input:hover{border-bottom-color:rgba(255,255,255,.3)} .word-edit input:focus{outline:none;border-bottom-color:var(–gold-bright)} .word-edit .edit-hint{font-family:”Space Mono”,monospace;font-size:.56rem;letter-spacing:.1em;text-transform:uppercase;color:rgba(255,255,255,.6)} .shuffling input{color:var(–coral)} .lovetype{position:relative;display:inline-flex;align-items:center;gap:.5em;margin-top:12px;background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.25);padding:.5em 1em;border-radius:999px;font-weight:700;font-size:.96rem} .lovetype .ltlabel{font-family:”Space Mono”,monospace;font-size:.56rem;letter-spacing:.12em;text-transform:uppercase;color:var(–gold-bright);margin-right:.2em} .tip{position:relative;display:inline-flex;border:none;background:none;cursor:help;padding:0} .tip .tipdot{width:17px;height:17px;border-radius:50%;background:rgba(255,255,255,.28);color:#fff;font-size:.7rem;display:inline-flex;align-items:center;justify-content:center;font-weight:700} .tip .tiptext{visibility:hidden;opacity:0;position:absolute;bottom:140%;left:50%;transform:translateX(-50%);width:230px;background:var(–ink);color:var(–paper);padding:10px 12px;border-radius:10px;font-size:.8rem;font-weight:500;line-height:1.4;letter-spacing:0;text-transform:none;transition:opacity .18s;z-index:30;box-shadow:var(–shadow)} .tip:hover .tiptext,.tip:focus .tiptext,.tip:focus-visible .tiptext{visibility:visible;opacity:1} /* feedback row */ .fbrow{position:relative;background:rgba(255,255,255,.08);border-top:1px solid rgba(255,255,255,.16);padding:14px 18px;text-align:center} .fbrow .fbk{font-family:”Space Mono”,monospace;font-size:.58rem;letter-spacing:.14em;text-transform:uppercase;color:rgba(255,255,255,.7);margin-bottom:8px} .fbrow .fbtns{display:flex;flex-wrap:wrap;gap:8px;justify-content:center} .fbtn{cursor:pointer;font-family:inherit;font-weight:600;font-size:.8rem;padding:.42em .8em;border-radius:999px;border:1px solid rgba(255,255,255,.32);background:rgba(255,255,255,.06);color:#fff;transition:all .14s} .fbtn:hover{background:rgba(255,255,255,.18)} .result-body{padding:24px 28px 26px} .rrow{padding:14px 0;border-bottom:1px dashed var(–line);opacity:0;transform:translateY(8px);transition:opacity .4s,transform .4s} .rrow.show{opacity:1;transform:none} .rrow:last-child{border-bottom:none} .rrow .rlabel{font-family:”Space Mono”,monospace;font-size:.66rem;letter-spacing:.14em;text-transform:uppercase;color:var(–teal-deep);font-weight:700;margin-bottom:5px} .rrow .rtext{font-size:1.04rem;color:var(–ink)} .rrow .motto{font-family:”Fraunces”;font-style:italic;font-size:1.3rem;color:var(–navy)} .caption-box{background:var(–paper);border:1px solid var(–line);border-radius:14px;padding:14px 16px;font-size:.98rem} /* ———- share card ———- */ .card-stage{display:grid;grid-template-columns:1.05fr .95fr;gap:26px;align-items:start;margin-top:16px} @media(max-width:880px){.card-stage{grid-template-columns:1fr}} .controls-label{font-weight:700;font-size:.82rem;color:var(–navy);margin:6px 0 8px;display:flex;align-items:center;justify-content:space-between;gap:8px} .format-chips,.theme-chips{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px} .card-shell{display:flex;justify-content:center} .shuffle-look{background:none;border:1px solid var(–line);border-radius:999px;padding:.3em .7em;font-family:”Space Mono”,monospace;font-size:.62rem;letter-spacing:.06em;text-transform:uppercase;color:var(–teal-deep);cursor:pointer} .shuffle-look:hover{border-color:var(–teal)} .fcard{width:100%;max-width:430px;position:relative;overflow:hidden;border-radius:18px;box-shadow:var(–shadow);aspect-ratio:1/1;display:flex;flex-direction:column;color:#fff;background:#15263F;transition:background .5s ease} .fcard.story{aspect-ratio:9/16} .fcard.post{aspect-ratio:1.91/1} .fcard.pin{aspect-ratio:2/3} .fcard.theme-swap{animation:themeSwap .5s ease} @keyframes themeSwap{0%{transform:scale(.97);opacity:.4}100%{transform:scale(1);opacity:1}} .fc-inner{position:relative;padding:26px;display:flex;flex-direction:column;height:100%;gap:8px;z-index:2} .fc-top{display:flex;align-items:center;justify-content:space-between;font-family:”Space Mono”,monospace;font-size:.6rem;letter-spacing:.14em;text-transform:uppercase} .fc-badge{border:1.5px solid currentColor;border-radius:999px;padding:.3em .7em;transform:rotate(-3deg)} .fc-mid{flex:1;display:flex;flex-direction:column;justify-content:center;text-align:center} .fc-roots-top{font-family:”Space Mono”,monospace;font-size:.62rem;letter-spacing:.08em;opacity:.85;margin-bottom:6px} .fc-word{font-family:”Fraunces”;font-weight:600;font-size:clamp(2.1rem,8vw,3.3rem);line-height:1;letter-spacing:-.01em} .fc-type{margin-top:12px;align-self:center;border-radius:999px;padding:.4em .9em;font-weight:700;font-size:.82rem;background:rgba(255,255,255,.16);border:1px solid rgba(255,255,255,.32)} .fc-motto{margin-top:14px;font-family:”Fraunces”;font-style:italic;font-size:1.04rem;opacity:.95;max-width:30ch;align-self:center} .fc-bottom{text-align:center;border-top:1px solid rgba(255,255,255,.22);padding-top:11px} .fc-cta{font-family:”Space Mono”,monospace;font-size:.64rem;letter-spacing:.06em} .fc-ctabadge{display:inline-block;margin-top:7px;font-family:”Space Mono”,monospace;font-size:.56rem;letter-spacing:.08em;border:1px dashed currentColor;border-radius:6px;padding:.25em .6em;opacity:.92} .fc-tex{position:absolute;inset:0;z-index:1;pointer-events:none} .fcard[data-theme=”passport”]{background:linear-gradient(150deg,#1d3350,#15263F 60%,#0e1b30)} .fcard[data-theme=”passport”] .fc-tex{background-image:radial-gradient(circle,rgba(255,255,255,.5) 1px,transparent 1px);background-size:18px 18px;opacity:.16} .fcard[data-theme=”passport”] .fc-top,.fcard[data-theme=”passport”] .fc-cta{color:var(–gold-bright)} .fcard[data-theme=”passport”] .fc-type{background:rgba(200,136,31,.22);border-color:rgba(224,165,46,.5);color:#ffe2a8} .fcard[data-theme=”table”]{background:linear-gradient(155deg,#b5512c,#9C3C1C 60%,#742c12);color:#fdeccb} .fcard[data-theme=”table”] .fc-tex{background:radial-gradient(circle at 50% 78%,rgba(253,236,203,.18),transparent 40%)} .fcard[data-theme=”table”] .fc-top,.fcard[data-theme=”table”] .fc-cta{color:#ffd9a0} .fcard[data-theme=”table”] .fc-type{background:rgba(253,236,203,.18);border-color:rgba(253,236,203,.4)} .fcard[data-theme=”airport”]{background:linear-gradient(155deg,#1c544c,#123c36);color:#e7f4f0} .fcard[data-theme=”airport”] .fc-tex{background:repeating-linear-gradient(90deg,transparent,transparent 24px,rgba(255,255,255,.07) 24px,rgba(255,255,255,.07) 26px)} .fcard[data-theme=”airport”] .fc-top,.fcard[data-theme=”airport”] .fc-cta{color:#a9e7dd} .fcard[data-theme=”airport”] .fc-type{background:rgba(169,231,221,.16);border-color:rgba(169,231,221,.4)} .fcard[data-theme=”postcard”]{background:linear-gradient(160deg,#fdf6e8,#f3e6cd);color:#3a2e1c} .fcard[data-theme=”postcard”] .fc-tex{background:radial-gradient(circle at 86% 14%,rgba(156,60,28,.12),transparent 22%)} .fcard[data-theme=”postcard”] .fc-word,.fcard[data-theme=”postcard”] .fc-motto{color:#15263F} .fcard[data-theme=”postcard”] .fc-top,.fcard[data-theme=”postcard”] .fc-cta{color:#9C3C1C} .fcard[data-theme=”postcard”] .fc-bottom{border-top-color:rgba(58,46,28,.25)} .fcard[data-theme=”postcard”] .fc-type{background:rgba(42,111,102,.14);border-color:rgba(42,111,102,.35);color:#1c544c} .fcard[data-theme=”postcard”] .fc-stampbox{position:absolute;top:18px;right:18px;width:46px;height:54px;border:2px dashed #9C3C1C;border-radius:4px;display:flex;align-items:center;justify-content:center;font-size:1.2rem;z-index:3;opacity:.8} .fcard[data-theme=”notebook”]{background:repeating-linear-gradient(#fffdf6,#fffdf6 25px,#cfe3ea 26px);color:#1d3a4d} .fcard[data-theme=”notebook”] .fc-inner{padding-left:34px} .fcard[data-theme=”notebook”]:before{content:””;position:absolute;left:20px;top:0;bottom:0;width:2px;background:#e2897f;z-index:2} .fcard[data-theme=”notebook”] .fc-word{font-family:”Caveat”,cursive;font-size:clamp(2.6rem,10vw,4rem)} .fcard[data-theme=”notebook”] .fc-motto{font-family:”Caveat”,cursive;font-style:normal;font-size:1.3rem} .fcard[data-theme=”notebook”] .fc-top,.fcard[data-theme=”notebook”] .fc-cta{color:#9C3C1C} .fcard[data-theme=”notebook”] .fc-bottom{border-top-color:rgba(29,58,77,.2)} .fcard[data-theme=”notebook”] .fc-type{background:rgba(42,111,102,.12);border-color:rgba(42,111,102,.3);color:#1c544c} .fcard[data-theme=”recipe”]{background:linear-gradient(160deg,#f7ecd6,#ecdcbc);color:#3a2e1c} .fcard[data-theme=”recipe”] .fc-tex{background-image:radial-gradient(circle,rgba(156,60,28,.10) 1px,transparent 1px);background-size:20px 20px} .fcard[data-theme=”recipe”] .fc-word{color:#9C3C1C} .fcard[data-theme=”recipe”] .fc-motto{color:#5a4327} .fcard[data-theme=”recipe”] .fc-top,.fcard[data-theme=”recipe”] .fc-cta{color:#9C3C1C} .fcard[data-theme=”recipe”] .fc-bottom{border-top-color:rgba(58,46,28,.25)} .fcard[data-theme=”recipe”] .fc-type{background:rgba(42,111,102,.14);border-color:rgba(42,111,102,.35);color:#1c544c} .card-actions{display:flex;flex-wrap:wrap;gap:10px} .cap-preview{margin-top:14px;background:var(–paper);border:1px solid var(–line);border-radius:14px;padding:14px 16px} .cap-preview .cpk{font-family:”Space Mono”,monospace;font-size:.6rem;letter-spacing:.12em;text-transform:uppercase;color:var(–teal-deep);font-weight:700;margin-bottom:6px} .cap-preview .cptext{font-size:.92rem;color:var(–ink-soft);white-space:pre-wrap} .consent{display:flex;gap:10px;align-items:flex-start;background:var(–paper);border:1px dashed var(–line);border-radius:12px;padding:12px 14px;font-size:.86rem;margin-top:14px} .consent input{margin-top:4px;width:18px;height:18px;accent-color:var(–teal);flex:0 0 auto} .cardalt{font-size:.78rem;color:var(–ink-soft);margin-top:10px;font-style:italic} /* ———- example carousel ———- */ .fam{background:linear-gradient(180deg,var(–paper),var(–paper-deep))} .carousel-head{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;flex-wrap:wrap} .carousel-ctrls{display:flex;gap:8px;align-items:center} .cbtn{width:42px;height:42px;border-radius:50%;border:1.5px solid var(–line);background:#fff;color:var(–navy);font-size:1.1rem;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .15s} .cbtn:hover{border-color:var(–teal);color:var(–teal-deep)} .carousel{margin-top:22px;display:flex;gap:18px;overflow-x:auto;scroll-snap-type:x mandatory;padding:6px 2px 16px;-webkit-overflow-scrolling:touch;scrollbar-width:thin} .carousel::-webkit-scrollbar{height:8px} .carousel::-webkit-scrollbar-thumb{background:var(–line);border-radius:8px} .famcard{scroll-snap-align:start;flex:0 0 300px;max-width:300px;background:#fff;border:1px solid var(–line);border-radius:18px;padding:22px;box-shadow:0 12px 30px -22px rgba(33,30,24,.6);display:flex;flex-direction:column;transition:transform .15s,box-shadow .2s} .famcard:hover{transform:translateY(-3px);box-shadow:0 20px 36px -22px rgba(33,30,24,.6)} .famcard .fc-roots{font-family:”Space Mono”,monospace;font-size:.72rem;letter-spacing:.04em;color:var(–terracotta-deep);font-weight:700} .famcard .fc-bigword{font-family:”Fraunces”;font-weight:600;font-size:2rem;color:var(–navy);line-height:1;margin-top:6px} .famcard .fc-typebadge{align-self:flex-start;margin-top:10px;background:rgba(42,111,102,.12);color:var(–teal-deep);border:1px solid rgba(42,111,102,.3);padding:.25em .7em;border-radius:999px;font-size:.72rem;font-weight:700} .famcard .fc-mean2{margin-top:10px;font-size:.92rem;color:var(–ink-soft);flex:1} .famcard .btn{margin-top:14px} /* how it works stepper */ .stepper{margin-top:28px;display:grid;grid-template-columns:1.1fr 1fr;gap:26px;align-items:center} @media(max-width:780px){.stepper{grid-template-columns:1fr}} .steptrack{display:flex;flex-direction:column;gap:10px} .steprow{display:flex;gap:14px;align-items:flex-start;background:#fff;border:1px solid var(–line);border-left:4px solid var(–line);border-radius:14px;padding:14px 16px;cursor:pointer;transition:all .18s} .steprow:hover{border-left-color:var(–teal)} .steprow[aria-selected=”true”]{border-left-color:var(–terracotta);box-shadow:var(–shadow);transform:translateX(4px)} .steprow .sn{font-family:”Space Mono”,monospace;font-weight:700;color:var(–terracotta);font-size:.8rem;flex:0 0 auto;margin-top:2px} .steprow h3{font-family:”Fraunces”;font-weight:600;font-size:1.1rem;color:var(–navy);margin-bottom:2px} .steprow p{font-size:.9rem;color:var(–ink-soft)} .steppreview{background:linear-gradient(150deg,#1b2f4d,#15263F);border-radius:var(–radius);min-height:230px;display:flex;align-items:center;justify-content:center;padding:24px;text-align:center;color:#fff;box-shadow:var(–shadow);position:relative;overflow:hidden} .steppreview:before{content:””;position:absolute;inset:0;opacity:.4;background-image:radial-gradient(circle,rgba(255,255,255,.3) 1px,transparent 1px);background-size:20px 20px} .steppreview .spv{position:relative;animation:rise .5s ease} .steppreview .spv .ic{font-size:2.6rem} .steppreview .spv .big{font-family:”Fraunces”;font-weight:600;font-size:1.7rem;margin-top:8px;color:var(–gold-bright)} .steppreview .spv .cap{font-size:.9rem;color:rgba(255,255,255,.85);margin-top:6px;max-width:30ch;margin-left:auto;margin-right:auto} /* ———- word wall ———- */ .wall-note{background:#fff;border:1px solid var(–line);border-left:4px solid var(–teal);border-radius:12px;padding:12px 14px;margin-top:16px;font-size:.9rem;color:var(–ink-soft)} .wall-bar{display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap;margin-top:16px} .wall-count{font-family:”Space Mono”,monospace;font-size:.78rem;letter-spacing:.04em;color:var(–teal-deep);font-weight:700} .wall-controls{display:flex;flex-wrap:wrap;gap:12px;margin:14px 0 4px} .wall-controls input,.wall-controls select{font-family:inherit;font-size:.95rem;background:#fff;border:1.5px solid var(–line);border-radius:12px;padding:.7em .9em;color:var(–ink)} .wall-controls input{flex:1;min-width:200px} .wall-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;margin-top:18px} @media(max-width:880px){.wall-grid{grid-template-columns:repeat(2,1fr)}} @media(max-width:560px){.wall-grid{grid-template-columns:1fr}} .wcard{background:#fff;border:1px solid var(–line);border-radius:18px;padding:22px;position:relative;box-shadow:0 10px 26px -22px rgba(33,30,24,.6);transition:transform .15s,box-shadow .2s} .wcard:hover{transform:translateY(-3px);box-shadow:0 18px 34px -22px rgba(33,30,24,.6)} .wcard.enter{animation:wIn .5s cubic-bezier(.2,.8,.3,1)} @keyframes wIn{0%{opacity:0;transform:translateY(16px) scale(.96)}100%{opacity:1;transform:none}} .wcard .wc-word{font-family:”Fraunces”;font-weight:600;font-size:1.7rem;color:var(–navy);line-height:1} .wcard .wc-type{display:inline-block;margin-top:8px;background:rgba(42,111,102,.12);color:var(–teal-deep);border:1px solid rgba(42,111,102,.3);padding:.25em .7em;border-radius:999px;font-size:.74rem;font-weight:700} .wcard .wc-roots{margin-top:10px;font-size:.82rem;color:var(–terracotta-deep);font-weight:600} .wcard .wc-mean{margin-top:8px;font-size:.92rem;color:var(–ink-soft)} .wcard .wc-try{margin-top:12px;font-family:inherit;font-weight:700;font-size:.78rem;color:var(–teal-deep);background:rgba(42,111,102,.1);border:1px solid rgba(42,111,102,.3);border-radius:999px;padding:.4em .9em;cursor:pointer;transition:all .14s} .wcard .wc-try:hover{background:var(–teal);color:#fff;border-color:var(–teal)} .wcard .wc-meta{margin-top:12px;font-family:”Space Mono”,monospace;font-size:.64rem;letter-spacing:.04em;color:var(–ink-soft);display:flex;justify-content:space-between;align-items:center;gap:8px} .wcard .wc-cta{margin-top:8px;font-family:”Space Mono”,monospace;font-size:.6rem;color:var(–teal-deep);opacity:.85} .wcard .wc-del{background:none;border:none;color:var(–ink-soft);cursor:pointer;font-size:.8rem;font-weight:700;font-family:inherit} .wcard .wc-del:hover{color:var(–terracotta-deep);text-decoration:underline} .wcard .seed-badge{position:absolute;top:14px;right:14px;font-family:”Space Mono”,monospace;font-size:.54rem;letter-spacing:.1em;color:var(–gold);text-transform:uppercase;border:1px solid rgba(200,136,31,.45);border-radius:999px;padding:.2em .55em} .empty{grid-column:1/-1;text-align:center;padding:46px 20px;border:2px dashed var(–line);border-radius:var(–radius);color:var(–ink-soft)} .empty .ic{font-size:2.4rem} /* refine details */ .refine{margin-top:18px;background:#fff;border:1px solid var(–line);border-radius:var(–radius);box-shadow:0 10px 26px -22px rgba(33,30,24,.5);overflow:hidden} .refine>summary{cursor:pointer;list-style:none;padding:18px 22px;font-family:”Fraunces”;font-weight:600;font-size:1.2rem;color:var(–navy);display:flex;align-items:center;justify-content:space-between} .refine>summary::-webkit-details-marker{display:none} .refine>summary .chev{transition:transform .2s;color:var(–terracotta)} .refine[open]>summary .chev{transform:rotate(180deg)} .refine .refine-body{padding:0 22px 24px} .grid2{display:grid;grid-template-columns:1fr 1fr;gap:16px} @media(max-width:680px){.grid2{grid-template-columns:1fr}} .field{display:flex;flex-direction:column;gap:6px;margin-bottom:16px} .field label{font-weight:700;font-size:.86rem;color:var(–navy)} .field .hint{font-weight:400;color:var(–ink-soft);font-size:.78rem} .field input{font-family:inherit;font-size:.96rem;color:var(–ink);background:var(–paper);border:1.5px solid var(–line);border-radius:12px;padding:.72em .85em;transition:border .15s,box-shadow .15s} .field input:focus{outline:none;border-color:var(–terracotta);box-shadow:0 0 0 4px rgba(192,81,47,.14)} .controls-label2{font-weight:700;font-size:.82rem;color:var(–navy);margin:6px 0 8px} .chips{display:flex;flex-wrap:wrap;gap:8px} .chip{cursor:pointer;user-select:none;font-size:.84rem;font-weight:600;padding:.5em .85em;border-radius:999px;border:1.5px solid var(–line);background:var(–paper);color:var(–ink);transition:all .14s;font-family:inherit} .chip:hover{border-color:var(–teal)} .chip[aria-pressed=”true”]{background:var(–teal);border-color:var(–teal);color:#fff} .chip.mood[aria-pressed=”true”]{background:var(–gold);border-color:var(–gold);color:#1f1402} .chip.style[aria-pressed=”true”]{background:var(–navy);border-color:var(–navy);color:#fff} /* ———- why / founder ———- */ .why{background:linear-gradient(180deg,var(–paper) 0%,var(–paper-deep) 100%)} .why-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:26px} @media(max-width:780px){.why-grid{grid-template-columns:1fr}} .why-item{background:#fff;border:1px solid var(–line);border-radius:16px;padding:22px} .why-item h3{font-family:”Fraunces”;font-weight:600;color:var(–navy);font-size:1.22rem;margin:6px 0} .why-item p{color:var(–ink-soft);font-size:.97rem} .why-item .ic{font-size:1.5rem} .founder{display:grid;grid-template-columns:.9fr 1.1fr;gap:30px;align-items:center;background:#fff;border:1px solid var(–line);border-radius:var(–radius);padding:34px;box-shadow:var(–shadow)} @media(max-width:780px){.founder{grid-template-columns:1fr}} .founder .passport{background:linear-gradient(150deg,var(–terracotta),var(–gold));border-radius:16px;padding:26px;color:#fff;position:relative;overflow:hidden;min-height:170px;display:flex;flex-direction:column;justify-content:center} .founder .passport:before{content:””;position:absolute;inset:0;opacity:.2;background-image:radial-gradient(circle,#fff 1px,transparent 1px);background-size:14px 14px} .founder .passport .big{font-family:”Fraunces”;font-weight:600;font-size:2.4rem;line-height:1;position:relative} .founder .passport .lbl{font-family:”Space Mono”,monospace;font-size:.64rem;letter-spacing:.14em;text-transform:uppercase;opacity:.95;position:relative} .founder p{color:var(–ink);font-size:1.04rem} .founder p+p{margin-top:12px} .founder p em{font-style:normal;color:var(–terracotta-deep);font-weight:700} /* footer */ footer{background:var(–navy);color:var(–paper);padding:52px 0 96px;margin-top:18px} footer .wrap{text-align:center} footer .fbrand{font-family:”Fraunces”;font-weight:600;font-size:1.55rem} footer .fpow{font-family:”Space Mono”,monospace;font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;color:var(–gold-bright);margin-top:6px} footer .fcta{max-width:52ch;margin:18px auto;color:rgba(251,245,233,.88)} footer a.visit{color:var(–paper);font-weight:700;text-decoration:none;border-bottom:2px solid var(–gold-bright);padding-bottom:2px} footer .fmeta{margin-top:22px;font-size:.78rem;color:rgba(251,245,233,.55)} /* sticky mobile action bar */ .mobar{position:fixed;left:0;right:0;bottom:0;z-index:120;display:none;background:rgba(21,38,63,.96);backdrop-filter:blur(8px);border-top:1px solid rgba(255,255,255,.12);padding:8px 10px calc(8px + env(safe-area-inset-bottom));gap:8px} .mobar.show{display:flex} .mobar button{flex:1;background:none;border:none;color:#fff;font-family:inherit;font-weight:700;font-size:.78rem;display:flex;flex-direction:column;align-items:center;gap:3px;padding:6px 4px;border-radius:12px;cursor:pointer} .mobar button .mi{font-size:1.1rem} .mobar button:active{background:rgba(255,255,255,.12)} .mobar button.primary{background:var(–terracotta)} @media(max-width:720px){.mobar.show{display:flex}} @media(min-width:721px){.mobar{display:none !important}} /* debug panel */ .debug{display:none;position:fixed;right:14px;bottom:14px;z-index:300;width:min(420px,92vw);max-height:80vh;overflow:auto;background:#0e1b30;color:#cfe3ea;border:1px solid var(–teal);border-radius:14px;padding:16px;font-family:”Space Mono”,monospace;font-size:.72rem;line-height:1.5;box-shadow:0 24px 60px -20px rgba(0,0,0,.7)} .debug.show{display:block} .debug h4{color:var(–gold-bright);font-size:.8rem;letter-spacing:.08em;text-transform:uppercase;margin-bottom:8px} .debug .row{display:flex;justify-content:space-between;gap:10px;padding:3px 0;border-bottom:1px solid rgba(255,255,255,.08);word-break:break-all} .debug .ok{color:#7fe3a4}.debug .bad{color:#ff9b87} .debug .closex{position:absolute;top:10px;right:12px;background:none;border:none;color:#cfe3ea;cursor:pointer;font-size:1rem} /* toast */ .toast{position:fixed;left:50%;bottom:84px;transform:translateX(-50%) translateY(20px);background:var(–ink);color:var(–paper);padding:13px 20px;border-radius:999px;font-weight:700;font-size:.92rem;box-shadow:var(–shadow);z-index:200;opacity:0;pointer-events:none;transition:all .28s cubic-bezier(.2,.7,.2,1)} .toast.show{opacity:1;transform:translateX(-50%) translateY(0)} .hidden{display:none !important} .center{text-align:center}
Deployment URL not finalized. Update DEPLOYED_APP_URL before publication.
★ Free family wordplay · No login

What language does your family speak when one country is not enough?

Two roots go in. One family word comes out. Make a word your family would actually use, with a motto, a caption, and a card you can share.

Filipino + Turkish → Turknoy Korean + Mexican → Kimchitaco Nigerian + Japanese → Naijapon
Word Forge Drop in two roots. Watch them blend.
Root one
Root two
See live examples
Try:

You are not half of anything. You are made of many roots.

See live examples
ManyRoots WordPlay Studio by TurknoyTravels100.world
This is playful, not definitive. Make a word in the Word Forge above, then a full result and a share card will appear right here. Edit, regenerate, or reject any word that does not feel like your family.
How it works

Some families are built in airports, video calls, recipes, and second languages.

This studio helps you name yours in four small steps. Tap a step to preview it.

Optional

Refine your word

The Word Forge is enough for most families. Open this to add more roots, set a style and a mood, and shape the meaning.

Open the full studio controls
Root 1 culture, country, language, or place
Root 2 culture, country, language, or place
Additional root optional
Where your family lives now optional
Where your family is connected to optional
Your main family experience Choose the one that feels truest.
Word style How should your word feel? You can change this and regenerate any time.
Family mood Shapes the tone of your caption and motto.
Family words or nicknames optional
A food, place, or ritual that feels like home optional
My Local Word Wall

Home is sometimes a sentence only your family understands.

Collect your family words here. Tap any card to try that mix in the Word Forge.

Private by design. Entries are saved only on this device in your browser. They are not posted publicly. If a public Word Wall launches later, submissions would be moderated before appearing publicly.
0 family words saved on this device
Filter by family language type
Why it matters

Distance does not divide a family. It teaches it a new language.

🍲

Food is a sentence

A shared dish can say more than words. Many families speak love through the table first.

📞

A call is a homecoming

Across time zones, a voice note or a video call becomes the door everyone walks through.

🧳

Roots and routes both count

Where your family comes from matters. So does every road it has traveled since.

Origin word
Turknoy
Turkish + Pinoy
Our story

One word among many

ManyRoots WordPlay Studio was inspired by Turknoy, a family word born from Turkish and Pinoy. But Turknoy is only one example. Around the world, families are creating their own languages across race, culture, distance, food, migration, love, and home. This free tool helps you find yours.

Turknoy is the origin word, not the boundary. It began with Turkish and Pinoy. Now it opens into a global wordplay studio for families with many roots.

ManyRoots WordPlay Studio
Powered by TurknoyTravels100.world

Create your family language. Share your word. Celebrate many roots and many routes.

Visit TurknoyTravels100.world
Many roots. Many routes. One family language. · Free family wordplay for the whole world.
Copied
/* ===================================================================== ManyRoots WordPlay Studio by TurknoyTravels100.world Static. No backend. No login. No paid API. NOTE: This script is written with ZERO ampersand characters so that WordPress wptexturize and WPCode entity-encoding cannot corrupt it. Logical AND is expressed with nested ifs or ternaries. ===================================================================== */ /* ===================== DEPLOYMENT CONSTANTS (single source of truth) ===================== */ var DEPLOYED_APP_URL = “https://turknoytravels100.world/manyroots/&#8221;; var BRAND_HOME_URL = “https://TurknoyTravels100.world&#8221;; var OG_IMAGE_URL = “https://turknoytravels100.world/wp-content/uploads/2026/05/og-image.png&#8221;; function isPlaceholder(u){ return u.indexOf(“FINAL_WORKING_APP_URL_HERE”) > -1; } function syncDeploymentUrls(){ try{ var can=document.querySelector(‘link[rel=”canonical”]’); if(can){ can.setAttribute(“href”, DEPLOYED_APP_URL); } var ogu=document.querySelector(‘meta[property=”og:url”]’); if(ogu){ ogu.setAttribute(“content”, DEPLOYED_APP_URL); } var ogi=document.querySelector(‘meta[property=”og:image”]’); if(ogi){ ogi.setAttribute(“content”, OG_IMAGE_URL); } var twi=document.querySelector(‘meta[name=”twitter:image”]’); if(twi){ twi.setAttribute(“content”, OG_IMAGE_URL); } }catch(e){} if(isPlaceholder(DEPLOYED_APP_URL)){ document.getElementById(“devBanner”).classList.add(“show”); } } /* ===================== DATA ===================== */ var CTAS = [ “Create yours at TurknoyTravels100.world”, “Made with ManyRoots WordPlay Studio by TurknoyTravels100.world”, “Find your family language at TurknoyTravels100.world” ]; var CANONICAL_BLENDS = [ { matchAnyOrder:[[“turkish”,”turkey”,”turk”],[“filipino”,”pinoy”,”philippine”,”philippines”,”tagalog”]], word:”Turknoy”, meaning:”Turkish and Pinoy, the origin word behind TurknoyTravels100.world.” } ]; var LOVE = { “Roots Love”: {ic:”\uD83C\uDF33″, tag:”honoring where you come from”, tip:”For families who hold their origins close and pass them forward.”}, “Routes Love”: {ic:”\uD83E\uDDED”, tag:”belonging built on the move”, tip:”For families whose identity grew across countries and journeys.”}, “Translation Love”:{ic:”\uD83D\uDDE3\uFE0F”, tag:”meeting between languages”, tip:”For families who love across more than one language, mixing words daily.”}, “Table Love”: {ic:”\uD83C\uDF72″, tag:”love served at the table”, tip:”For families who say the most through food, recipes, and shared meals.”}, “Distance Love”: {ic:”\uD83C\uDF19″, tag:”close even when far”, tip:”For families separated by miles who stay near in heart.”}, “Time Zone Love”: {ic:”\u23F0″, tag:”one home across many clocks”, tip:”For families living in different time zones who keep one emotional home.”}, “Ritual Love”: {ic:”\uD83D\uDD6F\uFE0F”, tag:”meaning made by repetition”, tip:”For families bound by holidays, traditions, and small repeated rituals.”}, “Nickname Love”: {ic:”\uD83D\uDCAC”, tag:”a private language of names”, tip:”For families with their own nicknames, inside words, and jokes.”}, “Return Love”: {ic:”\uD83C\uDFE1″, tag:”always finding the way home”, tip:”For families defined by reunions and the joy of coming back.”}, “Bridge Love”: {ic:”\uD83C\uDF09″, tag:”two worlds, one rhythm”, tip:”For families who build a bridge between cultures and races with care.”}, “ManyHomes Love”: {ic:”\uD83D\uDDFA\uFE0F”, tag:”home in more than one place”, tip:”For families who carry several homes and belong to all of them.”}, “Voice Note Love”: {ic:”\uD83C\uDF99\uFE0F”, tag:”closeness through every call”, tip:”For families who keep in touch through calls, voice notes, and messages.”}, “Airport Love”: {ic:”\u2708\uFE0F”, tag:”hellos worth the goodbyes”, tip:”For families who measure love in arrivals and departures.”}, “Story Love”: {ic:”\uD83D\uDCD6″, tag:”memory passed down”, tip:”For families who keep their history alive through stories across generations.”}, “Food Parcel Love”:{ic:”\uD83D\uDCE6″, tag:”care you can taste”, tip:”For families who send food, spices, and packages across the world as love.”} }; var EXP_MAP = { “Across cultures”: [“Bridge Love”,”Translation Love”,”ManyHomes Love”], “Across races”: [“Bridge Love”,”Roots Love”,”ManyHomes Love”], “Across countries”: [“Routes Love”,”ManyHomes Love”,”Return Love”], “Across languages”: [“Translation Love”,”Nickname Love”,”Bridge Love”], “Across distance”: [“Distance Love”,”Voice Note Love”,”Airport Love”], “Across time zones”: [“Time Zone Love”,”Distance Love”,”Voice Note Love”], “Across generations”: [“Story Love”,”Roots Love”,”Ritual Love”], “Across food traditions”: [“Table Love”,”Food Parcel Love”,”Ritual Love”], “Across holidays”: [“Ritual Love”,”Return Love”,”Story Love”], “Across many homes”: [“ManyHomes Love”,”Routes Love”,”Return Love”] }; var EXPERIENCES = Object.keys(EXP_MAP); var STYLES = [“Best”,”Funny”,”Poetic”,”Name-like”,”Food-inspired”,”Less food-based”,”More respectful”]; var MOODS = [“Warm”,”Funny”,”Proud”,”Poetic”,”Travel-inspired”,”Nostalgic”,”Kid-friendly”,”Social-ready”]; var THEMES = [ {id:”passport”, name:”Passport Stamp”, badge:”PASSPORT”, alt:”a navy passport-stamp card”}, {id:”table”, name:”Family Table”, badge:”ONE TABLE”, alt:”a warm terracotta family-table card”}, {id:”airport”, name:”Airport Goodbye”,badge:”BOARDING”, alt:”a teal airport boarding-pass card”}, {id:”postcard”, name:”Postcard Home”, badge:”POSTCARD”, alt:”a cream postcard with a stamp box”}, {id:”notebook”, name:”Kids Notebook”, badge:”OUR WORDS”, alt:”a lined notebook card in handwriting”}, {id:”recipe”, name:”Recipe Memory”, badge:”RECIPE”, alt:”a recipe-card style memory card”} ]; var LEXICON = [ {k:[“turkish”,”turkey”,”turk”], head:”turk”, flavor:”merhaba”, food:”simit”}, {k:[“filipino”,”pinoy”,”philippine”,”philippines”,”tagalog”,”pilipino”], head:”fili”, tail:”noy”, flavor:”mahal”, food:”adobo”}, {k:[“finnish”,”finland”,”suomi”], head:”fin”, flavor:”sisu”}, {k:[“indian”,”india”,”hindi”,”desi”], head:”ind”, flavor:”pyaar”, food:”masala”}, {k:[“british”,”britain”,”england”,”english”,”uk”], head:”brit”, tail:”shire”, flavor:”shire”}, {k:[“kenyan”,”kenya”,”swahili”], head:”ken”, flavor:”jambo”}, {k:[“french”,”france”,”francais”], head:”franc”, tail:”france”, flavor:”cherie”}, {k:[“korean”,”korea”,”hangul”], head:”kor”, flavor:”jeong”, food:”kimchi”}, {k:[“mexican”,”mexico”,”mexicano”], head:”mex”, flavor:”querido”, food:”taco”}, {k:[“nigerian”,”nigeria”,”naija”,”yoruba”,”igbo”], head:”naija”, flavor:”naija”}, {k:[“japanese”,”japan”,”nippon”,”nihon”], head:”japon”, tail:”japon”, flavor:”japon”}, {k:[“arab”,”arabic”,”arabian”], head:”habib”, flavor:”habibi”}, {k:[“brazilian”,”brazil”,”brasil”], head:”bra”, tail:”alegria”, flavor:”alegria”}, {k:[“italian”,”italy”,”italiano”], head:”ital”, flavor:”amore”, food:”pasta”}, {k:[“spanish”,”spain”,”espanol”,”espana”],head:”espa”, flavor:”carino”}, {k:[“greek”,”greece”,”ellinika”], head:”greco”, flavor:”agapi”}, {k:[“chinese”,”china”,”mandarin”,”han”], head:”chin”, flavor:”jia”}, {k:[“thai”,”thailand”], head:”thai”, flavor:”sabai”, food:”padthai”}, {k:[“vietnamese”,”vietnam”,”viet”], head:”viet”, flavor:”thuong”, food:”pho”}, {k:[“german”,”germany”,”deutsch”], head:”deut”, flavor:”heimat”}, {k:[“dutch”,”netherlands”,”holland”], head:”nether”,flavor:”gezellig”}, {k:[“polish”,”poland”,”polski”], head:”pol”, flavor:”kochanie”}, {k:[“portuguese”,”portugal”], head:”porto”, flavor:”saudade”}, {k:[“russian”,”russia”], head:”rus”, flavor:”rodina”}, {k:[“ukrainian”,”ukraine”], head:”ukra”, flavor:”rodyna”}, {k:[“egyptian”,”egypt”], head:”egy”, flavor:”habibi”}, {k:[“moroccan”,”morocco”], head:”maroc”, flavor:”baraka”}, {k:[“ethiopian”,”ethiopia”], head:”ethio”, flavor:”fiqir”, food:”injera”}, {k:[“ghanaian”,”ghana”], head:”ghana”, flavor:”akwaaba”}, {k:[“south african”,”mzansi”,”zulu”], head:”mzansi”,flavor:”ubuntu”}, {k:[“american”,”america”,”usa”,”united states”], head:”ameri”, flavor:”home”}, {k:[“canadian”,”canada”], head:”cana”, flavor:”home”}, {k:[“australian”,”australia”,”aussie”], head:”aussi”, flavor:”mate”}, {k:[“irish”,”ireland”,”eire”], head:”eire”, flavor:”gra”}, {k:[“scottish”,”scotland”], head:”scot”, flavor:”hame”}, {k:[“swedish”,”sweden”,”svensk”], head:”sven”, flavor:”fika”}, {k:[“norwegian”,”norway”,”norsk”], head:”norse”, flavor:”kos”}, {k:[“danish”,”denmark”,”dansk”], head:”dane”, flavor:”hygge”}, {k:[“lebanese”,”lebanon”], head:”leba”, flavor:”habibi”}, {k:[“syrian”,”syria”], head:”sham”, flavor:”habibi”}, {k:[“palestinian”,”palestine”], head:”pales”, flavor:”sumud”}, {k:[“iranian”,”iran”,”persian”,”farsi”], head:”pars”, flavor:”azizam”}, {k:[“pakistani”,”pakistan”,”urdu”], head:”pak”, flavor:”jaan”}, {k:[“bangladeshi”,”bangladesh”,”bengali”],head:”bangla”,flavor:”shonar”}, {k:[“sri lankan”,”sri lanka”,”tamil”,”sinhala”], head:”lanka”, flavor:”ammi”}, {k:[“nepali”,”nepal”], head:”nepa”, flavor:”maya”}, {k:[“indonesian”,”indonesia”,”bahasa”], head:”indo”, flavor:”sayang”}, {k:[“malaysian”,”malaysia”,”malay”], head:”malay”, flavor:”sayang”}, {k:[“singaporean”,”singapore”], head:”singa”, flavor:”lah”}, {k:[“colombian”,”colombia”], head:”colom”, flavor:”querido”}, {k:[“argentine”,”argentinian”,”argentina”], head:”arga”, flavor:”carino”}, {k:[“peruvian”,”peru”], head:”peru”, flavor:”carino”}, {k:[“jamaican”,”jamaica”], head:”jamai”, flavor:”irie”}, {k:[“cuban”,”cuba”], head:”cuba”, flavor:”mivida”}, {k:[“turkish cypriot”,”cypriot”,”cyprus”],head:”cypr”, flavor:”merhaba”} ]; /* ===================== HELPERS (zero ampersand) ===================== */ function bAND(a,b){ return a ? (b ? true : false) : false; } function cleanInput(s){ if(!s) return “”; return String(s).toLowerCase().trim().replace(/[^a-z\u00E0-\u00FF\s\-]/gi,””).replace(/\s+/g,” “); } function matchGroup(c,arr){ if(!c) return false; for(var i=0;i-1||arr[i].indexOf(c)>-1) return true; } return false; } function checkCanonical(c1,c2){ for(var i=0;i<CANONICAL_BLENDS.length;i++){ var g=CANONICAL_BLENDS[i].matchAnyOrder; var fwd = matchGroup(c1,g[0]) ? matchGroup(c2,g[1]) : false; var rev = matchGroup(c1,g[1]) ? matchGroup(c2,g[0]) : false; if(fwd||rev) return CANONICAL_BLENDS[i]; } return null; } function lex(c){ if(!c) return null; for(var i=0;i<LEXICON.length;i++){ var e=LEXICON[i]; for(var j=0;j-1||e.k[j].indexOf(c)>-1) return e; } } return null; } function stem(c){ if(!c) return “”; var w=c.split(” “)[0]; var s=w.replace(/(ish|ese|ian|ino|eans|ean|aise|ais|i)$/,””); if(s.length<3) s=w; return s; } function cap(s){ return s? s.charAt(0).toUpperCase()+s.slice(1):s; } function tidy(w){ if(!w) return ""; w=w.toLowerCase().replace(/(.)\1{2,}/g,"$1$1").replace(/([aeiou])\1+/g,"$1").replace(/([^aeiou])\1/g,"$1"); return cap(w); } function pronounceable(w){ var hasV=/[aeiouy\u00E0-\u00FF]/i.test(w); var manyC=/[^aeiouy\u00E0-\u00FF]{5,}/i.test(w); return hasV ? (!manyC) : false; } function createFamilyWord(r1,r2,r3,style){ var c1=cleanInput(r1), c2=cleanInput(r2), c3=cleanInput(r3); var l1=lex(c1), l2=lex(c2); var s1=stem(c1), s2=stem(c2), s3=stem(c3); var blend=[], food=[], suffix=[], poetic=[]; function add(arr,w){ if(w) arr.push(tidy(w)); } if(c1){ if(c2){ var headA=s1.slice(0,Math.max(3,Math.ceil(s1.length/2))); if(l1){ if(l1.head){ headA=l1.head; } } var tailB=c2.slice(Math.max(0,Math.floor(c2.length/2))); if(l2){ if(l2.tail){ tailB=l2.tail; } } add(blend, headA+tailB); var hb1=s1.slice(0,3); if(l1){ if(l1.head){ hb1=l1.head; } } var tb1=cap(s2); if(l2){ if(l2.tail){ tb1=l2.tail; } } add(blend, hb1+tb1); var hb2=s2.slice(0,3); if(l2){ if(l2.head){ hb2=l2.head; } } add(blend, hb2 + c1.slice(Math.max(0,Math.floor(c1.length/2)))); if(l1){ if(l2){ var lh=l1.head?l1.head:s1; var lf=l2.flavor?l2.flavor:s2; add(blend, lh+lf); if(l1.food){ if(l2.food){ add(food, l1.food+l2.food); } } if(l1.flavor){ if(l2.flavor){ add(poetic, l1.flavor+l2.flavor); } } }} }} if(c3){ add(blend, s1.slice(0,2)+s2.slice(0,2)+s3.slice(0,3)); } var sfx=["home","roots","route","clan","haven","nest"]; var base=s1||s2||"family"; if(l1){ if(l1.head){ base=l1.head; } } for(var i=0;i<sfx.length;i++){ add(suffix, base+sfx[i]); } add(poetic, base+"home"); add(poetic, base+"haven"); var order; switch(style){ case "Funny": order=[food,suffix,blend,poetic]; break; case "Poetic": order=[poetic,blend,suffix,food]; break; case "Name-like": order=[blend,poetic,suffix,food]; break; case "Food-inspired": order=[food,blend,poetic,suffix]; break; case "Less food-based": order=[blend,suffix,poetic]; break; case "More respectful": order=[blend,suffix]; break; default: order=[blend,food,suffix,poetic]; } var merged=[]; order.forEach(function(arr){ arr.forEach(function(w){ merged.push(w); }); }); var seen={}, out=[]; for(var k=0;k<merged.length;k++){ var w=merged[k]; if(!w) continue; if(w.length14) continue; if(!pronounceable(w)) continue; if(w.toLowerCase()===c1||w.toLowerCase()===c2) continue; var key=w.toLowerCase(); if(seen[key]) continue; seen[key]=1; out.push(w); } if(out.length===0) out=[“ManyRoots”,”OneHome”,”Routeling”]; return out; } function loveCandidates(exp, words, home){ var base=(EXP_MAP[exp]||[“Bridge Love”,”ManyHomes Love”,”Routes Love”]).slice(); var t=cleanInput(words)+” “+cleanInput(home); function bump(type){ var i=base.indexOf(type); if(i>0) base.splice(i,1); if(base[0]!==type) base.unshift(type); } if(/call|voice|video|message|text|whatsapp|facetime/.test(t)) bump(“Voice Note Love”); if(/food|dish|recipe|cook|meal|kitchen|adobo|kimchi|simit|rice|bread|soup|taco|pasta/.test(t)) bump(“Table Love”); if(/parcel|package|send|box|spice/.test(t)) bump(“Food Parcel Love”); if(/airport|flight|visit|reunion|gate|arrival/.test(t)) bump(“Airport Love”); if(/nick|name|lola|lolo|anne|baba|tito|tita|nana|dede/.test(t)) bump(“Nickname Love”); var seen={},out=[]; for(var i=0;i1?”histories”:”roads”)+”. One table. One family.”,”Two climates. Many stories. One home.”,”Far in miles. Close in love.”,”Many homes. One heartbeat.”]; var poetic=[“We are a sentence only we can finish.”,”Home is the word we built together.”,”Distance learned our names.”]; var funny=[“Loud kitchen. Soft hearts. Many roots.”,”Built in airports and group chats.”,”Two passports. One snack rule.”]; var set= style===”Poetic”?poetic : style===”Funny”?funny : warm; return set[seed % set.length]; } function createCaption(word,love,motto,style,seed){ var lt=LOVE[love]?LOVE[love].tag:”shared belonging”; var cta=CTAS[seed % CTAS.length]; var t=[ “We found our family word: “+word+”. Our family language type is “+love+”, where “+lt+”. “+motto+” “+cta, “Meet “+word+”. Our family language type is “+love+”: “+lt+”. Many roots, many routes, one family language. “+cta, “Our family love language is “+love+”: “+lt+”. This is “+word+”. “+cta, word+” is the word for our family. “+love+”, “+lt+”. “+cta ]; return t[seed % t.length]; } function createStoryLine(roots,livesNow,connectedTo,love,seed){ var rt=roots.join(” and “); var place=livesNow?(” Now we live in “+livesNow+”.”):””; var conn=connectedTo?(” Our hearts stay tied to “+connectedTo+”.”):””; var lt=LOVE[love]?LOVE[love].tag:”belonging across worlds”; var t=[ “We are a “+rt+” family who learned that “+lt+” needs its own word.”+place+conn, “From “+rt+”, we built a home that travels with us, fluent in “+lt+”.”+place+conn, “A “+rt+” family writing its own quiet language of “+lt+”.”+conn+place ]; return t[seed % t.length]; } function createShareText(word,love,motto,seed){ var cta=CTAS[(seed+1)%CTAS.length]; return “Our family word is “+word+”, a “+love+” family. “+motto+” “+cta; } function igCaption(word,love,motto,roots){ return word+” is the word for our family. “+roots+”. Family language type: “+love+”. “+motto+”\n\nMake yours free at TurknoyTravels100.world\n#ManyRoots #FamilyLanguage #TurknoyTravels100 #MixedFamily #ThirdCulture #ManyRootsManyRoutes”; } function storyCaption(word,love,motto,story){ return story+”\n\nSo we gave it a word: “+word+”. A “+love+” family. “+motto+”\n\nMake your family word at TurknoyTravels100.world”; } /* ===================== STATE + STORAGE ===================== */ var state={ exp:”Across cultures”, style:”Best”, mood:”Warm”, seed:0, result:null, format:”square”, theme:”passport”, canon:null, lastInputs:null }; var memStore={}, WALL_KEY=”manyroots_wordwall_v2″; function storeGet(k){ try{ return window.localStorage.getItem(k); }catch(e){ return (k in memStore)?memStore[k]:null; } } function storeSet(k,v){ try{ window.localStorage.setItem(k,v); return true; }catch(e){ memStore[k]=v; return false; } } function lsAvailable(){ try{ var t=”__mr_test__”; window.localStorage.setItem(t,”1″); window.localStorage.removeItem(t); return true; }catch(e){ return false; } } var SAMPLES=[ {word:”Farhome”, roots:”Philippines + Qatar + Finland”, type:”Time Zone Love”, meaning:”A family that lives across clocks but keeps one emotional home.”, region:”Worldwide”, date:”Sample”, sample:true}, {word:”Kimchitaco”, roots:”Korean + Mexican”, type:”Table Love”, meaning:”A family table where spice, laughter, and love speak louder than borders.”, region:”Worldwide”, date:”Sample”, sample:true}, {word:”Naijapon”, roots:”Nigerian + Japanese”, type:”Bridge Love”, meaning:”A family rhythm built from warmth, respect, and shared care.”, region:”Worldwide”, date:”Sample”, sample:true}, {word:”Habibalegria”, roots:”Arab + Brazilian”, type:”Routes Love”, meaning:”Where affection, music, hospitality, and joy become one family language.”, region:”Worldwide”, date:”Sample”, sample:true}, {word:”Turknoy”, roots:”Turkish + Filipino”, type:”ManyHomes Love”, meaning:”Turkish and Pinoy, the origin word behind TurknoyTravels100.world.”, region:”Worldwide”, date:”Sample”, sample:true} ]; function loadWall(){ var raw=storeGet(WALL_KEY); if(!raw){ storeSet(WALL_KEY,JSON.stringify(SAMPLES)); return SAMPLES.slice(); } try{ return JSON.parse(raw); }catch(e){ return SAMPLES.slice(); } } function saveWall(a){ storeSet(WALL_KEY,JSON.stringify(a)); } /* ===================== SMALL DOM UTILS ===================== */ function el(id){ return document.getElementById(id); } function val(id){ return el(id).value.trim(); } function ph(id){ return el(id).placeholder; } function reducedMotion(){ try{ return window.matchMedia(“(prefers-reduced-motion: reduce)”).matches; }catch(e){ return false; } } function motionPaused(){ return document.body.classList.contains(“motion-paused”); } function noMotion(){ return reducedMotion() ? true : motionPaused(); } function announce(msg){ el(“srStatus”).textContent=msg; } function escapeHtml(s){ var A=String.fromCharCode(38); var map={}; map[A]=A+”amp;”; map[“”]=A+”gt;”; map[‘”‘]=A+”quot;”; map[“‘”]=A+”#39;”; var re=new RegExp(“[“+A+”\”‘]”,”g”); return String(s).replace(re,function(c){ return map[c]; }); } function escapeAttr(s){ return escapeHtml(s); } function toast(msg){ var t=el(“toast”); t.textContent=msg; t.classList.add(“show”); clearTimeout(t._tm); t._tm=setTimeout(function(){t.classList.remove(“show”);},2200); } function copiedFlash(btn){ if(!btn) return; btn.classList.add(“copied”); clearTimeout(btn._ct); btn._ct=setTimeout(function(){ btn.classList.remove(“copied”); },1500); } /* ===================== CHIPS ===================== */ function makeChip(text,activeVal,onPick,extraClass){ var b=document.createElement(“button”); b.type=”button”; b.className=”chip “+(extraClass||””); b.textContent=text; b.setAttribute(“aria-pressed”, text===activeVal?”true”:”false”); b.onclick=function(){ onPick(text); }; return b; } function setPressed(containerId,v){ document.querySelectorAll(“#”+containerId+” .chip”).forEach(function(n){ n.setAttribute(“aria-pressed”, n.textContent===v?”true”:”false”); }); } function buildChips(){ var ec=el(“expChips”); EXPERIENCES.forEach(function(e){ ec.appendChild(makeChip(e,state.exp,function(v){state.exp=v;setPressed(“expChips”,v);})); }); var sc=el(“styleChips”); STYLES.forEach(function(s){ sc.appendChild(makeChip(s,state.style,function(v){ state.style=v; setPressed(“styleChips”,v); if(state.result){ generate(true); } }, “style”)); }); var mc=el(“moodChips”); MOODS.forEach(function(m){ mc.appendChild(makeChip(m,state.mood,function(v){state.mood=v;setPressed(“moodChips”,v); if(state.result){ updateCaption(); }},”mood”)); }); } function buildThemeChips(){ var tc=el(“themeChips”); THEMES.forEach(function(t){ var b=document.createElement(“button”); b.type=”button”; b.className=”chip”; b.textContent=t.name; b.setAttribute(“aria-pressed”, t.id===state.theme?”true”:”false”); b.onclick=function(){ state.theme=t.id; document.querySelectorAll(“#themeChips .chip”).forEach(function(n){n.setAttribute(“aria-pressed”,”false”);}); b.setAttribute(“aria-pressed”,”true”); applyTheme(true); }; tc.appendChild(b); }); } function buildFormatChips(){ var formats=[[“square”,”Instagram square”],[“story”,”Instagram story”],[“post”,”Facebook post”],[“pin”,”Pinterest vertical”]]; var fc=el(“formatChips”); formats.forEach(function(f){ var b=document.createElement(“button”); b.type=”button”; b.className=”chip”; b.textContent=f[1]; b.setAttribute(“aria-pressed”, f[0]===state.format?”true”:”false”); b.onclick=function(){ state.format=f[0]; document.querySelectorAll(“#formatChips .chip”).forEach(function(n){n.setAttribute(“aria-pressed”,”false”);}); b.setAttribute(“aria-pressed”,”true”); applyFormat(); }; fc.appendChild(b); }); } function applyFormat(){ var c=el(“shareCard”); c.className=”fcard “+(state.format===”square”?””:state.format); c.setAttribute(“data-theme”,state.theme); updateCardAlt(); } function applyTheme(animate){ var c=el(“shareCard”); c.setAttribute(“data-theme”,state.theme); var th=THEMES.filter(function(x){return x.id===state.theme;})[0]; el(“cardBadge”).textContent=th.badge; document.querySelector(“.fc-stampbox”).style.display = state.theme===”postcard”?”flex”:”none”; if(animate){ if(!noMotion()){ c.classList.remove(“theme-swap”); void c.offsetWidth; c.classList.add(“theme-swap”); } } updateCardAlt(); } /* ===================== GENERATION ===================== */ function gatherInputs(){ var roots=[]; [“root1″,”root2″,”root3”].forEach(function(id){ var v=val(id); if(v) roots.push(v); }); return { roots:roots, livesNow:val(“livesNow”), connectedTo:val(“connectedTo”), words:val(“words”), home:val(“home”) }; } function generate(regen){ var inp=gatherInputs(); if(inp.roots.length<1){ toast("Add at least one root to begin"); announce("Please add at least one root to begin."); el("miniRoot1").focus(); return; } state.lastInputs=inp; if(regen){ state.seed++; } else { state.seed=0; } var seed=state.seed; var canon=checkCanonical(cleanInput(inp.roots[0]), cleanInput(inp.roots[1]||"")); state.canon=canon; var words=createFamilyWord(inp.roots[0], inp.roots[1]||"", inp.roots[2]||"", state.style); if(canon){ words=[canon.word].concat(words.filter(function(w){return w.toLowerCase()!==canon.word.toLowerCase();})); } var word=words[seed % words.length]; var loves=loveCandidates(state.exp, inp.words, inp.home); var love=loves[seed % loves.length]; var meaning=createMeaning(inp.roots, love, inp.home, state.style, seed, canon?canon.meaning:null); var motto=createMotto(inp.roots, love, state.style, seed); var caption=createCaption(word, love, motto, state.style, seed); var story=createStoryLine(inp.roots, inp.livesNow, inp.connectedTo, love, seed); state.result={ word:word, love:love, meaning:meaning, motto:motto, caption:caption, story:story, roots:inp.roots.join(" + ") }; renderResult(regen); } function staged(){ var rows=document.querySelectorAll("#resultWrap .rrow"); rows.forEach(function(r){ r.classList.remove("show"); }); if(noMotion()){ rows.forEach(function(r){ r.classList.add("show"); }); return; } rows.forEach(function(r,ix){ setTimeout(function(){ r.classList.add("show"); }, 140*(ix+1)); }); } function fireStamp(){ var s=el("stampFound"); s.classList.remove("go"); void s.offsetWidth; if(!noMotion()){ s.classList.add("go"); } else { s.style.opacity="1"; } } function pulseRoutes(){ var c=el("collage"); if(noMotion()) return; c.classList.remove("firepulse"); void c.offsetWidth; c.classList.add("firepulse"); } function renderResult(regen){ var r=state.result, lv=LOVE[r.love]; el("preNudge").classList.add("hidden"); el("resultWrap").classList.remove("hidden"); var input=el("rWord"); input.value=r.word; if(!noMotion()){ shuffleWord(input, r.word); } el("rLoveName").textContent=r.love; el("rLoveEmoji").textContent=lv.ic; el("rLoveTip").textContent=lv.tip; el("rMeaning").textContent=r.meaning; el("rLove2").textContent="Your family love language is "+r.love+", namely "+lv.tag+"."; el("rMotto").textContent="\u201C"+r.motto+"\u201D"; el("rStory").textContent=r.story; el("rCaption").textContent=r.caption; updateCardFromState(r.word); staged(); fireStamp(); pulseRoutes(); announce("Generated the family word "+r.word+". Family language type "+r.love+". You can edit the word."); if(!regen){ el("resultWrap").scrollIntoView({behavior:noMotion()?"auto":"smooth", block:"start"}); } } function updateCaption(){ var r=state.result; if(!r) return; r.caption=createCaption(document.getElementById("rWord").value.trim()||r.word, r.love, r.motto, state.style, state.seed); el("rCaption").textContent=r.caption; updateCapPreview(); } function updateCapPreview(){ var r=state.result; if(!r) return; var w=val("rWord")||r.word; el("capPreview").textContent=igCaption(w, r.love, r.motto, r.roots); } function updateCardFromState(wordOverride){ var r=state.result; if(!r) return; var lv=LOVE[r.love]; var w=wordOverride || val("rWord") || r.word; el("cardWord").textContent=w; el("cardRootsTop").textContent=r.roots; el("cardType").textContent=lv.ic+" "+r.love; el("cardMotto").textContent="\u201C"+r.motto+"\u201D"; applyTheme(false); applyFormat(); updateCapPreview(); } function updateCardAlt(){ var r=state.result; if(!r) return; var th=THEMES.filter(function(x){return x.id===state.theme;})[0]; var w=val("rWord")||r.word; el("cardAlt").textContent="Card preview: "+th.alt+" showing the family word "+w+", roots "+r.roots+", family language type "+r.love+", and the line Create yours at TurknoyTravels100.world."; } function shuffleWord(input, finalWord){ var letters="ABCDEFGHIJKLMNOPQRSTUVWXYZ", frames=10, i=0; input.parentNode.classList.add("shuffling"); var iv=setInterval(function(){ var s=""; for(var k=0;k<finalWord.length;k++){ if(kframes){ clearInterval(iv); input.value=finalWord; input.parentNode.classList.remove(“shuffling”); updateCardFromState(); } },45); } /* feedback nudges */ function applyFeedback(style){ state.style=style; setPressed(“styleChips”,style); if(state.result){ generate(false); } toast(“Reforged: “+style.toLowerCase()); } /* live forge preview */ function quickPreview(){ var r1=val(“miniRoot1”)||ph(“miniRoot1”); var r2=val(“miniRoot2”)||ph(“miniRoot2″); var c1=cleanInput(r1), c2=cleanInput(r2); var canon=checkCanonical(c1,c2); var w; if(canon){ w=canon.word; } else { var list=createFamilyWord(r1,r2,””,”Best”); w=list[0]; } var elp=el(“forgePreview”); if(noMotion()){ elp.textContent=w; return; } elp.classList.add(“flip”); setTimeout(function(){ elp.textContent=w; elp.classList.remove(“flip”); }, 170); } function runMini(){ var r1=val(“miniRoot1”)||ph(“miniRoot1”); var r2=val(“miniRoot2”)||ph(“miniRoot2”); el(“root1”).value=r1; el(“root2”).value=r2; el(“root3″).value=””; generate(false); } /* ===================== EXAMPLE CAROUSEL ===================== */ var FAMILIES=[ {r1:”Filipino”, r2:”Turkish”, word:”Turknoy”, type:”ManyHomes Love”, mean:”Turkish and Pinoy, the origin word for a family at home in more than one place.”}, {r1:”Korean”, r2:”Mexican”, word:”Kimchitaco”, type:”Table Love”, mean:”A family table where spice, laughter, and love speak louder than borders.”}, {r1:”Nigerian”, r2:”Japanese”, word:”Naijapon”, type:”Bridge Love”, mean:”A family rhythm built from warmth, respect, and shared care.”}, {r1:”Indian”, r2:”British”, word:”Masalashire”, type:”Translation Love”, mean:”Two languages at one table, seasoned with everyday affection.”}, {r1:”Arab”, r2:”Brazilian”, word:”Habibalegria”, type:”Routes Love”, mean:”Where affection, music, hospitality, and joy become one family language.”}, {r1:”Filipino”, r2:”Finnish”, word:”Filifin”, type:”Time Zone Love”, mean:”Sauna quiet meets island warmth, close across every clock.”} ]; var carTimer=null, carPaused=false; function buildCarousel(){ var box=el(“carousel”); box.innerHTML=””; FAMILIES.forEach(function(f){ var lv=LOVE[f.type]||{ic:”\uD83D\uDC9B”}; var c=document.createElement(“div”); c.className=”famcard”; c.innerHTML= ‘
‘+escapeHtml(f.r1)+” + “+escapeHtml(f.r2)+’
‘+ ‘
‘+escapeHtml(f.word)+’
‘+ ‘‘+lv.ic+” “+escapeHtml(f.type)+’‘+ ‘
‘+escapeHtml(f.mean)+’
‘; var btn=document.createElement(“button”); btn.className=”btn btn-soft btn-sm”; btn.textContent=”Try this mix”; btn.onclick=function(){ tryMix(f.r1,f.r2); }; c.appendChild(btn); box.appendChild(c); }); } function carAdvance(){ var box=el(“carousel”); var max=box.scrollWidth-box.clientWidth-4; if(box.scrollLeft>=max){ box.scrollTo({left:0,behavior:noMotion()?”auto”:”smooth”}); } else { box.scrollBy({left:318,behavior:noMotion()?”auto”:”smooth”}); } } function carStart(){ if(noMotion()){ return; } if(carPaused){ return; } clearInterval(carTimer); carTimer=setInterval(carAdvance,4500); } function carStop(){ clearInterval(carTimer); } function tryMix(r1,r2){ el(“miniRoot1”).value=r1; el(“miniRoot2”).value=r2; quickPreview(); el(“forge”).scrollIntoView({behavior:noMotion()?”auto”:”smooth”, block:”center”}); setTimeout(function(){ runMini(); }, noMotion()?0:420); } /* ===================== STEPPER ===================== */ var STEPS=[ {n:”01″, h:”Add your roots”, p:”Two or three cultures, countries, languages, or places that made your family.”, ic:”\uD83C\uDF0D”, big:”Two roots”, cap:”Filipino + Turkish, or any mix that is yours.”}, {n:”02″, h:”Forge the word”, p:”Watch the roots blend into one word in the live preview, then make it.”, ic:”\uD83E\uDDEC”, big:”Turknoy”, cap:”Two roots go in. One family word comes out.”}, {n:”03″, h:”Get your result”, p:”A word, a family language type, a meaning, a motto, and a caption. Edit the word freely.”, ic:”\u2728″, big:”Your result”, cap:”Nudge it more poetic, funnier, or more name-like.”}, {n:”04″, h:”Theme and share”, p:”Pick a card theme, download a story card, copy your caption, and save to your local wall.”, ic:”\uD83D\uDCEE”, big:”Share it”, cap:”Six themes, four formats, one screenshot-ready card.”} ]; function buildStepper(){ var track=el(“steptrack”); STEPS.forEach(function(s,ix){ var row=document.createElement(“button”); row.className=”steprow”; row.type=”button”; row.setAttribute(“role”,”tab”); row.setAttribute(“aria-selected”, ix===0?”true”:”false”); row.innerHTML=’‘+s.n+’

‘+escapeHtml(s.h)+’

‘+escapeHtml(s.p)+’

‘; row.onclick=function(){ selectStep(ix); }; track.appendChild(row); }); selectStep(0); } function selectStep(ix){ document.querySelectorAll(“#steptrack .steprow”).forEach(function(r,i){ r.setAttribute(“aria-selected”, i===ix?”true”:”false”); }); var s=STEPS[ix]; var pv=el(“stepPreview”); pv.innerHTML=’
‘+s.ic+’
‘+escapeHtml(s.big)+’
‘+escapeHtml(s.cap)+’
‘; } /* ===================== WORD WALL ===================== */ function buildWallFilter(){ var sel=el(“wallFilter”); sel.innerHTML=””; var all=document.createElement(“option”); all.value=””; all.textContent=”All family language types”; sel.appendChild(all); Object.keys(LOVE).forEach(function(t){ var o=document.createElement(“option”); o.value=t; o.textContent=LOVE[t].ic+” “+t; sel.appendChild(o); }); sel.onchange=renderWall; } function updateWallCount(){ var data=loadWall(); var mine=data.filter(function(e){ return !e.sample; }).length; el(“wallCount”).textContent = (mine===1 ? “1 family word” : mine+” family words”) + ” saved on this device”; } function renderWall(newWord){ var grid=el(“wallGrid”), data=loadWall(); var q=el(“wallSearch”).value.toLowerCase().trim(); var f=el(“wallFilter”).value; var filtered=data.filter(function(e){ var hay=(e.word+” “+e.roots+” “+e.meaning+” “+(e.name||””)+” “+(e.region||””)).toLowerCase(); var okq = q ? (hay.indexOf(q)>-1) : true; var okf = f ? (e.type===f) : true; return bAND(okq, okf); }); grid.innerHTML=””; if(filtered.length===0){ grid.innerHTML=’
\uD83D\uDDFA\uFE0F

No words here yet.
Make your family word above, then add the first word to your local wall.

‘; updateWallCount(); return; } filtered.forEach(function(e){ var lv=LOVE[e.type]||{ic:”\uD83D\uDC9B”}; var card=document.createElement(“div”); card.className=”wcard”; if(newWord){ if(e.word===newWord){ if(!e.sample){ card.className=”wcard enter”; } } } var badge=e.sample?’Global seed‘:”; var parts=String(e.roots).split(“+”); var pr1=(parts[0]||””).trim(), pr2=(parts[1]||””).trim(); var del=e.sample?”:’‘; card.innerHTML=badge+ ‘
‘+escapeHtml(e.word)+’
‘+ ‘‘+lv.ic+’ ‘+escapeHtml(e.type)+’‘+ ‘
‘+escapeHtml(e.roots)+’
‘+ ‘
‘+escapeHtml(e.meaning)+’
‘+ (e.name?’
From ‘+escapeHtml(e.name)+’
‘:”)+ ‘
‘+ ‘
‘+escapeHtml(e.region||”Worldwide”)+’ \u00B7 ‘+escapeHtml(e.date)+’‘+del+’
‘+ ‘
Create yours at TurknoyTravels100.world
‘; grid.appendChild(card); }); grid.querySelectorAll(“.wc-del”).forEach(function(b){ b.onclick=function(){ var w=b.getAttribute(“data-word”),d=b.getAttribute(“data-date”); saveWall(loadWall().filter(function(x){ var same = (x.word===w) ? ((x.date===d) ? (!x.sample) : false) : false; return !same; })); renderWall(); toast(“Removed from your local wall”); announce(“Removed “+w+” from your local wall.”); }; }); grid.querySelectorAll(“.wc-try”).forEach(function(b){ b.onclick=function(){ tryMix(b.getAttribute(“data-r1”), b.getAttribute(“data-r2”)); }; }); updateWallCount(); } function addToWall(){ if(!state.result){ toast(“Make a word first”); return; } if(!el(“consentBox”).checked){ toast(“Please confirm the consent box first”); announce(“Please confirm the consent box before adding to the wall.”); return; } var r=state.result, w=val(“rWord”)||r.word; var entry={ word:w, roots:r.roots, type:r.love, meaning:r.meaning, name:val(“displayName”), region:val(“displayRegion”)||”Worldwide”, date:new Date().toLocaleDateString(undefined,{year:”numeric”,month:”short”,day:”numeric”}), sample:false }; var a=loadWall(); a.unshift(entry); saveWall(a); el(“wallSearch”).value=””; el(“wallFilter”).value=””; renderWall(w); toast(“Added to your local wall”); announce(“Added “+w+” to your local Word Wall.”); el(“wall”).scrollIntoView({behavior:noMotion()?”auto”:”smooth”, block:”start”}); } function clearWall(){ var ok=window.confirm(“Clear all the family words you saved on this device? The global seed examples will stay. This cannot be undone.”); if(!ok) return; saveWall(loadWall().filter(function(x){ return x.sample; })); renderWall(); toast(“Your local wall was cleared”); announce(“Cleared your local Word Wall.”); } /* ===================== EXPORT / COPY / SHARE ===================== */ function downloadCard(){ var node=el(“shareCard”); var ok=false; if(window.htmlToImage){ if(htmlToImage.toPng){ ok=true; } } if(ok){ htmlToImage.toPng(node,{pixelRatio:2,cacheBust:true}) .then(function(url){ var a=document.createElement(“a”); a.download=”ManyRoots-“+(state.result?state.result.word:”card”)+”-“+state.theme+”-“+state.format+”.png”; a.href=url; a.click(); toast(“Card downloaded as PNG”); }) .catch(function(){ toast(“PNG export is blocked here. It works on the live hosted page.”); }); } else { toast(“PNG export library not loaded. See README to connect it.”); } } function copyText(txt,msg,btn){ var can=false; if(navigator.clipboard){ if(navigator.clipboard.writeText){ can=true; } } if(can){ navigator.clipboard.writeText(txt).then(function(){ toast(msg||”Copied”); copiedFlash(btn); }).catch(function(){ fallbackCopy(txt,msg,btn); }); } else { fallbackCopy(txt,msg,btn); } } function fallbackCopy(txt,msg,btn){ var ta=document.createElement(“textarea”); ta.value=txt; ta.style.position=”fixed”; ta.style.opacity=”0″; document.body.appendChild(ta); ta.select(); try{ document.execCommand(“copy”); toast(msg||”Copied”); copiedFlash(btn); }catch(e){ toast(“Copy not supported”); } document.body.removeChild(ta); } function shareNow(){ if(!state.result) return; var r=state.result, w=val(“rWord”)||r.word; var txt=createShareText(w, r.love, r.motto, state.seed); if(navigator.share){ navigator.share({title:”Our Family Language: “+w, text:txt, url:DEPLOYED_APP_URL}).catch(function(){ copyText(txt,”Share text copied”); }); } else { copyText(txt,”Share text copied”); } } function shuffleLook(){ var t=THEMES[Math.floor(Math.random()*THEMES.length)]; var fmts=[“square”,”story”,”post”,”pin”]; var fm=fmts[Math.floor(Math.random()*fmts.length)]; state.theme=t.id; state.format=fm; document.querySelectorAll(“#themeChips .chip”).forEach(function(n){ n.setAttribute(“aria-pressed”, n.textContent===t.name?”true”:”false”); }); document.querySelectorAll(“#formatChips .chip”).forEach(function(n){ n.setAttribute(“aria-pressed”,”false”); }); var fmtLabel={square:”Instagram square”,story:”Instagram story”,post:”Facebook post”,pin:”Pinterest vertical”}[fm]; document.querySelectorAll(“#formatChips .chip”).forEach(function(n){ if(n.textContent===fmtLabel){ n.setAttribute(“aria-pressed”,”true”); } }); applyTheme(true); applyFormat(); toast(“New look: “+t.name); } /* ===================== HERO ANIMATIONS ===================== */ var MORPH=[“Turknoy”,”Kimchitaco”,”Naijapon”,”Filifin”,”Masalashire”,”Habibalegria”]; var morphTimer=null, mi=0; function startMorph(){ if(noMotion()){ el(“morphWord”).textContent=MORPH[0]; el(“twCursor”).style.display=”none”; return; } var node=el(“morphWord”); var cur=””, target=MORPH[mi], typing=true, ci=0; clearInterval(morphTimer); morphTimer=setInterval(function(){ if(motionPaused()) return; if(typing){ ci++; node.textContent=target.slice(0,ci); if(ci>=target.length){ typing=false; setTimeout(function(){},10); } } else { ci–; node.textContent=target.slice(0,Math.max(0,ci)); if(ci560){ bar.classList.add(“show”); } else { bar.classList.remove(“show”); } } window.addEventListener(“scroll”, onScroll, {passive:true}); onScroll(); el(“moMake”).onclick=function(){ el(“forge”).scrollIntoView({behavior:noMotion()?”auto”:”smooth”,block:”center”}); el(“miniRoot1”).focus(); }; el(“moCard”).onclick=function(){ if(state.result){ el(“shareCard”).scrollIntoView({behavior:noMotion()?”auto”:”smooth”,block:”center”}); } else { toast(“Make your family word first”); el(“forge”).scrollIntoView({behavior:noMotion()?”auto”:”smooth”,block:”center”}); } }; el(“moWall”).onclick=function(){ el(“wall”).scrollIntoView({behavior:noMotion()?”auto”:”smooth”,block:”start”}); }; } /* ===================== DEBUG PANEL ===================== */ function initDebug(){ if(location.search.indexOf(“debug=true”)===-1) return; var p=el(“debugPanel”); p.classList.add(“show”); el(“debugClose”).onclick=function(){ p.classList.remove(“show”); }; function det(sel,attr){ var n=document.querySelector(sel); return n?n.getAttribute(attr):”(none)”; } var can=det(‘link[rel=”canonical”]’,”href”); var ogu=det(‘meta[property=”og:url”]’,”content”); var ogi=det(‘meta[property=”og:image”]’,”content”); var twi=det(‘meta[name=”twitter:image”]’,”content”); function ynRow(label,good,detail){ return ‘
‘+label+’‘+(good?”OK”:”CHECK”)+(detail?(” “+detail):””)+’
‘; } function valRow(label,v){ return ‘
‘+label+’‘+escapeHtml(v)+’
‘; } var canOk = (can===DEPLOYED_APP_URL); var oguOk = (ogu===DEPLOYED_APP_URL); var ogiOk = (ogi===OG_IMAGE_URL); var twiOk = (twi===OG_IMAGE_URL); var allUrlOk = bAND(bAND(canOk,oguOk), bAND(ogiOk,twiOk)); var h2i=false; if(window.htmlToImage){ if(htmlToImage.toPng){ h2i=true; } } var html=””; html+=valRow(“DEPLOYED_APP_URL”, DEPLOYED_APP_URL); html+=valRow(“BRAND_HOME_URL”, BRAND_HOME_URL); html+=valRow(“OG_IMAGE_URL”, OG_IMAGE_URL); html+=valRow(“location.href”, location.href); html+=valRow(“canonical detected”, can); html+=valRow(“og:url detected”, ogu); html+=valRow(“og:image detected”, ogi); html+=valRow(“twitter:image detected”, twi); html+=ynRow(“canonical matches”, canOk); html+=ynRow(“og:url matches”, oguOk); html+=ynRow(“og:image matches”, ogiOk); html+=ynRow(“twitter:image matches”, twiOk); html+=ynRow(“ALL url values match”, allUrlOk); html+=ynRow(“placeholder not used”, !isPlaceholder(DEPLOYED_APP_URL)); html+=ynRow(“html-to-image loaded”, h2i); html+=ynRow(“localStorage available”, lsAvailable()); html+=ynRow(“reduced motion detected”, reducedMotion(), reducedMotion()?”(on)”:”(off)”); el(“debugBody”).innerHTML=html; } /* ===================== INIT ===================== */ document.addEventListener(“DOMContentLoaded”, function(){ syncDeploymentUrls(); buildChips(); buildThemeChips(); buildFormatChips(); buildWallFilter(); renderWall(); buildCarousel(); buildStepper(); initMobar(); initDebug(); document.querySelector(“.fc-stampbox”).style.display=”none”; /* refine + generate */ el(“generateBtn”).onclick=function(){ generate(false); }; el(“regenBtn”).onclick=function(){ generate(true); }; /* card actions */ el(“downloadBtn”).onclick=downloadCard; el(“heroDownloadBtn”).onclick=function(){ if(!state.result){ runMini(); setTimeout(downloadCard, noMotion()?60:520); } else { el(“shareCard”).scrollIntoView({behavior:noMotion()?”auto”:”smooth”,block:”center”}); setTimeout(downloadCard, 120); } }; el(“copyIgBtn”).onclick=function(){ if(state.result){ var w=val(“rWord”)||state.result.word; copyText(igCaption(w,state.result.love,state.result.motto,state.result.roots),”Instagram caption copied”, el(“copyIgBtn”)); } }; el(“copyStoryBtn”).onclick=function(){ if(state.result){ var w=val(“rWord”)||state.result.word; copyText(storyCaption(w,state.result.love,state.result.motto,state.result.story),”Family story caption copied”, el(“copyStoryBtn”)); } }; el(“shareBtn”).onclick=shareNow; el(“shuffleLook”).onclick=shuffleLook; el(“addWallBtn”).onclick=addToWall; el(“clearWallBtn”).onclick=clearWall; el(“wallSearch”).oninput=function(){ renderWall(); }; el(“consentBox”).onchange=function(){ el(“addWallBtn”).disabled=!this.checked; }; /* editable word updates the card live */ el(“rWord”).addEventListener(“input”, function(){ if(state.result){ updateCardFromState(); updateCardAlt(); } }); /* feedback nudges */ document.querySelectorAll(“#fbBtns .fbtn”).forEach(function(b){ b.onclick=function(){ applyFeedback(b.getAttribute(“data-style”)); }; }); /* forge */ el(“miniBtn”).onclick=runMini; el(“miniRoot1”).addEventListener(“input”, quickPreview); el(“miniRoot2”).addEventListener(“input”, quickPreview); el(“miniRoot2”).addEventListener(“keydown”, function(e){ if(e.key===”Enter”){ runMini(); } }); document.querySelectorAll(“.forge-chips .ex”).forEach(function(b){ b.onclick=function(){ document.querySelectorAll(“.forge-chips .ex”).forEach(function(x){ x.classList.remove(“sel”); }); b.classList.add(“sel”); el(“miniRoot1”).value=b.getAttribute(“data-r1”); el(“miniRoot2”).value=b.getAttribute(“data-r2”); quickPreview(); runMini(); }; }); /* carousel controls */ el(“carPrev”).onclick=function(){ el(“carousel”).scrollBy({left:-318,behavior:noMotion()?”auto”:”smooth”}); }; el(“carNext”).onclick=function(){ el(“carousel”).scrollBy({left:318,behavior:noMotion()?”auto”:”smooth”}); }; el(“carPause”).onclick=function(){ carPaused=!carPaused; var b=el(“carPause”); b.setAttribute(“aria-pressed”, carPaused?”true”:”false”); b.innerHTML=carPaused?”\u25B6″:”\u23F8″; if(carPaused){ carStop(); } else { carStart(); } }; el(“carousel”).addEventListener(“mouseenter”, carStop); el(“carousel”).addEventListener(“mouseleave”, function(){ if(!carPaused){ carStart(); } }); /* motion toggle */ el(“motionToggle”).onclick=toggleMotion; /* start ambient motion */ startMorph(); startWom(); carStart(); });