Heading 1
Heading 2
Heading 3
This is some text inside of a div block.
Turn scattered ideas into work that
runs itself.
DLJK LLC helps businesses and organizations build clear, credible systems through website development, digital services, business consulting, and organizational support.
Four ways to build momentum
Structured services that trade complexity and disarray for elegant workflows and functional design.

Website Development
Clean, credible digital homes for businesses with somewhere to go.

Digital Services
Constructing the pipes and forms that make a digital operation run.

Business Consulting
A practical second set of eyes for the moving parts of your business.

Organizational support
Maintaining steady, usable systems behind the visible work.
Your Vision.
Our Support.
You don't need a big agency to move an idea forward. DLJK LLC. understands the goal, identifies the right pieces, and helps assemble them with care — creativity, technology, organization, and business support, in the proportion your work actually needs.
A clear route from idea to motion
No overcomplication. Every engagement starts with understanding the real needs and ends with something you can use.
Understand
Learn your goals, needs, constraints, and what's currently getting in the way.
Plan
Identify the right tools, services, priorities, and next steps for the work.
Build
Create the website, system, resource, or structure that makes the plan tangible.
Support
Help you move forward practically with updates, guidance, and continued clarity.
Your business deserves a website that works for you
Your website is often the first impression of your business. DLJK LLC. builds clean, credible, professional sites that make it easier for the right people to understand what you do and take the next step.

New Websites

Website Redesigns

CMS Content

