Author SHA1 Message Date
github-actions[bot]andGitHub cff72b5efb chore(deps): update dependency vue to v3.5.44
Automated dependency update. All tests passed.
2026-10-16 03:20:01 +00:00
github-actions[bot]andGitHub 6d17dee1be chore(deps): update dependency postcss to v8.5.30
Automated dependency update. All tests passed.
2026-10-15 03:20:06 +00:00
github-actions[bot]andGitHub 3decffe43d chore(deps): update dependency @vitejs/plugin-vue to v6.0.10
Automated dependency update. All tests passed.
2026-10-13 03:26:11 +00:00
github-actions[bot]andGitHub 8f3fe90c6c chore(deps): update dependency vite to v8.3.4
Automated dependency update. All tests passed.
2026-10-11 03:25:11 +00:00
github-actions[bot]andGitHub a313618aa5 chore(deps): update dependency vue-router to v5.4.0
Automated dependency update. All tests passed.
2026-10-10 03:23:28 +00:00
github-actions[bot]andGitHub f6c37a1c62 chore(deps): update dependency vite to v8.3.3
Automated dependency update. All tests passed.
2026-10-09 03:23:55 +00:00
github-actions[bot]andGitHub c3896f9213 chore(deps): update dependency postcss to v8.5.29
Automated dependency update. All tests passed.
2026-10-08 03:24:00 +00:00
github-actions[bot]andGitHub 0cc20dc876 chore(deps): update dependency vue-router to v5
Automated dependency update. All tests passed.
2026-10-06 03:21:59 +00:00
github-actions[bot]andGitHub f8680e6adc chore(deps): update dependency vite to v8
Automated dependency update. All tests passed.
2026-10-05 03:27:55 +00:00
github-actions[bot]andGitHub 53b0014673 chore(deps): update dependency @vitejs/plugin-vue to v6
Automated dependency update. All tests passed.
2026-10-04 04:21:29 +00:00
github-actions[bot]andGitHub 835abc925c chore(deps): update dependencies
Automated dependency update. All tests passed.
2026-10-04 04:20:32 +00:00
lukaszraczylo 4a6db8cb77 ci(deps): update dependencies with Renovate [skip ci] 2026-10-03 18:45:08 +01:00
lukaszraczylo 9536a9b501 kimi-changes 2026-02-19 23:33:32 +00:00
lukaszraczylo 08a6e0dd5c Add assessment page. 2025-12-13 02:03:10 +00:00
lukaszraczylo c7dd4d0371 Update user experience. 2025-12-13 01:38:45 +00:00
28 changed files with 4268 additions and 1583 deletions
+21
View File
@@ -0,0 +1,21 @@
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
+43 -7
View File
@@ -4,22 +4,58 @@
<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" />
<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) -->
<script>
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')
}
(function() {
const theme = localStorage.theme;
const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (theme === 'dark' || (!theme && systemDark)) {
document.documentElement.classList.add('dark');
}
})();
</script>
</head>
<body class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 transition-colors duration-300">
<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>
<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>
+1163 -831
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": "^4.3.0"
"vue-router": "^5.0.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue": "^6.0.0",
"autoprefixer": "^10.4.18",
"postcss": "^8.4.35",
"tailwindcss": "^3.4.1",
"vite": "^5.1.6"
"vite": "^8.0.0"
}
}
+68 -7
View File
@@ -1,14 +1,25 @@
<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">
<div class="min-h-screen flex flex-col bg-white dark:bg-gray-900 transition-colors duration-300">
<ReadingProgress />
<NavBar />
<main class="flex-1">
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in">
<transition
name="page"
mode="out-in"
appear
>
<component :is="Component" />
</transition>
</router-view>
@@ -18,13 +29,63 @@ import Footer from '@/components/layout/Footer.vue'
</template>
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s ease;
/* Page transition animations */
.page-enter-active,
.page-leave-active {
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.fade-enter-from,
.fade-leave-to {
.page-enter-from {
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>
+491 -21
View File
@@ -2,66 +2,536 @@
@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/70 dark:bg-gray-800/70 backdrop-blur-lg border border-white/20 dark:border-gray-700/50;
@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);
}
.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-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;
@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;
}
.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 10px 40px -10px rgba(0, 0, 0, 0.1);
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);
}
.dark .shadow-modern {
box-shadow: 0 10px 40px -10px rgba(0, 0, 0, 0.4);
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);
}
/* Primary button with enhanced effects */
.btn-primary {
@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;
@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);
}
.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 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;
@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;
}
.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-3xl md:text-4xl font-bold text-gray-900 dark:text-gray-100 mb-4;
@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;
}
.section-subtitle {
@apply text-lg text-gray-600 dark:text-gray-300;
@apply text-base sm:text-lg md:text-xl text-gray-600 dark:text-gray-300 px-2 sm:px-0 leading-relaxed;
}
/* Enhanced card with 3D hover */
.card {
@apply glass p-6 rounded-xl transition-all duration-300 hover:shadow-lg;
@apply glass p-4 sm:p-6 lg:p-8 rounded-2xl transition-all duration-500;
transform-style: preserve-3d;
perspective: 1000px;
}
.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 text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 font-medium transition-colors duration-200;
@apply relative 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-12 h-12 rounded-xl flex items-center justify-center flex-shrink-0 transition-transform duration-300 group-hover:scale-110;
@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;
}
}
@layer utilities {
.animate-delay-100 {
animation-delay: 0.1s;
/* 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-200 {
animation-delay: 0.2s;
.animate-fade-in-up {
animation: fadeInUp 0.6s ease-out forwards;
opacity: 0;
}
.animate-delay-300 {
animation-delay: 0.3s;
.animate-scale-in {
animation: scaleIn 0.5s ease-out forwards;
}
.animate-delay-1000 {
animation-delay: 1s;
.animate-slide-in-right {
animation: slideInRight 0.5s ease-out forwards;
}
.animate-delay-2000 {
animation-delay: 2s;
.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;
}
}
+85 -44
View File
@@ -1,84 +1,125 @@
<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="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>
<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>
</div>
<span class="text-xl font-bold gradient-text">BEAT</span>
</div>
<p class="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">
<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">
<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 mt-2">
<p class="text-gray-500 dark:text-gray-500 text-sm">
Built for how developers actually work.
</p>
</div>
<!-- Quick Links -->
<div>
<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
<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 }}
</RouterLink>
</li>
</ul>
</div>
<!-- Resources -->
<div>
<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>.
<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>.
</p>
<div class="flex space-x-3">
<div class="flex gap-2">
<a
href="https://github.com/lukaszraczylo"
target="_blank"
class="text-gray-500 hover:text-gray-900 dark:hover:text-gray-100 transition-colors"
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"
aria-label="GitHub"
>
<i class="fab fa-github text-xl"></i>
<i class="fab fa-github text-lg"></i>
</a>
<a
href="https://www.linkedin.com/in/raczylo/"
target="_blank"
class="text-gray-500 hover:text-blue-600 transition-colors"
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"
aria-label="LinkedIn"
>
<i class="fab fa-linkedin text-xl"></i>
<i class="fab fa-linkedin text-lg"></i>
</a>
</div>
</div>
</div>
<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.
<!-- 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
</p>
<p class="text-gray-400 dark:text-gray-600 text-xs">
<p class="text-gray-400 dark:text-gray-600 text-xs italic">
Attribution appreciated. Improvement welcomed. Dogma discouraged.
</p>
</div>
+169 -38
View File
@@ -1,98 +1,229 @@
<script setup>
import { ref } from 'vue'
import { ref, onMounted, onUnmounted } 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' },
{ 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' }
{ 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' }
]
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 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>
<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>
</div>
<span class="text-xl font-bold gradient-text hidden sm:inline">BEAT</span>
<span
class="text-lg sm:text-xl font-bold gradient-text hidden sm:inline transition-all duration-300 group-hover:tracking-wide"
>BEAT</span>
</RouterLink>
<div class="hidden lg:flex space-x-4 xl:space-x-6">
<!-- Desktop Navigation - hidden on mobile, shown on lg+ -->
<div class="hidden lg:flex items-center space-x-1">
<RouterLink
v-for="item in navItems"
v-for="(item, index) in navItems"
:key="item.path"
:to="item.path"
class="nav-link text-sm"
:class="{ 'text-blue-600 dark:text-blue-400': route.path === 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` }"
>
{{ 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>
<div class="flex items-center space-x-2">
<!-- Right side actions -->
<div class="flex items-center gap-1 sm:gap-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 min-w-[44px] min-h-[44px] flex items-center justify-center transition-colors duration-200"
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"
aria-label="View author on GitHub"
>
<i class="fab fa-github text-xl"></i>
<i class="fab fa-github text-lg sm: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 min-w-[44px] min-h-[44px] flex items-center justify-center"
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"
aria-label="Toggle menu"
aria-expanded="mobileMenuOpen"
aria-controls="mobile-menu"
>
<i v-if="!mobileMenuOpen" class="fas fa-bars text-xl"></i>
<i v-else class="fas fa-times text-xl"></i>
<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>
</button>
</div>
</div>
</div>
<!-- Mobile Menu Overlay -->
<transition
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-150 ease-in"
leave-from-class="opacity-100 translate-y-0"
leave-to-class="opacity-0 -translate-y-2"
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="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">
<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-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"
>
<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">
<RouterLink
v-for="item in navItems"
v-for="(item, index) in navItems"
:key="item.path"
:to="item.path"
@click="closeMobileMenu"
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 }"
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` }"
>
{{ item.label }}
<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>
</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>
@@ -0,0 +1,63 @@
<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>
+12 -5
View File
@@ -7,23 +7,30 @@ defineProps({
gradient: {
type: String,
default: null
},
glow: {
type: String,
default: null
}
})
</script>
<template>
<div
class="glass p-6 rounded-xl transition-all duration-300"
:class="{ 'hover:shadow-lg hover:-translate-y-1': hover }"
class="card"
:class="{
'hover:-translate-y-2': hover,
[`shadow-glow-${glow}`]: glow
}"
>
<div v-if="gradient" class="flex items-start gap-4">
<div v-if="gradient" class="flex items-start gap-5">
<div
class="icon-box"
class="icon-box w-14 h-14 rounded-2xl"
:class="gradient"
>
<slot name="icon"></slot>
</div>
<div class="flex-1">
<div class="flex-1 min-w-0">
<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-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>
<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>
<button
@click="copyCode"
class="text-gray-400 hover:text-white transition-colors p-1"
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"
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-4 overflow-x-auto"><code ref="codeRef" class="text-sm text-gray-100 font-mono"><slot></slot></code></pre>
<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>
</div>
</template>
+75
View File
@@ -0,0 +1,75 @@
<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>
+23 -8
View File
@@ -15,24 +15,39 @@ defineProps({
gradient: {
type: String,
default: 'from-blue-500 to-blue-600'
},
href: {
type: String,
default: null
}
})
</script>
<template>
<div class="glass p-5 rounded-xl group hover:shadow-lg transition-all duration-300">
<div class="flex items-start gap-4">
<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="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="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="gradient"
>
<i :class="icon" class="text-white"></i>
<i :class="icon" class="text-white text-xl"></i>
</div>
<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>
<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>
<slot></slot>
</div>
</div>
</div>
</component>
</template>
+101
View File
@@ -0,0 +1,101 @@
<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>
+29 -9
View File
@@ -16,18 +16,38 @@ defineProps({
</script>
<template>
<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 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>
<div class="overflow-x-auto">
<!-- 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">
<table class="w-full">
<thead>
<tr class="bg-gray-50 dark:bg-gray-800/50">
<tr class="bg-gray-50/80 dark:bg-gray-800/80">
<th
v-for="header in headers"
:key="header"
class="px-6 py-3 text-left text-xs font-semibold text-gray-600 dark:text-gray-400 uppercase tracking-wider"
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"
>
{{ header }}
</th>
@@ -37,14 +57,14 @@ defineProps({
<tr
v-for="(row, index) in rows"
:key="index"
class="hover:bg-gray-50 dark:hover:bg-gray-800/30 transition-colors"
class="hover:bg-gray-50/50 dark:hover:bg-gray-800/30 transition-all duration-200 group"
>
<td
v-for="(cell, cellIndex) in row"
:key="cellIndex"
class="px-6 py-4 text-sm text-gray-700 dark:text-gray-300"
class="px-4 md:px-6 py-3 md:py-4 text-sm text-gray-700 dark:text-gray-300"
>
<span v-html="cell"></span>
<span v-html="cell" class="group-hover:text-gray-900 dark:group-hover:text-gray-100 transition-colors"></span>
</td>
</tr>
</tbody>
+69
View File
@@ -0,0 +1,69 @@
<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
@@ -0,0 +1,350 @@
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,6 +40,11 @@ const routes = [
path: '/reference',
name: 'Reference',
component: () => import('@/views/ReferenceView.vue')
},
{
path: '/assessment',
name: 'Assessment',
component: () => import('@/views/AssessmentView.vue')
}
]
+78 -60
View File
@@ -35,92 +35,104 @@ const warningSigns = [
<template>
<div>
<!-- Hero -->
<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>
<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>
<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-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 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>
<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">
<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">
Common ways teams fail at BEAT—and how to fix them.
</p>
</div>
</section>
<!-- Process Anti-Patterns -->
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-20 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-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 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>
<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-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<section class="py-20 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300">
<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 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 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>
<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-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-20 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-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 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>
<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-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<section class="py-20 bg-gray-50 dark:bg-gray-800/30 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">When BEAT Isn't Working</h2>
<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>
<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-4 mb-8">
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-5 mb-10">
<div
v-for="sign in warningSigns"
v-for="(sign, index) in warningSigns"
:key="sign"
class="glass p-4 rounded-xl border-l-4 border-red-500"
class="card p-5 border-l-4 border-red-500"
:style="{ animationDelay: `${index * 100}ms` }"
>
<div class="flex items-center gap-3">
<i class="fas fa-exclamation-circle text-red-500"></i>
<span class="text-gray-700 dark:text-gray-300 text-sm">{{ sign }}</span>
<i class="fas fa-exclamation-circle text-red-500 text-lg"></i>
<span class="text-gray-700 dark:text-gray-300">{{ sign }}</span>
</div>
</div>
</div>
<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 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>
<div>
<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>
<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>
</div>
</div>
</div>
@@ -128,60 +140,66 @@ const warningSigns = [
</section>
<!-- Where BEAT Fits -->
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-20 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="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Where BEAT Fits</h2>
<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>
<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="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>
<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>
Works Best For
</h3>
<ul class="space-y-2">
<ul class="space-y-3">
<li
v-for="item in whereItFits.worksFor"
:key="item"
class="text-sm text-gray-600 dark:text-gray-400 flex items-center gap-2"
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"
>
<i class="fas fa-check text-green-500 text-xs"></i>
<i class="fas fa-check text-emerald-500"></i>
{{ item }}
</li>
</ul>
</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>
<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>
Fits Poorly For
</h3>
<ul class="space-y-2">
<ul class="space-y-3">
<li
v-for="item in whereItFits.fitsPoorly"
:key="item"
class="text-sm text-gray-600 dark:text-gray-400 flex items-center gap-2"
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"
>
<i class="fas fa-times text-red-500 text-xs"></i>
<i class="fas fa-times text-red-500"></i>
{{ item }}
</li>
</ul>
</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>
<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>
Can Adapt For
</h3>
<ul class="space-y-2">
<ul class="space-y-3">
<li
v-for="item in whereItFits.canAdapt"
:key="item"
class="text-sm text-gray-600 dark:text-gray-400 flex items-center gap-2"
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"
>
<i class="fas fa-adjust text-amber-500 text-xs"></i>
<i class="fas fa-adjust text-amber-500"></i>
{{ item }}
</li>
</ul>
+411
View File
@@ -0,0 +1,411 @@
<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>
+134 -87
View File
@@ -1,106 +1,124 @@
<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.' },
{ name: 'Work Items', time: 'days', description: 'Title, context, done condition. Three lines.' },
{ name: 'Projects', time: 'week+', description: 'Half-page doc with breakdown. No more.' }
{ 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' }
]
const bucketColors = {
red: 'from-red-500 to-red-600 border-red-500',
red: 'from-red-500 to-red-600 border-red-500 shadow-glow-red',
amber: 'from-amber-500 to-amber-600 border-amber-500',
blue: 'from-blue-500 to-blue-600 border-blue-500',
blue: 'from-blue-500 to-blue-600 border-blue-500 shadow-glow-blue',
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-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>
<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>
<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-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 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>
<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">
<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">
The principles guide us. The framework implements them.
</p>
</div>
</section>
<!-- Roles -->
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-20 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="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Roles</h2>
<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>
<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 in roles"
v-for="(role, index) in roles"
:key="role.name"
class="glass p-6 rounded-xl group hover:shadow-lg transition-all duration-300"
class="card group p-8 text-center"
:style="{ animationDelay: `${index * 100}ms` }"
>
<div
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="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="role.gradient"
>
<i :class="role.icon" class="text-white text-xl"></i>
<i :class="role.icon" class="text-white text-2xl"></i>
</div>
<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>
<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>
</div>
</div>
</div>
</section>
<!-- Beats -->
<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>
<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>
<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 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 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>
<h4 class="font-semibold text-gray-900 dark:text-gray-100 mb-2">Beat Start</h4>
<h4 class="font-bold text-xl 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">
<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 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>
<h4 class="font-semibold text-gray-900 dark:text-gray-100 mb-2">During Beat</h4>
<h4 class="font-bold text-xl 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">
<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 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>
<h4 class="font-semibold text-gray-900 dark:text-gray-100 mb-2">Beat Close</h4>
<h4 class="font-bold text-xl 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-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.
<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>
</p>
</div>
</div>
@@ -108,89 +126,115 @@ const bucketColors = {
</section>
<!-- Work Items -->
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-20 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="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Work Items</h2>
<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>
<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 in workItems"
v-for="(item, index) in workItems"
:key="item.name"
class="glass p-6 rounded-xl hover:shadow-lg transition-all duration-300"
class="card group p-8"
:style="{ animationDelay: `${index * 100}ms` }"
>
<div class="flex items-center gap-3 mb-3">
<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>
<span class="text-2xl font-bold gradient-text">{{ item.name }}</span>
</div>
<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">
<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">
{{ item.time }}
</div>
<p class="text-gray-600 dark:text-gray-400 text-sm">{{ item.description }}</p>
<p class="text-gray-600 dark:text-gray-400">{{ item.description }}</p>
</div>
</div>
<div class="mt-8 text-center">
<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 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>
</div>
</div>
</section>
<!-- Prioritization -->
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<section class="py-20 bg-gray-50 dark:bg-gray-800/30 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">Prioritization Buckets</h2>
<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>
<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-4">
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-5">
<div
v-for="bucket in priorityBuckets"
v-for="(bucket, index) in priorityBuckets"
:key="bucket.name"
class="glass p-5 rounded-xl border-l-4 hover:shadow-lg transition-all duration-300"
class="card p-6 border-l-4"
:class="bucketColors[bucket.color]"
:style="{ animationDelay: `${index * 100}ms` }"
>
<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>
<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>
</div>
</div>
</div>
</section>
<!-- The Board -->
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-20 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="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">The Board</h2>
<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>
<p class="text-gray-600 dark:text-gray-400">A simple kanban with priority built in.</p>
</div>
<CodeBlock title="Board Flow">ICE → LATER → NEXT → IN PROGRESS → DONE</CodeBlock>
<!-- 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>
<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 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>
<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="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 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>
<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="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 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>
<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>
@@ -198,17 +242,20 @@ const bucketColors = {
</section>
<!-- Constraints -->
<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">
<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">
<div
v-for="item in constraints"
v-for="(item, index) in constraints"
:key="item.constraint"
class="bg-white/10 backdrop-blur-sm p-4 rounded-xl"
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` }"
>
<div class="text-white/70 text-sm mb-1">{{ item.constraint }}</div>
<div class="text-white text-xl font-bold">{{ item.limit }}</div>
<div class="text-white text-2xl font-bold">{{ item.limit }}</div>
</div>
</div>
</div>
+157 -106
View File
@@ -1,111 +1,158 @@
<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-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' }
{ 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' }
]
const keyNumbers = [
{ 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' }
{ 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.' },
]
</script>
<template>
<div>
<!-- Hero Section -->
<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>
<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>
<div class="relative max-w-6xl mx-auto px-4 sm:px-6">
<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="text-center">
<!-- Logo with glow effect -->
<div class="mb-6 sm:mb-8 flex justify-center animate-fade-in-up">
<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
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>
</div>
<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">
<!-- 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">
The <span class="gradient-text">BEAT</span> Manifesto
</h1>
<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">
<!-- 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">
<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>
<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">
<!-- 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">
A software delivery methodology built for how developers actually work.
<br class="hidden sm:block" />
Created by <strong>Lukasz Raczylo</strong>.
<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>
</p>
<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">
<!-- 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">
<i class="fas fa-book-open mr-2"></i>
Start Reading
</RouterLink>
<RouterLink to="/reference" class="btn-secondary">
<i class="fas fa-list mr-2"></i>
Quick Reference
<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>
</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 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">
<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">
<div
v-for="item in keyNumbers"
v-for="(item, index) in keyNumbers"
:key="item.label"
class="glass p-6 rounded-xl text-center group hover:shadow-lg transition-all duration-300"
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` }"
>
<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
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>
<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 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>
</div>
</div>
</section>
<!-- Introduction -->
<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">
<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">
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-8">
<p class="text-gray-600 dark:text-gray-400 leading-relaxed mb-6 sm:mb-8 text-sm sm:text-base">
BEAT emerges from research on how developers actually work. We built it for these realities, not against them.
</p>
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-4">
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4">
<div
v-for="stat in researchStats"
v-for="(stat, index) in researchStats"
:key="stat.stat"
class="flex items-center gap-3 p-3 rounded-lg bg-white/50 dark:bg-gray-700/50"
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` }"
>
<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>
<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>
</div>
</div>
</div>
@@ -113,33 +160,34 @@ const keyNumbers = [
</section>
<!-- Navigation Cards -->
<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">
<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">
<h2 class="section-title">Explore the Manifesto</h2>
<p class="section-subtitle">Deep dive into each aspect of BEAT</p>
</div>
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-6">
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-5 lg:gap-6">
<RouterLink
v-for="card in navCards"
v-for="(card, index) in navCards"
:key="card.path"
:to="card.path"
class="glass p-6 rounded-xl group hover:shadow-lg transition-all duration-300 hover:-translate-y-1"
class="group card p-5 sm:p-6 lg:p-8"
:style="{ animationDelay: `${index * 100}ms` }"
>
<div class="flex items-start gap-4">
<div class="flex items-start gap-4 sm:gap-5">
<div
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="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="card.gradient"
>
<i :class="card.icon" class="text-white"></i>
<i :class="card.icon" class="text-white text-lg sm:text-xl"></i>
</div>
<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">
<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">
{{ card.title }}
<i class="fas fa-arrow-right ml-2 text-sm opacity-0 group-hover:opacity-100 transition-opacity"></i>
<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>
</h3>
<p class="text-sm text-gray-600 dark:text-gray-400">{{ card.description }}</p>
<p class="text-xs sm:text-sm text-gray-600 dark:text-gray-400 leading-relaxed">{{ card.description }}</p>
</div>
</div>
</RouterLink>
@@ -148,59 +196,62 @@ const keyNumbers = [
</section>
<!-- Commitment Section -->
<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>
<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>
</div>
<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>
<p class="text-white/70 text-xs sm:text-sm leading-relaxed pl-13 sm:pl-16">{{ item.description }}</p>
</div>
</div>
</div>
</section>
<!-- Summary -->
<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>
<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>
</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>
+67 -56
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' },
{ ...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' }
{ ...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' }
]
const whatWeDont = [
@@ -18,48 +18,53 @@ const whatWeDont = [
<template>
<div>
<!-- Hero -->
<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>
<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>
<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-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 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>
<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">
<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">
When someone new joins a BEAT team, here's how to get them up to speed.
</p>
</div>
</section>
<!-- Weekly Timeline -->
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-20 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-8">
<div class="space-y-6">
<div
v-for="(week, index) in weeks"
:key="week.title"
class="glass p-6 sm:p-8 rounded-2xl hover:shadow-lg transition-all duration-300"
class="card p-8"
:style="{ animationDelay: `${index * 150}ms` }"
>
<div class="flex items-start gap-6">
<div class="flex flex-col sm:flex-row sm:items-start gap-6">
<div
class="w-16 h-16 rounded-xl bg-gradient-to-br flex items-center justify-center flex-shrink-0"
class="w-20 h-20 rounded-2xl bg-gradient-to-br flex items-center justify-center flex-shrink-0 shadow-lg"
:class="week.gradient"
>
<i :class="week.icon" class="text-white text-xl"></i>
<i :class="week.icon" class="text-white text-2xl"></i>
</div>
<div class="flex-1">
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">{{ week.title }}</h3>
<ul class="space-y-3">
<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">
<li
v-for="item in week.items"
:key="item"
class="flex items-start gap-3 text-gray-600 dark:text-gray-400"
class="flex items-start gap-3 p-3 rounded-xl bg-gray-50 dark:bg-gray-800/50"
>
<i class="fas fa-check-circle text-green-500 mt-1"></i>
<span>{{ item }}</span>
<i class="fas fa-check-circle text-emerald-500 mt-1"></i>
<span class="text-gray-700 dark:text-gray-300">{{ item }}</span>
</li>
</ul>
</div>
@@ -70,68 +75,69 @@ const whatWeDont = [
</section>
<!-- First Month -->
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<section class="py-20 bg-gray-50 dark:bg-gray-800/30 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">{{ onboarding.firstMonth.title }}</h2>
<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>
<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-4">
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-5">
<div
v-for="(item, index) in onboarding.firstMonth.items"
:key="item"
class="glass p-5 rounded-xl hover:shadow-lg transition-all duration-300"
class="card p-6 group"
:style="{ animationDelay: `${index * 100}ms` }"
>
<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 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>
<p class="text-gray-700 dark:text-gray-300 text-sm">{{ item }}</p>
<p class="text-gray-700 dark:text-gray-300 pt-2">{{ item }}</p>
</div>
</div>
</div>
</div>
</section>
<!-- Connector's Responsibility -->
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<!-- Connector's Responsibility & What We Don't -->
<section class="py-20 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="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 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>
<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-4 text-sm">
<p class="text-gray-600 dark:text-gray-400 mb-6">
The Connector (or Enabler if no Connector) ensures:
</p>
<ul class="space-y-3">
<li class="flex items-start gap-3 text-sm text-gray-600 dark:text-gray-400">
<li class="flex items-start gap-3 p-3 rounded-xl bg-cyan-50 dark:bg-cyan-900/20">
<i class="fas fa-check text-cyan-500 mt-1"></i>
Documentation is current and findable
<span class="text-gray-700 dark:text-gray-300">Documentation is current and findable</span>
</li>
<li class="flex items-start gap-3 text-sm text-gray-600 dark:text-gray-400">
<li class="flex items-start gap-3 p-3 rounded-xl bg-cyan-50 dark:bg-cyan-900/20">
<i class="fas fa-check text-cyan-500 mt-1"></i>
New member has a "buddy" for questions (informal, not mandatory pairing)
<span class="text-gray-700 dark:text-gray-300">New member has a "buddy" for questions (informal, not mandatory pairing)</span>
</li>
<li class="flex items-start gap-3 text-sm text-gray-600 dark:text-gray-400">
<li class="flex items-start gap-3 p-3 rounded-xl bg-cyan-50 dark:bg-cyan-900/20">
<i class="fas fa-check text-cyan-500 mt-1"></i>
First tasks are well-scoped and achievable
<span class="text-gray-700 dark:text-gray-300">First tasks are well-scoped and achievable</span>
</li>
<li class="flex items-start gap-3 text-sm text-gray-600 dark:text-gray-400">
<li class="flex items-start gap-3 p-3 rounded-xl bg-cyan-50 dark:bg-cyan-900/20">
<i class="fas fa-check text-cyan-500 mt-1"></i>
Overwhelm is caught early
<span class="text-gray-700 dark:text-gray-300">Overwhelm is caught early</span>
</li>
</ul>
</div>
<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 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>
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100">What We Don't Do</h3>
</div>
@@ -139,10 +145,10 @@ const whatWeDont = [
<li
v-for="item in whatWeDont"
:key="item"
class="flex items-start gap-3 text-sm text-gray-600 dark:text-gray-400"
class="flex items-start gap-3 p-3 rounded-xl bg-red-50 dark:bg-red-900/20"
>
<i class="fas fa-times text-red-500 mt-1"></i>
{{ item }}
<span class="text-gray-700 dark:text-gray-300">{{ item }}</span>
</li>
</ul>
</div>
@@ -151,10 +157,15 @@ const whatWeDont = [
</section>
<!-- Summary -->
<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">
<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">
Onboarding should feel like a gradual ramp, not a firehose or an abandonment.
</p>
</div>
+263 -170
View File
@@ -1,97 +1,153 @@
<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-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>
<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>
<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-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 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>
<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">
<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">
How we work day-to-day: meetings, collaboration, incidents, and technical practices.
</p>
</div>
</section>
<!-- Meetings -->
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-20 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="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Meetings</h2>
<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>
<p class="text-gray-600 dark:text-gray-400">Hard limits protect our time.</p>
</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 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>
</div>
</div>
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-4">
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-5">
<div
v-for="ceremony in ceremonies"
v-for="(ceremony, index) in ceremonies"
:key="ceremony.name"
class="glass p-5 rounded-xl hover:shadow-lg transition-all duration-300"
class="card p-6"
:style="{ animationDelay: `${index * 100}ms` }"
>
<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>
<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>
<p class="text-sm text-gray-600 dark:text-gray-400">{{ ceremony.purpose }}</p>
</div>
</div>
<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.
<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>
</p>
</div>
</div>
</section>
<!-- Daily Check-in -->
<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>
<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>
<p class="text-gray-600 dark:text-gray-400">Replace standups with written updates.</p>
</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="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="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 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>
<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 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>
<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 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>
</div>
</div>
@@ -99,66 +155,68 @@ Blocked by: [nothing / specific issue]</CodeBlock>
</section>
<!-- Collaboration -->
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-20 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="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Collaboration</h2>
<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>
<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">
<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>
<!-- 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>
<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>
<!-- 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>
</div>
<div class="mt-8 p-4 rounded-lg bg-gray-100 dark:bg-gray-800">
<div class="mt-8 p-5 rounded-xl 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>
@@ -167,134 +225,169 @@ Blocked by: [nothing / specific issue]</CodeBlock>
</section>
<!-- Definition of Done -->
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<section class="py-20 bg-gray-50 dark:bg-gray-800/30 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">Definition of Done</h2>
<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>
<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="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">
<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">
<li
v-for="item in definitionOfDone.code"
:key="item"
class="flex items-center gap-3 text-sm text-gray-600 dark:text-gray-400"
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"
>
<i class="fas fa-check text-green-500"></i>
{{ item }}
<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>
</li>
</ul>
</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-file-alt text-purple-500 mr-2"></i>
For Non-Code
</h3>
<ul class="space-y-2">
<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">
<li
v-for="item in definitionOfDone.nonCode"
:key="item"
class="flex items-center gap-3 text-sm text-gray-600 dark:text-gray-400"
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"
>
<i class="fas fa-check text-green-500"></i>
{{ item }}
<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>
</li>
</ul>
</div>
</div>
<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..."
<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>
</p>
</div>
</div>
</section>
<!-- Incidents -->
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-20 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="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Incidents & Emergencies</h2>
<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>
<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="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
<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>
</li>
<li class="flex items-center gap-2">
<i class="fas fa-exclamation-triangle text-red-500"></i>
Data integrity is at risk
<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>
<li class="flex items-center gap-2">
<i class="fas fa-exclamation-triangle text-red-500"></i>
Security vulnerability being exploited
<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>
<li class="flex items-center gap-2">
<i class="fas fa-exclamation-triangle text-red-500"></i>
Significant revenue or reputation impact
<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>
</ul>
</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 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>
</div>
<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.
<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>
</p>
</div>
</div>
</section>
<!-- Technical Practices -->
<section class="py-16 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<section class="py-20 bg-gray-50 dark:bg-gray-800/30 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">Technical Practices</h2>
<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>
<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-4">
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-5">
<div
v-for="practice in technicalPractices"
v-for="(practice, index) in technicalPractices"
:key="practice.name"
class="glass p-5 rounded-xl hover:shadow-lg transition-all duration-300"
class="card p-6 group"
:style="{ animationDelay: `${index * 100}ms` }"
>
<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>
<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>
</div>
</div>
<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 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>
</div>
</section>
+61 -42
View File
@@ -2,27 +2,31 @@
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' },
{ 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' }
{ 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' }
]
</script>
<template>
<div>
<!-- Hero -->
<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>
<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>
<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 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>
<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">
<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">
Guiding principles organized into four categories: Focus, Communication, Autonomy, and Sustainability.
</p>
</div>
@@ -30,40 +34,44 @@ const categories = [
<!-- Principles by Category -->
<section
v-for="category in categories"
v-for="(category, catIndex) in categories"
:key="category.key"
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'"
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'"
>
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="flex items-center gap-4 mb-8">
<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="w-12 h-12 rounded-xl bg-gradient-to-br flex items-center justify-center"
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="category.gradient"
>
<i :class="category.icon" class="text-white"></i>
<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>
</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-6">
<div class="space-y-4 sm:space-y-5">
<div
v-for="principle in principles[category.key]"
v-for="(principle, index) in principles[category.key]"
:key="principle.number"
class="glass p-6 sm:p-8 rounded-xl hover:shadow-lg transition-all duration-300"
class="card group p-5 sm:p-6 lg:p-8"
:style="{ animationDelay: `${index * 100}ms` }"
>
<div class="flex items-start gap-4">
<div class="flex items-start gap-3 sm:gap-5">
<div
class="w-10 h-10 rounded-full bg-gradient-to-br flex items-center justify-center flex-shrink-0"
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="category.gradient"
>
<span class="text-white font-bold">{{ principle.number }}</span>
<span class="text-white font-bold text-sm sm:text-base lg:text-lg">{{ principle.number }}</span>
</div>
<div>
<h3 class="text-lg sm:text-xl font-bold text-gray-900 dark:text-gray-100 mb-3">
<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">
{{ principle.title }}
</h3>
<p class="text-gray-600 dark:text-gray-400 leading-relaxed">
<p class="text-gray-600 dark:text-gray-400 leading-relaxed text-sm sm:text-base">
{{ principle.description }}
</p>
</div>
@@ -74,22 +82,33 @@ const categories = [
</section>
<!-- Summary -->
<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">
<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">
<div
v-for="category in categories"
v-for="(category, index) in categories"
:key="category.key"
class="bg-white/10 backdrop-blur-sm p-4 rounded-xl"
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` }"
>
<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 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>
<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] }}
<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>
</li>
</ul>
</div>
+193 -45
View File
@@ -1,6 +1,6 @@
<script setup>
import TableCard from '@/components/ui/TableCard.vue'
import CodeBlock from '@/components/ui/CodeBlock.vue'
import CopyButton from '@/components/ui/CopyButton.vue'
import { coreValues, teamValues, constraints, priorityBuckets, roles, ceremonies, definitionOfDone, incidentProtocol } from '@/data/manifesto'
const coreValuesHeaders = ['We Value More', 'Over']
@@ -39,61 +39,108 @@ 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-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>
<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>
<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-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 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>
<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.
<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.
</p>
</div>
</section>
<!-- Core Values -->
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-10 sm:py-14 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Core Values</h2>
<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>
<TableCard :headers="coreValuesHeaders" :rows="coreValuesRows" />
</div>
</section>
<!-- Team Values -->
<section class="py-12 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<section class="py-10 sm:py-14 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Team Values</h2>
<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>
<TableCard :headers="teamValuesHeaders" :rows="teamValuesRows" />
</div>
</section>
<!-- The Numbers -->
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-10 sm:py-14 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">The Numbers</h2>
<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>
<TableCard :headers="constraintsHeaders" :rows="constraintsRows" />
</div>
</section>
<!-- Buckets & Roles -->
<section class="py-12 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<section class="py-10 sm:py-14 bg-gray-50 dark:bg-gray-800/30 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>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Priority Buckets</h2>
<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>
<TableCard :headers="bucketsHeaders" :rows="bucketsRows" />
</div>
<div>
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Roles</h2>
<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>
<TableCard :headers="rolesHeaders" :rows="rolesRows" />
</div>
</div>
@@ -101,60 +148,161 @@ const ceremoniesRows = ceremonies.map(c => [
</section>
<!-- Ceremonies -->
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-10 sm:py-14 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-4">Ceremonies</h2>
<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>
<TableCard :headers="ceremoniesHeaders" :rows="ceremoniesRows" />
</div>
</section>
<!-- Templates -->
<section class="py-12 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<!-- Templates with Copy Buttons -->
<section class="py-10 sm:py-14 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<h2 class="text-xl font-bold text-gray-900 dark:text-gray-100 mb-6">Templates</h2>
<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>
<div class="grid md:grid-cols-2 gap-6">
<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>
<!-- 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>
<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>
<!-- 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>
</div>
</div>
</section>
<!-- Definition of Done -->
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-10 sm:py-14 bg-white dark:bg-gray-900 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<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 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>
</div>
</section>
<!-- Incident Protocol -->
<section class="py-12 bg-gray-50 dark:bg-gray-800/50 transition-colors duration-300">
<section class="py-10 sm:py-14 bg-gray-50 dark:bg-gray-800/30 transition-colors duration-300">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<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 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>
</div>
</section>
<!-- Footer Note -->
<section class="py-12 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-10 sm:py-14 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-6 rounded-xl">
<p class="text-gray-600 dark:text-gray-400 text-sm mb-2">
BEAT v1.0 by <strong>Lukasz Raczylo</strong>
<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>
</p>
<p class="text-gray-500 dark:text-gray-500 text-xs">
<p class="text-gray-500 dark:text-gray-500 text-sm italic">
Attribution appreciated. Improvement welcomed. Dogma discouraged.
</p>
</div>
+43 -34
View File
@@ -1,5 +1,4 @@
<script setup>
import IconCard from '@/components/ui/IconCard.vue'
import TableCard from '@/components/ui/TableCard.vue'
import { coreValues, teamValues } from '@/data/manifesto'
@@ -13,27 +12,31 @@ const coreValuesRows = coreValues.map(v => [
<template>
<div>
<!-- Hero -->
<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>
<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>
<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-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 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>
<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">
<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">
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-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-20 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="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4">Core Values</h2>
<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>
<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>
@@ -44,18 +47,19 @@ 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 in coreValues"
v-for="(value, index) in coreValues"
:key="value.valueMore"
class="glass p-6 rounded-xl group hover:shadow-lg transition-all duration-300"
class="card group"
:style="{ animationDelay: `${index * 100}ms` }"
>
<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 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>
<h3 class="font-semibold text-gray-900 dark:text-gray-100">{{ value.valueMore }}</h3>
<h3 class="font-semibold text-lg text-gray-900 dark:text-gray-100">{{ value.valueMore }}</h3>
</div>
<p class="text-sm text-gray-500 dark:text-gray-500">
over {{ value.over }}
over <span class="text-gray-700 dark:text-gray-300">{{ value.over }}</span>
</p>
</div>
</div>
@@ -63,10 +67,12 @@ const coreValuesRows = coreValues.map(v => [
</section>
<!-- Team Values -->
<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>
<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>
<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>
@@ -74,20 +80,21 @@ const coreValuesRows = coreValues.map(v => [
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-6">
<div
v-for="value in teamValues"
v-for="(value, index) in teamValues"
:key="value.name"
class="glass p-6 rounded-xl group hover:shadow-lg transition-all duration-300"
class="card group p-8"
:style="{ animationDelay: `${index * 100}ms` }"
>
<div class="flex items-center gap-4 mb-4">
<div class="flex items-center gap-5 mb-5">
<div
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="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="value.gradient"
>
<i :class="value.icon" class="text-white"></i>
<i :class="value.icon" class="text-white text-xl"></i>
</div>
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100">{{ value.name }}</h3>
<h3 class="text-2xl font-bold text-gray-900 dark:text-gray-100">{{ value.name }}</h3>
</div>
<p class="text-gray-600 dark:text-gray-400 text-sm leading-relaxed">
<p class="text-gray-600 dark:text-gray-400 leading-relaxed">
{{ value.description }}
</p>
</div>
@@ -96,11 +103,13 @@ const coreValuesRows = coreValues.map(v => [
</section>
<!-- Summary -->
<section class="py-16 bg-white dark:bg-gray-900 transition-colors duration-300">
<section class="py-20 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">
<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">
<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">
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>
+87 -6
View File
@@ -11,19 +11,100 @@ 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-up': 'fadeInUp 0.6s ease-out',
'float': 'float 3s ease-in-out infinite',
'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',
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
},
fadeInUp: {
'0%': { opacity: '0', transform: 'translateY(20px)' },
'0%': { opacity: '0', transform: 'translateY(30px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
float: {
'0%, 100%': { transform: 'translateY(0px)' },
'50%': { transform: 'translateY(-10px)' },
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)' },
},
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',
},
},
},