Author SHA1 Message Date
dependabot[bot]andGitHub 1129c79699 Bump esbuild in /public in the npm_and_yarn group across 1 directory
Bumps the npm_and_yarn group with 1 update in the /public directory: [esbuild](https://github.com/evanw/esbuild).


Updates `esbuild` from 0.21.5 to 0.25.12
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG-2024.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.21.5...v0.25.12)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-version: 0.25.12
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <[email protected]>
2025-12-13 01:01:04 +00:00
28 changed files with 1667 additions and 4245 deletions
-21
View File
@@ -1,21 +0,0 @@
name: Update dependencies
on:
workflow_dispatch:
schedule:
- cron: "0 3 * * *"
permissions:
actions: write
contents: write
issues: write
pull-requests: write
jobs:
update:
uses: lukaszraczylo/shared-actions/.github/workflows/renovate-autoupdate.yaml@main
with:
go: false
node-working-directory: public
require-node-tests: false
release-workflow: deploy.yml
+7 -43
View File
@@ -4,58 +4,22 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#3b82f6" />
<!-- Primary Meta Tags -->
<title>BEAT - Balanced. Empowered. Async. Teams.</title>
<meta name="description" content="The BEAT Manifesto - A software delivery methodology built for how developers actually work. Deep work, async communication, individual autonomy, sustainable pace." />
<meta name="keywords" content="BEAT, software development methodology, agile alternative, remote work, async communication, deep work, developer productivity" />
<meta name="author" content="Lukasz Raczylo" />
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website" />
<meta property="og:title" content="BEAT - Balanced. Empowered. Async. Teams." />
<meta property="og:description" content="A software delivery methodology built for how developers actually work." />
<meta property="og:site_name" content="BEAT Manifesto" />
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:title" content="BEAT - Balanced. Empowered. Async. Teams." />
<meta property="twitter:description" content="A software delivery methodology built for how developers actually work." />
<!-- Preconnect for performance -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="dns-prefetch" href="https://cdnjs.cloudflare.com" />
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<!-- Dark mode initialization (prevents flash) -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
<script>
(function() {
const theme = localStorage.theme;
const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (theme === 'dark' || (!theme && systemDark)) {
document.documentElement.classList.add('dark');
}
})();
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
</script>
</head>
<body class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 transition-colors duration-300 antialiased">
<!-- Skip to main content link for accessibility -->
<a href="#main-content" class="skip-link">Skip to main content</a>
<body class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 transition-colors duration-300">
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
<!-- No-JS fallback -->
<noscript>
<div style="padding: 2rem; text-align: center; font-family: system-ui, sans-serif;">
<h1 style="font-size: 1.5rem; margin-bottom: 1rem;">JavaScript Required</h1>
<p>This website requires JavaScript to function properly. Please enable JavaScript in your browser settings.</p>
</div>
</noscript>
</body>
</html>
+918 -1143
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -10,13 +10,13 @@
},
"dependencies": {
"vue": "^3.4.21",
"vue-router": "^5.0.0"
"vue-router": "^4.3.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.0",
"@vitejs/plugin-vue": "^5.0.4",
"autoprefixer": "^10.4.18",
"postcss": "^8.4.35",
"tailwindcss": "^3.4.1",
"vite": "^8.0.0"
"vite": "^7.2.7"
}
}
+7 -68
View File
@@ -1,25 +1,14 @@
<script setup>
import { onMounted } from 'vue'
import NavBar from '@/components/layout/NavBar.vue'
import Footer from '@/components/layout/Footer.vue'
import ReadingProgress from '@/components/layout/ReadingProgress.vue'
onMounted(() => {
document.documentElement.style.scrollBehavior = 'smooth'
})
</script>
<template>
<div class="min-h-screen flex flex-col bg-white dark:bg-gray-900 transition-colors duration-300">
<ReadingProgress />
<div class="min-h-screen flex flex-col">
<NavBar />
<main class="flex-1">
<router-view v-slot="{ Component }">
<transition
name="page"
mode="out-in"
appear
>
<transition name="fade" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
@@ -29,63 +18,13 @@ onMounted(() => {
</template>
<style>
/* Page transition animations */
.page-enter-active,
.page-leave-active {
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s ease;
}
.page-enter-from {
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: translateY(20px) scale(0.98);
}
.page-leave-to {
opacity: 0;
transform: translateY(-10px) scale(0.98);
}
.page-enter-to,
.page-leave-from {
opacity: 1;
transform: translateY(0) scale(1);
}
/* Ensure content is visible during transition */
.page-enter-active > *,
.page-leave-active > * {
will-change: opacity, transform;
}
/* Improved focus visible styles for accessibility */
:focus-visible {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
.dark :focus-visible {
outline-color: #60a5fa;
}
/* Remove focus outline for mouse users, keep for keyboard */
:focus:not(:focus-visible) {
outline: none;
}
/* Smooth scroll behavior */
html {
scroll-behavior: smooth;
}
/* Reduce motion for users who prefer it */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
</style>
+21 -491
View File
@@ -2,536 +2,66 @@
@tailwind components;
@tailwind utilities;
@layer base {
/* Ensure smooth scrolling */
html {
scroll-behavior: smooth;
-webkit-tap-highlight-color: transparent;
}
/* Better touch targets on mobile */
button, a {
touch-action: manipulation;
}
/* Selection colors */
::selection {
@apply bg-blue-500/30 text-blue-900 dark:text-blue-100;
}
/* Improved focus visible for accessibility */
:focus-visible {
@apply outline-2 outline-offset-2 outline-blue-500;
}
.dark :focus-visible {
@apply outline-blue-400;
}
/* Skip link for accessibility */
.skip-link {
@apply sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:px-4 focus:py-2 focus:bg-blue-600 focus:text-white focus:rounded-lg;
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
@apply bg-gray-100 dark:bg-gray-800;
}
::-webkit-scrollbar-thumb {
@apply bg-gray-300 dark:bg-gray-600 rounded-full;
}
::-webkit-scrollbar-thumb:hover {
@apply bg-gray-400 dark:bg-gray-500;
}
/* Responsive base styles */
body {
@apply text-sm sm:text-base;
overflow-x: hidden;
}
}
@layer components {
/* Container that adapts to all screen sizes */
.container-responsive {
@apply w-full mx-auto px-4 sm:px-6 lg:px-8 xl:px-12 2xl:max-w-7xl 3xl:max-w-8xl 4xl:max-w-9xl;
}
/* Enhanced glass morphism */
.glass {
@apply bg-white/80 dark:bg-gray-800/80 backdrop-blur-xl border border-white/30 dark:border-gray-700/50;
box-shadow:
0 4px 6px -1px rgba(0, 0, 0, 0.05),
0 2px 4px -2px rgba(0, 0, 0, 0.05),
inset 0 1px 0 0 rgba(255, 255, 255, 0.6);
@apply bg-white/70 dark:bg-gray-800/70 backdrop-blur-lg border border-white/20 dark:border-gray-700/50;
}
.dark .glass {
box-shadow:
0 4px 6px -1px rgba(0, 0, 0, 0.3),
0 2px 4px -2px rgba(0, 0, 0, 0.2),
inset 0 1px 0 0 rgba(255, 255, 255, 0.05);
}
/* Gradient text with animation */
.gradient-text {
@apply bg-clip-text text-transparent;
background-image: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 50%, #06b6d4 100%);
background-size: 200% 200%;
animation: gradient-shift 8s ease infinite;
@apply bg-gradient-to-r from-blue-600 via-purple-600 to-cyan-600 dark:from-blue-400 dark:via-purple-400 dark:to-cyan-400 bg-clip-text text-transparent;
}
.dark .gradient-text {
background-image: linear-gradient(135deg, #60a5fa 0%, #a78bfa 50%, #22d3ee 100%);
}
@keyframes gradient-shift {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
/* Modern shadow */
.shadow-modern {
box-shadow:
0 20px 25px -5px rgba(0, 0, 0, 0.08),
0 8px 10px -6px rgba(0, 0, 0, 0.05),
0 0 0 1px rgba(0, 0, 0, 0.02);
box-shadow: 0 10px 40px -10px rgba(0, 0, 0, 0.1);
}
.dark .shadow-modern {
box-shadow:
0 20px 25px -5px rgba(0, 0, 0, 0.4),
0 8px 10px -6px rgba(0, 0, 0, 0.2),
0 0 0 1px rgba(255, 255, 255, 0.02);
box-shadow: 0 10px 40px -10px rgba(0, 0, 0, 0.4);
}
/* Primary button with enhanced effects */
.btn-primary {
@apply relative overflow-hidden bg-gradient-to-r from-blue-600 to-purple-600 text-white px-4 sm:px-6 py-2.5 sm:py-3 rounded-xl font-semibold transition-all duration-300;
box-shadow:
0 4px 6px -1px rgba(59, 130, 246, 0.3),
0 2px 4px -2px rgba(59, 130, 246, 0.2),
inset 0 1px 0 0 rgba(255, 255, 255, 0.2);
@apply bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white px-6 py-3 rounded-lg font-medium transition-all duration-300 shadow-lg hover:shadow-xl hover:scale-105;
}
.btn-primary::before {
content: '';
@apply absolute inset-0 bg-gradient-to-r from-purple-600 to-blue-600 opacity-0 transition-opacity duration-300;
}
.btn-primary:hover {
@apply scale-105;
box-shadow:
0 10px 15px -3px rgba(59, 130, 246, 0.4),
0 4px 6px -4px rgba(59, 130, 246, 0.3),
inset 0 1px 0 0 rgba(255, 255, 255, 0.2);
}
.btn-primary:hover::before {
@apply opacity-100;
}
.btn-primary:active {
@apply scale-100;
}
.btn-primary > * {
@apply relative z-10;
}
/* Secondary button */
.btn-secondary {
@apply glass text-gray-900 dark:text-gray-100 px-4 sm:px-6 py-2.5 sm:py-3 rounded-xl font-semibold transition-all duration-300;
@apply glass hover:shadow-lg text-gray-900 dark:text-gray-100 px-6 py-3 rounded-lg font-medium transition-all duration-300 hover:scale-105;
}
.btn-secondary:hover {
@apply scale-105;
box-shadow:
0 10px 15px -3px rgba(0, 0, 0, 0.1),
0 4px 6px -4px rgba(0, 0, 0, 0.05);
}
.dark .btn-secondary:hover {
box-shadow:
0 10px 15px -3px rgba(0, 0, 0, 0.4),
0 4px 6px -4px rgba(0, 0, 0, 0.2);
}
/* Section titles - responsive */
.section-title {
@apply text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold text-gray-900 dark:text-gray-100 mb-3 sm:mb-4 tracking-tight;
letter-spacing: -0.02em;
@apply text-3xl md:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4;
}
.section-subtitle {
@apply text-base sm:text-lg md:text-xl text-gray-600 dark:text-gray-300 px-2 sm:px-0 leading-relaxed;
@apply text-lg text-gray-600 dark:text-gray-300;
}
/* Enhanced card with 3D hover */
.card {
@apply glass p-4 sm:p-6 lg:p-8 rounded-2xl transition-all duration-500;
transform-style: preserve-3d;
perspective: 1000px;
@apply glass p-6 rounded-xl transition-all duration-300 hover:shadow-lg;
}
.card:hover {
@apply -translate-y-1 sm:-translate-y-2;
box-shadow:
0 25px 50px -12px rgba(0, 0, 0, 0.15),
0 0 0 1px rgba(255, 255, 255, 0.1) inset;
}
.dark .card:hover {
box-shadow:
0 25px 50px -12px rgba(0, 0, 0, 0.5),
0 0 0 1px rgba(255, 255, 255, 0.05) inset;
}
/* Navigation link */
.nav-link {
@apply relative text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 font-medium transition-colors duration-200;
@apply text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 font-medium transition-colors duration-200;
}
.nav-link::after {
content: '';
@apply absolute -bottom-1 left-0 w-0 h-0.5 bg-gradient-to-r from-blue-500 to-purple-500 transition-all duration-300 rounded-full;
}
.nav-link:hover::after {
@apply w-full;
}
/* Icon box */
.icon-box {
@apply w-10 h-10 sm:w-12 sm:h-12 rounded-xl flex items-center justify-center flex-shrink-0;
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.group:hover .icon-box {
transform: scale(1.1) rotate(3deg);
}
/* Section padding - responsive */
.section-padding {
@apply py-12 sm:py-16 md:py-20 lg:py-24;
}
/* Gradient border effect */
.gradient-border {
position: relative;
background: linear-gradient(135deg, rgba(59, 130, 246, 0.1), rgba(139, 92, 246, 0.1));
}
.gradient-border::before {
content: '';
position: absolute;
inset: 0;
padding: 1px;
border-radius: inherit;
background: linear-gradient(135deg, #3b82f6, #8b5cf6, #06b6d4);
-webkit-mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
}
/* Shimmer loading effect */
.shimmer {
background: linear-gradient(
90deg,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0.4) 50%,
rgba(255, 255, 255, 0) 100%
);
background-size: 200% 100%;
animation: shimmer 2s infinite;
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
/* Glow effects */
.glow-blue {
box-shadow: 0 0 20px rgba(59, 130, 246, 0.3), 0 0 40px rgba(59, 130, 246, 0.1);
}
.glow-purple {
box-shadow: 0 0 20px rgba(139, 92, 246, 0.3), 0 0 40px rgba(139, 92, 246, 0.1);
}
/* Number badge */
.number-badge {
@apply w-8 h-8 sm:w-10 sm:h-10 rounded-full bg-gradient-to-br from-blue-500 to-purple-500 flex items-center justify-center text-white font-bold text-sm sm:text-base;
box-shadow: 0 4px 6px -1px rgba(59, 130, 246, 0.3);
}
/* Status indicators */
.status-dot {
@apply w-2 h-2 rounded-full;
animation: pulse-dot 2s ease-in-out infinite;
}
@keyframes pulse-dot {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.5; transform: scale(1.2); }
}
/* Code block styling */
.code-block {
@apply font-mono text-xs sm:text-sm bg-gray-900 text-gray-100 p-3 sm:p-4 rounded-xl;
box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.3);
}
/* Feature highlight */
.feature-highlight {
@apply relative;
}
.feature-highlight::before {
content: '';
@apply absolute -inset-2 bg-gradient-to-r from-blue-500/10 to-purple-500/10 rounded-xl -z-10;
filter: blur(8px);
}
/* Mobile-optimized touch targets */
.touch-target {
@apply min-h-[44px] min-w-[44px];
}
/* Responsive table wrapper */
.table-wrapper {
@apply overflow-x-auto -mx-4 px-4 sm:mx-0 sm:px-0;
-webkit-overflow-scrolling: touch;
}
/* Responsive grid gaps */
.grid-responsive {
@apply gap-4 sm:gap-5 lg:gap-6;
@apply w-12 h-12 rounded-xl flex items-center justify-center flex-shrink-0 transition-transform duration-300 group-hover:scale-110;
}
}
@layer utilities {
/* Animation delays */
.animate-delay-100 { animation-delay: 0.1s; }
.animate-delay-200 { animation-delay: 0.2s; }
.animate-delay-300 { animation-delay: 0.3s; }
.animate-delay-400 { animation-delay: 0.4s; }
.animate-delay-500 { animation-delay: 0.5s; }
.animate-delay-600 { animation-delay: 0.6s; }
.animate-delay-700 { animation-delay: 0.7s; }
.animate-delay-800 { animation-delay: 0.8s; }
.animate-delay-1000 { animation-delay: 1s; }
.animate-delay-2000 { animation-delay: 2s; }
/* Custom animations */
.animate-fade-in {
animation: fadeIn 0.6s ease-out forwards;
.animate-delay-100 {
animation-delay: 0.1s;
}
.animate-fade-in-up {
animation: fadeInUp 0.6s ease-out forwards;
opacity: 0;
.animate-delay-200 {
animation-delay: 0.2s;
}
.animate-scale-in {
animation: scaleIn 0.5s ease-out forwards;
.animate-delay-300 {
animation-delay: 0.3s;
}
.animate-slide-in-right {
animation: slideInRight 0.5s ease-out forwards;
.animate-delay-1000 {
animation-delay: 1s;
}
.animate-float {
animation: float 6s ease-in-out infinite;
}
.animate-pulse-slow {
animation: pulse-slow 4s ease-in-out infinite;
}
.animate-spin-slow {
animation: spin 8s linear infinite;
}
/* Hover lift effect */
.hover-lift {
@apply transition-all duration-300;
}
.hover-lift:hover {
@apply -translate-y-1;
box-shadow: 0 10px 20px -5px rgba(0, 0, 0, 0.1);
}
/* Text balance for better typography */
.text-balance {
text-wrap: balance;
}
/* Backdrop blur utilities */
.backdrop-blur-xs {
backdrop-filter: blur(2px);
}
/* Safe area for notched phones */
.safe-area-inset {
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}
.safe-area-bottom {
padding-bottom: env(safe-area-inset-bottom);
}
}
/* Keyframe animations */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.9);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes slideInRight {
from {
opacity: 0;
transform: translateX(30px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes float {
0%, 100% { transform: translateY(0px) rotate(0deg); }
33% { transform: translateY(-15px) rotate(1deg); }
66% { transform: translateY(-8px) rotate(-1deg); }
}
@keyframes pulse-slow {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
/* Print styles */
@media print {
.glass {
@apply bg-white border-gray-200;
box-shadow: none !important;
}
.gradient-text {
background: none !important;
@apply text-gray-900;
}
/* Hide non-essential elements when printing */
nav, footer, .no-print {
display: none !important;
}
/* Ensure good contrast for printed content */
body {
@apply text-black bg-white;
}
/* Page breaks */
.page-break {
page-break-before: always;
}
/* Prevent orphans and widows */
p, li {
orphans: 3;
widows: 3;
}
}
/* Mobile-specific optimizations */
@media (max-width: 640px) {
/* Larger touch targets on small screens */
button,
a {
@apply min-h-[44px] min-w-[44px];
}
/* Adjust card padding */
.card {
@apply p-4;
}
/* Smaller hero text on mobile */
.section-title {
@apply text-2xl;
}
}
/* Tablet optimizations */
@media (min-width: 768px) and (max-width: 1024px) {
.card {
@apply p-6;
}
}
/* Ultrawide screen optimizations */
@media (min-width: 1920px) {
/* Larger text for better readability at distance */
body {
@apply text-lg;
}
/* More spacious layouts */
.section-padding {
@apply py-28;
}
/* Larger cards */
.card {
@apply p-10;
}
}
/* Landscape mode on mobile */
@media (max-height: 500px) and (orientation: landscape) {
.section-padding {
@apply py-8;
}
.hero-min-height {
min-height: auto;
.animate-delay-2000 {
animation-delay: 2s;
}
}
+44 -85
View File
@@ -1,125 +1,84 @@
<script setup>
const currentYear = new Date().getFullYear()
const quickLinks = [
{ path: '/values', label: 'Core Values' },
{ path: '/principles', label: '12 Principles' },
{ path: '/framework', label: 'Framework' },
{ path: '/reference', label: 'Quick Reference' },
]
const resources = [
{ path: '/assessment', label: 'Team Assessment' },
{ path: '/anti-patterns', label: 'Anti-Patterns' },
{ path: '/onboarding', label: 'Onboarding' },
{ path: '/practices', label: 'Practices' },
]
</script>
<template>
<footer class="relative bg-gray-50 dark:bg-gray-800/50 border-t border-gray-200 dark:border-gray-700 transition-colors duration-300">
<!-- Top gradient line -->
<div class="absolute top-0 left-0 right-0 h-px bg-gradient-to-r from-transparent via-blue-500/50 to-transparent"></div>
<div class="w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 xl:px-12 py-10 sm:py-12 lg:py-16">
<!-- Main footer content - responsive grid -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8 lg:gap-12">
<!-- Brand -->
<div class="sm:col-span-2 lg:col-span-1">
<RouterLink to="/" class="flex items-center gap-3 group mb-4">
<div
class="w-10 h-10 sm:w-12 sm:h-12 rounded-xl bg-gradient-to-br from-blue-600 to-purple-600 flex items-center justify-center transition-all duration-300 group-hover:scale-110 group-hover:rotate-3 group-hover:shadow-glow-blue"
>
<span class="text-white font-bold text-lg sm:text-xl">B</span>
<footer class="bg-gray-50 dark:bg-gray-800/50 border-t border-gray-200 dark:border-gray-700 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6 py-12">
<div class="grid md:grid-cols-3 gap-8">
<div>
<div class="flex items-center gap-2 mb-4">
<div class="w-10 h-10 rounded-lg bg-gradient-to-br from-blue-600 to-purple-600 flex items-center justify-center">
<span class="text-white font-bold text-lg">B</span>
</div>
<div>
<span class="text-lg sm:text-xl font-bold gradient-text block">BEAT</span>
<span class="text-xs text-gray-500 dark:text-gray-400">v1.0</span>
</div>
</RouterLink>
<p class="text-gray-600 dark:text-gray-400 text-sm leading-relaxed mb-2">
<span class="text-xl font-bold gradient-text">BEAT</span>
</div>
<p class="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">
<strong>B</strong>alanced. <strong>E</strong>mpowered. <strong>A</strong>sync. <strong>T</strong>eams.
</p>
<p class="text-gray-500 dark:text-gray-500 text-sm">
<p class="text-gray-500 dark:text-gray-500 text-sm mt-2">
Built for how developers actually work.
</p>
</div>
<!-- Quick Links -->
<div>
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-4 flex items-center gap-2 text-sm sm:text-base">
<i class="fas fa-compass text-blue-500 text-sm"></i>
Explore
</h3>
<ul class="space-y-2">
<li v-for="link in quickLinks" :key="link.path">
<RouterLink
:to="link.path"
class="text-sm text-gray-600 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors duration-200 flex items-center gap-2 group"
>
<span class="w-1.5 h-1.5 rounded-full bg-gray-300 dark:bg-gray-600 group-hover:bg-blue-500 transition-colors"></span>
{{ link.label }}
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-4">Quick Links</h3>
<ul class="space-y-2 text-sm">
<li>
<RouterLink to="/values" class="text-gray-600 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
Core Values
</RouterLink>
</li>
<li>
<RouterLink to="/principles" class="text-gray-600 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
12 Principles
</RouterLink>
</li>
<li>
<RouterLink to="/framework" class="text-gray-600 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
Framework
</RouterLink>
</li>
<li>
<RouterLink to="/reference" class="text-gray-600 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
Quick Reference
</RouterLink>
</li>
</ul>
</div>
<!-- Resources -->
<div>
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-4 flex items-center gap-2 text-sm sm:text-base">
<i class="fas fa-book text-purple-500 text-sm"></i>
Resources
</h3>
<ul class="space-y-2">
<li v-for="link in resources" :key="link.path">
<RouterLink
:to="link.path"
class="text-sm text-gray-600 dark:text-gray-400 hover:text-purple-600 dark:hover:text-purple-400 transition-colors duration-200 flex items-center gap-2 group"
>
<span class="w-1.5 h-1.5 rounded-full bg-gray-300 dark:bg-gray-600 group-hover:bg-purple-500 transition-colors"></span>
{{ link.label }}
</RouterLink>
</li>
</ul>
</div>
<!-- Author -->
<div>
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-4 flex items-center gap-2 text-sm sm:text-base">
<i class="fas fa-user text-cyan-500 text-sm"></i>
Created By
</h3>
<p class="text-gray-600 dark:text-gray-400 text-sm mb-4">
The BEAT Manifesto was created by <strong class="text-gray-900 dark:text-gray-100">Lukasz Raczylo</strong>.
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-4">Created By</h3>
<p class="text-gray-600 dark:text-gray-400 text-sm mb-3">
The BEAT Manifesto was created by <strong>Lukasz Raczylo</strong>.
</p>
<div class="flex gap-2">
<div class="flex space-x-3">
<a
href="https://github.com/lukaszraczylo"
target="_blank"
class="w-10 h-10 rounded-lg bg-gray-100 dark:bg-gray-700 flex items-center justify-center text-gray-500 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-200 dark:hover:bg-gray-600 transition-all duration-300 hover:scale-110"
class="text-gray-500 hover:text-gray-900 dark:hover:text-gray-100 transition-colors"
aria-label="GitHub"
>
<i class="fab fa-github text-lg"></i>
<i class="fab fa-github text-xl"></i>
</a>
<a
href="https://www.linkedin.com/in/raczylo/"
target="_blank"
class="w-10 h-10 rounded-lg bg-gray-100 dark:bg-gray-700 flex items-center justify-center text-gray-500 hover:text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/30 transition-all duration-300 hover:scale-110"
class="text-gray-500 hover:text-blue-600 transition-colors"
aria-label="LinkedIn"
>
<i class="fab fa-linkedin text-lg"></i>
<i class="fab fa-linkedin text-xl"></i>
</a>
</div>
</div>
</div>
<!-- Bottom bar -->
<div class="mt-8 sm:mt-10 lg:mt-12 pt-6 sm:pt-8 border-t border-gray-200 dark:border-gray-700">
<div class="flex flex-col sm:flex-row justify-between items-center gap-3 sm:gap-4 text-center sm:text-left">
<p class="text-gray-500 dark:text-gray-500 text-xs sm:text-sm">
&copy; {{ currentYear }} BEAT Manifesto by Lukasz Raczylo
<div class="mt-8 pt-8 border-t border-gray-200 dark:border-gray-700">
<div class="flex flex-col sm:flex-row justify-between items-center gap-4">
<p class="text-gray-500 dark:text-gray-500 text-sm">
&copy; {{ currentYear }} BEAT Manifesto by Lukasz Raczylo. Open for use and adaptation.
</p>
<p class="text-gray-400 dark:text-gray-600 text-xs italic">
<p class="text-gray-400 dark:text-gray-600 text-xs">
Attribution appreciated. Improvement welcomed. Dogma discouraged.
</p>
</div>
+36 -167
View File
@@ -1,229 +1,98 @@
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { ref } from 'vue'
import { RouterLink, useRoute } from 'vue-router'
import ThemeToggle from './ThemeToggle.vue'
const route = useRoute()
const mobileMenuOpen = ref(false)
const scrolled = ref(false)
const navItems = [
{ path: '/', label: 'Home', icon: 'fas fa-home' },
{ path: '/values', label: 'Values', icon: 'fas fa-heart' },
{ path: '/principles', label: 'Principles', icon: 'fas fa-compass' },
{ path: '/framework', label: 'Framework', icon: 'fas fa-sitemap' },
{ path: '/practices', label: 'Practices', icon: 'fas fa-cogs' },
{ path: '/onboarding', label: 'Onboarding', icon: 'fas fa-user-plus' },
{ path: '/anti-patterns', label: 'Anti-Patterns', icon: 'fas fa-exclamation-triangle' },
{ path: '/reference', label: 'Reference', icon: 'fas fa-book' },
{ path: '/assessment', label: 'Assessment', icon: 'fas fa-clipboard-check' }
{ path: '/', label: 'Home' },
{ path: '/values', label: 'Values' },
{ path: '/principles', label: 'Principles' },
{ path: '/framework', label: 'Framework' },
{ path: '/practices', label: 'Practices' },
{ path: '/onboarding', label: 'Onboarding' },
{ path: '/anti-patterns', label: 'Anti-Patterns' },
{ path: '/reference', label: 'Reference' }
]
const toggleMobileMenu = () => {
mobileMenuOpen.value = !mobileMenuOpen.value
// Prevent body scroll when menu is open
document.body.style.overflow = mobileMenuOpen.value ? 'hidden' : ''
}
const closeMobileMenu = () => {
mobileMenuOpen.value = false
document.body.style.overflow = ''
}
const handleScroll = () => {
scrolled.value = window.scrollY > 20
}
// Close mobile menu on route change
watch(() => route.path, () => {
closeMobileMenu()
})
// Close mobile menu on escape key
const handleEscape = (e) => {
if (e.key === 'Escape' && mobileMenuOpen.value) {
closeMobileMenu()
}
}
onMounted(() => {
window.addEventListener('scroll', handleScroll, { passive: true })
window.addEventListener('keydown', handleEscape)
handleScroll()
})
onUnmounted(() => {
window.removeEventListener('scroll', handleScroll)
window.removeEventListener('keydown', handleEscape)
document.body.style.overflow = ''
})
import { watch } from 'vue'
</script>
<template>
<nav
class="fixed w-full z-50 transition-all duration-500"
:class="[
scrolled
? 'bg-white/90 dark:bg-gray-900/90 backdrop-blur-xl shadow-modern'
: 'bg-transparent'
]"
>
<!-- Top gradient line -->
<div
class="h-1 bg-gradient-to-r from-blue-500 via-purple-500 to-cyan-500 transition-all duration-500"
:class="scrolled ? 'opacity-100' : 'opacity-0'"
></div>
<div class="w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 xl:px-12">
<div class="flex justify-between h-14 sm:h-16 items-center">
<!-- Logo -->
<RouterLink
to="/"
class="flex items-center gap-2 sm:gap-3 group"
>
<div
class="w-8 h-8 sm:w-10 sm:h-10 rounded-lg sm:rounded-xl bg-gradient-to-br from-blue-600 to-purple-600 flex items-center justify-center transition-all duration-300 group-hover:scale-110 group-hover:rotate-3 group-hover:shadow-glow-blue"
>
<span class="text-white font-bold text-sm sm:text-lg">B</span>
<nav class="fixed w-full glass shadow-modern z-50 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="flex justify-between h-16 items-center">
<RouterLink to="/" class="flex items-center hover:opacity-80 transition-opacity duration-300 gap-2">
<div class="w-10 h-10 rounded-lg bg-gradient-to-br from-blue-600 to-purple-600 flex items-center justify-center">
<span class="text-white font-bold text-lg">B</span>
</div>
<span
class="text-lg sm:text-xl font-bold gradient-text hidden sm:inline transition-all duration-300 group-hover:tracking-wide"
>BEAT</span>
<span class="text-xl font-bold gradient-text hidden sm:inline">BEAT</span>
</RouterLink>
<!-- Desktop Navigation - hidden on mobile, shown on lg+ -->
<div class="hidden lg:flex items-center space-x-1">
<div class="hidden lg:flex space-x-4 xl:space-x-6">
<RouterLink
v-for="(item, index) in navItems"
v-for="item in navItems"
:key="item.path"
:to="item.path"
class="relative px-2 xl:px-3 py-2 text-xs xl:text-sm font-medium rounded-lg transition-all duration-300"
:class="[
route.path === item.path
? 'text-blue-600 dark:text-blue-400 bg-blue-50/50 dark:bg-blue-900/20'
: 'text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-100/50 dark:hover:bg-gray-800/50'
]"
:style="{ animationDelay: `${index * 50}ms` }"
class="nav-link text-sm"
:class="{ 'text-blue-600 dark:text-blue-400': route.path === item.path }"
>
{{ item.label }}
<!-- Active indicator -->
<span
v-if="route.path === item.path"
class="absolute -bottom-1 left-1/2 -translate-x-1/2 w-1 h-1 rounded-full bg-blue-500"
></span>
</RouterLink>
</div>
<!-- Right side actions -->
<div class="flex items-center gap-1 sm:gap-2">
<div class="flex items-center space-x-2">
<ThemeToggle />
<a
href="https://github.com/lukaszraczylo"
target="_blank"
class="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 p-2 sm:p-2.5 rounded-lg min-w-[40px] min-h-[40px] flex items-center justify-center transition-all duration-300 hover:bg-gray-100/50 dark:hover:bg-gray-800/50 hover:scale-110"
class="text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 p-2 min-w-[44px] min-h-[44px] flex items-center justify-center transition-colors duration-200"
aria-label="View author on GitHub"
>
<i class="fab fa-github text-lg sm:text-xl"></i>
<i class="fab fa-github text-xl"></i>
</a>
<!-- Mobile menu button -->
<button
@click="toggleMobileMenu"
class="lg:hidden text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 p-2 sm:p-2.5 rounded-lg min-w-[44px] min-h-[44px] flex items-center justify-center transition-all duration-300 hover:bg-gray-100/50 dark:hover:bg-gray-800/50"
class="lg:hidden text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 p-2 min-w-[44px] min-h-[44px] flex items-center justify-center"
aria-label="Toggle menu"
aria-expanded="mobileMenuOpen"
aria-controls="mobile-menu"
>
<transition name="rotate" mode="out-in">
<i v-if="!mobileMenuOpen" key="menu" class="fas fa-bars text-lg sm:text-xl"></i>
<i v-else key="close" class="fas fa-times text-lg sm:text-xl"></i>
</transition>
<i v-if="!mobileMenuOpen" class="fas fa-bars text-xl"></i>
<i v-else class="fas fa-times text-xl"></i>
</button>
</div>
</div>
</div>
<!-- Mobile Menu Overlay -->
<transition
enter-active-class="transition duration-300 ease-out"
enter-from-class="opacity-0"
enter-to-class="opacity-100"
leave-active-class="transition duration-200 ease-in"
leave-from-class="opacity-100"
leave-to-class="opacity-0"
>
<div
v-if="mobileMenuOpen"
class="fixed inset-0 bg-black/50 backdrop-blur-sm lg:hidden z-40"
@click="closeMobileMenu"
aria-hidden="true"
></div>
</transition>
<!-- Mobile Menu Panel -->
<transition
enter-active-class="transition duration-300 ease-out"
enter-from-class="opacity-0 -translate-y-4"
enter-active-class="transition duration-200 ease-out"
enter-from-class="opacity-0 -translate-y-2"
enter-to-class="opacity-100 translate-y-0"
leave-active-class="transition duration-200 ease-in"
leave-active-class="transition duration-150 ease-in"
leave-from-class="opacity-100 translate-y-0"
leave-to-class="opacity-0 -translate-y-4"
leave-to-class="opacity-0 -translate-y-2"
>
<div
v-if="mobileMenuOpen"
id="mobile-menu"
class="lg:hidden absolute top-full left-0 right-0 bg-white/95 dark:bg-gray-900/95 backdrop-blur-xl border-b border-gray-200 dark:border-gray-700 shadow-2xl max-h-[80vh] overflow-y-auto"
>
<div class="px-4 py-4 space-y-1 w-full max-w-7xl mx-auto">
<div v-if="mobileMenuOpen" class="lg:hidden border-t border-gray-200 dark:border-gray-700">
<div class="px-4 py-3 space-y-1 bg-white dark:bg-gray-800">
<RouterLink
v-for="(item, index) in navItems"
v-for="item in navItems"
:key="item.path"
:to="item.path"
@click="closeMobileMenu"
class="flex items-center gap-3 px-4 py-3 rounded-xl font-medium transition-all duration-300"
:class="[
route.path === item.path
? 'text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20'
: 'text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-50 dark:hover:bg-gray-800'
]"
:style="{ animationDelay: `${index * 30}ms` }"
class="block px-3 py-3 text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-50 dark:hover:bg-gray-700 rounded font-medium"
:class="{ 'text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20': route.path === item.path }"
>
<div
class="w-10 h-10 rounded-lg flex items-center justify-center"
:class="route.path === item.path ? 'bg-blue-100 dark:bg-blue-800' : 'bg-gray-100 dark:bg-gray-800'"
>
<i :class="item.icon" class="text-sm"></i>
</div>
<span class="flex-1">{{ item.label }}</span>
<i
v-if="route.path === item.path"
class="fas fa-chevron-right text-xs text-blue-500"
></i>
{{ item.label }}
</RouterLink>
</div>
<!-- Mobile menu footer -->
<div class="px-4 py-4 border-t border-gray-200 dark:border-gray-700">
<p class="text-xs text-center text-gray-500 dark:text-gray-500">
BEAT Manifesto v1.0
</p>
</div>
</div>
</transition>
</nav>
</template>
<style scoped>
.rotate-enter-active,
.rotate-leave-active {
transition: all 0.2s ease;
}
.rotate-enter-from,
.rotate-leave-to {
opacity: 0;
transform: rotate(-90deg);
}
</style>
@@ -1,63 +0,0 @@
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const progress = ref(0)
const showBackToTop = ref(false)
const calculateProgress = () => {
const windowHeight = window.innerHeight
const documentHeight = document.documentElement.scrollHeight - windowHeight
const scrollTop = window.scrollY
if (documentHeight > 0) {
progress.value = Math.min(100, Math.max(0, (scrollTop / documentHeight) * 100))
}
showBackToTop.value = scrollTop > 500
}
const scrollToTop = () => {
window.scrollTo({
top: 0,
behavior: 'smooth'
})
}
onMounted(() => {
window.addEventListener('scroll', calculateProgress, { passive: true })
calculateProgress()
})
onUnmounted(() => {
window.removeEventListener('scroll', calculateProgress)
})
</script>
<template>
<!-- Reading Progress Bar -->
<div class="fixed top-0 left-0 right-0 h-1 z-[60] bg-transparent">
<div
class="h-full bg-gradient-to-r from-blue-500 via-purple-500 to-cyan-500 transition-all duration-150 ease-out"
:style="{ width: `${progress}%` }"
></div>
</div>
<!-- Back to Top Button -->
<transition
enter-active-class="transition duration-300 ease-out"
enter-from-class="opacity-0 translate-y-4"
enter-to-class="opacity-100 translate-y-0"
leave-active-class="transition duration-200 ease-in"
leave-from-class="opacity-100 translate-y-0"
leave-to-class="opacity-0 translate-y-4"
>
<button
v-if="showBackToTop"
@click="scrollToTop"
class="fixed bottom-8 right-8 w-12 h-12 rounded-full bg-gradient-to-br from-blue-600 to-purple-600 text-white shadow-lg hover:shadow-xl hover:scale-110 transition-all duration-300 z-50 flex items-center justify-center group"
aria-label="Back to top"
>
<i class="fas fa-arrow-up group-hover:-translate-y-0.5 transition-transform"></i>
</button>
</transition>
</template>
+5 -12
View File
@@ -7,30 +7,23 @@ defineProps({
gradient: {
type: String,
default: null
},
glow: {
type: String,
default: null
}
})
</script>
<template>
<div
class="card"
:class="{
'hover:-translate-y-2': hover,
[`shadow-glow-${glow}`]: glow
}"
class="glass p-6 rounded-xl transition-all duration-300"
:class="{ 'hover:shadow-lg hover:-translate-y-1': hover }"
>
<div v-if="gradient" class="flex items-start gap-5">
<div v-if="gradient" class="flex items-start gap-4">
<div
class="icon-box w-14 h-14 rounded-2xl"
class="icon-box"
:class="gradient"
>
<slot name="icon"></slot>
</div>
<div class="flex-1 min-w-0">
<div class="flex-1">
<slot></slot>
</div>
</div>
+4 -4
View File
@@ -25,17 +25,17 @@ const copyCode = async () => {
<template>
<div class="rounded-xl overflow-hidden bg-gray-900 dark:bg-gray-950">
<div v-if="title" class="flex items-center justify-between px-3 sm:px-4 py-2 bg-gray-800 dark:bg-gray-900 border-b border-gray-700">
<span class="text-gray-400 text-xs sm:text-sm font-medium truncate mr-2">{{ title }}</span>
<div v-if="title" class="flex items-center justify-between px-4 py-2 bg-gray-800 dark:bg-gray-900 border-b border-gray-700">
<span class="text-gray-400 text-sm font-medium">{{ title }}</span>
<button
@click="copyCode"
class="text-gray-400 hover:text-white transition-colors p-2 min-w-[40px] min-h-[40px] flex items-center justify-center flex-shrink-0"
class="text-gray-400 hover:text-white transition-colors p-1"
aria-label="Copy code"
>
<i v-if="copied" class="fas fa-check text-green-400"></i>
<i v-else class="fas fa-copy"></i>
</button>
</div>
<pre class="p-3 sm:p-4 overflow-x-auto text-xs sm:text-sm"><code ref="codeRef" class="text-gray-100 font-mono whitespace-pre-wrap break-words sm:whitespace-pre sm:break-normal"><slot></slot></code></pre>
<pre class="p-4 overflow-x-auto"><code ref="codeRef" class="text-sm text-gray-100 font-mono"><slot></slot></code></pre>
</div>
</template>
-75
View File
@@ -1,75 +0,0 @@
<script setup>
import { ref } from 'vue'
const props = defineProps({
text: {
type: String,
required: true
},
label: {
type: String,
default: 'Copy'
},
copiedLabel: {
type: String,
default: 'Copied!'
}
})
const copied = ref(false)
const error = ref(false)
const copyToClipboard = async () => {
try {
await navigator.clipboard.writeText(props.text)
copied.value = true
error.value = false
setTimeout(() => {
copied.value = false
}, 2000)
} catch (err) {
error.value = true
setTimeout(() => {
error.value = false
}, 2000)
}
}
</script>
<template>
<button
@click="copyToClipboard"
class="inline-flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium transition-all duration-200"
:class="[
copied
? 'bg-emerald-100 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300'
: error
? 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300'
: 'bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-700'
]"
:title="copied ? copiedLabel : label"
>
<transition name="scale" mode="out-in">
<i v-if="copied" key="check" class="fas fa-check"></i>
<i v-else-if="error" key="error" class="fas fa-exclamation-circle"></i>
<i v-else key="copy" class="fas fa-copy"></i>
</transition>
<span v-if="copied">{{ copiedLabel }}</span>
<span v-else-if="error">Failed</span>
<span v-else>{{ label }}</span>
</button>
</template>
<style scoped>
.scale-enter-active,
.scale-leave-active {
transition: all 0.2s ease;
}
.scale-enter-from,
.scale-leave-to {
opacity: 0;
transform: scale(0.8);
}
</style>
+8 -23
View File
@@ -15,39 +15,24 @@ defineProps({
gradient: {
type: String,
default: 'from-blue-500 to-blue-600'
},
href: {
type: String,
default: null
}
})
</script>
<template>
<component
:is="href ? 'a' : 'div'"
:href="href"
class="group card p-6 cursor-pointer"
:class="{ 'hover:-translate-y-2': href }"
>
<div class="flex items-start gap-5">
<div class="glass p-5 rounded-xl group hover:shadow-lg transition-all duration-300">
<div class="flex items-start gap-4">
<div
class="w-14 h-14 rounded-2xl bg-gradient-to-br flex items-center justify-center flex-shrink-0 transition-all duration-300 group-hover:scale-110 group-hover:rotate-3"
class="w-12 h-12 rounded-xl bg-gradient-to-br flex items-center justify-center flex-shrink-0 group-hover:scale-110 transition-transform duration-300"
:class="gradient"
>
<i :class="icon" class="text-white text-xl"></i>
<i :class="icon" class="text-white"></i>
</div>
<div class="flex-1 min-w-0">
<h3 class="font-semibold text-lg text-gray-900 dark:text-gray-100 mb-2 flex items-center gap-2">
{{ title }}
<i
v-if="href"
class="fas fa-arrow-right text-sm opacity-0 -translate-x-2 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-300 text-blue-500"
></i>
</h3>
<p v-if="description" class="text-sm text-gray-600 dark:text-gray-400 leading-relaxed">{{ description }}</p>
<div>
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-1">{{ title }}</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">{{ description }}</p>
<slot></slot>
</div>
</div>
</component>
</div>
</template>
-101
View File
@@ -1,101 +0,0 @@
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const props = defineProps({
delay: {
type: Number,
default: 0
},
direction: {
type: String,
default: 'up', // 'up', 'down', 'left', 'right'
validator: (value) => ['up', 'down', 'left', 'right'].includes(value)
},
distance: {
type: Number,
default: 30
},
duration: {
type: Number,
default: 600
},
once: {
type: Boolean,
default: true
},
threshold: {
type: Number,
default: 0.1
}
})
const elementRef = ref(null)
const isVisible = ref(false)
const getInitialTransform = () => {
switch (props.direction) {
case 'up': return `translateY(${props.distance}px)`
case 'down': return `translateY(-${props.distance}px)`
case 'left': return `translateX(${props.distance}px)`
case 'right': return `translateX(-${props.distance}px)`
default: return `translateY(${props.distance}px)`
}
}
let observer = null
onMounted(() => {
if (!elementRef.value) return
observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setTimeout(() => {
isVisible.value = true
}, props.delay)
if (props.once && observer) {
observer.unobserve(entry.target)
}
} else if (!props.once) {
isVisible.value = false
}
})
},
{
threshold: props.threshold,
rootMargin: '0px 0px -50px 0px'
}
)
observer.observe(elementRef.value)
})
onUnmounted(() => {
if (observer && elementRef.value) {
observer.unobserve(elementRef.value)
}
})
</script>
<template>
<div
ref="elementRef"
class="scroll-reveal"
:class="{ 'is-visible': isVisible }"
:style="{
opacity: isVisible ? 1 : 0,
transform: isVisible ? 'translate(0)' : getInitialTransform(),
transition: `opacity ${duration}ms cubic-bezier(0.4, 0, 0.2, 1), transform ${duration}ms cubic-bezier(0.4, 0, 0.2, 1)`
}"
>
<slot></slot>
</div>
</template>
<style scoped>
.scroll-reveal {
will-change: opacity, transform;
}
</style>
+9 -29
View File
@@ -16,38 +16,18 @@ defineProps({
</script>
<template>
<div class="glass rounded-2xl overflow-hidden">
<div v-if="title" class="px-4 sm:px-6 py-3 sm:py-4 border-b border-gray-200 dark:border-gray-700 bg-gray-50/50 dark:bg-gray-800/50">
<h3 class="font-semibold text-gray-900 dark:text-gray-100 text-sm sm:text-base">{{ title }}</h3>
<div class="glass rounded-xl overflow-hidden">
<div v-if="title" class="px-6 py-4 border-b border-gray-200 dark:border-gray-700">
<h3 class="font-semibold text-gray-900 dark:text-gray-100">{{ title }}</h3>
</div>
<!-- Mobile card view - shown on small screens -->
<div class="block sm:hidden">
<div
v-for="(row, rowIndex) in rows"
:key="rowIndex"
class="p-4 border-b border-gray-200 dark:border-gray-700 last:border-b-0 hover:bg-gray-50/50 dark:hover:bg-gray-800/30 transition-colors"
>
<div
v-for="(cell, cellIndex) in row"
:key="cellIndex"
class="py-1.5"
>
<span class="text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider">{{ headers[cellIndex] }}: </span>
<span class="text-sm text-gray-700 dark:text-gray-300" v-html="cell"></span>
</div>
</div>
</div>
<!-- Desktop table view - hidden on mobile, shown on sm+ -->
<div class="hidden sm:block overflow-x-auto">
<div class="overflow-x-auto">
<table class="w-full">
<thead>
<tr class="bg-gray-50/80 dark:bg-gray-800/80">
<tr class="bg-gray-50 dark:bg-gray-800/50">
<th
v-for="header in headers"
:key="header"
class="px-4 md:px-6 py-3 text-left text-xs font-semibold text-gray-600 dark:text-gray-400 uppercase tracking-wider whitespace-nowrap"
class="px-6 py-3 text-left text-xs font-semibold text-gray-600 dark:text-gray-400 uppercase tracking-wider"
>
{{ header }}
</th>
@@ -57,14 +37,14 @@ defineProps({
<tr
v-for="(row, index) in rows"
:key="index"
class="hover:bg-gray-50/50 dark:hover:bg-gray-800/30 transition-all duration-200 group"
class="hover:bg-gray-50 dark:hover:bg-gray-800/30 transition-colors"
>
<td
v-for="(cell, cellIndex) in row"
:key="cellIndex"
class="px-4 md:px-6 py-3 md:py-4 text-sm text-gray-700 dark:text-gray-300"
class="px-6 py-4 text-sm text-gray-700 dark:text-gray-300"
>
<span v-html="cell" class="group-hover:text-gray-900 dark:group-hover:text-gray-100 transition-colors"></span>
<span v-html="cell"></span>
</td>
</tr>
</tbody>
-69
View File
@@ -1,69 +0,0 @@
<script setup>
import { ref } from 'vue'
const props = defineProps({
text: {
type: String,
required: true
},
position: {
type: String,
default: 'top',
validator: (value) => ['top', 'bottom', 'left', 'right'].includes(value)
}
})
const show = ref(false)
const positionClasses = {
top: 'bottom-full left-1/2 -translate-x-1/2 mb-2',
bottom: 'top-full left-1/2 -translate-x-1/2 mt-2',
left: 'right-full top-1/2 -translate-y-1/2 mr-2',
right: 'left-full top-1/2 -translate-y-1/2 ml-2'
}
const arrowClasses = {
top: 'top-full left-1/2 -translate-x-1/2 -mt-1 border-l-transparent border-r-transparent border-b-transparent',
bottom: 'bottom-full left-1/2 -translate-x-1/2 -mb-1 border-l-transparent border-r-transparent border-t-transparent',
left: 'left-full top-1/2 -translate-y-1/2 -ml-1 border-t-transparent border-b-transparent border-r-transparent',
right: 'right-full top-1/2 -translate-y-1/2 -mr-1 border-t-transparent border-b-transparent border-l-transparent'
}
</script>
<template>
<div
class="relative inline-block"
@mouseenter="show = true"
@mouseleave="show = false"
@focus="show = true"
@blur="show = false"
>
<slot></slot>
<transition
enter-active-class="transition duration-200 ease-out"
enter-from-class="opacity-0 scale-95"
enter-to-class="opacity-100 scale-100"
leave-active-class="transition duration-150 ease-in"
leave-from-class="opacity-100 scale-100"
leave-to-class="opacity-0 scale-95"
>
<div
v-if="show"
:class="[
'absolute z-50 px-3 py-2 text-sm font-medium text-white bg-gray-900 dark:bg-gray-700 rounded-lg shadow-lg whitespace-nowrap pointer-events-none',
positionClasses[position]
]"
role="tooltip"
>
{{ text }}
<div
:class="[
'absolute w-2 h-2 bg-gray-900 dark:bg-gray-700 rotate-45 border-4 border-gray-900 dark:border-gray-700',
arrowClasses[position]
]"
></div>
</div>
</transition>
</div>
</template>
-350
View File
@@ -1,350 +0,0 @@
export const assessmentCategories = [
{
id: 'focus',
title: 'Focus & Deep Work',
icon: 'fas fa-brain',
gradient: 'from-blue-500 to-cyan-500',
color: 'blue'
},
{
id: 'communication',
title: 'Communication',
icon: 'fas fa-comments',
gradient: 'from-purple-500 to-pink-500',
color: 'purple'
},
{
id: 'autonomy',
title: 'Autonomy & Trust',
icon: 'fas fa-user-shield',
gradient: 'from-green-500 to-emerald-500',
color: 'green'
},
{
id: 'sustainability',
title: 'Sustainability',
icon: 'fas fa-leaf',
gradient: 'from-amber-500 to-orange-500',
color: 'amber'
}
]
export const assessmentQuestions = [
// Focus & Deep Work
{
id: 1,
category: 'focus',
question: 'How often do you get uninterrupted blocks of 2+ hours for focused work?',
options: [
{ value: 1, label: 'Rarely or never', description: 'Constant interruptions throughout the day' },
{ value: 2, label: 'Sometimes', description: 'Maybe once or twice a week' },
{ value: 3, label: 'Often', description: 'Most days I can find some focus time' },
{ value: 4, label: 'Always', description: 'I have protected focus blocks daily' }
]
},
{
id: 2,
category: 'focus',
question: 'How many meetings do you have in a typical week?',
options: [
{ value: 1, label: '10+ hours', description: 'Meetings dominate my calendar' },
{ value: 2, label: '5-10 hours', description: 'Significant meeting load' },
{ value: 3, label: '2-5 hours', description: 'Moderate amount of meetings' },
{ value: 4, label: 'Under 2 hours', description: 'Minimal meeting time' }
]
},
{
id: 3,
category: 'focus',
question: 'How is productivity measured on your team?',
options: [
{ value: 1, label: 'Hours worked / time online', description: 'Presence-based metrics' },
{ value: 2, label: 'Tasks completed / velocity', description: 'Activity-based metrics' },
{ value: 3, label: 'Mix of activity and outcomes', description: 'Some outcome focus' },
{ value: 4, label: 'Outcomes delivered', description: 'Results matter, not hours' }
]
},
// Communication
{
id: 4,
category: 'communication',
question: 'How are most decisions communicated and documented?',
options: [
{ value: 1, label: 'Verbal only', description: 'Discussed but rarely written down' },
{ value: 2, label: 'Scattered notes', description: 'Some docs, but hard to find' },
{ value: 3, label: 'Mostly documented', description: 'Important decisions get written' },
{ value: 4, label: 'Always written first', description: 'Write-first culture' }
]
},
{
id: 5,
category: 'communication',
question: 'What\'s the expected response time to messages?',
options: [
{ value: 1, label: 'Immediate', description: 'Expected to respond within minutes' },
{ value: 2, label: 'Within hours', description: 'Same-day responses expected' },
{ value: 3, label: 'Within a day', description: '24-hour response is acceptable' },
{ value: 4, label: 'Async-friendly', description: 'Response when working, no pressure' }
]
},
{
id: 6,
category: 'communication',
question: 'How are urgent issues escalated?',
options: [
{ value: 1, label: 'Everything is urgent', description: 'No clear priority system' },
{ value: 2, label: 'Depends on who\'s asking', description: 'Urgency varies by person' },
{ value: 3, label: 'Some prioritization', description: 'We try to triage' },
{ value: 4, label: 'Clear escalation path', description: 'Urgent = phone, else async' }
]
},
// Autonomy & Trust
{
id: 7,
category: 'autonomy',
question: 'How is work assigned to team members?',
options: [
{ value: 1, label: 'Top-down assignment', description: 'Manager decides who does what' },
{ value: 2, label: 'Mostly assigned', description: 'Some choice, but limited' },
{ value: 3, label: 'Collaborative', description: 'Team discusses, then assigns' },
{ value: 4, label: 'Pull-based', description: 'Developers choose from prioritized work' }
]
},
{
id: 8,
category: 'autonomy',
question: 'Can developers choose their own tools and approaches?',
options: [
{ value: 1, label: 'No', description: 'Strict standardization' },
{ value: 2, label: 'Limited', description: 'Some flexibility within constraints' },
{ value: 3, label: 'Mostly yes', description: 'Freedom with guidelines' },
{ value: 4, label: 'Full autonomy', description: 'Trust makers to make decisions' }
]
},
{
id: 9,
category: 'autonomy',
question: 'Can team members push back on work they disagree with?',
options: [
{ value: 1, label: 'No', description: 'Expected to comply' },
{ value: 2, label: 'Discouraged', description: 'Possible but not welcomed' },
{ value: 3, label: 'Sometimes', description: 'Depends on the situation' },
{ value: 4, label: 'Encouraged', description: 'Challenges are valued' }
]
},
// Sustainability
{
id: 10,
category: 'sustainability',
question: 'How often does your team work overtime?',
options: [
{ value: 1, label: 'Frequently', description: 'Overtime is normal' },
{ value: 2, label: 'Often', description: 'Regular crunch periods' },
{ value: 3, label: 'Sometimes', description: 'Occasional overtime' },
{ value: 4, label: 'Rarely', description: 'Sustainable pace is protected' }
]
},
{
id: 11,
category: 'sustainability',
question: 'What happens when deadlines conflict with capacity?',
options: [
{ value: 1, label: 'Work harder', description: 'Team pushes through' },
{ value: 2, label: 'Negotiate later', description: 'Promise now, adjust later' },
{ value: 3, label: 'Discuss options', description: 'Some scope flexibility' },
{ value: 4, label: 'Cut scope', description: 'We never cut rest, only scope' }
]
},
{
id: 12,
category: 'sustainability',
question: 'Do team members have time for learning and exploration?',
options: [
{ value: 1, label: 'No', description: 'Always feature work' },
{ value: 2, label: 'Personal time only', description: 'Learning is on your own time' },
{ value: 3, label: 'Sometimes', description: 'When we have slack' },
{ value: 4, label: 'Protected time', description: '20% for exploration built in' }
]
}
]
export const beatRecommendations = {
focus: {
low: {
title: 'Your Focus is Under Attack',
description: 'Constant interruptions and meetings are destroying your team\'s ability to do deep work. Research shows it takes 52 minutes to reach focus and 23 minutes to recover from interruption.',
recommendations: [
'Establish 4-hour daily sacred blocks where no meetings or interruptions are allowed',
'Limit meetings to 2 hours per week maximum',
'Measure outcomes, not hours worked or time online',
'Let makers choose when their focus time occurs'
],
beatPrinciple: 'Protect the focus state above all else. The uninterrupted mind produces the best work.'
},
medium: {
title: 'Focus Needs Protection',
description: 'You have some focus time, but it\'s inconsistent. With more structure, your team could dramatically increase productivity.',
recommendations: [
'Formalize sacred blocks and make them non-negotiable',
'Audit your meeting calendar - can 50% become async?',
'Create clear signals for when someone is in focus mode',
'Track interruption patterns and address the sources'
],
beatPrinciple: 'Presence does not equal productivity. A maker in focus for four hours outproduces a maker in meetings for eight.'
},
high: {
title: 'Strong Focus Culture',
description: 'Your team values deep work. BEAT can help you maintain and strengthen this culture as you scale.',
recommendations: [
'Document your focus practices for new team members',
'Continue protecting what\'s working',
'Share your approach with other teams',
'Watch for gradual erosion of focus time'
],
beatPrinciple: 'Interruptions are not free. Every "quick question" costs more than it appears.'
}
},
communication: {
low: {
title: 'Communication is Chaotic',
description: 'Without written documentation and async practices, knowledge is lost, decisions are forgotten, and everyone stays chained to chat.',
recommendations: [
'Adopt a "write first" policy for all decisions',
'Set expectation: responses within 24 working hours, not minutes',
'Create clear channels: urgent = phone, everything else waits',
'Replace daily standups with written async check-ins'
],
beatPrinciple: 'Writing is thinking made visible. Decisions not documented did not happen.'
},
medium: {
title: 'Communication Needs Structure',
description: 'You have some good practices, but inconsistency leads to confusion about when to interrupt vs. when to wait.',
recommendations: [
'Define clear response time expectations',
'Create templates for common communication (check-ins, decisions)',
'Establish when sync communication is appropriate',
'Build a searchable knowledge base'
],
beatPrinciple: 'Synchronous time is expensive. Spend it wisely. If it can be written, write it.'
},
high: {
title: 'Effective Async Communication',
description: 'Your team communicates well asynchronously. Keep refining and documenting these practices.',
recommendations: [
'Mentor other teams in async practices',
'Continuously improve documentation',
'Maintain clear escalation paths',
'Review and prune old documentation regularly'
],
beatPrinciple: 'Response time is not reaction time. Async means responding when working, not responding immediately.'
}
},
autonomy: {
low: {
title: 'Trust is Missing',
description: 'Top-down control stifles creativity and ownership. Developers who can\'t make decisions become disengaged and stop innovating.',
recommendations: [
'Shift from assigning work to letting developers pull work',
'Provide goals and constraints, not detailed instructions',
'Trust makers to choose their tools and approaches',
'Create safe space for pushing back on poorly conceived work'
],
beatPrinciple: 'Trust makers to make. Those who build the thing decide how to build it.'
},
medium: {
title: 'Autonomy is Inconsistent',
description: 'Some freedom exists, but it varies. Building genuine trust requires consistent practices.',
recommendations: [
'Define clear boundaries: what decisions can makers own?',
'Make "pull not push" the default for work assignment',
'Encourage challenges and alternative proposals',
'Remove approval bottlenecks where possible'
],
beatPrinciple: 'The maker\'s "no" is valid. This is not insubordination—it is ownership.'
},
high: {
title: 'High-Trust Environment',
description: 'Your team operates with real autonomy. This is rare and valuable—protect it.',
recommendations: [
'Document how autonomy works for new members',
'Guard against creeping micromanagement',
'Share your culture openly',
'Continue empowering individual decision-making'
],
beatPrinciple: 'Pull, don\'t push. Work is not assigned. Work is pulled by those with capacity and interest.'
}
},
sustainability: {
low: {
title: 'Burnout Risk is High',
description: 'Regular overtime and no time for learning is a recipe for burnout, turnover, and declining quality.',
recommendations: [
'Plan at 80% capacity, leaving slack for life',
'When deadlines conflict, cut scope—never cut rest',
'Protect 20% time for learning and exploration',
'Make overtime a red flag, not a badge of honor'
],
beatPrinciple: 'Sustainable pace is not optional. Overtime is a red flag, not a badge of honor.'
},
medium: {
title: 'Sustainability Needs Attention',
description: 'You\'re managing, but there are warning signs. Building in more slack now prevents bigger problems later.',
recommendations: [
'Track overtime patterns and address root causes',
'Formally protect exploration time',
'Review capacity planning—are you over 80%?',
'Watch for burnout warning signs'
],
beatPrinciple: 'The team\'s health is the Enabler\'s responsibility. Someone must watch for warning signs.'
},
high: {
title: 'Sustainable Pace Culture',
description: 'Your team has built healthy work habits. This enables long-term high performance.',
recommendations: [
'Maintain your boundaries under pressure',
'Help other teams learn sustainable practices',
'Continue investing in learning time',
'Celebrate sustainable delivery over heroics'
],
beatPrinciple: 'Exploration time is not a reward. It is a requirement. This is how we stay sharp.'
}
}
}
export const overallAssessment = {
struggling: {
range: [12, 24],
title: 'Significant Opportunity for Improvement',
icon: 'fas fa-exclamation-triangle',
color: 'red',
description: 'Your team faces significant challenges that BEAT is designed to solve. The good news: there\'s tremendous potential for improvement.',
callToAction: 'Start with the biggest pain point. Small changes compound over time.'
},
developing: {
range: [25, 36],
title: 'Building Better Practices',
icon: 'fas fa-seedling',
color: 'amber',
description: 'Your team has some good foundations but inconsistent practices. BEAT can provide the structure to level up.',
callToAction: 'Focus on making existing good practices consistent and documented.'
},
strong: {
range: [37, 42],
title: 'Strong Foundation',
icon: 'fas fa-chart-line',
color: 'blue',
description: 'Your team already practices many BEAT principles. Formalizing them will help you scale and onboard new members.',
callToAction: 'Document what works and share it with your organization.'
},
excellent: {
range: [43, 48],
title: 'BEAT-Ready Team',
icon: 'fas fa-star',
color: 'green',
description: 'Congratulations! Your team is already aligned with BEAT principles. Consider adopting the framework formally.',
callToAction: 'You\'re ready to fully adopt BEAT and become ambassadors for these practices.'
}
}
-5
View File
@@ -40,11 +40,6 @@ const routes = [
path: '/reference',
name: 'Reference',
component: () => import('@/views/ReferenceView.vue')
},
{
path: '/assessment',
name: 'Assessment',
component: () => import('@/views/AssessmentView.vue')
}
]
+60 -78
View File
@@ -35,104 +35,92 @@ const warningSigns = [
<template>
<div>
<!-- Hero -->
<section class="relative pt-32 sm:pt-40 pb-16 sm:pb-20 overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-red-50 via-orange-50 to-amber-50 dark:from-gray-900 dark:via-red-950/20 dark:to-orange-950/20 transition-colors duration-300"></div>
<div class="absolute top-20 -left-20 w-96 h-96 bg-red-400/20 dark:bg-red-500/20 rounded-full filter blur-3xl animate-float"></div>
<div class="absolute top-40 -right-20 w-80 h-80 bg-orange-400/20 dark:bg-orange-500/20 rounded-full filter blur-3xl animate-float animate-delay-2000"></div>
<section class="relative pt-24 sm:pt-32 pb-12 sm:pb-16 overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-red-50 via-orange-50 to-amber-50 dark:from-gray-900 dark:via-red-900/10 dark:to-orange-900/10 transition-colors duration-300"></div>
<div class="absolute top-0 -left-4 w-72 h-72 bg-red-300 dark:bg-red-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float"></div>
<div class="absolute top-0 -right-4 w-72 h-72 bg-orange-300 dark:bg-orange-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-1000"></div>
<div class="relative max-w-6xl mx-auto px-4 sm:px-6 text-center">
<div class="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300 text-sm font-medium mb-6 animate-fade-in-up">
<i class="fas fa-exclamation-triangle"></i>
Watch Out
<div class="w-16 h-16 rounded-xl bg-gradient-to-br from-red-500 to-orange-500 flex items-center justify-center mx-auto mb-6 animate-fade-in-up">
<i class="fas fa-exclamation-triangle text-white text-2xl"></i>
</div>
<div class="w-20 h-20 rounded-2xl bg-gradient-to-br from-red-500 to-orange-500 flex items-center justify-center mx-auto mb-8 animate-fade-in-up animate-delay-100">
<i class="fas fa-exclamation-triangle text-white text-3xl"></i>
</div>
<h1 class="section-title animate-fade-in-up animate-delay-200">Anti-Patterns</h1>
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-300">
<h1 class="section-title animate-fade-in-up animate-delay-100">Anti-Patterns</h1>
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-200">
Common ways teams fail at BEAT—and how to fix them.
</p>
</div>
</section>
<!-- Process Anti-Patterns -->
<section class="py-20 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="flex items-center gap-4 mb-10">
<div class="w-14 h-14 rounded-2xl bg-gradient-to-br from-red-500 to-red-600 flex items-center justify-center shadow-lg">
<i class="fas fa-cogs text-white text-xl"></i>
</div>
<div>
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100">Process Anti-Patterns</h2>
<p class="text-gray-500 dark:text-gray-400">Issues in how work flows</p>
<div class="flex items-center gap-4 mb-8">
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-red-500 to-red-600 flex items-center justify-center">
<i class="fas fa-cogs text-white"></i>
</div>
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100">Process Anti-Patterns</h2>
</div>
<TableCard :headers="processHeaders" :rows="processRows" />
</div>
</section>
<!-- People Anti-Patterns -->
<section class="py-20 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300">
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="flex items-center gap-4 mb-10">
<div class="w-14 h-14 rounded-2xl bg-gradient-to-br from-amber-500 to-amber-600 flex items-center justify-center shadow-lg">
<i class="fas fa-users text-white text-xl"></i>
</div>
<div>
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100">People Anti-Patterns</h2>
<p class="text-gray-500 dark:text-gray-400">Issues in team dynamics</p>
<div class="flex items-center gap-4 mb-8">
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-amber-500 to-amber-600 flex items-center justify-center">
<i class="fas fa-users text-white"></i>
</div>
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100">People Anti-Patterns</h2>
</div>
<TableCard :headers="peopleHeaders" :rows="peopleRows" />
</div>
</section>
<!-- Organizational Anti-Patterns -->
<section class="py-20 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="flex items-center gap-4 mb-10">
<div class="w-14 h-14 rounded-2xl bg-gradient-to-br from-purple-500 to-purple-600 flex items-center justify-center shadow-lg">
<i class="fas fa-building text-white text-xl"></i>
</div>
<div>
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100">Organizational Anti-Patterns</h2>
<p class="text-gray-500 dark:text-gray-400">Issues from outside the team</p>
<div class="flex items-center gap-4 mb-8">
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-purple-500 to-purple-600 flex items-center justify-center">
<i class="fas fa-building text-white"></i>
</div>
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100">Organizational Anti-Patterns</h2>
</div>
<TableCard :headers="orgHeaders" :rows="orgRows" />
</div>
</section>
<!-- Warning Signs -->
<section class="py-20 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300">
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-14">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">When BEAT Isn't Working</h2>
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">When BEAT Isn't Working</h2>
<p class="text-gray-600 dark:text-gray-400">Signs the methodology isn't serving the team:</p>
</div>
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-5 mb-10">
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-4 mb-8">
<div
v-for="(sign, index) in warningSigns"
v-for="sign in warningSigns"
:key="sign"
class="card p-5 border-l-4 border-red-500"
:style="{ animationDelay: `${index * 100}ms` }"
class="glass p-4 rounded-xl border-l-4 border-red-500"
>
<div class="flex items-center gap-3">
<i class="fas fa-exclamation-circle text-red-500 text-lg"></i>
<span class="text-gray-700 dark:text-gray-300">{{ sign }}</span>
<i class="fas fa-exclamation-circle text-red-500"></i>
<span class="text-gray-700 dark:text-gray-300 text-sm">{{ sign }}</span>
</div>
</div>
</div>
<div class="card p-8 bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800">
<div class="flex items-start gap-5">
<div class="w-14 h-14 rounded-xl bg-blue-500 flex items-center justify-center flex-shrink-0">
<i class="fas fa-lightbulb text-white text-xl"></i>
<div class="glass p-6 rounded-xl bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800">
<div class="flex items-start gap-4">
<div class="w-10 h-10 rounded-lg bg-blue-500 flex items-center justify-center flex-shrink-0">
<i class="fas fa-lightbulb text-white"></i>
</div>
<div>
<h4 class="font-bold text-blue-800 dark:text-blue-200 mb-2 text-lg">Response</h4>
<p class="text-blue-700 dark:text-blue-300">Discuss in Beat Close. Adapt the framework. BEAT is a tool, not a religion. If it's not working, change it or choose something else.</p>
<h4 class="font-semibold text-blue-800 dark:text-blue-200 mb-2">Response</h4>
<p class="text-blue-700 dark:text-blue-300 text-sm">
Discuss in Beat Close. Adapt the framework. BEAT is a tool, not a religion. If it's not working, change it or choose something else.
</p>
</div>
</div>
</div>
@@ -140,66 +128,60 @@ const warningSigns = [
</section>
<!-- Where BEAT Fits -->
<section class="py-20 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-14">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">Where BEAT Fits</h2>
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Where BEAT Fits</h2>
<p class="text-gray-600 dark:text-gray-400">Know your context. Adapt accordingly.</p>
</div>
<div class="grid md:grid-cols-3 gap-6">
<div class="card p-8 border-t-4 border-emerald-500">
<h3 class="font-bold text-xl text-gray-900 dark:text-gray-100 mb-6 flex items-center gap-3">
<div class="w-12 h-12 rounded-xl bg-emerald-100 dark:bg-emerald-900/30 flex items-center justify-center">
<i class="fas fa-check-circle text-emerald-500 text-xl"></i>
</div>
<div class="glass p-6 rounded-xl border-t-4 border-green-500">
<h3 class="font-bold text-gray-900 dark:text-gray-100 mb-4 flex items-center gap-2">
<i class="fas fa-check-circle text-green-500"></i>
Works Best For
</h3>
<ul class="space-y-3">
<ul class="space-y-2">
<li
v-for="item in whereItFits.worksFor"
:key="item"
class="text-gray-600 dark:text-gray-400 flex items-center gap-3 p-3 rounded-xl bg-emerald-50 dark:bg-emerald-900/20"
class="text-sm text-gray-600 dark:text-gray-400 flex items-center gap-2"
>
<i class="fas fa-check text-emerald-500"></i>
<i class="fas fa-check text-green-500 text-xs"></i>
{{ item }}
</li>
</ul>
</div>
<div class="card p-8 border-t-4 border-red-500">
<h3 class="font-bold text-xl text-gray-900 dark:text-gray-100 mb-6 flex items-center gap-3">
<div class="w-12 h-12 rounded-xl bg-red-100 dark:bg-red-900/30 flex items-center justify-center">
<i class="fas fa-times-circle text-red-500 text-xl"></i>
</div>
<div class="glass p-6 rounded-xl border-t-4 border-red-500">
<h3 class="font-bold text-gray-900 dark:text-gray-100 mb-4 flex items-center gap-2">
<i class="fas fa-times-circle text-red-500"></i>
Fits Poorly For
</h3>
<ul class="space-y-3">
<ul class="space-y-2">
<li
v-for="item in whereItFits.fitsPoorly"
:key="item"
class="text-gray-600 dark:text-gray-400 flex items-center gap-3 p-3 rounded-xl bg-red-50 dark:bg-red-900/20"
class="text-sm text-gray-600 dark:text-gray-400 flex items-center gap-2"
>
<i class="fas fa-times text-red-500"></i>
<i class="fas fa-times text-red-500 text-xs"></i>
{{ item }}
</li>
</ul>
</div>
<div class="card p-8 border-t-4 border-amber-500">
<h3 class="font-bold text-xl text-gray-900 dark:text-gray-100 mb-6 flex items-center gap-3">
<div class="w-12 h-12 rounded-xl bg-amber-100 dark:bg-amber-900/30 flex items-center justify-center">
<i class="fas fa-sliders-h text-amber-500 text-xl"></i>
</div>
<div class="glass p-6 rounded-xl border-t-4 border-amber-500">
<h3 class="font-bold text-gray-900 dark:text-gray-100 mb-4 flex items-center gap-2">
<i class="fas fa-sliders-h text-amber-500"></i>
Can Adapt For
</h3>
<ul class="space-y-3">
<ul class="space-y-2">
<li
v-for="item in whereItFits.canAdapt"
:key="item"
class="text-gray-600 dark:text-gray-400 flex items-center gap-3 p-3 rounded-xl bg-amber-50 dark:bg-amber-900/20"
class="text-sm text-gray-600 dark:text-gray-400 flex items-center gap-2"
>
<i class="fas fa-adjust text-amber-500"></i>
<i class="fas fa-adjust text-amber-500 text-xs"></i>
{{ item }}
</li>
</ul>
-411
View File
@@ -1,411 +0,0 @@
<script setup>
import { ref, computed } from 'vue'
import { RouterLink } from 'vue-router'
import { assessmentCategories, assessmentQuestions, beatRecommendations, overallAssessment } from '@/data/assessment'
const currentStep = ref(0)
const answers = ref({})
const showResults = ref(false)
const totalQuestions = assessmentQuestions.length
const currentQuestion = computed(() => assessmentQuestions[currentStep.value - 1])
const progress = computed(() => Math.round((Object.keys(answers.value).length / totalQuestions) * 100))
const startAssessment = () => {
currentStep.value = 1
answers.value = {}
showResults.value = false
}
const selectAnswer = (questionId, value) => {
answers.value[questionId] = value
if (currentStep.value < totalQuestions) {
setTimeout(() => {
currentStep.value++
}, 300)
} else {
setTimeout(() => {
showResults.value = true
currentStep.value = totalQuestions + 1
}, 300)
}
}
const goBack = () => {
if (currentStep.value > 1) {
currentStep.value--
}
}
const restartAssessment = () => {
currentStep.value = 0
answers.value = {}
showResults.value = false
}
const categoryScores = computed(() => {
const scores = {}
assessmentCategories.forEach(cat => {
const categoryQuestions = assessmentQuestions.filter(q => q.category === cat.id)
const categoryAnswers = categoryQuestions.map(q => answers.value[q.id] || 0)
const total = categoryAnswers.reduce((a, b) => a + b, 0)
const max = categoryQuestions.length * 4
scores[cat.id] = {
score: total,
max,
percentage: Math.round((total / max) * 100),
level: total <= max * 0.4 ? 'low' : total <= max * 0.7 ? 'medium' : 'high'
}
})
return scores
})
const totalScore = computed(() => {
return Object.values(answers.value).reduce((a, b) => a + b, 0)
})
const overallLevel = computed(() => {
const score = totalScore.value
if (score <= 24) return overallAssessment.struggling
if (score <= 36) return overallAssessment.developing
if (score <= 42) return overallAssessment.strong
return overallAssessment.excellent
})
const getRecommendation = (categoryId) => {
const level = categoryScores.value[categoryId]?.level || 'low'
return beatRecommendations[categoryId][level]
}
const colorClasses = {
blue: {
bg: 'bg-blue-50 dark:bg-blue-900/20',
border: 'border-blue-200 dark:border-blue-800',
text: 'text-blue-600 dark:text-blue-400',
gradient: 'from-blue-500 to-blue-600',
progress: 'bg-blue-500'
},
purple: {
bg: 'bg-purple-50 dark:bg-purple-900/20',
border: 'border-purple-200 dark:border-purple-800',
text: 'text-purple-600 dark:text-purple-400',
gradient: 'from-purple-500 to-purple-600',
progress: 'bg-purple-500'
},
green: {
bg: 'bg-emerald-50 dark:bg-emerald-900/20',
border: 'border-emerald-200 dark:border-emerald-800',
text: 'text-emerald-600 dark:text-emerald-400',
gradient: 'from-emerald-500 to-emerald-600',
progress: 'bg-emerald-500'
},
amber: {
bg: 'bg-amber-50 dark:bg-amber-900/20',
border: 'border-amber-200 dark:border-amber-800',
text: 'text-amber-600 dark:text-amber-400',
gradient: 'from-amber-500 to-amber-600',
progress: 'bg-amber-500'
},
red: {
bg: 'bg-red-50 dark:bg-red-900/20',
border: 'border-red-200 dark:border-red-800',
text: 'text-red-600 dark:text-red-400',
gradient: 'from-red-500 to-red-600',
progress: 'bg-red-500'
}
}
</script>
<template>
<div>
<!-- Hero -->
<section class="relative pt-28 sm:pt-32 lg:pt-40 pb-10 sm:pb-12 lg:pb-16 overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-indigo-50 via-purple-50 to-pink-50 dark:from-gray-900 dark:via-indigo-950/20 dark:to-purple-950/20 transition-colors duration-300"></div>
<div class="absolute top-20 -left-20 w-72 h-72 sm:w-96 sm:h-96 bg-indigo-400/20 dark:bg-indigo-500/20 rounded-full filter blur-3xl animate-float"></div>
<div class="absolute top-40 -right-20 w-64 h-64 sm:w-80 sm:h-80 bg-purple-400/20 dark:bg-purple-500/20 rounded-full filter blur-3xl animate-float animate-delay-2000"></div>
<div class="relative w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 xl:px-12 text-center">
<div class="inline-flex items-center gap-2 px-3 sm:px-4 py-1.5 sm:py-2 rounded-full bg-indigo-100 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 text-xs sm:text-sm font-medium mb-4 sm:mb-6 animate-fade-in-up">
<i class="fas fa-clipboard-check"></i>
Self-Assessment
</div>
<div class="w-16 h-16 sm:w-20 sm:h-20 rounded-xl sm:rounded-2xl bg-gradient-to-br from-indigo-500 to-purple-500 flex items-center justify-center mx-auto mb-6 sm:mb-8 animate-fade-in-up animate-delay-100">
<i class="fas fa-clipboard-check text-white text-2xl sm:text-3xl"></i>
</div>
<h1 class="section-title animate-fade-in-up animate-delay-200">Team Assessment</h1>
<p class="section-subtitle max-w-2xl lg:max-w-3xl mx-auto animate-fade-in-up animate-delay-300">
Discover how BEAT can help your team deliver better and faster.
</p>
</div>
</section>
<!-- Intro Screen -->
<section v-if="currentStep === 0" class="py-8 sm:py-10 lg:py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="w-full max-w-3xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="card p-6 sm:p-8 lg:p-10 text-center">
<div class="w-20 h-20 sm:w-24 sm:h-24 rounded-full bg-gradient-to-br from-indigo-500 to-purple-500 flex items-center justify-center mx-auto mb-6 sm:mb-8 shadow-glow-purple">
<i class="fas fa-tasks text-white text-2xl sm:text-4xl"></i>
</div>
<h2 class="text-xl sm:text-2xl lg:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-3 sm:mb-4">
How BEAT-Ready is Your Team?
</h2>
<p class="text-gray-600 dark:text-gray-400 mb-6 sm:mb-8 leading-relaxed text-sm sm:text-base">
Answer 12 quick questions about your current practices. We'll analyze your responses and show you specifically how BEAT principles can help your team.
</p>
<div class="grid grid-cols-2 sm:grid-cols-4 gap-3 sm:gap-4 mb-6 sm:mb-8">
<div v-for="cat in assessmentCategories" :key="cat.id" class="p-3 sm:p-4 rounded-xl" :class="colorClasses[cat.color].bg">
<div
class="w-10 h-10 sm:w-12 sm:h-12 rounded-lg sm:rounded-xl bg-gradient-to-br flex items-center justify-center mx-auto mb-2 sm:mb-3"
:class="cat.gradient"
>
<i :class="cat.icon" class="text-white text-base sm:text-xl"></i>
</div>
<div class="text-xs sm:text-sm text-gray-700 dark:text-gray-300 font-medium">{{ cat.title }}</div>
</div>
</div>
<div class="flex flex-wrap items-center justify-center gap-2 sm:gap-4 text-xs sm:text-sm text-gray-500 dark:text-gray-500 mb-6 sm:mb-8">
<span class="flex items-center gap-1.5 sm:gap-2 px-3 sm:px-4 py-1.5 sm:py-2 rounded-full bg-gray-100 dark:bg-gray-800">
<i class="fas fa-clock"></i> 3-5 min
</span>
<span class="flex items-center gap-1.5 sm:gap-2 px-3 sm:px-4 py-1.5 sm:py-2 rounded-full bg-gray-100 dark:bg-gray-800">
<i class="fas fa-shield-alt"></i> Anonymous
</span>
<span class="flex items-center gap-1.5 sm:gap-2 px-3 sm:px-4 py-1.5 sm:py-2 rounded-full bg-gray-100 dark:bg-gray-800">
<i class="fas fa-chart-bar"></i> Instant results
</span>
</div>
<button @click="startAssessment" class="btn-primary text-sm sm:text-base px-8 sm:px-10 py-3 sm:py-4">
<i class="fas fa-play mr-2"></i>
Start Assessment
</button>
</div>
</div>
</section>
<!-- Question Screen -->
<section v-else-if="!showResults" class="py-6 sm:py-8 lg:py-10 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="w-full max-w-3xl mx-auto px-4 sm:px-6 lg:px-8">
<!-- Progress Bar -->
<div class="mb-5 sm:mb-6">
<div class="flex items-center justify-between text-xs sm:text-sm text-gray-600 dark:text-gray-400 mb-2">
<span class="font-medium">Question {{ currentStep }} of {{ totalQuestions }}</span>
<span>{{ progress }}% complete</span>
</div>
<div class="h-2.5 sm:h-3 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
<div
class="h-full bg-gradient-to-r from-indigo-500 to-purple-500 transition-all duration-500 ease-out rounded-full"
:style="{ width: `${progress}%` }"
></div>
</div>
</div>
<!-- Category Badge -->
<div class="mb-4 sm:mb-6">
<span
class="inline-flex items-center gap-1.5 sm:gap-2 px-3 sm:px-4 py-1.5 sm:py-2 rounded-full text-xs sm:text-sm font-medium"
:class="[colorClasses[assessmentCategories.find(c => c.id === currentQuestion.category)?.color || 'blue'].bg, colorClasses[assessmentCategories.find(c => c.id === currentQuestion.category)?.color || 'blue'].text]"
>
<i :class="assessmentCategories.find(c => c.id === currentQuestion.category)?.icon" class="text-xs"></i>
{{ assessmentCategories.find(c => c.id === currentQuestion.category)?.title }}
</span>
</div>
<!-- Question Card -->
<div class="card p-5 sm:p-6 lg:p-8">
<h2 class="text-base sm:text-lg lg:text-xl font-bold text-gray-900 dark:text-gray-100 mb-5 sm:mb-6">
{{ currentQuestion.question }}
</h2>
<div class="space-y-2.5 sm:space-y-3">
<button
v-for="option in currentQuestion.options"
:key="option.value"
@click="selectAnswer(currentQuestion.id, option.value)"
class="w-full p-3 sm:p-4 lg:p-5 rounded-xl border-2 text-left transition-all duration-200 hover:shadow-md min-h-[64px] sm:min-h-[72px] group"
:class="[
answers[currentQuestion.id] === option.value
? 'border-indigo-500 bg-indigo-50 dark:bg-indigo-900/20'
: 'border-gray-200 dark:border-gray-700 hover:border-indigo-300 dark:hover:border-indigo-600'
]"
>
<div class="flex items-start gap-3 sm:gap-4">
<div
class="w-5 h-5 sm:w-6 sm:h-6 rounded-full border-2 flex items-center justify-center flex-shrink-0 mt-0.5 transition-colors"
:class="[
answers[currentQuestion.id] === option.value
? 'border-indigo-500 bg-indigo-500'
: 'border-gray-300 dark:border-gray-600 group-hover:border-indigo-400'
]"
>
<i v-if="answers[currentQuestion.id] === option.value" class="fas fa-check text-white text-xs"></i>
</div>
<div>
<div class="font-semibold text-gray-900 dark:text-gray-100 mb-0.5 sm:mb-1 text-sm sm:text-base">{{ option.label }}</div>
<div class="text-xs sm:text-sm text-gray-500 dark:text-gray-500">{{ option.description }}</div>
</div>
</div>
</button>
</div>
<div class="flex items-center justify-between mt-5 sm:mt-6 pt-4 sm:pt-5 border-t border-gray-200 dark:border-gray-700">
<button
v-if="currentStep > 1"
@click="goBack"
class="text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 transition-colors px-3 sm:px-4 py-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 text-sm sm:text-base"
>
<i class="fas fa-arrow-left mr-2"></i>
Back
</button>
<div v-else></div>
<div class="hidden sm:flex items-center gap-1.5">
<div
v-for="i in totalQuestions"
:key="i"
class="w-2 h-2 rounded-full transition-colors"
:class="[
i === currentStep ? 'bg-indigo-500' :
answers[i] ? 'bg-indigo-300 dark:bg-indigo-700' :
'bg-gray-300 dark:bg-gray-600'
]"
></div>
</div>
<div class="sm:hidden text-xs sm:text-sm text-gray-500 dark:text-gray-500">
{{ currentStep }}/{{ totalQuestions }}
</div>
</div>
</div>
</div>
</section>
<!-- Results Screen -->
<section v-else class="py-6 sm:py-8 lg:py-10 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="w-full max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<!-- Overall Score -->
<div class="card p-6 sm:p-8 lg:p-10 mb-6 sm:mb-8 text-center">
<div
class="w-16 h-16 sm:w-20 sm:h-20 lg:w-24 lg:h-24 rounded-full flex items-center justify-center mx-auto mb-4 sm:mb-6"
:class="colorClasses[overallLevel.color].bg"
>
<i :class="[overallLevel.icon, colorClasses[overallLevel.color].text]" class="text-2xl sm:text-3xl lg:text-4xl"></i>
</div>
<h2 class="text-lg sm:text-xl lg:text-2xl font-bold text-gray-900 dark:text-gray-100 mb-2">
{{ overallLevel.title }}
</h2>
<div class="text-2xl sm:text-3xl lg:text-4xl font-bold gradient-text mb-3 sm:mb-4">
{{ totalScore }} / 48
</div>
<p class="text-gray-600 dark:text-gray-400 max-w-xl mx-auto mb-3 sm:mb-4 text-sm sm:text-base">
{{ overallLevel.description }}
</p>
<div
class="inline-flex items-center gap-2 px-4 sm:px-5 py-2 sm:py-2.5 rounded-xl"
:class="[colorClasses[overallLevel.color].bg, colorClasses[overallLevel.color].border]"
>
<i class="fas fa-lightbulb" :class="colorClasses[overallLevel.color].text"></i>
<span class="font-medium text-sm sm:text-base" :class="colorClasses[overallLevel.color].text">{{ overallLevel.callToAction }}</span>
</div>
</div>
<!-- Category Breakdown -->
<h3 class="text-base sm:text-lg lg:text-xl font-bold text-gray-900 dark:text-gray-100 mb-4 sm:mb-5 flex items-center gap-2 sm:gap-3">
<div class="w-0.5 sm:w-1 h-5 sm:h-6 rounded-full bg-gradient-to-b from-indigo-500 to-purple-500"></div>
Category Breakdown
</h3>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4 mb-6 sm:mb-8">
<div
v-for="cat in assessmentCategories"
:key="cat.id"
class="card p-4 sm:p-5"
>
<div class="flex items-center gap-3 sm:gap-4 mb-3 sm:mb-4">
<div
class="w-10 h-10 sm:w-12 sm:h-12 rounded-lg sm:rounded-xl bg-gradient-to-br flex items-center justify-center"
:class="cat.gradient"
>
<i :class="cat.icon" class="text-white text-base sm:text-lg"></i>
</div>
<div class="flex-1 min-w-0">
<div class="font-semibold text-gray-900 dark:text-gray-100 text-sm sm:text-base truncate">{{ cat.title }}</div>
<div class="text-xs sm:text-sm" :class="colorClasses[cat.color].text">
{{ categoryScores[cat.id]?.percentage }}% ({{ categoryScores[cat.id]?.score }}/{{ categoryScores[cat.id]?.max }})
</div>
</div>
</div>
<div class="h-2 sm:h-2.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
<div
class="h-full rounded-full transition-all duration-1000"
:class="colorClasses[cat.color].progress"
:style="{ width: `${categoryScores[cat.id]?.percentage}%` }"
></div>
</div>
</div>
</div>
<!-- Detailed Recommendations -->
<h3 class="text-base sm:text-lg lg:text-xl font-bold text-gray-900 dark:text-gray-100 mb-4 sm:mb-5 flex items-center gap-2 sm:gap-3">
<div class="w-0.5 sm:w-1 h-5 sm:h-6 rounded-full bg-gradient-to-b from-emerald-500 to-teal-500"></div>
How BEAT Can Help
</h3>
<div class="space-y-4 sm:space-y-5 mb-6 sm:mb-8">
<div
v-for="cat in assessmentCategories"
:key="cat.id"
class="card p-4 sm:p-5 lg:p-6"
>
<div class="flex items-start gap-3 sm:gap-4 mb-3 sm:mb-4">
<div
class="w-10 h-10 sm:w-12 sm:h-12 rounded-lg sm:rounded-xl bg-gradient-to-br flex items-center justify-center flex-shrink-0"
:class="cat.gradient"
>
<i :class="cat.icon" class="text-white text-base sm:text-lg"></i>
</div>
<div class="flex-1 min-w-0">
<h4 class="font-bold text-gray-900 dark:text-gray-100 text-sm sm:text-base lg:text-lg">{{ getRecommendation(cat.id).title }}</h4>
<p class="text-gray-600 dark:text-gray-400 mt-0.5 sm:mt-1 text-xs sm:text-sm">{{ getRecommendation(cat.id).description }}</p>
</div>
</div>
<div class="space-y-1.5 sm:space-y-2 mb-3 sm:mb-4">
<div
v-for="rec in getRecommendation(cat.id).recommendations"
:key="rec"
class="flex items-start gap-2 sm:gap-3 p-2.5 sm:p-3 rounded-lg"
:class="colorClasses[cat.color].bg"
>
<i class="fas fa-check-circle mt-0.5 text-xs sm:text-sm" :class="colorClasses[cat.color].text"></i>
<span class="text-gray-700 dark:text-gray-300 text-xs sm:text-sm">{{ rec }}</span>
</div>
</div>
<div class="flex items-start gap-2 sm:gap-3 p-3 sm:p-4 rounded-lg bg-gray-50 dark:bg-gray-800 border-l-4" :class="colorClasses[cat.color].border">
<i class="fas fa-quote-left text-gray-400 mt-0.5 text-xs sm:text-sm"></i>
<p class="text-gray-600 dark:text-gray-400 italic text-xs sm:text-sm">{{ getRecommendation(cat.id).beatPrinciple }}</p>
</div>
</div>
</div>
<!-- CTA -->
<div class="p-6 sm:p-8 lg:p-10 rounded-2xl sm:rounded-3xl bg-gradient-to-br from-indigo-600 via-purple-600 to-pink-600 text-center">
<h3 class="text-lg sm:text-xl lg:text-2xl font-bold text-white mb-2 sm:mb-3">Ready to Transform Your Team?</h3>
<p class="text-white/80 mb-4 sm:mb-6 max-w-xl mx-auto text-sm sm:text-base">
Explore the full BEAT manifesto and start implementing these practices today.
</p>
<div class="flex flex-col sm:flex-row gap-2 sm:gap-3 justify-center">
<RouterLink to="/values" class="bg-white text-indigo-600 px-5 sm:px-6 py-2.5 sm:py-3 rounded-lg font-semibold hover:bg-gray-100 transition-colors min-h-[48px] flex items-center justify-center text-sm sm:text-base">
<i class="fas fa-book-open mr-2"></i>
Read the Manifesto
</RouterLink>
<button @click="restartAssessment" class="bg-white/20 text-white px-5 sm:px-6 py-2.5 sm:py-3 rounded-lg font-semibold hover:bg-white/30 transition-colors min-h-[48px] flex items-center justify-center text-sm sm:text-base">
<i class="fas fa-redo mr-2"></i>
Retake Assessment
</button>
</div>
</div>
</div>
</section>
</div>
</template>
+87 -134
View File
@@ -1,124 +1,106 @@
<script setup>
import CodeBlock from '@/components/ui/CodeBlock.vue'
import { roles, priorityBuckets, ceremonies, constraints } from '@/data/manifesto'
const workItems = [
{ name: 'Tasks', time: 'hours', description: 'A one-liner. No ceremony needed.', icon: 'fas fa-check', color: 'blue' },
{ name: 'Work Items', time: 'days', description: 'Title, context, done condition. Three lines.', icon: 'fas fa-tasks', color: 'purple' },
{ name: 'Projects', time: 'week+', description: 'Half-page doc with breakdown. No more.', icon: 'fas fa-folder', color: 'emerald' }
{ name: 'Tasks', time: 'hours', description: 'A one-liner. No ceremony needed.' },
{ name: 'Work Items', time: 'days', description: 'Title, context, done condition. Three lines.' },
{ name: 'Projects', time: 'week+', description: 'Half-page doc with breakdown. No more.' }
]
const bucketColors = {
red: 'from-red-500 to-red-600 border-red-500 shadow-glow-red',
red: 'from-red-500 to-red-600 border-red-500',
amber: 'from-amber-500 to-amber-600 border-amber-500',
blue: 'from-blue-500 to-blue-600 border-blue-500 shadow-glow-blue',
blue: 'from-blue-500 to-blue-600 border-blue-500',
gray: 'from-gray-500 to-gray-600 border-gray-500'
}
const boardColumns = [
{ name: 'ICE', color: 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400', icon: 'fas fa-snowflake' },
{ name: 'LATER', color: 'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300', icon: 'fas fa-clock' },
{ name: 'NEXT', color: 'bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-300', icon: 'fas fa-arrow-up' },
{ name: 'IN PROGRESS', color: 'bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300', icon: 'fas fa-spinner' },
{ name: 'DONE', color: 'bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300', icon: 'fas fa-check-circle' }
]
</script>
<template>
<div>
<!-- Hero -->
<section class="relative pt-32 sm:pt-40 pb-16 sm:pb-20 overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-purple-50 via-indigo-50 to-blue-50 dark:from-gray-900 dark:via-purple-950/20 dark:to-indigo-950/20 transition-colors duration-300"></div>
<div class="absolute top-20 -left-20 w-96 h-96 bg-purple-400/20 dark:bg-purple-500/20 rounded-full filter blur-3xl animate-float"></div>
<div class="absolute top-40 -right-20 w-80 h-80 bg-indigo-400/20 dark:bg-indigo-500/20 rounded-full filter blur-3xl animate-float animate-delay-2000"></div>
<section class="relative pt-24 sm:pt-32 pb-12 sm:pb-16 overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-purple-50 via-indigo-50 to-blue-50 dark:from-gray-900 dark:via-purple-900/10 dark:to-indigo-900/10 transition-colors duration-300"></div>
<div class="absolute top-0 -left-4 w-72 h-72 bg-purple-300 dark:bg-purple-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float"></div>
<div class="absolute top-0 -right-4 w-72 h-72 bg-indigo-300 dark:bg-indigo-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-1000"></div>
<div class="relative max-w-6xl mx-auto px-4 sm:px-6 text-center">
<div class="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300 text-sm font-medium mb-6 animate-fade-in-up">
<i class="fas fa-sitemap"></i>
Implementation
<div class="w-16 h-16 rounded-xl bg-gradient-to-br from-purple-500 to-indigo-500 flex items-center justify-center mx-auto mb-6 animate-fade-in-up">
<i class="fas fa-sitemap text-white text-2xl"></i>
</div>
<div class="w-20 h-20 rounded-2xl bg-gradient-to-br from-purple-500 to-indigo-500 flex items-center justify-center mx-auto mb-8 animate-fade-in-up animate-delay-100 shadow-glow-purple">
<i class="fas fa-sitemap text-white text-3xl"></i>
</div>
<h1 class="section-title animate-fade-in-up animate-delay-200">The Framework</h1>
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-300">
<h1 class="section-title animate-fade-in-up animate-delay-100">The Framework</h1>
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-200">
The principles guide us. The framework implements them.
</p>
</div>
</section>
<!-- Roles -->
<section class="py-20 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-14">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">Roles</h2>
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Roles</h2>
<p class="text-gray-600 dark:text-gray-400">We recognize three roles, loosely held.</p>
</div>
<div class="grid md:grid-cols-3 gap-6">
<div
v-for="(role, index) in roles"
v-for="role in roles"
:key="role.name"
class="card group p-8 text-center"
:style="{ animationDelay: `${index * 100}ms` }"
class="glass p-6 rounded-xl group hover:shadow-lg transition-all duration-300"
>
<div
class="w-20 h-20 rounded-2xl bg-gradient-to-br flex items-center justify-center mx-auto mb-6 group-hover:scale-110 group-hover:rotate-3 transition-all duration-300 shadow-lg"
class="w-14 h-14 rounded-xl bg-gradient-to-br flex items-center justify-center mb-4 group-hover:scale-110 transition-transform duration-300"
:class="role.gradient"
>
<i :class="role.icon" class="text-white text-2xl"></i>
<i :class="role.icon" class="text-white text-xl"></i>
</div>
<h3 class="text-2xl font-bold text-gray-900 dark:text-gray-100 mb-4">{{ role.name }}</h3>
<p class="text-gray-600 dark:text-gray-400 leading-relaxed">{{ role.description }}</p>
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-3">{{ role.name }}</h3>
<p class="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">{{ role.description }}</p>
</div>
</div>
</div>
</section>
<!-- Beats -->
<section class="py-20 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300 relative overflow-hidden">
<div class="absolute top-0 right-0 w-96 h-96 bg-blue-500/5 dark:bg-blue-500/10 rounded-full filter blur-3xl"></div>
<div class="max-w-6xl mx-auto px-4 sm:px-6 relative">
<div class="text-center mb-14">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">Beats</h2>
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Beats</h2>
<p class="text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
We work in beats—flexible iterations of one to two weeks.
</p>
</div>
<div class="glass p-8 sm:p-10 rounded-3xl">
<!-- Timeline -->
<div class="grid md:grid-cols-3 gap-8 relative">
<!-- Connecting line -->
<div class="hidden md:block absolute top-12 left-0 right-0 h-0.5 bg-gradient-to-r from-blue-500 via-purple-500 to-emerald-500"></div>
<div class="text-center relative">
<div class="w-24 h-24 rounded-full bg-gradient-to-br from-blue-500 to-cyan-500 flex items-center justify-center mx-auto mb-6 relative z-10 shadow-glow-blue group-hover:scale-110 transition-transform">
<i class="fas fa-play text-white text-2xl"></i>
<div class="glass p-8 rounded-2xl">
<div class="grid md:grid-cols-3 gap-8">
<div class="text-center">
<div class="w-12 h-12 rounded-full bg-gradient-to-br from-blue-500 to-cyan-500 flex items-center justify-center mx-auto mb-4">
<i class="fas fa-play text-white"></i>
</div>
<h4 class="font-bold text-xl text-gray-900 dark:text-gray-100 mb-2">Beat Start</h4>
<h4 class="font-semibold text-gray-900 dark:text-gray-100 mb-2">Beat Start</h4>
<p class="text-sm text-gray-600 dark:text-gray-400">Review priorities and pull initial work</p>
</div>
<div class="text-center relative">
<div class="w-24 h-24 rounded-full bg-gradient-to-br from-purple-500 to-pink-500 flex items-center justify-center mx-auto mb-6 relative z-10 shadow-glow-purple">
<i class="fas fa-cogs text-white text-2xl"></i>
<div class="text-center">
<div class="w-12 h-12 rounded-full bg-gradient-to-br from-purple-500 to-pink-500 flex items-center justify-center mx-auto mb-4">
<i class="fas fa-cogs text-white"></i>
</div>
<h4 class="font-bold text-xl text-gray-900 dark:text-gray-100 mb-2">During Beat</h4>
<h4 class="font-semibold text-gray-900 dark:text-gray-100 mb-2">During Beat</h4>
<p class="text-sm text-gray-600 dark:text-gray-400">Check in async daily, work autonomously</p>
</div>
<div class="text-center relative">
<div class="w-24 h-24 rounded-full bg-gradient-to-br from-emerald-500 to-teal-500 flex items-center justify-center mx-auto mb-6 relative z-10">
<i class="fas fa-flag-checkered text-white text-2xl"></i>
<div class="text-center">
<div class="w-12 h-12 rounded-full bg-gradient-to-br from-green-500 to-emerald-500 flex items-center justify-center mx-auto mb-4">
<i class="fas fa-flag-checkered text-white"></i>
</div>
<h4 class="font-bold text-xl text-gray-900 dark:text-gray-100 mb-2">Beat Close</h4>
<h4 class="font-semibold text-gray-900 dark:text-gray-100 mb-2">Beat Close</h4>
<p class="text-sm text-gray-600 dark:text-gray-400">Reflect: what worked, what didn't, what to improve</p>
</div>
</div>
<div class="mt-10 p-5 rounded-xl bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800">
<p class="text-sm text-blue-800 dark:text-blue-200 flex items-start gap-3">
<i class="fas fa-info-circle mt-0.5"></i>
<span>Beats have <strong>goals</strong>, not commitments. We aim; we do not promise. There is no sprint pressure, no velocity tracking, no burndown theater.</span>
<div class="mt-8 p-4 rounded-lg bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800">
<p class="text-sm text-blue-800 dark:text-blue-200">
<i class="fas fa-info-circle mr-2"></i>
Beats have <strong>goals</strong>, not commitments. We aim; we do not promise. There is no sprint pressure, no velocity tracking, no burndown theater.
</p>
</div>
</div>
@@ -126,115 +108,89 @@ const boardColumns = [
</section>
<!-- Work Items -->
<section class="py-20 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-14">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">Work Items</h2>
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Work Items</h2>
<p class="text-gray-600 dark:text-gray-400">Documentation effort scales with task size.</p>
</div>
<div class="grid md:grid-cols-3 gap-6">
<div
v-for="(item, index) in workItems"
v-for="item in workItems"
:key="item.name"
class="card group p-8"
:style="{ animationDelay: `${index * 100}ms` }"
class="glass p-6 rounded-xl hover:shadow-lg transition-all duration-300"
>
<div class="flex items-center gap-4 mb-4">
<div
class="w-14 h-14 rounded-xl bg-gradient-to-br flex items-center justify-center group-hover:scale-110 transition-all duration-300"
:class="[
item.color === 'blue' ? 'from-blue-500 to-blue-600' :
item.color === 'purple' ? 'from-purple-500 to-purple-600' :
'from-emerald-500 to-emerald-600'
]"
>
<i :class="item.icon" class="text-white text-xl"></i>
</div>
<div class="flex items-center gap-3 mb-3">
<span class="text-2xl font-bold gradient-text">{{ item.name }}</span>
</div>
<div class="inline-block px-4 py-1.5 rounded-full bg-gray-100 dark:bg-gray-700 text-sm text-gray-600 dark:text-gray-400 mb-4 font-medium">
<div class="inline-block px-3 py-1 rounded-full bg-gray-100 dark:bg-gray-700 text-sm text-gray-600 dark:text-gray-400 mb-3">
{{ item.time }}
</div>
<p class="text-gray-600 dark:text-gray-400">{{ item.description }}</p>
<p class="text-gray-600 dark:text-gray-400 text-sm">{{ item.description }}</p>
</div>
</div>
<div class="mt-8 text-center">
<p class="text-gray-500 dark:text-gray-500">
We size with <strong class="text-gray-700 dark:text-gray-300">S/M/L</strong>, not story points. We do not groom. We do not point. We do not track velocity.
<p class="text-gray-500 dark:text-gray-500 text-sm">
We size with <strong>S/M/L</strong>, not story points. We do not groom. We do not point. We do not track velocity.
</p>
</div>
</div>
</section>
<!-- Prioritization -->
<section class="py-20 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300">
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-14">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">Prioritization Buckets</h2>
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Prioritization Buckets</h2>
<p class="text-gray-600 dark:text-gray-400">We use four buckets to organize work.</p>
</div>
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-5">
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-4">
<div
v-for="(bucket, index) in priorityBuckets"
v-for="bucket in priorityBuckets"
:key="bucket.name"
class="card p-6 border-l-4"
class="glass p-5 rounded-xl border-l-4 hover:shadow-lg transition-all duration-300"
:class="bucketColors[bucket.color]"
:style="{ animationDelay: `${index * 100}ms` }"
>
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-3">{{ bucket.name }}</h3>
<p class="text-sm text-gray-600 dark:text-gray-400 leading-relaxed">{{ bucket.description }}</p>
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 mb-2">{{ bucket.name }}</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">{{ bucket.description }}</p>
</div>
</div>
</div>
</section>
<!-- The Board -->
<section class="py-20 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-14">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">The Board</h2>
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">The Board</h2>
<p class="text-gray-600 dark:text-gray-400">A simple kanban with priority built in.</p>
</div>
<!-- Visual Board Flow -->
<div class="glass p-6 sm:p-8 rounded-3xl overflow-x-auto mb-8">
<div class="flex items-center justify-start sm:justify-center gap-3 min-w-max sm:min-w-0">
<template v-for="(col, index) in boardColumns" :key="col.name">
<div
class="flex items-center gap-2 px-4 py-3 rounded-xl font-medium"
:class="col.color"
>
<i :class="col.icon" class="text-sm"></i>
<span class="text-sm">{{ col.name }}</span>
</div>
<i v-if="index < boardColumns.length - 1" class="fas fa-arrow-right text-gray-400"></i>
</template>
</div>
</div>
<CodeBlock title="Board Flow">ICE → LATER → NEXT → IN PROGRESS → DONE</CodeBlock>
<div class="grid sm:grid-cols-3 gap-5">
<div class="card p-6 text-center group">
<div class="w-14 h-14 rounded-xl bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center mx-auto mb-4 group-hover:scale-110 transition-transform">
<i class="fas fa-user text-blue-500 text-xl"></i>
<div class="mt-8 grid sm:grid-cols-3 gap-4">
<div class="glass p-4 rounded-lg">
<div class="flex items-center gap-2 mb-2">
<i class="fas fa-user text-blue-500"></i>
<span class="font-semibold text-gray-900 dark:text-gray-100">WIP Limit</span>
</div>
<span class="font-semibold text-gray-900 dark:text-gray-100 block mb-1">WIP Limit</span>
<p class="text-sm text-gray-600 dark:text-gray-400">3 items per maker</p>
</div>
<div class="card p-6 text-center group">
<div class="w-14 h-14 rounded-xl bg-purple-100 dark:bg-purple-900/30 flex items-center justify-center mx-auto mb-4 group-hover:scale-110 transition-transform">
<i class="fas fa-sort-amount-up text-purple-500 text-xl"></i>
<div class="glass p-4 rounded-lg">
<div class="flex items-center gap-2 mb-2">
<i class="fas fa-sort-amount-up text-purple-500"></i>
<span class="font-semibold text-gray-900 dark:text-gray-100">NEXT is Ordered</span>
</div>
<span class="font-semibold text-gray-900 dark:text-gray-100 block mb-1">NEXT is Ordered</span>
<p class="text-sm text-gray-600 dark:text-gray-400">Pull from top</p>
</div>
<div class="card p-6 text-center group">
<div class="w-14 h-14 rounded-xl bg-amber-100 dark:bg-amber-900/30 flex items-center justify-center mx-auto mb-4 group-hover:scale-110 transition-transform">
<i class="fas fa-clock text-amber-500 text-xl"></i>
<div class="glass p-4 rounded-lg">
<div class="flex items-center gap-2 mb-2">
<i class="fas fa-clock text-amber-500"></i>
<span class="font-semibold text-gray-900 dark:text-gray-100">Stale Items</span>
</div>
<span class="font-semibold text-gray-900 dark:text-gray-100 block mb-1">Stale Items</span>
<p class="text-sm text-gray-600 dark:text-gray-400">Return to backlog after 5 days</p>
</div>
</div>
@@ -242,20 +198,17 @@ const boardColumns = [
</section>
<!-- Constraints -->
<section class="py-20 relative overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-purple-600 via-indigo-600 to-blue-600"></div>
<div class="relative max-w-5xl mx-auto px-4 sm:px-6">
<h2 class="text-3xl sm:text-4xl font-bold text-white text-center mb-12">The Numbers</h2>
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-5">
<section class="py-16 bg-gradient-to-br from-purple-600 via-indigo-600 to-blue-600">
<div class="max-w-4xl mx-auto px-4 sm:px-6">
<h2 class="text-2xl sm:text-3xl font-bold text-white text-center mb-8">The Numbers</h2>
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-4">
<div
v-for="(item, index) in constraints"
v-for="item in constraints"
:key="item.constraint"
class="bg-white/10 backdrop-blur-sm p-5 rounded-2xl border border-white/10 hover:bg-white/20 transition-all duration-300"
:style="{ animationDelay: `${index * 50}ms` }"
class="bg-white/10 backdrop-blur-sm p-4 rounded-xl"
>
<div class="text-white/70 text-sm mb-1">{{ item.constraint }}</div>
<div class="text-white text-2xl font-bold">{{ item.limit }}</div>
<div class="text-white text-xl font-bold">{{ item.limit }}</div>
</div>
</div>
</div>
+106 -157
View File
@@ -1,158 +1,111 @@
<script setup>
import { RouterLink } from 'vue-router'
import IconCard from '@/components/ui/IconCard.vue'
import { researchStats } from '@/data/manifesto'
const navCards = [
{ path: '/values', title: 'Values', description: 'Core & team values that guide everything', icon: 'fas fa-heart', gradient: 'from-rose-500 to-pink-500', color: 'rose' },
{ path: '/principles', title: 'Principles', description: 'The 12 principles of BEAT', icon: 'fas fa-compass', gradient: 'from-blue-500 to-cyan-500', color: 'blue' },
{ path: '/framework', title: 'Framework', description: 'Roles, beats, and the board', icon: 'fas fa-sitemap', gradient: 'from-purple-500 to-indigo-500', color: 'purple' },
{ path: '/practices', title: 'Practices', description: 'Meetings, collaboration, incidents', icon: 'fas fa-cogs', gradient: 'from-emerald-500 to-teal-500', color: 'emerald' },
{ path: '/onboarding', title: 'Onboarding', description: 'Getting started with BEAT', icon: 'fas fa-user-plus', gradient: 'from-amber-500 to-orange-500', color: 'amber' },
{ path: '/reference', title: 'Reference', description: 'Quick lookup tables', icon: 'fas fa-book', gradient: 'from-cyan-500 to-sky-500', color: 'cyan' }
{ path: '/values', title: 'Values', description: 'Core & team values that guide everything', icon: 'fas fa-heart', gradient: 'from-red-500 to-pink-500' },
{ path: '/principles', title: 'Principles', description: 'The 12 principles of BEAT', icon: 'fas fa-compass', gradient: 'from-blue-500 to-cyan-500' },
{ path: '/framework', title: 'Framework', description: 'Roles, beats, and the board', icon: 'fas fa-sitemap', gradient: 'from-purple-500 to-indigo-500' },
{ path: '/practices', title: 'Practices', description: 'Meetings, collaboration, incidents', icon: 'fas fa-cogs', gradient: 'from-green-500 to-emerald-500' },
{ path: '/onboarding', title: 'Onboarding', description: 'Getting started with BEAT', icon: 'fas fa-user-plus', gradient: 'from-amber-500 to-orange-500' },
{ path: '/reference', title: 'Reference', description: 'Quick lookup tables', icon: 'fas fa-book', gradient: 'from-cyan-500 to-blue-500' }
]
const keyNumbers = [
{ value: '4hrs', label: 'Sacred Focus Block', icon: 'fas fa-brain', color: 'blue' },
{ value: '2hrs', label: 'Max Meetings/Week', icon: 'fas fa-calendar', color: 'purple' },
{ value: '80%', label: 'Planning Capacity', icon: 'fas fa-battery-three-quarters', color: 'emerald' },
{ value: '20%', label: 'Exploration Time', icon: 'fas fa-flask', color: 'amber' }
]
const commitments = [
{ icon: 'fas fa-shield-alt', title: 'Protecting focus', description: 'We will not interrupt sacred time. We will wait.' },
{ icon: 'fas fa-pen', title: 'Defaulting to async', description: 'We will write first, meet only when writing fails.' },
{ icon: 'fas fa-handshake', title: 'Trusting makers', description: 'We will provide goals, not instructions. Constraints, not control.' },
{ icon: 'fas fa-heart', title: 'Sustaining pace', description: 'We will cut scope before we cut rest. We will plan for humans.' },
{ value: '4hrs', label: 'Sacred Focus Block', icon: 'fas fa-brain' },
{ value: '2hrs', label: 'Max Meetings/Week', icon: 'fas fa-calendar' },
{ value: '80%', label: 'Planning Capacity', icon: 'fas fa-battery-three-quarters' },
{ value: '20%', label: 'Exploration Time', icon: 'fas fa-flask' }
]
</script>
<template>
<div>
<!-- Hero Section -->
<section class="relative min-h-[85vh] sm:min-h-[90vh] flex items-center justify-center overflow-hidden">
<!-- Animated background blobs -->
<div class="absolute inset-0 bg-gradient-to-br from-blue-50 via-purple-50 to-cyan-50 dark:from-gray-900 dark:via-blue-950/30 dark:to-purple-950/30 transition-colors duration-500"></div>
<!-- Floating orbs - responsive sizing -->
<div class="absolute top-20 left-[5%] w-48 h-48 sm:w-72 sm:h-72 lg:w-96 lg:h-96 bg-blue-400/20 dark:bg-blue-500/20 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-3xl animate-float"></div>
<div class="absolute top-40 right-[5%] w-56 h-56 sm:w-80 sm:h-80 lg:w-[28rem] lg:h-[28rem] bg-purple-400/20 dark:bg-purple-500/20 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-3xl animate-float animate-delay-2000"></div>
<div class="absolute -bottom-10 left-1/4 w-52 h-52 sm:w-72 sm:h-72 lg:w-80 lg:h-80 bg-cyan-400/20 dark:bg-cyan-500/20 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-3xl animate-float animate-delay-1000"></div>
<!-- Grid pattern overlay -->
<div class="absolute inset-0 bg-[url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjAiIGhlaWdodD0iNjAiIHZpZXdCb3g9IjAgMCA2MCA2MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxnIGZpbGw9IiM5Y2EzYWYiIGZpbGwtb3BhY2l0eT0iMC4wNSI+PHBhdGggZD0iTTM2IDM0aDR2NGgtNHpNMjQgMjRoNHY0aC00eiIvPjwvZz48L2c+PC9zdmc+')] opacity-50"></div>
<section class="relative pt-24 sm:pt-32 pb-16 sm:pb-24 overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-blue-50 via-purple-50 to-cyan-50 dark:from-gray-900 dark:via-blue-900/20 dark:to-purple-900/20 transition-colors duration-300"></div>
<div class="absolute top-0 -left-4 w-72 h-72 bg-blue-300 dark:bg-blue-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float"></div>
<div class="absolute top-0 -right-4 w-72 h-72 bg-purple-300 dark:bg-purple-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-1000"></div>
<div class="absolute -bottom-8 left-20 w-72 h-72 bg-cyan-300 dark:bg-cyan-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-2000"></div>
<div class="relative w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 xl:px-12 py-16 sm:py-20 lg:py-24">
<div class="relative max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center">
<!-- Logo with glow effect -->
<div class="mb-6 sm:mb-8 flex justify-center animate-fade-in-up">
<div
class="relative w-20 h-20 sm:w-28 sm:h-28 lg:w-36 lg:h-36 rounded-2xl bg-gradient-to-br from-blue-600 via-purple-600 to-cyan-600 flex items-center justify-center shadow-2xl animate-float"
>
<!-- Glow effect -->
<div class="absolute inset-0 rounded-2xl bg-gradient-to-br from-blue-600 via-purple-600 to-cyan-600 blur-xl opacity-50 animate-pulse-slow"></div>
<span class="relative text-white text-3xl sm:text-5xl lg:text-6xl font-bold">B</span>
<div class="w-24 h-24 sm:w-32 sm:h-32 rounded-2xl bg-gradient-to-br from-blue-600 via-purple-600 to-cyan-600 flex items-center justify-center shadow-xl animate-float">
<span class="text-white text-4xl sm:text-5xl font-bold">B</span>
</div>
</div>
<!-- Title - responsive sizing -->
<h1 class="text-4xl sm:text-5xl md:text-6xl lg:text-7xl xl:text-8xl font-bold text-gray-900 dark:text-gray-100 mb-4 sm:mb-6 leading-tight animate-fade-in-up animate-delay-100">
<h1 class="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold text-gray-900 dark:text-gray-100 mb-4 sm:mb-6 leading-tight animate-fade-in-up animate-delay-100">
The <span class="gradient-text">BEAT</span> Manifesto
</h1>
<!-- Subtitle -->
<p class="text-xl sm:text-2xl md:text-3xl lg:text-4xl text-gray-700 dark:text-gray-200 mb-4 sm:mb-6 animate-fade-in-up animate-delay-200 font-medium tracking-tight">
<p class="text-xl sm:text-2xl md:text-3xl text-gray-700 dark:text-gray-200 mb-4 animate-fade-in-up animate-delay-200 font-medium">
<span class="text-blue-600 dark:text-blue-400">B</span>alanced.
<span class="text-purple-600 dark:text-purple-400">E</span>mpowered.
<span class="text-cyan-600 dark:text-cyan-400">A</span>sync.
<span class="text-pink-600 dark:text-pink-400">T</span>eams.
</p>
<!-- Description -->
<p class="text-base sm:text-lg lg:text-xl text-gray-600 dark:text-gray-400 mb-8 sm:mb-10 max-w-2xl lg:max-w-3xl mx-auto animate-fade-in-up animate-delay-300 leading-relaxed px-4 sm:px-0">
<p class="text-base sm:text-lg text-gray-600 dark:text-gray-400 mb-8 max-w-2xl mx-auto animate-fade-in-up animate-delay-300">
A software delivery methodology built for how developers actually work.
<span class="block mt-2 text-gray-500 dark:text-gray-500">Created by <strong class="text-gray-700 dark:text-gray-300">Lukasz Raczylo</strong>.</span>
<br class="hidden sm:block" />
Created by <strong>Lukasz Raczylo</strong>.
</p>
<!-- CTA Buttons - stack on mobile, side by side on larger screens -->
<div class="flex flex-col sm:flex-row gap-3 sm:gap-4 justify-center animate-fade-in-up animate-delay-400 px-4 sm:px-0">
<RouterLink to="/values" class="btn-primary text-sm sm:text-base px-6 sm:px-8 py-3 sm:py-4">
<div class="flex flex-col sm:flex-row gap-4 justify-center animate-fade-in-up animate-delay-300">
<RouterLink to="/values" class="btn-primary">
<i class="fas fa-book-open mr-2"></i>
Start Reading
</RouterLink>
<RouterLink to="/assessment" class="btn-secondary text-sm sm:text-base px-6 sm:px-8 py-3 sm:py-4">
<i class="fas fa-clipboard-check mr-2"></i>
Take Assessment
<RouterLink to="/reference" class="btn-secondary">
<i class="fas fa-list mr-2"></i>
Quick Reference
</RouterLink>
</div>
</div>
</div>
<!-- Scroll indicator - hide on very small screens -->
<div class="absolute bottom-4 sm:bottom-8 left-1/2 -translate-x-1/2 animate-bounce-subtle hidden sm:block">
<div class="w-6 h-10 rounded-full border-2 border-gray-400 dark:border-gray-600 flex items-start justify-center p-2">
<div class="w-1.5 h-3 rounded-full bg-gray-400 dark:bg-gray-600 animate-pulse"></div>
</div>
</div>
</section>
<!-- Key Numbers -->
<section class="py-12 sm:py-16 lg:py-20 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 xl:px-12">
<div class="grid grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4 lg:gap-6">
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-6">
<div
v-for="(item, index) in keyNumbers"
v-for="item in keyNumbers"
:key="item.label"
class="group card text-center p-4 sm:p-6 lg:p-8"
:class="`hover:border-${item.color}-300 dark:hover:border-${item.color}-700`"
:style="{ animationDelay: `${index * 100}ms` }"
class="glass p-6 rounded-xl text-center group hover:shadow-lg transition-all duration-300"
>
<div
class="w-10 h-10 sm:w-12 sm:h-12 lg:w-14 lg:h-14 rounded-xl sm:rounded-2xl bg-gradient-to-br flex items-center justify-center mx-auto mb-3 sm:mb-4 transition-all duration-300 group-hover:scale-110 group-hover:rotate-3"
:class="[
item.color === 'blue' ? 'from-blue-500 to-blue-600 shadow-glow-blue' :
item.color === 'purple' ? 'from-purple-500 to-purple-600 shadow-glow-purple' :
item.color === 'emerald' ? 'from-emerald-500 to-emerald-600' :
'from-amber-500 to-amber-600'
]"
>
<i :class="item.icon" class="text-white text-base sm:text-xl lg:text-2xl"></i>
<div class="w-12 h-12 rounded-full bg-gradient-to-br from-blue-500 to-purple-500 flex items-center justify-center mx-auto mb-3 group-hover:scale-110 transition-transform duration-300">
<i :class="item.icon" class="text-white"></i>
</div>
<div class="text-2xl sm:text-3xl lg:text-4xl xl:text-5xl font-bold gradient-text mb-1 sm:mb-2">{{ item.value }}</div>
<div class="text-xs sm:text-sm text-gray-600 dark:text-gray-400 font-medium">{{ item.label }}</div>
<div class="text-3xl sm:text-4xl font-bold gradient-text mb-1">{{ item.value }}</div>
<div class="text-sm text-gray-600 dark:text-gray-400">{{ item.label }}</div>
</div>
</div>
</div>
</section>
<!-- Introduction -->
<section class="py-12 sm:py-16 lg:py-20 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300 relative overflow-hidden">
<!-- Decorative elements -->
<div class="absolute top-0 right-0 w-48 h-48 sm:w-64 sm:h-64 bg-blue-500/5 dark:bg-blue-500/10 rounded-full filter blur-3xl"></div>
<div class="absolute bottom-0 left-0 w-48 h-48 sm:w-64 sm:h-64 bg-purple-500/5 dark:bg-purple-500/10 rounded-full filter blur-3xl"></div>
<div class="w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 xl:px-12 relative">
<div class="glass p-6 sm:p-8 lg:p-12 xl:p-16 rounded-2xl sm:rounded-3xl">
<div class="flex items-center gap-3 mb-4 sm:mb-6">
<div class="w-1 h-6 sm:h-8 rounded-full bg-gradient-to-b from-blue-500 to-purple-500"></div>
<h2 class="text-xl sm:text-2xl font-bold text-gray-900 dark:text-gray-100">Our Philosophy</h2>
</div>
<p class="text-lg sm:text-xl lg:text-2xl text-gray-700 dark:text-gray-300 leading-relaxed mb-4 sm:mb-6 font-light">
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<div class="max-w-4xl mx-auto px-4 sm:px-6">
<div class="glass p-8 sm:p-12 rounded-2xl">
<p class="text-lg sm:text-xl text-gray-700 dark:text-gray-300 leading-relaxed mb-6">
We are uncovering better ways of building software by doing it and helping others do it.
</p>
<p class="text-gray-600 dark:text-gray-400 leading-relaxed mb-6 sm:mb-8 text-sm sm:text-base">
<p class="text-gray-600 dark:text-gray-400 leading-relaxed mb-8">
BEAT emerges from research on how developers actually work. We built it for these realities, not against them.
</p>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4">
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-4">
<div
v-for="(stat, index) in researchStats"
v-for="stat in researchStats"
:key="stat.stat"
class="flex items-center gap-3 p-3 sm:p-4 rounded-xl bg-white/60 dark:bg-gray-700/50 hover:bg-white dark:hover:bg-gray-700 transition-all duration-300 group"
:style="{ animationDelay: `${index * 50}ms` }"
class="flex items-center gap-3 p-3 rounded-lg bg-white/50 dark:bg-gray-700/50"
>
<span class="text-xl sm:text-2xl font-bold text-transparent bg-clip-text bg-gradient-to-br from-blue-500 to-purple-500">{{ stat.stat }}</span>
<span class="text-xs sm:text-sm text-gray-600 dark:text-gray-400">{{ stat.description }}</span>
<span class="text-xl font-bold text-blue-600 dark:text-blue-400">{{ stat.stat }}</span>
<span class="text-sm text-gray-600 dark:text-gray-400">{{ stat.description }}</span>
</div>
</div>
</div>
@@ -160,34 +113,33 @@ const commitments = [
</section>
<!-- Navigation Cards -->
<section class="py-12 sm:py-16 lg:py-20 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 xl:px-12">
<div class="text-center mb-10 sm:mb-14">
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-12">
<h2 class="section-title">Explore the Manifesto</h2>
<p class="section-subtitle">Deep dive into each aspect of BEAT</p>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-5 lg:gap-6">
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-6">
<RouterLink
v-for="(card, index) in navCards"
v-for="card in navCards"
:key="card.path"
:to="card.path"
class="group card p-5 sm:p-6 lg:p-8"
:style="{ animationDelay: `${index * 100}ms` }"
class="glass p-6 rounded-xl group hover:shadow-lg transition-all duration-300 hover:-translate-y-1"
>
<div class="flex items-start gap-4 sm:gap-5">
<div class="flex items-start gap-4">
<div
class="w-12 h-12 sm:w-14 sm:h-14 rounded-xl sm:rounded-2xl bg-gradient-to-br flex items-center justify-center flex-shrink-0 transition-all duration-300 group-hover:scale-110 group-hover:rotate-6"
class="w-12 h-12 rounded-xl bg-gradient-to-br flex items-center justify-center flex-shrink-0 group-hover:scale-110 transition-transform duration-300"
:class="card.gradient"
>
<i :class="card.icon" class="text-white text-lg sm:text-xl"></i>
<i :class="card.icon" class="text-white"></i>
</div>
<div class="flex-1 min-w-0">
<h3 class="font-semibold text-base sm:text-lg text-gray-900 dark:text-gray-100 mb-1 sm:mb-2 flex items-center gap-2 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors">
<div>
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-1 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors">
{{ card.title }}
<i class="fas fa-arrow-right text-xs sm:text-sm opacity-0 -translate-x-2 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-300"></i>
<i class="fas fa-arrow-right ml-2 text-sm opacity-0 group-hover:opacity-100 transition-opacity"></i>
</h3>
<p class="text-xs sm:text-sm text-gray-600 dark:text-gray-400 leading-relaxed">{{ card.description }}</p>
<p class="text-sm text-gray-600 dark:text-gray-400">{{ card.description }}</p>
</div>
</div>
</RouterLink>
@@ -196,62 +148,59 @@ const commitments = [
</section>
<!-- Commitment Section -->
<section class="py-12 sm:py-16 lg:py-20 relative overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-blue-600 via-purple-600 to-cyan-600"></div>
<!-- Animated background pattern -->
<div class="absolute inset-0 opacity-10">
<div class="absolute top-0 left-0 w-full h-full bg-[url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PHBhdHRlcm4gaWQ9ImEiIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGggZD0iTTAgNDBoNDBWMEgwVjQwWiIgZmlsbD0ibm9uZSIvPjxwYXRoIGQ9Ik0wIDQwaDQwVjBIMFY0MFoiIGZpbGw9IiNmZmZmZmYiIGZpbGwtb3BhY2l0eT0iMC4xIi8+PC9wYXR0ZXJuPjwvZGVmcz48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2EpIi8+PC9zdmc+')] animate-pulse-slow"></div>
</div>
<div class="relative w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 xl:px-12">
<div class="text-center mb-8 sm:mb-12">
<h2 class="text-2xl sm:text-3xl lg:text-4xl font-bold text-white mb-3 sm:mb-4">The BEAT Commitment</h2>
<p class="text-white/70 text-base sm:text-lg">By adopting BEAT, we commit to:</p>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4 lg:gap-5">
<div
v-for="(item, index) in commitments"
:key="item.title"
class="group bg-white/10 backdrop-blur-sm p-5 sm:p-6 rounded-xl sm:rounded-2xl border border-white/10 hover:bg-white/20 transition-all duration-300 hover:-translate-y-1"
:style="{ animationDelay: `${index * 100}ms` }"
>
<div class="flex items-center gap-3 sm:gap-4 mb-2 sm:mb-3">
<div class="w-10 h-10 sm:w-12 sm:h-12 rounded-lg sm:rounded-xl bg-white/20 flex items-center justify-center transition-all duration-300 group-hover:scale-110 group-hover:bg-white/30">
<i :class="item.icon" class="text-white text-base sm:text-xl"></i>
</div>
<span class="text-white font-semibold text-base sm:text-lg">{{ item.title }}</span>
<section class="py-16 bg-gradient-to-br from-blue-600 via-purple-600 to-cyan-600">
<div class="max-w-4xl mx-auto px-4 sm:px-6 text-center">
<h2 class="text-3xl sm:text-4xl font-bold text-white mb-8">The BEAT Commitment</h2>
<div class="grid sm:grid-cols-2 gap-4 text-left">
<div class="bg-white/10 backdrop-blur-sm p-6 rounded-xl">
<div class="flex items-center gap-3 mb-2">
<i class="fas fa-shield-alt text-white"></i>
<span class="text-white font-semibold">Protecting focus</span>
</div>
<p class="text-white/70 text-xs sm:text-sm leading-relaxed pl-13 sm:pl-16">{{ item.description }}</p>
<p class="text-white/80 text-sm">We will not interrupt sacred time. We will wait.</p>
</div>
<div class="bg-white/10 backdrop-blur-sm p-6 rounded-xl">
<div class="flex items-center gap-3 mb-2">
<i class="fas fa-pen text-white"></i>
<span class="text-white font-semibold">Defaulting to async</span>
</div>
<p class="text-white/80 text-sm">We will write first, meet only when writing fails.</p>
</div>
<div class="bg-white/10 backdrop-blur-sm p-6 rounded-xl">
<div class="flex items-center gap-3 mb-2">
<i class="fas fa-handshake text-white"></i>
<span class="text-white font-semibold">Trusting makers</span>
</div>
<p class="text-white/80 text-sm">We will provide goals, not instructions. Constraints, not control.</p>
</div>
<div class="bg-white/10 backdrop-blur-sm p-6 rounded-xl">
<div class="flex items-center gap-3 mb-2">
<i class="fas fa-heart text-white"></i>
<span class="text-white font-semibold">Sustaining pace</span>
</div>
<p class="text-white/80 text-sm">We will cut scope before we cut rest. We will plan for humans.</p>
</div>
</div>
</div>
</section>
<!-- Summary -->
<section class="py-12 sm:py-16 lg:py-20 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 xl:px-12 text-center">
<div class="glass p-6 sm:p-8 lg:p-10 xl:p-14 rounded-2xl sm:rounded-3xl relative overflow-hidden">
<!-- Decorative gradient -->
<div class="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-blue-500 via-purple-500 to-cyan-500"></div>
<div class="font-mono text-base sm:text-lg lg:text-xl xl:text-2xl text-gray-700 dark:text-gray-300 space-y-2 sm:space-y-3">
<p class="hover:text-blue-600 dark:hover:text-blue-400 transition-colors cursor-default">We protect focus.</p>
<p class="hover:text-purple-600 dark:hover:text-purple-400 transition-colors cursor-default">We write things down.</p>
<p class="hover:text-cyan-600 dark:hover:text-cyan-400 transition-colors cursor-default">We trust each other.</p>
<p class="hover:text-emerald-600 dark:hover:text-emerald-400 transition-colors cursor-default">We work sustainably.</p>
<p class="hover:text-pink-600 dark:hover:text-pink-400 transition-colors cursor-default">We ship and learn.</p>
</div>
<div class="mt-6 sm:mt-8 pt-6 sm:pt-8 border-t border-gray-200 dark:border-gray-700">
<p class="text-gray-500 dark:text-gray-500 italic text-base sm:text-lg">
BEAT: Built for how developers actually work.
</p>
<p class="mt-3 sm:mt-4 text-xs sm:text-sm text-gray-400 dark:text-gray-600">
BEAT v1.0 by Lukasz Raczylo
</p>
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-4xl mx-auto px-4 sm:px-6 text-center">
<div class="glass p-8 rounded-2xl">
<div class="font-mono text-lg sm:text-xl text-gray-700 dark:text-gray-300 space-y-2">
<p>We protect focus.</p>
<p>We write things down.</p>
<p>We trust each other.</p>
<p>We work sustainably.</p>
<p>We ship and learn.</p>
</div>
<p class="mt-6 text-gray-500 dark:text-gray-500 italic">
BEAT: Built for how developers actually work.
</p>
<p class="mt-4 text-sm text-gray-400 dark:text-gray-600">
BEAT v1.0 by Lukasz Raczylo
</p>
</div>
</div>
</section>
+56 -67
View File
@@ -2,9 +2,9 @@
import { onboarding } from '@/data/manifesto'
const weeks = [
{ ...onboarding.weekOne, icon: 'fas fa-eye', gradient: 'from-blue-500 to-cyan-500', color: 'blue' },
{ ...onboarding.weekTwo, icon: 'fas fa-hand-pointer', gradient: 'from-purple-500 to-pink-500', color: 'purple' },
{ ...onboarding.weekThree, icon: 'fas fa-rocket', gradient: 'from-emerald-500 to-teal-500', color: 'emerald' }
{ ...onboarding.weekOne, icon: 'fas fa-eye', gradient: 'from-blue-500 to-cyan-500' },
{ ...onboarding.weekTwo, icon: 'fas fa-hand-pointer', gradient: 'from-purple-500 to-pink-500' },
{ ...onboarding.weekThree, icon: 'fas fa-rocket', gradient: 'from-green-500 to-emerald-500' }
]
const whatWeDont = [
@@ -18,53 +18,48 @@ const whatWeDont = [
<template>
<div>
<!-- Hero -->
<section class="relative pt-32 sm:pt-40 pb-16 sm:pb-20 overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-amber-50 via-orange-50 to-red-50 dark:from-gray-900 dark:via-amber-950/20 dark:to-orange-950/20 transition-colors duration-300"></div>
<div class="absolute top-20 -left-20 w-96 h-96 bg-amber-400/20 dark:bg-amber-500/20 rounded-full filter blur-3xl animate-float"></div>
<div class="absolute top-40 -right-20 w-80 h-80 bg-orange-400/20 dark:bg-orange-500/20 rounded-full filter blur-3xl animate-float animate-delay-2000"></div>
<section class="relative pt-24 sm:pt-32 pb-12 sm:pb-16 overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-amber-50 via-orange-50 to-red-50 dark:from-gray-900 dark:via-amber-900/10 dark:to-orange-900/10 transition-colors duration-300"></div>
<div class="absolute top-0 -left-4 w-72 h-72 bg-amber-300 dark:bg-amber-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float"></div>
<div class="absolute top-0 -right-4 w-72 h-72 bg-orange-300 dark:bg-orange-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-1000"></div>
<div class="relative max-w-6xl mx-auto px-4 sm:px-6 text-center">
<div class="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-300 text-sm font-medium mb-6 animate-fade-in-up">
<i class="fas fa-user-plus"></i>
Getting Started
<div class="w-16 h-16 rounded-xl bg-gradient-to-br from-amber-500 to-orange-500 flex items-center justify-center mx-auto mb-6 animate-fade-in-up">
<i class="fas fa-user-plus text-white text-2xl"></i>
</div>
<div class="w-20 h-20 rounded-2xl bg-gradient-to-br from-amber-500 to-orange-500 flex items-center justify-center mx-auto mb-8 animate-fade-in-up animate-delay-100">
<i class="fas fa-user-plus text-white text-3xl"></i>
</div>
<h1 class="section-title animate-fade-in-up animate-delay-200">Onboarding to BEAT</h1>
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-300">
<h1 class="section-title animate-fade-in-up animate-delay-100">Onboarding to BEAT</h1>
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-200">
When someone new joins a BEAT team, here's how to get them up to speed.
</p>
</div>
</section>
<!-- Weekly Timeline -->
<section class="py-20 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="space-y-6">
<div class="space-y-8">
<div
v-for="(week, index) in weeks"
:key="week.title"
class="card p-8"
:style="{ animationDelay: `${index * 150}ms` }"
class="glass p-6 sm:p-8 rounded-2xl hover:shadow-lg transition-all duration-300"
>
<div class="flex flex-col sm:flex-row sm:items-start gap-6">
<div class="flex items-start gap-6">
<div
class="w-20 h-20 rounded-2xl bg-gradient-to-br flex items-center justify-center flex-shrink-0 shadow-lg"
class="w-16 h-16 rounded-xl bg-gradient-to-br flex items-center justify-center flex-shrink-0"
:class="week.gradient"
>
<i :class="week.icon" class="text-white text-2xl"></i>
<i :class="week.icon" class="text-white text-xl"></i>
</div>
<div class="flex-1">
<h3 class="text-2xl font-bold text-gray-900 dark:text-gray-100 mb-5">{{ week.title }}</h3>
<ul class="grid sm:grid-cols-2 gap-3">
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">{{ week.title }}</h3>
<ul class="space-y-3">
<li
v-for="item in week.items"
:key="item"
class="flex items-start gap-3 p-3 rounded-xl bg-gray-50 dark:bg-gray-800/50"
class="flex items-start gap-3 text-gray-600 dark:text-gray-400"
>
<i class="fas fa-check-circle text-emerald-500 mt-1"></i>
<span class="text-gray-700 dark:text-gray-300">{{ item }}</span>
<i class="fas fa-check-circle text-green-500 mt-1"></i>
<span>{{ item }}</span>
</li>
</ul>
</div>
@@ -75,69 +70,68 @@ const whatWeDont = [
</section>
<!-- First Month -->
<section class="py-20 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300">
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-14">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">{{ onboarding.firstMonth.title }}</h2>
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">{{ onboarding.firstMonth.title }}</h2>
<p class="text-gray-600 dark:text-gray-400">By the end of the first month, new members should:</p>
</div>
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-5">
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-4">
<div
v-for="(item, index) in onboarding.firstMonth.items"
:key="item"
class="card p-6 group"
:style="{ animationDelay: `${index * 100}ms` }"
class="glass p-5 rounded-xl hover:shadow-lg transition-all duration-300"
>
<div class="flex items-start gap-4">
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-amber-500 to-orange-500 flex items-center justify-center flex-shrink-0 group-hover:scale-110 transition-transform">
<span class="text-white text-lg font-bold">{{ index + 1 }}</span>
<div class="flex items-start gap-3">
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-amber-500 to-orange-500 flex items-center justify-center flex-shrink-0">
<span class="text-white text-sm font-bold">{{ index + 1 }}</span>
</div>
<p class="text-gray-700 dark:text-gray-300 pt-2">{{ item }}</p>
<p class="text-gray-700 dark:text-gray-300 text-sm">{{ item }}</p>
</div>
</div>
</div>
</div>
</section>
<!-- Connector's Responsibility & What We Don't -->
<section class="py-20 bg-white dark:bg-gray-900 transition-colors duration-300">
<!-- Connector's Responsibility -->
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="grid md:grid-cols-2 gap-8">
<div class="card p-8">
<div class="flex items-center gap-4 mb-6">
<div class="w-14 h-14 rounded-xl bg-gradient-to-br from-cyan-500 to-blue-500 flex items-center justify-center">
<i class="fas fa-project-diagram text-white text-xl"></i>
<div class="glass p-6 rounded-xl">
<div class="flex items-center gap-3 mb-6">
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-cyan-500 to-blue-500 flex items-center justify-center">
<i class="fas fa-project-diagram text-white"></i>
</div>
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100">Connector's Responsibility</h3>
</div>
<p class="text-gray-600 dark:text-gray-400 mb-6">
<p class="text-gray-600 dark:text-gray-400 mb-4 text-sm">
The Connector (or Enabler if no Connector) ensures:
</p>
<ul class="space-y-3">
<li class="flex items-start gap-3 p-3 rounded-xl bg-cyan-50 dark:bg-cyan-900/20">
<li class="flex items-start gap-3 text-sm text-gray-600 dark:text-gray-400">
<i class="fas fa-check text-cyan-500 mt-1"></i>
<span class="text-gray-700 dark:text-gray-300">Documentation is current and findable</span>
Documentation is current and findable
</li>
<li class="flex items-start gap-3 p-3 rounded-xl bg-cyan-50 dark:bg-cyan-900/20">
<li class="flex items-start gap-3 text-sm text-gray-600 dark:text-gray-400">
<i class="fas fa-check text-cyan-500 mt-1"></i>
<span class="text-gray-700 dark:text-gray-300">New member has a "buddy" for questions (informal, not mandatory pairing)</span>
New member has a "buddy" for questions (informal, not mandatory pairing)
</li>
<li class="flex items-start gap-3 p-3 rounded-xl bg-cyan-50 dark:bg-cyan-900/20">
<li class="flex items-start gap-3 text-sm text-gray-600 dark:text-gray-400">
<i class="fas fa-check text-cyan-500 mt-1"></i>
<span class="text-gray-700 dark:text-gray-300">First tasks are well-scoped and achievable</span>
First tasks are well-scoped and achievable
</li>
<li class="flex items-start gap-3 p-3 rounded-xl bg-cyan-50 dark:bg-cyan-900/20">
<li class="flex items-start gap-3 text-sm text-gray-600 dark:text-gray-400">
<i class="fas fa-check text-cyan-500 mt-1"></i>
<span class="text-gray-700 dark:text-gray-300">Overwhelm is caught early</span>
Overwhelm is caught early
</li>
</ul>
</div>
<div class="card p-8 border-l-4 border-red-500">
<div class="flex items-center gap-4 mb-6">
<div class="w-14 h-14 rounded-xl bg-gradient-to-br from-red-500 to-pink-500 flex items-center justify-center">
<i class="fas fa-times text-white text-xl"></i>
<div class="glass p-6 rounded-xl border-l-4 border-red-500">
<div class="flex items-center gap-3 mb-6">
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-red-500 to-pink-500 flex items-center justify-center">
<i class="fas fa-times text-white"></i>
</div>
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100">What We Don't Do</h3>
</div>
@@ -145,10 +139,10 @@ const whatWeDont = [
<li
v-for="item in whatWeDont"
:key="item"
class="flex items-start gap-3 p-3 rounded-xl bg-red-50 dark:bg-red-900/20"
class="flex items-start gap-3 text-sm text-gray-600 dark:text-gray-400"
>
<i class="fas fa-times text-red-500 mt-1"></i>
<span class="text-gray-700 dark:text-gray-300">{{ item }}</span>
{{ item }}
</li>
</ul>
</div>
@@ -157,15 +151,10 @@ const whatWeDont = [
</section>
<!-- Summary -->
<section class="py-20 relative overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-amber-500 via-orange-500 to-red-500"></div>
<div class="relative max-w-4xl mx-auto px-4 sm:px-6 text-center">
<div class="w-20 h-20 rounded-full bg-white/20 flex items-center justify-center mx-auto mb-8">
<i class="fas fa-bullseye text-white text-3xl"></i>
</div>
<h2 class="text-3xl sm:text-4xl font-bold text-white mb-6">The Goal</h2>
<p class="text-white/90 text-xl leading-relaxed">
<section class="py-16 bg-gradient-to-br from-amber-500 via-orange-500 to-red-500">
<div class="max-w-4xl mx-auto px-4 sm:px-6 text-center">
<h2 class="text-2xl sm:text-3xl font-bold text-white mb-4">The Goal</h2>
<p class="text-white/90 text-lg">
Onboarding should feel like a gradual ramp, not a firehose or an abandonment.
</p>
</div>
+170 -263
View File
@@ -1,153 +1,97 @@
<script setup>
import CodeBlock from '@/components/ui/CodeBlock.vue'
import { ceremonies, incidentProtocol, technicalPractices, definitionOfDone } from '@/data/manifesto'
const meetingLimits = [
{ value: '2 hours', label: 'per week total', icon: 'fas fa-clock', color: 'blue' },
{ value: '1 hour', label: 'maximum per meeting', icon: 'fas fa-hourglass-half', color: 'purple' },
{ value: 'Agenda', label: 'required or cancelled', icon: 'fas fa-list-check', color: 'emerald' }
]
const collaborationSteps = [
{ text: 'Post when stuck', icon: 'fas fa-comment-dots' },
{ text: 'Someone responds when available', icon: 'fas fa-reply' },
{ text: 'Sync briefly if needed', icon: 'fas fa-video' },
{ text: 'Return to solo work', icon: 'fas fa-user' }
]
const multiMakerPrinciples = [
{ title: 'Break vertically.', desc: 'Each maker owns an end-to-end slice.', icon: 'fas fa-arrows-alt-v' },
{ title: 'Define interfaces first.', desc: 'Work in parallel against contracts.', icon: 'fas fa-plug' },
{ title: 'Coordinate via doc.', desc: 'One feature doc as source of truth.', icon: 'fas fa-file-alt' },
{ title: 'Sync only when stuck.', desc: 'Document outcome. Return to async.', icon: 'fas fa-sync' }
]
</script>
<template>
<div>
<!-- Hero -->
<section class="relative pt-32 sm:pt-40 pb-16 sm:pb-20 overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-emerald-50 via-teal-50 to-cyan-50 dark:from-gray-900 dark:via-emerald-950/20 dark:to-teal-950/20 transition-colors duration-300"></div>
<div class="absolute top-20 -left-20 w-96 h-96 bg-emerald-400/20 dark:bg-emerald-500/20 rounded-full filter blur-3xl animate-float"></div>
<div class="absolute top-40 -right-20 w-80 h-80 bg-teal-400/20 dark:bg-teal-500/20 rounded-full filter blur-3xl animate-float animate-delay-2000"></div>
<section class="relative pt-24 sm:pt-32 pb-12 sm:pb-16 overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-green-50 via-emerald-50 to-cyan-50 dark:from-gray-900 dark:via-green-900/10 dark:to-emerald-900/10 transition-colors duration-300"></div>
<div class="absolute top-0 -left-4 w-72 h-72 bg-green-300 dark:bg-green-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float"></div>
<div class="absolute top-0 -right-4 w-72 h-72 bg-emerald-300 dark:bg-emerald-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-1000"></div>
<div class="relative max-w-6xl mx-auto px-4 sm:px-6 text-center">
<div class="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-emerald-100 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300 text-sm font-medium mb-6 animate-fade-in-up">
<i class="fas fa-cogs"></i>
Day-to-Day
<div class="w-16 h-16 rounded-xl bg-gradient-to-br from-green-500 to-emerald-500 flex items-center justify-center mx-auto mb-6 animate-fade-in-up">
<i class="fas fa-cogs text-white text-2xl"></i>
</div>
<div class="w-20 h-20 rounded-2xl bg-gradient-to-br from-emerald-500 to-teal-500 flex items-center justify-center mx-auto mb-8 animate-fade-in-up animate-delay-100">
<i class="fas fa-cogs text-white text-3xl"></i>
</div>
<h1 class="section-title animate-fade-in-up animate-delay-200">Practices</h1>
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-300">
<h1 class="section-title animate-fade-in-up animate-delay-100">Practices</h1>
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-200">
How we work day-to-day: meetings, collaboration, incidents, and technical practices.
</p>
</div>
</section>
<!-- Meetings -->
<section class="py-20 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-14">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">Meetings</h2>
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Meetings</h2>
<p class="text-gray-600 dark:text-gray-400">Hard limits protect our time.</p>
</div>
<div class="glass p-8 sm:p-10 rounded-3xl mb-10">
<div class="grid sm:grid-cols-3 gap-8">
<div
v-for="(item, index) in meetingLimits"
:key="item.label"
class="text-center group"
:style="{ animationDelay: `${index * 100}ms` }"
>
<div
class="w-16 h-16 rounded-2xl flex items-center justify-center mx-auto mb-4 transition-all duration-300 group-hover:scale-110"
:class="[
item.color === 'blue' ? 'bg-blue-100 dark:bg-blue-900/30' :
item.color === 'purple' ? 'bg-purple-100 dark:bg-purple-900/30' :
'bg-emerald-100 dark:bg-emerald-900/30'
]"
>
<i :class="[item.icon, 'text-2xl', item.color === 'blue' ? 'text-blue-500' : item.color === 'purple' ? 'text-purple-500' : 'text-emerald-500']"></i>
</div>
<div class="text-3xl sm:text-4xl font-bold gradient-text mb-2">{{ item.value }}</div>
<div class="text-gray-600 dark:text-gray-400 text-sm">{{ item.label }}</div>
<div class="glass p-6 rounded-2xl mb-8">
<div class="grid sm:grid-cols-3 gap-6 text-center">
<div>
<div class="text-3xl font-bold gradient-text mb-2">2 hours</div>
<div class="text-gray-600 dark:text-gray-400 text-sm">per week total</div>
</div>
<div>
<div class="text-3xl font-bold gradient-text mb-2">1 hour</div>
<div class="text-gray-600 dark:text-gray-400 text-sm">maximum per meeting</div>
</div>
<div>
<div class="text-3xl font-bold gradient-text mb-2">Agenda</div>
<div class="text-gray-600 dark:text-gray-400 text-sm">required or cancelled</div>
</div>
</div>
</div>
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-5">
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-4">
<div
v-for="(ceremony, index) in ceremonies"
v-for="ceremony in ceremonies"
:key="ceremony.name"
class="card p-6"
:style="{ animationDelay: `${index * 100}ms` }"
class="glass p-5 rounded-xl hover:shadow-lg transition-all duration-300"
>
<h3 class="font-semibold text-lg text-gray-900 dark:text-gray-100 mb-2">{{ ceremony.name }}</h3>
<div class="inline-block px-3 py-1 rounded-full bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 text-sm font-medium mb-3">
{{ ceremony.duration }}
</div>
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-2">{{ ceremony.name }}</h3>
<div class="text-sm text-blue-600 dark:text-blue-400 mb-2">{{ ceremony.duration }}</div>
<p class="text-sm text-gray-600 dark:text-gray-400">{{ ceremony.purpose }}</p>
</div>
</div>
<div class="mt-8 p-5 rounded-xl bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800">
<p class="text-sm text-amber-800 dark:text-amber-200 flex items-start gap-3">
<i class="fas fa-lightbulb mt-0.5"></i>
<span>If a topic needs more than one hour: write first, comment async, meet on the delta. <strong>Never extend.</strong></span>
<div class="mt-8 p-4 rounded-lg bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800">
<p class="text-sm text-amber-800 dark:text-amber-200">
<i class="fas fa-lightbulb mr-2"></i>
If a topic needs more than one hour: write first, comment async, meet on the delta. Never extend.
</p>
</div>
</div>
</section>
<!-- Daily Check-in -->
<section class="py-20 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300 relative overflow-hidden">
<div class="absolute bottom-0 left-0 w-96 h-96 bg-blue-500/5 dark:bg-blue-500/10 rounded-full filter blur-3xl"></div>
<div class="max-w-6xl mx-auto px-4 sm:px-6 relative">
<div class="text-center mb-14">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">Daily Check-in</h2>
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Daily Check-in</h2>
<p class="text-gray-600 dark:text-gray-400">Replace standups with written updates.</p>
</div>
<div class="max-w-2xl mx-auto">
<!-- Visual Check-in Template -->
<div class="glass p-8 rounded-3xl mb-8">
<div class="space-y-4">
<div class="flex items-center gap-4 p-4 rounded-xl bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800">
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center flex-shrink-0">
<i class="fas fa-tasks text-white"></i>
</div>
<div>
<div class="text-xs text-blue-600 dark:text-blue-400 font-semibold uppercase tracking-wide">Working on</div>
<div class="text-gray-700 dark:text-gray-300">[current task]</div>
</div>
</div>
<div class="flex items-center gap-4 p-4 rounded-xl bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800">
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-amber-500 to-amber-600 flex items-center justify-center flex-shrink-0">
<i class="fas fa-hand-paper text-white"></i>
</div>
<div>
<div class="text-xs text-amber-600 dark:text-amber-400 font-semibold uppercase tracking-wide">Blocked by</div>
<div class="text-gray-700 dark:text-gray-300">[nothing / specific issue]</div>
</div>
</div>
</div>
</div>
<div class="max-w-xl mx-auto">
<CodeBlock title="Check-in Template">Working on: [current task]
Blocked by: [nothing / specific issue]</CodeBlock>
<div class="grid grid-cols-3 gap-4">
<div class="card p-5 text-center group">
<i class="fas fa-clock text-blue-500 text-2xl mb-3 group-hover:scale-110 transition-transform block"></i>
<div class="text-sm text-gray-600 dark:text-gray-400 font-medium">Post once daily</div>
<div class="mt-6 grid sm:grid-cols-3 gap-4">
<div class="glass p-4 rounded-lg text-center">
<i class="fas fa-clock text-blue-500 text-xl mb-2"></i>
<div class="text-sm text-gray-600 dark:text-gray-400">Post once daily</div>
</div>
<div class="card p-5 text-center group">
<i class="fas fa-stopwatch text-purple-500 text-2xl mb-3 group-hover:scale-110 transition-transform block"></i>
<div class="text-sm text-gray-600 dark:text-gray-400 font-medium">Two minutes</div>
<div class="glass p-4 rounded-lg text-center">
<i class="fas fa-stopwatch text-purple-500 text-xl mb-2"></i>
<div class="text-sm text-gray-600 dark:text-gray-400">Two minutes</div>
</div>
<div class="card p-5 text-center group">
<i class="fas fa-users-slash text-emerald-500 text-2xl mb-3 group-hover:scale-110 transition-transform block"></i>
<div class="text-sm text-gray-600 dark:text-gray-400 font-medium">No gathering</div>
<div class="glass p-4 rounded-lg text-center">
<i class="fas fa-users-slash text-green-500 text-xl mb-2"></i>
<div class="text-sm text-gray-600 dark:text-gray-400">No gathering required</div>
</div>
</div>
</div>
@@ -155,68 +99,66 @@ const multiMakerPrinciples = [
</section>
<!-- Collaboration -->
<section class="py-20 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-14">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">Collaboration</h2>
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Collaboration</h2>
<p class="text-gray-600 dark:text-gray-400">Default mode is solo deep work.</p>
</div>
<div class="grid md:grid-cols-2 gap-8">
<!-- Ad-hoc Help -->
<div class="card p-8">
<div class="flex items-center gap-4 mb-6">
<div class="w-14 h-14 rounded-xl bg-gradient-to-br from-blue-500 to-cyan-500 flex items-center justify-center">
<i class="fas fa-hand-holding-heart text-white text-xl"></i>
</div>
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100">Ad-hoc Help</h3>
</div>
<div class="space-y-4">
<div
v-for="(step, index) in collaborationSteps"
:key="step.text"
class="flex items-center gap-4 p-4 rounded-xl bg-gray-50 dark:bg-gray-800/50 hover:bg-blue-50 dark:hover:bg-blue-900/20 transition-colors"
:style="{ animationDelay: `${index * 100}ms` }"
>
<div class="w-10 h-10 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 flex items-center justify-center flex-shrink-0 font-bold">
{{ index + 1 }}
</div>
<div class="flex items-center gap-3">
<i :class="step.icon" class="text-blue-500"></i>
<span class="text-gray-700 dark:text-gray-300">{{ step.text }}</span>
</div>
</div>
</div>
<div class="glass p-6 rounded-xl">
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 mb-4">
<i class="fas fa-hand-holding-heart text-blue-500 mr-2"></i>
Ad-hoc Help
</h3>
<ol class="space-y-3 text-sm text-gray-600 dark:text-gray-400">
<li class="flex items-start gap-3">
<span class="w-6 h-6 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 flex items-center justify-center flex-shrink-0 text-xs font-bold">1</span>
Post when stuck
</li>
<li class="flex items-start gap-3">
<span class="w-6 h-6 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 flex items-center justify-center flex-shrink-0 text-xs font-bold">2</span>
Someone responds when available
</li>
<li class="flex items-start gap-3">
<span class="w-6 h-6 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 flex items-center justify-center flex-shrink-0 text-xs font-bold">3</span>
Sync briefly if needed
</li>
<li class="flex items-start gap-3">
<span class="w-6 h-6 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 flex items-center justify-center flex-shrink-0 text-xs font-bold">4</span>
Return to solo work
</li>
</ol>
</div>
<!-- Multi-Maker Work -->
<div class="card p-8">
<div class="flex items-center gap-4 mb-6">
<div class="w-14 h-14 rounded-xl bg-gradient-to-br from-purple-500 to-pink-500 flex items-center justify-center">
<i class="fas fa-users text-white text-xl"></i>
</div>
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100">Multi-Maker Work</h3>
</div>
<div class="space-y-4">
<div
v-for="(principle, index) in multiMakerPrinciples"
:key="principle.title"
class="flex items-start gap-4 p-4 rounded-xl bg-gray-50 dark:bg-gray-800/50 hover:bg-purple-50 dark:hover:bg-purple-900/20 transition-colors"
:style="{ animationDelay: `${index * 100}ms` }"
>
<div class="w-10 h-10 rounded-full bg-emerald-100 dark:bg-emerald-900/30 flex items-center justify-center flex-shrink-0">
<i :class="principle.icon" class="text-emerald-500"></i>
</div>
<div>
<span class="font-semibold text-gray-900 dark:text-gray-100 block">{{ principle.title }}</span>
<span class="text-sm text-gray-600 dark:text-gray-400">{{ principle.desc }}</span>
</div>
</div>
</div>
<div class="glass p-6 rounded-xl">
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 mb-4">
<i class="fas fa-users text-purple-500 mr-2"></i>
Multi-Maker Work
</h3>
<ul class="space-y-3 text-sm text-gray-600 dark:text-gray-400">
<li class="flex items-start gap-3">
<i class="fas fa-check-circle text-green-500 mt-0.5"></i>
<span><strong>Break vertically.</strong> Each maker owns an end-to-end slice.</span>
</li>
<li class="flex items-start gap-3">
<i class="fas fa-check-circle text-green-500 mt-0.5"></i>
<span><strong>Define interfaces first.</strong> Work in parallel against contracts.</span>
</li>
<li class="flex items-start gap-3">
<i class="fas fa-check-circle text-green-500 mt-0.5"></i>
<span><strong>Coordinate via doc.</strong> One feature doc as source of truth.</span>
</li>
<li class="flex items-start gap-3">
<i class="fas fa-check-circle text-green-500 mt-0.5"></i>
<span><strong>Sync only when stuck.</strong> Document outcome. Return to async.</span>
</li>
</ul>
</div>
</div>
<div class="mt-8 p-5 rounded-xl bg-gray-100 dark:bg-gray-800">
<div class="mt-8 p-4 rounded-lg bg-gray-100 dark:bg-gray-800">
<p class="text-sm text-gray-600 dark:text-gray-400 text-center">
We do not schedule pairing. We do not mandate walkthroughs. We do not assign buddies. Collaboration is initiated by those who need it.
</p>
@@ -225,169 +167,134 @@ const multiMakerPrinciples = [
</section>
<!-- Definition of Done -->
<section class="py-20 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300">
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-14">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">Definition of Done</h2>
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Definition of Done</h2>
<p class="text-gray-600 dark:text-gray-400">Work is not done until it meets these criteria.</p>
</div>
<div class="grid md:grid-cols-2 gap-8">
<div class="card p-8">
<div class="flex items-center gap-4 mb-6">
<div class="w-14 h-14 rounded-xl bg-gradient-to-br from-blue-500 to-cyan-500 flex items-center justify-center">
<i class="fas fa-code text-white text-xl"></i>
</div>
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100">For Code</h3>
</div>
<ul class="space-y-3">
<div class="glass p-6 rounded-xl">
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 mb-4">
<i class="fas fa-code text-blue-500 mr-2"></i>
For Code
</h3>
<ul class="space-y-2">
<li
v-for="item in definitionOfDone.code"
:key="item"
class="flex items-center gap-3 p-3 rounded-xl bg-emerald-50 dark:bg-emerald-900/20 border border-emerald-200 dark:border-emerald-800"
class="flex items-center gap-3 text-sm text-gray-600 dark:text-gray-400"
>
<div class="w-8 h-8 rounded-full bg-emerald-500 flex items-center justify-center flex-shrink-0">
<i class="fas fa-check text-white text-sm"></i>
</div>
<span class="text-gray-700 dark:text-gray-300">{{ item }}</span>
<i class="fas fa-check text-green-500"></i>
{{ item }}
</li>
</ul>
</div>
<div class="card p-8">
<div class="flex items-center gap-4 mb-6">
<div class="w-14 h-14 rounded-xl bg-gradient-to-br from-purple-500 to-pink-500 flex items-center justify-center">
<i class="fas fa-file-alt text-white text-xl"></i>
</div>
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100">For Non-Code</h3>
</div>
<ul class="space-y-3">
<div class="glass p-6 rounded-xl">
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 mb-4">
<i class="fas fa-file-alt text-purple-500 mr-2"></i>
For Non-Code
</h3>
<ul class="space-y-2">
<li
v-for="item in definitionOfDone.nonCode"
:key="item"
class="flex items-center gap-3 p-3 rounded-xl bg-purple-50 dark:bg-purple-900/20 border border-purple-200 dark:border-purple-800"
class="flex items-center gap-3 text-sm text-gray-600 dark:text-gray-400"
>
<div class="w-8 h-8 rounded-full bg-purple-500 flex items-center justify-center flex-shrink-0">
<i class="fas fa-check text-white text-sm"></i>
</div>
<span class="text-gray-700 dark:text-gray-300">{{ item }}</span>
<i class="fas fa-check text-green-500"></i>
{{ item }}
</li>
</ul>
</div>
</div>
<div class="mt-8 p-5 rounded-xl bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800">
<p class="text-sm text-blue-800 dark:text-blue-200 flex items-start gap-3">
<i class="fas fa-info-circle mt-0.5"></i>
<span>The team owns this definition. Adjust it as needed. But once agreed, honor it. "Done" means done—not "done but..." or "done except..."</span>
<div class="mt-8 p-4 rounded-lg bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800">
<p class="text-sm text-blue-800 dark:text-blue-200">
<i class="fas fa-info-circle mr-2"></i>
The team owns this definition. Adjust it as needed. But once agreed, honor it. "Done" means done—not "done but..." or "done except..."
</p>
</div>
</div>
</section>
<!-- Incidents -->
<section class="py-20 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-14">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">Incidents & Emergencies</h2>
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Incidents & Emergencies</h2>
<p class="text-gray-600 dark:text-gray-400">When production breaks, normal rules suspend temporarily.</p>
</div>
<div class="grid md:grid-cols-2 gap-8 mb-8">
<div class="card p-8 border-l-4 border-red-500">
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-6 flex items-center gap-3">
<i class="fas fa-exclamation-triangle text-red-500"></i>
What Qualifies
</h3>
<ul class="space-y-4">
<li class="flex items-center gap-3 p-3 rounded-xl bg-red-50 dark:bg-red-900/20">
<i class="fas fa-times-circle text-red-500"></i>
<span class="text-gray-700 dark:text-gray-300">Users cannot complete critical actions</span>
<div class="glass p-6 rounded-xl border-l-4 border-red-500">
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 mb-4">What Qualifies</h3>
<ul class="space-y-2 text-sm text-gray-600 dark:text-gray-400">
<li class="flex items-center gap-2">
<i class="fas fa-exclamation-triangle text-red-500"></i>
Users cannot complete critical actions
</li>
<li class="flex items-center gap-3 p-3 rounded-xl bg-red-50 dark:bg-red-900/20">
<i class="fas fa-times-circle text-red-500"></i>
<span class="text-gray-700 dark:text-gray-300">Data integrity is at risk</span>
<li class="flex items-center gap-2">
<i class="fas fa-exclamation-triangle text-red-500"></i>
Data integrity is at risk
</li>
<li class="flex items-center gap-3 p-3 rounded-xl bg-red-50 dark:bg-red-900/20">
<i class="fas fa-times-circle text-red-500"></i>
<span class="text-gray-700 dark:text-gray-300">Security vulnerability being exploited</span>
<li class="flex items-center gap-2">
<i class="fas fa-exclamation-triangle text-red-500"></i>
Security vulnerability being exploited
</li>
<li class="flex items-center gap-3 p-3 rounded-xl bg-red-50 dark:bg-red-900/20">
<i class="fas fa-times-circle text-red-500"></i>
<span class="text-gray-700 dark:text-gray-300">Significant revenue or reputation impact</span>
<li class="flex items-center gap-2">
<i class="fas fa-exclamation-triangle text-red-500"></i>
Significant revenue or reputation impact
</li>
</ul>
</div>
<div class="card p-8">
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-6 flex items-center gap-3">
<i class="fas fa-clipboard-list text-blue-500"></i>
Incident Protocol
</h3>
<div class="relative">
<!-- Flow line -->
<div class="absolute left-5 top-8 bottom-8 w-0.5 bg-gradient-to-b from-red-500 via-orange-500 to-green-500 hidden sm:block"></div>
<div class="space-y-4">
<div
v-for="(step, index) in incidentProtocol"
:key="step.step"
class="flex items-start gap-4"
>
<div
class="w-10 h-10 rounded-full flex items-center justify-center flex-shrink-0 z-10 text-sm font-bold"
:class="[
index === 0 ? 'bg-red-500 text-white' :
index === 1 ? 'bg-orange-500 text-white' :
index === 2 ? 'bg-amber-500 text-white' :
index === 3 ? 'bg-blue-500 text-white' :
'bg-green-500 text-white'
]"
>
{{ index + 1 }}
</div>
<div class="flex-1 pb-2">
<div class="font-semibold text-gray-900 dark:text-gray-100">{{ step.step.replace(/^\d+\.\s*/, '') }}</div>
<div class="text-sm text-gray-600 dark:text-gray-400">{{ step.description }}</div>
</div>
</div>
</div>
</div>
<div class="glass p-6 rounded-xl">
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 mb-4">Incident Protocol</h3>
<ol class="space-y-3">
<li
v-for="step in incidentProtocol"
:key="step.step"
class="flex items-start gap-3"
>
<span class="font-bold text-blue-600 dark:text-blue-400 text-sm">{{ step.step }}</span>
<span class="text-sm text-gray-600 dark:text-gray-400">{{ step.description }}</span>
</li>
</ol>
</div>
</div>
<div class="p-5 rounded-xl bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800">
<p class="text-sm text-amber-800 dark:text-amber-200 flex items-start gap-3">
<i class="fas fa-lightbulb mt-0.5"></i>
<span>This is not normal work. Incidents should be rare. If they're frequent, that's a systemic problem to solve—not a reason to abandon sustainable pace.</span>
<div class="p-4 rounded-lg bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800">
<p class="text-sm text-amber-800 dark:text-amber-200">
<i class="fas fa-lightbulb mr-2"></i>
This is not normal work. Incidents should be rare. If they're frequent, that's a systemic problem to solve—not a reason to abandon sustainable pace.
</p>
</div>
</div>
</section>
<!-- Technical Practices -->
<section class="py-20 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300">
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-14">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">Technical Practices</h2>
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Technical Practices</h2>
<p class="text-gray-600 dark:text-gray-400">Optional practices that align well with BEAT principles.</p>
</div>
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-5">
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-4">
<div
v-for="(practice, index) in technicalPractices"
v-for="practice in technicalPractices"
:key="practice.name"
class="card p-6 group"
:style="{ animationDelay: `${index * 100}ms` }"
class="glass p-5 rounded-xl hover:shadow-lg transition-all duration-300"
>
<h3 class="font-semibold text-lg text-gray-900 dark:text-gray-100 mb-3 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors">
{{ practice.name }}
</h3>
<p class="text-sm text-gray-600 dark:text-gray-400 leading-relaxed">{{ practice.description }}</p>
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-2">{{ practice.name }}</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">{{ practice.description }}</p>
</div>
</div>
<p class="mt-10 text-center text-gray-500 dark:text-gray-500">
These are not mandated. They are offered as practices that support focus, speed, and quality. <strong class="text-gray-700 dark:text-gray-300">Adopt what serves you. Discard what doesn't.</strong>
<p class="mt-8 text-center text-sm text-gray-500 dark:text-gray-500">
These are not mandated. They are offered as practices that support focus, speed, and quality. Adopt what serves you. Discard what doesn't.
</p>
</div>
</section>
+42 -61
View File
@@ -2,31 +2,27 @@
import { principles } from '@/data/manifesto'
const categories = [
{ key: 'focus', title: 'On Focus', icon: 'fas fa-bullseye', gradient: 'from-blue-500 to-cyan-500', color: 'blue', desc: 'Protecting the deep work state' },
{ key: 'communication', title: 'On Communication', icon: 'fas fa-comments', gradient: 'from-purple-500 to-pink-500', color: 'purple', desc: 'Writing first, meeting wisely' },
{ key: 'autonomy', title: 'On Autonomy', icon: 'fas fa-user-shield', gradient: 'from-emerald-500 to-teal-500', color: 'emerald', desc: 'Trusting makers to make' },
{ key: 'sustainability', title: 'On Sustainability', icon: 'fas fa-leaf', gradient: 'from-amber-500 to-orange-500', color: 'amber', desc: 'Pace that lasts' }
{ key: 'focus', title: 'On Focus', icon: 'fas fa-bullseye', gradient: 'from-blue-500 to-cyan-500', color: 'blue' },
{ key: 'communication', title: 'On Communication', icon: 'fas fa-comments', gradient: 'from-purple-500 to-pink-500', color: 'purple' },
{ key: 'autonomy', title: 'On Autonomy', icon: 'fas fa-user-shield', gradient: 'from-green-500 to-emerald-500', color: 'green' },
{ key: 'sustainability', title: 'On Sustainability', icon: 'fas fa-leaf', gradient: 'from-amber-500 to-orange-500', color: 'amber' }
]
</script>
<template>
<div>
<!-- Hero -->
<section class="relative pt-28 sm:pt-32 lg:pt-40 pb-12 sm:pb-16 lg:pb-20 overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-blue-50 via-purple-50 to-green-50 dark:from-gray-900 dark:via-blue-950/20 dark:to-purple-950/20 transition-colors duration-300"></div>
<div class="absolute top-20 -left-20 w-72 h-72 sm:w-96 sm:h-96 bg-blue-400/20 dark:bg-blue-500/20 rounded-full filter blur-3xl animate-float"></div>
<div class="absolute top-40 -right-20 w-64 h-64 sm:w-80 sm:h-80 bg-purple-400/20 dark:bg-purple-500/20 rounded-full filter blur-3xl animate-float animate-delay-2000"></div>
<section class="relative pt-24 sm:pt-32 pb-12 sm:pb-16 overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-blue-50 via-purple-50 to-green-50 dark:from-gray-900 dark:via-blue-900/10 dark:to-purple-900/10 transition-colors duration-300"></div>
<div class="absolute top-0 -left-4 w-72 h-72 bg-blue-300 dark:bg-blue-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float"></div>
<div class="absolute top-0 -right-4 w-72 h-72 bg-purple-300 dark:bg-purple-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-1000"></div>
<div class="relative w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 xl:px-12 text-center">
<div class="inline-flex items-center gap-2 px-3 sm:px-4 py-1.5 sm:py-2 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 text-xs sm:text-sm font-medium mb-4 sm:mb-6 animate-fade-in-up">
<i class="fas fa-compass"></i>
Guiding Principles
<div class="relative max-w-6xl mx-auto px-4 sm:px-6 text-center">
<div class="w-16 h-16 rounded-xl bg-gradient-to-br from-blue-500 to-cyan-500 flex items-center justify-center mx-auto mb-6 animate-fade-in-up">
<i class="fas fa-compass text-white text-2xl"></i>
</div>
<div class="w-16 h-16 sm:w-20 sm:h-20 rounded-xl sm:rounded-2xl bg-gradient-to-br from-blue-500 to-cyan-500 flex items-center justify-center mx-auto mb-6 sm:mb-8 animate-fade-in-up animate-delay-100 shadow-glow-blue">
<i class="fas fa-compass text-white text-2xl sm:text-3xl"></i>
</div>
<h1 class="section-title animate-fade-in-up animate-delay-200">The Twelve Principles</h1>
<p class="section-subtitle max-w-2xl lg:max-w-3xl mx-auto animate-fade-in-up animate-delay-300">
<h1 class="section-title animate-fade-in-up animate-delay-100">The Twelve Principles</h1>
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-200">
Guiding principles organized into four categories: Focus, Communication, Autonomy, and Sustainability.
</p>
</div>
@@ -34,44 +30,40 @@ const categories = [
<!-- Principles by Category -->
<section
v-for="(category, catIndex) in categories"
v-for="category in categories"
:key="category.key"
class="py-12 sm:py-16 lg:py-20 transition-colors duration-300 relative"
:class="catIndex % 2 === 0 ? 'bg-white dark:bg-gray-900' : 'bg-gray-50 dark:bg-gray-800/30'"
class="py-16 transition-colors duration-300"
:class="categories.indexOf(category) % 2 === 0 ? 'bg-white dark:bg-gray-900' : 'bg-gray-50 dark:bg-gray-800/50'"
>
<div class="w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 xl:px-12">
<div class="flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4 mb-6 sm:mb-10">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="flex items-center gap-4 mb-8">
<div
class="w-12 h-12 sm:w-14 sm:h-14 lg:w-16 lg:h-16 rounded-xl sm:rounded-2xl bg-gradient-to-br flex items-center justify-center flex-shrink-0 shadow-lg"
class="w-12 h-12 rounded-xl bg-gradient-to-br flex items-center justify-center"
:class="category.gradient"
>
<i :class="category.icon" class="text-white text-xl sm:text-2xl"></i>
</div>
<div>
<h2 class="text-xl sm:text-2xl lg:text-3xl font-bold text-gray-900 dark:text-gray-100">{{ category.title }}</h2>
<p class="text-gray-500 dark:text-gray-400 text-sm sm:text-base">{{ category.desc }}</p>
<i :class="category.icon" class="text-white"></i>
</div>
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100">{{ category.title }}</h2>
</div>
<div class="space-y-4 sm:space-y-5">
<div class="space-y-6">
<div
v-for="(principle, index) in principles[category.key]"
v-for="principle in principles[category.key]"
:key="principle.number"
class="card group p-5 sm:p-6 lg:p-8"
:style="{ animationDelay: `${index * 100}ms` }"
class="glass p-6 sm:p-8 rounded-xl hover:shadow-lg transition-all duration-300"
>
<div class="flex items-start gap-3 sm:gap-5">
<div class="flex items-start gap-4">
<div
class="w-9 h-9 sm:w-10 sm:h-10 lg:w-12 lg:h-12 rounded-lg sm:rounded-xl bg-gradient-to-br flex items-center justify-center flex-shrink-0 shadow-md group-hover:scale-110 transition-all duration-300"
class="w-10 h-10 rounded-full bg-gradient-to-br flex items-center justify-center flex-shrink-0"
:class="category.gradient"
>
<span class="text-white font-bold text-sm sm:text-base lg:text-lg">{{ principle.number }}</span>
<span class="text-white font-bold">{{ principle.number }}</span>
</div>
<div class="flex-1 min-w-0">
<h3 class="text-lg sm:text-xl lg:text-2xl font-bold text-gray-900 dark:text-gray-100 mb-2 sm:mb-3 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors">
<div>
<h3 class="text-lg sm:text-xl font-bold text-gray-900 dark:text-gray-100 mb-3">
{{ principle.title }}
</h3>
<p class="text-gray-600 dark:text-gray-400 leading-relaxed text-sm sm:text-base">
<p class="text-gray-600 dark:text-gray-400 leading-relaxed">
{{ principle.description }}
</p>
</div>
@@ -82,33 +74,22 @@ const categories = [
</section>
<!-- Summary -->
<section class="py-12 sm:py-16 lg:py-20 relative overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-blue-600 via-purple-600 to-emerald-600"></div>
<!-- Animated pattern -->
<div class="absolute inset-0 opacity-10">
<div class="absolute top-0 left-0 w-full h-full bg-[url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PHBhdHRlcm4gaWQ9InAiIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGggZD0iTTAgNDBoNDBWMEgwVjQwWiIgZmlsbD0ibm9uZSIvPjxwYXRoIGQ9Ik0wIDQwaDQwVjBIMFY0MFoiIGZpbGw9IiNmZmYiIGZpbGwtb3BhY2l0eT0iMC4xIi8+PC9wYXR0ZXJuPjwvZGVmcz48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI3ApIi8+PC9zdmc+')] animate-pulse-slow"></div>
</div>
<div class="relative w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 xl:px-12">
<h2 class="text-2xl sm:text-3xl lg:text-4xl font-bold text-white text-center mb-8 sm:mb-10">Principles in Summary</h2>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 sm:gap-5">
<section class="py-16 bg-gradient-to-br from-blue-600 via-purple-600 to-green-600">
<div class="max-w-4xl mx-auto px-4 sm:px-6 text-center">
<h2 class="text-2xl sm:text-3xl font-bold text-white mb-6">Principles in Summary</h2>
<div class="grid sm:grid-cols-2 gap-4 text-left">
<div
v-for="(category, index) in categories"
v-for="category in categories"
:key="category.key"
class="bg-white/10 backdrop-blur-sm p-5 sm:p-6 rounded-xl sm:rounded-2xl border border-white/10 hover:bg-white/20 transition-all duration-300"
:style="{ animationDelay: `${index * 100}ms` }"
class="bg-white/10 backdrop-blur-sm p-4 rounded-xl"
>
<div class="flex items-center gap-3 mb-3 sm:mb-4">
<div class="w-9 h-9 sm:w-10 sm:h-10 rounded-lg sm:rounded-xl bg-white/20 flex items-center justify-center">
<i :class="category.icon" class="text-white"></i>
</div>
<span class="text-white font-semibold text-base sm:text-lg">{{ category.title }}</span>
<div class="flex items-center gap-2 mb-2">
<i :class="category.icon" class="text-white"></i>
<span class="text-white font-semibold">{{ category.title }}</span>
</div>
<ul class="text-white/80 text-xs sm:text-sm space-y-1.5 sm:space-y-2">
<li v-for="p in principles[category.key]" :key="p.number" class="flex items-center gap-2">
<span class="w-5 h-5 rounded-full bg-white/20 flex items-center justify-center text-xs flex-shrink-0">{{ p.number }}</span>
<span class="truncate">{{ p.title.split('.')[0] }}</span>
<ul class="text-white/80 text-sm space-y-1">
<li v-for="p in principles[category.key]" :key="p.number">
{{ p.number }}. {{ p.title.split('.')[0] }}
</li>
</ul>
</div>
+45 -193
View File
@@ -1,6 +1,6 @@
<script setup>
import TableCard from '@/components/ui/TableCard.vue'
import CopyButton from '@/components/ui/CopyButton.vue'
import CodeBlock from '@/components/ui/CodeBlock.vue'
import { coreValues, teamValues, constraints, priorityBuckets, roles, ceremonies, definitionOfDone, incidentProtocol } from '@/data/manifesto'
const coreValuesHeaders = ['We Value More', 'Over']
@@ -39,108 +39,61 @@ const ceremoniesRows = ceremonies.map(c => [
c.duration,
c.purpose
])
const spottedIssueFlow = [
{ question: 'Blocking your work?', answer: 'Fix now', icon: 'fas fa-ban', color: 'red' },
{ question: '5 minutes or less?', answer: 'Fix now', icon: 'fas fa-clock', color: 'amber' },
{ question: 'More than 5 minutes?', answer: 'Log it, continue', icon: 'fas fa-sticky-note', color: 'blue' },
{ question: 'Production critical?', answer: 'Flag team', icon: 'fas fa-exclamation-triangle', color: 'purple' }
]
const colorMap = {
red: { bg: 'from-red-500 to-red-600', border: 'border-red-200 dark:border-red-800', text: 'text-red-700 dark:text-red-300', badge: 'bg-red-50 dark:bg-red-900/20' },
amber: { bg: 'from-amber-500 to-amber-600', border: 'border-amber-200 dark:border-amber-800', text: 'text-amber-700 dark:text-amber-300', badge: 'bg-amber-50 dark:bg-amber-900/20' },
blue: { bg: 'from-blue-500 to-blue-600', border: 'border-blue-200 dark:border-blue-800', text: 'text-blue-700 dark:text-blue-300', badge: 'bg-blue-50 dark:bg-blue-900/20' },
purple: { bg: 'from-purple-500 to-purple-600', border: 'border-purple-200 dark:border-purple-800', text: 'text-purple-700 dark:text-purple-300', badge: 'bg-purple-50 dark:bg-purple-900/20' }
}
const incidentColors = [
'from-red-500 to-red-600',
'from-orange-500 to-orange-600',
'from-amber-500 to-amber-600',
'from-blue-500 to-blue-600',
'from-green-500 to-green-600'
]
// Template text for copying
const dailyCheckinTemplate = `Working on: [current task]
Blocked by: [nothing / specific issue]`
const definitionOfDoneText = definitionOfDone.code.join('\n')
</script>
<template>
<div>
<!-- Hero -->
<section class="relative pt-32 sm:pt-40 pb-16 sm:pb-20 overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-cyan-50 via-blue-50 to-indigo-50 dark:from-gray-900 dark:via-cyan-950/20 dark:to-blue-950/20 transition-colors duration-300"></div>
<div class="absolute top-20 -left-20 w-96 h-96 bg-cyan-400/20 dark:bg-cyan-500/20 rounded-full filter blur-3xl animate-float"></div>
<div class="absolute top-40 -right-20 w-80 h-80 bg-blue-400/20 dark:bg-blue-500/20 rounded-full filter blur-3xl animate-float animate-delay-2000"></div>
<section class="relative pt-24 sm:pt-32 pb-12 sm:pb-16 overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-cyan-50 via-blue-50 to-indigo-50 dark:from-gray-900 dark:via-cyan-900/10 dark:to-blue-900/10 transition-colors duration-300"></div>
<div class="absolute top-0 -left-4 w-72 h-72 bg-cyan-300 dark:bg-cyan-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float"></div>
<div class="absolute top-0 -right-4 w-72 h-72 bg-blue-300 dark:bg-blue-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-1000"></div>
<div class="relative max-w-6xl mx-auto px-4 sm:px-6 text-center">
<div class="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-cyan-100 dark:bg-cyan-900/30 text-cyan-700 dark:text-cyan-300 text-sm font-medium mb-6 animate-fade-in-up">
<i class="fas fa-book"></i>
Quick Lookup
<div class="w-16 h-16 rounded-xl bg-gradient-to-br from-cyan-500 to-blue-500 flex items-center justify-center mx-auto mb-6 animate-fade-in-up">
<i class="fas fa-book text-white text-2xl"></i>
</div>
<div class="w-20 h-20 rounded-2xl bg-gradient-to-br from-cyan-500 to-blue-500 flex items-center justify-center mx-auto mb-8 animate-fade-in-up animate-delay-100">
<i class="fas fa-book text-white text-3xl"></i>
</div>
<h1 class="section-title animate-fade-in-up animate-delay-200">Quick Reference</h1>
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-300">
Everything you need at a glance. Copy templates with one click.
<h1 class="section-title animate-fade-in-up animate-delay-100">Quick Reference</h1>
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-200">
Everything you need at a glance. Print this page and keep it handy.
</p>
</div>
</section>
<!-- Core Values -->
<section class="py-10 sm:py-14 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="flex items-center gap-3 mb-6">
<div class="w-1 h-6 rounded-full bg-gradient-to-b from-rose-500 to-pink-500"></div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100">Core Values</h2>
</div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Core Values</h2>
<TableCard :headers="coreValuesHeaders" :rows="coreValuesRows" />
</div>
</section>
<!-- Team Values -->
<section class="py-10 sm:py-14 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300">
<section class="py-12 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="flex items-center gap-3 mb-6">
<div class="w-1 h-6 rounded-full bg-gradient-to-b from-blue-500 to-purple-500"></div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100">Team Values</h2>
</div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Team Values</h2>
<TableCard :headers="teamValuesHeaders" :rows="teamValuesRows" />
</div>
</section>
<!-- The Numbers -->
<section class="py-10 sm:py-14 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="flex items-center gap-3 mb-6">
<div class="w-1 h-6 rounded-full bg-gradient-to-b from-purple-500 to-indigo-500"></div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100">The Numbers</h2>
</div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">The Numbers</h2>
<TableCard :headers="constraintsHeaders" :rows="constraintsRows" />
</div>
</section>
<!-- Buckets & Roles -->
<section class="py-10 sm:py-14 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300">
<section class="py-12 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="grid md:grid-cols-2 gap-8">
<div>
<div class="flex items-center gap-3 mb-6">
<div class="w-1 h-6 rounded-full bg-gradient-to-b from-amber-500 to-orange-500"></div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100">Priority Buckets</h2>
</div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Priority Buckets</h2>
<TableCard :headers="bucketsHeaders" :rows="bucketsRows" />
</div>
<div>
<div class="flex items-center gap-3 mb-6">
<div class="w-1 h-6 rounded-full bg-gradient-to-b from-emerald-500 to-teal-500"></div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100">Roles</h2>
</div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Roles</h2>
<TableCard :headers="rolesHeaders" :rows="rolesRows" />
</div>
</div>
@@ -148,161 +101,60 @@ const definitionOfDoneText = definitionOfDone.code.join('\n')
</section>
<!-- Ceremonies -->
<section class="py-10 sm:py-14 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="flex items-center gap-3 mb-6">
<div class="w-1 h-6 rounded-full bg-gradient-to-b from-cyan-500 to-blue-500"></div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100">Ceremonies</h2>
</div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Ceremonies</h2>
<TableCard :headers="ceremoniesHeaders" :rows="ceremoniesRows" />
</div>
</section>
<!-- Templates with Copy Buttons -->
<section class="py-10 sm:py-14 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300">
<!-- Templates -->
<section class="py-12 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="flex items-center gap-3 mb-8">
<div class="w-1 h-6 rounded-full bg-gradient-to-b from-pink-500 to-rose-500"></div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100">Templates</h2>
<span class="px-2 py-1 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 text-xs font-medium">Click to copy</span>
</div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-6">Templates</h2>
<div class="grid md:grid-cols-2 gap-6">
<!-- Daily Check-in Card -->
<div class="card p-6">
<div class="flex items-center justify-between mb-5">
<h3 class="font-semibold text-gray-900 dark:text-gray-100 flex items-center gap-3">
<div class="w-10 h-10 rounded-xl bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center">
<i class="fas fa-calendar-check text-blue-500"></i>
</div>
Daily Check-in
</h3>
<CopyButton :text="dailyCheckinTemplate" label="Copy" />
</div>
<div class="space-y-3">
<div class="flex items-center gap-4 p-4 rounded-xl bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800">
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center flex-shrink-0">
<i class="fas fa-tasks text-white"></i>
</div>
<div>
<div class="text-xs text-blue-600 dark:text-blue-400 font-semibold uppercase tracking-wide">Working on</div>
<div class="text-gray-700 dark:text-gray-300">[current task]</div>
</div>
</div>
<div class="flex items-center gap-4 p-4 rounded-xl bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800">
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-amber-500 to-amber-600 flex items-center justify-center flex-shrink-0">
<i class="fas fa-hand-paper text-white"></i>
</div>
<div>
<div class="text-xs text-amber-600 dark:text-amber-400 font-semibold uppercase tracking-wide">Blocked by</div>
<div class="text-gray-700 dark:text-gray-300">[nothing / specific issue]</div>
</div>
</div>
</div>
<div>
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-3">Daily Check-in</h3>
<CodeBlock>Working on: [task]
Blocked by: [nothing / issue]</CodeBlock>
</div>
<!-- Spotted Issue Decision Flow -->
<div class="card p-6">
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-5 flex items-center gap-3">
<div class="w-10 h-10 rounded-xl bg-purple-100 dark:bg-purple-900/30 flex items-center justify-center">
<i class="fas fa-code-branch text-purple-500"></i>
</div>
Spotted Issue Decision
</h3>
<div class="space-y-3">
<div
v-for="(item, index) in spottedIssueFlow"
:key="index"
class="flex items-center gap-3 p-3 rounded-xl border"
:class="[colorMap[item.color].badge, colorMap[item.color].border]"
>
<div
class="w-10 h-10 rounded-xl bg-gradient-to-br flex items-center justify-center flex-shrink-0"
:class="colorMap[item.color].bg"
>
<i :class="item.icon" class="text-white"></i>
</div>
<div class="flex-1 min-w-0">
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">{{ item.question }}</span>
</div>
<i class="fas fa-arrow-right text-xs opacity-50"></i>
<span class="text-sm font-bold whitespace-nowrap" :class="colorMap[item.color].text">{{ item.answer }}</span>
</div>
</div>
<div>
<h3 class="font-semibold text-gray-900 dark:text-gray-100 mb-3">Spotted Issue Decision</h3>
<CodeBlock>Blocking? → Fix now
≤5 min? → Fix now
>5 min? → Log it, continue
Critical? → Flag team</CodeBlock>
</div>
</div>
</div>
</section>
<!-- Definition of Done -->
<section class="py-10 sm:py-14 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="flex items-center justify-between mb-6">
<div class="flex items-center gap-3">
<div class="w-1 h-6 rounded-full bg-gradient-to-b from-emerald-500 to-green-500"></div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100">Definition of Done (Code)</h2>
</div>
<CopyButton :text="definitionOfDoneText" label="Copy All" />
</div>
<div class="card p-6">
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-3">
<div
v-for="item in definitionOfDone.code"
:key="item"
class="flex items-center gap-3 p-4 rounded-xl bg-emerald-50 dark:bg-emerald-900/20 border border-emerald-200 dark:border-emerald-800"
>
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-emerald-500 to-emerald-600 flex items-center justify-center flex-shrink-0">
<i class="fas fa-check text-white text-sm"></i>
</div>
<span class="text-sm text-gray-700 dark:text-gray-300">{{ item }}</span>
</div>
</div>
</div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Definition of Done (Code)</h2>
<CodeBlock>{{ definitionOfDone.code.map(item => '✓ ' + item).join('\n') }}</CodeBlock>
</div>
</section>
<!-- Incident Protocol -->
<section class="py-10 sm:py-14 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300">
<section class="py-12 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="flex items-center gap-3 mb-6">
<div class="w-1 h-6 rounded-full bg-gradient-to-b from-red-500 to-orange-500"></div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100">Incident Protocol</h2>
</div>
<div class="card p-6">
<div class="relative">
<!-- Flow line for desktop -->
<div class="hidden sm:block absolute left-6 top-12 bottom-12 w-0.5 bg-gradient-to-b from-red-500 via-orange-500 via-amber-500 via-blue-500 to-green-500"></div>
<div class="space-y-4">
<div
v-for="(step, index) in incidentProtocol"
:key="step.step"
class="flex items-start gap-4"
>
<div
class="w-12 h-12 rounded-xl flex items-center justify-center flex-shrink-0 z-10 shadow-lg"
:class="incidentColors[index]"
>
<span class="text-white font-bold">{{ index + 1 }}</span>
</div>
<div class="flex-1 pb-2 pt-2">
<div class="font-semibold text-gray-900 dark:text-gray-100">{{ step.step.replace(/^\d+\.\s*/, '') }}</div>
<div class="text-sm text-gray-600 dark:text-gray-400">{{ step.description }}</div>
</div>
</div>
</div>
</div>
</div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Incident Protocol</h2>
<CodeBlock>{{ incidentProtocol.map(step => step.step + ' ' + step.description.split('.')[0]).join('\n') }}</CodeBlock>
</div>
</section>
<!-- Footer Note -->
<section class="py-10 sm:py-14 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-4xl mx-auto px-4 sm:px-6 text-center">
<div class="card p-8">
<p class="text-gray-600 dark:text-gray-400 mb-2">
BEAT v1.0 by <strong class="text-gray-900 dark:text-gray-100">Lukasz Raczylo</strong>
<div class="glass p-6 rounded-xl">
<p class="text-gray-600 dark:text-gray-400 text-sm mb-2">
BEAT v1.0 by <strong>Lukasz Raczylo</strong>
</p>
<p class="text-gray-500 dark:text-gray-500 text-sm italic">
<p class="text-gray-500 dark:text-gray-500 text-xs">
Attribution appreciated. Improvement welcomed. Dogma discouraged.
</p>
</div>
+34 -43
View File
@@ -1,4 +1,5 @@
<script setup>
import IconCard from '@/components/ui/IconCard.vue'
import TableCard from '@/components/ui/TableCard.vue'
import { coreValues, teamValues } from '@/data/manifesto'
@@ -12,31 +13,27 @@ const coreValuesRows = coreValues.map(v => [
<template>
<div>
<!-- Hero -->
<section class="relative pt-32 sm:pt-40 pb-16 sm:pb-20 overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-rose-50 via-pink-50 to-purple-50 dark:from-gray-900 dark:via-rose-950/20 dark:to-pink-950/20 transition-colors duration-300"></div>
<div class="absolute top-20 -left-20 w-96 h-96 bg-rose-400/20 dark:bg-rose-500/20 rounded-full filter blur-3xl animate-float"></div>
<div class="absolute top-40 -right-20 w-80 h-80 bg-pink-400/20 dark:bg-pink-500/20 rounded-full filter blur-3xl animate-float animate-delay-2000"></div>
<section class="relative pt-24 sm:pt-32 pb-12 sm:pb-16 overflow-hidden">
<div class="absolute inset-0 bg-gradient-to-br from-red-50 via-pink-50 to-purple-50 dark:from-gray-900 dark:via-red-900/10 dark:to-pink-900/10 transition-colors duration-300"></div>
<div class="absolute top-0 -left-4 w-72 h-72 bg-red-300 dark:bg-red-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float"></div>
<div class="absolute top-0 -right-4 w-72 h-72 bg-pink-300 dark:bg-pink-500 rounded-full mix-blend-multiply dark:mix-blend-soft-light filter blur-xl opacity-20 animate-float animate-delay-1000"></div>
<div class="relative max-w-6xl mx-auto px-4 sm:px-6 text-center">
<div class="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-rose-100 dark:bg-rose-900/30 text-rose-700 dark:text-rose-300 text-sm font-medium mb-6 animate-fade-in-up">
<i class="fas fa-heart"></i>
Foundation
<div class="w-16 h-16 rounded-xl bg-gradient-to-br from-red-500 to-pink-500 flex items-center justify-center mx-auto mb-6 animate-fade-in-up">
<i class="fas fa-heart text-white text-2xl"></i>
</div>
<div class="w-20 h-20 rounded-2xl bg-gradient-to-br from-rose-500 to-pink-500 flex items-center justify-center mx-auto mb-8 animate-fade-in-up animate-delay-100 shadow-glow-blue">
<i class="fas fa-heart text-white text-3xl"></i>
</div>
<h1 class="section-title animate-fade-in-up animate-delay-200">Values</h1>
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-300">
<h1 class="section-title animate-fade-in-up animate-delay-100">Values</h1>
<p class="section-subtitle max-w-2xl mx-auto animate-fade-in-up animate-delay-200">
The foundation of everything we do. What we value in our work and how we treat each other.
</p>
</div>
</section>
<!-- Core Values -->
<section class="py-20 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-14">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">Core Values</h2>
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Core Values</h2>
<p class="text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
While there is value in the items on the right, we value the items on the left more.
</p>
@@ -47,19 +44,18 @@ const coreValuesRows = coreValues.map(v => [
<!-- Visual Cards -->
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-6 mt-12">
<div
v-for="(value, index) in coreValues"
v-for="value in coreValues"
:key="value.valueMore"
class="card group"
:style="{ animationDelay: `${index * 100}ms` }"
class="glass p-6 rounded-xl group hover:shadow-lg transition-all duration-300"
>
<div class="flex items-center gap-4 mb-4">
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-blue-500 to-purple-500 flex items-center justify-center group-hover:scale-110 transition-all duration-300">
<i :class="value.icon" class="text-white"></i>
<div class="flex items-center gap-4 mb-3">
<div class="w-10 h-10 rounded-lg bg-gradient-to-br from-blue-500 to-purple-500 flex items-center justify-center group-hover:scale-110 transition-transform duration-300">
<i :class="value.icon" class="text-white text-sm"></i>
</div>
<h3 class="font-semibold text-lg text-gray-900 dark:text-gray-100">{{ value.valueMore }}</h3>
<h3 class="font-semibold text-gray-900 dark:text-gray-100">{{ value.valueMore }}</h3>
</div>
<p class="text-sm text-gray-500 dark:text-gray-500">
over <span class="text-gray-700 dark:text-gray-300">{{ value.over }}</span>
over {{ value.over }}
</p>
</div>
</div>
@@ -67,12 +63,10 @@ const coreValuesRows = coreValues.map(v => [
</section>
<!-- Team Values -->
<section class="py-20 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300 relative overflow-hidden">
<div class="absolute bottom-0 right-0 w-96 h-96 bg-purple-500/5 dark:bg-purple-500/10 rounded-full filter blur-3xl"></div>
<div class="max-w-6xl mx-auto px-4 sm:px-6 relative">
<div class="text-center mb-14">
<h2 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4">The Five Team Values</h2>
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">The Five Team Values</h2>
<p class="text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
Beyond what we value in our work, we hold these values in how we treat each other.
</p>
@@ -80,21 +74,20 @@ const coreValuesRows = coreValues.map(v => [
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-6">
<div
v-for="(value, index) in teamValues"
v-for="value in teamValues"
:key="value.name"
class="card group p-8"
:style="{ animationDelay: `${index * 100}ms` }"
class="glass p-6 rounded-xl group hover:shadow-lg transition-all duration-300"
>
<div class="flex items-center gap-5 mb-5">
<div class="flex items-center gap-4 mb-4">
<div
class="w-16 h-16 rounded-2xl bg-gradient-to-br flex items-center justify-center group-hover:scale-110 group-hover:rotate-3 transition-all duration-300"
class="w-12 h-12 rounded-xl bg-gradient-to-br flex items-center justify-center group-hover:scale-110 transition-transform duration-300"
:class="value.gradient"
>
<i :class="value.icon" class="text-white text-xl"></i>
<i :class="value.icon" class="text-white"></i>
</div>
<h3 class="text-2xl font-bold text-gray-900 dark:text-gray-100">{{ value.name }}</h3>
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100">{{ value.name }}</h3>
</div>
<p class="text-gray-600 dark:text-gray-400 leading-relaxed">
<p class="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">
{{ value.description }}
</p>
</div>
@@ -103,13 +96,11 @@ const coreValuesRows = coreValues.map(v => [
</section>
<!-- Summary -->
<section class="py-20 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-4xl mx-auto px-4 sm:px-6 text-center">
<div class="glass p-10 sm:p-14 rounded-3xl relative overflow-hidden">
<div class="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-rose-500 via-pink-500 to-purple-500"></div>
<h3 class="text-2xl font-bold text-gray-900 dark:text-gray-100 mb-6">Values in Action</h3>
<p class="text-gray-600 dark:text-gray-400 leading-relaxed text-lg">
<div class="glass p-8 rounded-2xl">
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Values in Action</h3>
<p class="text-gray-600 dark:text-gray-400 leading-relaxed">
These values are not just words on a page. They guide our daily decisions, how we interact with each other, and how we approach every piece of work. When in doubt, return to these values.
</p>
</div>
+5 -86
View File
@@ -11,100 +11,19 @@ export default {
sans: ['Inter', 'system-ui', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace'],
},
// Extended screens for better responsive control
screens: {
'xs': '475px',
'3xl': '1920px',
'4xl': '2560px',
},
// Extended max-width for ultrawide support
maxWidth: {
'8xl': '88rem',
'9xl': '96rem',
},
// Responsive font sizes
fontSize: {
'display': ['clamp(2.5rem, 8vw, 6rem)', { lineHeight: '1.1', letterSpacing: '-0.02em' }],
'display-sm': ['clamp(2rem, 5vw, 3.5rem)', { lineHeight: '1.15', letterSpacing: '-0.02em' }],
'title': ['clamp(1.5rem, 4vw, 2.5rem)', { lineHeight: '1.2', letterSpacing: '-0.01em' }],
'body-lg': ['clamp(1rem, 1.5vw, 1.25rem)', { lineHeight: '1.7' }],
'body': ['clamp(0.875rem, 1.2vw, 1rem)', { lineHeight: '1.6' }],
},
animation: {
'fade-in': 'fadeIn 0.6s ease-out forwards',
'fade-in-up': 'fadeInUp 0.6s ease-out forwards',
'fade-in-down': 'fadeInDown 0.6s ease-out forwards',
'scale-in': 'scaleIn 0.5s ease-out forwards',
'slide-in-right': 'slideInRight 0.5s ease-out forwards',
'slide-in-left': 'slideInLeft 0.5s ease-out forwards',
'float': 'float 6s ease-in-out infinite',
'float-delayed': 'float 6s ease-in-out infinite 3s',
'pulse-slow': 'pulseSlow 4s ease-in-out infinite',
'spin-slow': 'spin 8s linear infinite',
'bounce-subtle': 'bounceSubtle 2s ease-in-out infinite',
'gradient-shift': 'gradientShift 8s ease infinite',
'shimmer': 'shimmer 2s infinite',
'fade-in-up': 'fadeInUp 0.6s ease-out',
'float': 'float 3s ease-in-out infinite',
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
},
fadeInUp: {
'0%': { opacity: '0', transform: 'translateY(30px)' },
'0%': { opacity: '0', transform: 'translateY(20px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
fadeInDown: {
'0%': { opacity: '0', transform: 'translateY(-20px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
scaleIn: {
'0%': { opacity: '0', transform: 'scale(0.95)' },
'100%': { opacity: '1', transform: 'scale(1)' },
},
slideInRight: {
'0%': { opacity: '0', transform: 'translateX(30px)' },
'100%': { opacity: '1', transform: 'translateX(0)' },
},
slideInLeft: {
'0%': { opacity: '0', transform: 'translateX(-30px)' },
'100%': { opacity: '1', transform: 'translateX(0)' },
},
float: {
'0%, 100%': { transform: 'translateY(0px) rotate(0deg)' },
'33%': { transform: 'translateY(-15px) rotate(1deg)' },
'66%': { transform: 'translateY(-8px) rotate(-1deg)' },
'0%, 100%': { transform: 'translateY(0px)' },
'50%': { transform: 'translateY(-10px)' },
},
pulseSlow: {
'0%, 100%': { opacity: '1' },
'50%': { opacity: '0.7' },
},
bounceSubtle: {
'0%, 100%': { transform: 'translateY(0)' },
'50%': { transform: 'translateY(-5px)' },
},
gradientShift: {
'0%, 100%': { backgroundPosition: '0% 50%' },
'50%': { backgroundPosition: '100% 50%' },
},
shimmer: {
'0%': { backgroundPosition: '-200% 0' },
'100%': { backgroundPosition: '200% 0' },
},
},
boxShadow: {
'glow-blue': '0 0 20px rgba(59, 130, 246, 0.3), 0 0 40px rgba(59, 130, 246, 0.1)',
'glow-purple': '0 0 20px rgba(139, 92, 246, 0.3), 0 0 40px rgba(139, 92, 246, 0.1)',
'glow-cyan': '0 0 20px rgba(6, 182, 212, 0.3), 0 0 40px rgba(6, 182, 212, 0.1)',
'modern': '0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 8px 10px -6px rgba(0, 0, 0, 0.05)',
'modern-hover': '0 25px 50px -12px rgba(0, 0, 0, 0.15)',
},
transitionTimingFunction: {
'bounce-out': 'cubic-bezier(0.34, 1.56, 0.64, 1)',
},
spacing: {
'18': '4.5rem',
'22': '5.5rem',
},
},
},