Ongoing Support
Explore Our Services
For the work that has somewhere to go
small businesses
Entrepreneurs
Startups
Nonprofits and organizations
Service providers
Community organizations
Professionals
organizational support
Built to be useful
Portfolio in progress
websites
Site & digital projects
Designed to make a business legible at a glance.
digital projects
Systems that stick
Resources and solutions that keep work moving.
support
Business support
Organization, workflows, consulting, and implementation.
Have an idea?
Let's talk.
Whether you need a new website, better business organization, or support with a digital project, start by sharing what you're working on.
Let's Talk
document.addEventListener("DOMContentLoaded", () => {
init();
});
function init() {
gsap.registerPlugin(CustomEase);
const smoothEase = CustomEase.create("smoothEase", ".32, .72, 0, 1");
// Run both animations
initSecondaryButtonTilt();
initButtonDotHover(smoothEase);
svgHover();
tagsFallAnim();
workAnim();
frontCardsAnim();
}
function initButtonDotHover(smoothEase) {
document.querySelectorAll(".btn").forEach((btn) => {
const bg = btn.querySelector(".btn-bg");
const dot = btn.querySelector(".btn-dot");
const text = btn.querySelector(".btn-text");
if (!bg || !dot || !text) return;
const enterTl = gsap
.timeline({ paused: true })
.to(
bg,
{ scaleX: 1.02, scaleY: 1.07, duration: 0.5, ease: smoothEase },
0
)
.to(text, { x: -5, duration: 0.5, ease: smoothEase }, 0)
.to(
dot,
{
scaleX: 0.23,
scaleY: 0.2,
y: -19.2,
duration: 0.2,
ease: "power1.in",
},
0
)
.to(
dot,
{
scaleX: 0.21,
scaleY: 0.76,
y: -1.6,
borderRadius: 4,
duration: 0.36,
ease: "back.out(2.2)",
},
0.2
);
function playEnter() {
enterTl.timeScale(1);
enterTl.play();
}
function playLeave() {
enterTl.timeScale(1.2).reverse();
}
btn.addEventListener("mouseenter", playEnter);
btn.addEventListener("mouseleave", playLeave);
btn.addEventListener("focus", playEnter);
btn.addEventListener("blur", playLeave);
});
}
function initSecondaryButtonTilt() {
document.querySelectorAll(".btn.secondary").forEach((btn) => {
const text = btn.querySelector(".btn-text");
if (!text) return;
const btn2Tl = gsap
.timeline({ paused: true })
.to(btn, { scale: 1.05, rotateZ: 10, duration: 0.4 })
.to(text, { rotateZ: -10, duration: 0.4 }, "<");
function playEnter() {
btn2Tl.timeScale(1);
btn2Tl.play();
}
function playLeave() {
btn2Tl.timeScale(1.2).reverse();
}
btn.addEventListener("mouseenter", playEnter);
btn.addEventListener("mouseleave", playLeave);
btn.addEventListener("focus", playEnter);
btn.addEventListener("blur", playLeave);
});
}
function svgHover() {
const mm = gsap.matchMedia();
mm.add("(hover: hover) and (pointer: fine)", () => {
const wrap = document.querySelector(".layout.websites");
const items = gsap.utils.toArray(".hightlights", wrap);
const imgs = gsap.utils.toArray(".highlights-img", wrap);
const dist = 20;
// Stack all images, show only the first
gsap.set(imgs, { display: "block", autoAlpha: 0, y: dist });
gsap.set(imgs[0], { autoAlpha: 1, y: 0 });
let current = 0;
let tl;
const handlers = items.map((item, i) => {
const handler = () => {
if (i === current) return;
// Stop any running sequence so fast hovering never stacks animations
if (tl) tl.kill();
tl = gsap.timeline();
// 1. Everything else fades out and drifts up
tl.to(
imgs.filter((img) => img !== imgs[i]),
{
autoAlpha: 0,
y: -dist,
duration: 0.3,
ease: "power2.in",
overwrite: true,
}
);
// 2. Only after that, the new image rises in from below
tl.fromTo(
imgs[i],
{ autoAlpha: 0, y: dist },
{
autoAlpha: 1,
y: 0,
duration: 0.6,
ease: "power3.out",
overwrite: true,
}
);
current = i;
};
item.addEventListener("mouseenter", handler);
return handler;
});
return () => {
if (tl) tl.kill();
items.forEach((item, i) =>
item.removeEventListener("mouseenter", handlers[i])
);
gsap.set(imgs, { clearProps: "all" });
};
});
}
function tagsFallAnim() {
const mm = gsap.matchMedia();
// Pointer devices only. Reduced motion users get nothing.
mm.add(
"(hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference)",
() => {
const section = document.querySelector(".section.audience");
const tags = gsap.utils.toArray(".audience-tag", section);
const GROUND_PADDING = 12; // gap between the tags and the section's bottom edge
const RETURN_DELAY = 1.2; // seconds spent lying on the ground
const RETURN_TIME = 2; // slow return to place
const state = new WeakMap(); // tag -> { falling: boolean, tl: timeline }
const handlers = tags.map((tag) => {
state.set(tag, { falling: false, tl: null });
const onEnter = () => {
const s = state.get(tag);
if (s.falling) return; // already dropping, let it land
if (s.tl) s.tl.kill(); // interrupted mid-return: fall again from where it is
// Distance from the tag's natural position to the ground
const currentY = gsap.getProperty(tag, "y");
const naturalBottom = tag.getBoundingClientRect().bottom - currentY;
const groundBottom =
section.getBoundingClientRect().bottom - GROUND_PADDING;
const dist = Math.max(0, groundBottom - naturalBottom);
const fall = Math.max(1.2, Math.min(2.4, dist / 250)); // slower fall
s.falling = true;
s.tl = gsap.timeline();
s.tl
// Fall: bounce.out reads as gravity plus a bounce on impact
.to(
tag,
{
y: dist,
x: gsap.utils.random(-25, 25),
duration: fall,
ease: "bounce.out",
onComplete: () => {
s.falling = false;
},
},
0
)
// Tilt while dropping (bounce.out first hits the ground at about 36% of the duration)
.to(
tag,
{
rotation: gsap.utils.random(-30, 30),
duration: fall * 0.36,
ease: "power1.in",
},
0
)
// Straighten out flat as it lands
.to(
tag,
{
rotation: 0,
duration: fall * 0.3,
ease: "power2.out",
},
fall * 0.36
)
// Rest on the ground, then drift slowly back home
.to(
tag,
{
y: 0,
x: 0,
rotation: 0,
duration: RETURN_TIME,
ease: "power3.inOut",
},
`+=${RETURN_DELAY}`
);
};
tag.addEventListener("mouseenter", onEnter);
return onEnter;
});
// Cleanup if the media query stops matching
return () => {
tags.forEach((tag, i) => {
tag.removeEventListener("mouseenter", handlers[i]);
const s = state.get(tag);
if (s && s.tl) s.tl.kill();
});
gsap.set(tags, { clearProps: "all" });
};
}
);
}
function frontCardsAnim() {
const mm = gsap.matchMedia();
// Pointer devices only, so touch devices never run this
mm.add("(hover: hover) and (pointer: fine)", () => {
const cards = gsap.utils.toArray(".front-card");
const cleanups = cards.map((card) => {
const anim = card.querySelector(".front-card-anim");
const texts = card.querySelectorAll(".text-md"); // both texts, h3 stays visible
const tl = gsap
.timeline({ paused: true, defaults: { ease: "power3.out" } })
.to(anim, { opacity: 1, duration: 0.3 })
.to(anim, { scale: 1, duration: 0.5 }, "<")
.to(texts, { opacity: 0, duration: 0.3 }, "<");
const enter = () => tl.play();
const leave = () => tl.reverse();
card.addEventListener("mouseenter", enter);
card.addEventListener("mouseleave", leave);
return () => {
card.removeEventListener("mouseenter", enter);
card.removeEventListener("mouseleave", leave);
tl.kill();
gsap.set([anim, texts], { clearProps: "all" });
};
});
return () => cleanups.forEach((fn) => fn());
});
}
function workAnim() {
const colors = [
{ bg: "#2e5d86", ink: "#fff" },
{ bg: "#6f8c7b", ink: "#fff" },
{ bg: "#1b2c46", ink: "#fff" },
{ bg: "#181511", ink: "#fff" },
];
const items = [...document.querySelectorAll(".works-row")].map((row, i) => {
const { bg, ink } = colors[i] || colors[0];
const tl = gsap
.timeline({
paused: true,
defaults: {
duration: 0.2,
ease: "power3.in",
easeReverse: "power3.out",
overwrite: "auto",
},
})
.to(row, { backgroundColor: bg }, 0)
.to(
row.querySelectorAll(".text-sm, .text-works, .text-md, .work-tag"),
{ color: ink, borderColor: ink },
0
)
.to(
row.querySelector(".works-arrow"),
{ rotation: 45, filter: "invert(1)" },
0
);
return { row, tl };
});
// Mouse and pen: hover in and out
items.forEach(({ row, tl }) => {
row.addEventListener(
"pointerenter",
(e) => e.pointerType !== "touch" && tl.play()
);
row.addEventListener(
"pointerleave",
(e) => e.pointerType !== "touch" && tl.reverse()
);
});
// Touch: color whichever row is under the finger, even while scrolling
let active = null;
let release;
const setActive = (item) => {
if (item === active) return;
active?.tl.reverse();
item?.tl.play();
active = item;
};
const track = (e) => {
release?.kill();
const t = e.touches[0];
const el = document.elementFromPoint(t.clientX, t.clientY);
const row = el && el.closest(".works-row");
setActive(items.find((it) => it.row === row) || null);
};
const end = () => {
release = gsap.delayedCall(0.3, () => setActive(null)); // brief hold so a tap registers
};
document.addEventListener("touchstart", track, { passive: true });
document.addEventListener("touchmove", track, { passive: true });
document.addEventListener("touchend", end);
document.addEventListener("touchcancel", end);
}