From cb080255b4fec488b3587f6d50e581f503be7445 Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Tue, 26 May 2026 00:40:36 +0300 Subject: [PATCH 1/2] Refactor templates for improved user experience and accessibility - Updated the newsletter subscription section in base.html for clarity and enhanced call-to-action. - Enhanced form validation in contact.html with error messages and accessibility attributes. - Redesigned the "Why Choose Us" section in index.html for better layout and readability. - Improved the pricing section in pricing.html with consistent terminology and visual enhancements. - Added new project showcases in projects.html to highlight recent work and outcomes. --- ...-31-53Z__src-templates-all-public-pages.md | 106 ++++++++ .impeccable/design.json | 131 ++++++++++ DESIGN.md | 222 ++++++++++++++++ PRODUCT.md | 36 +++ src/apps/core/middleware.py | 5 +- src/static/css/main.css | 176 +++++++++++-- src/templates/about.html | 151 +++-------- src/templates/base.html | 29 +- src/templates/contact.html | 58 +++- src/templates/index.html | 247 ++++++++---------- src/templates/pricing.html | 22 +- src/templates/projects.html | 50 +++- 12 files changed, 931 insertions(+), 302 deletions(-) create mode 100644 .impeccable/critique/2026-05-25T21-31-53Z__src-templates-all-public-pages.md create mode 100644 .impeccable/design.json create mode 100644 DESIGN.md create mode 100644 PRODUCT.md diff --git a/.impeccable/critique/2026-05-25T21-31-53Z__src-templates-all-public-pages.md b/.impeccable/critique/2026-05-25T21-31-53Z__src-templates-all-public-pages.md new file mode 100644 index 0000000..6d02726 --- /dev/null +++ b/.impeccable/critique/2026-05-25T21-31-53Z__src-templates-all-public-pages.md @@ -0,0 +1,106 @@ +--- +target: all public pages +total_score: 24 +p0_count: 0 +p1_count: 2 +timestamp: 2026-05-25T21-31-53Z +slug: src-templates-all-public-pages +--- +## Design Health Score + +| # | Heuristic | Score | Key Issue | +|---|-----------|-------|-----------| +| 1 | Visibility of System Status | 3 | No loading states on tab switches; newsletter email input has no feedback | +| 2 | Match System / Real World | 3 | Good use of familiar language; "SOW" jargon in process step 4 | +| 3 | User Control and Freedom | 3 | No back-to-top; tab switches lose scroll position | +| 4 | Consistency and Standards | 2 | Every page uses identical hero pattern (badge + heading + paragraph); repetitive | +| 5 | Error Prevention | 2 | Newsletter email input isn't a real form; contact form lacks inline validation | +| 6 | Recognition Rather Than Recall | 3 | Navigation is clear; tab panels require recall of which tab was active | +| 7 | Flexibility and Efficiency | 2 | No keyboard shortcuts; no quick-jump anchors on long pages | +| 8 | Aesthetic and Minimalist Design | 2 | Card grid repetition across pages; information density could be higher | +| 9 | Error Recovery | 2 | Contact form has no visible error states in template; no inline error messaging | +| 10 | Help and Documentation | 2 | No FAQ; pricing page doesn't explain what "Discovery Call" includes | +| **Total** | | **24/40** | **Needs Work** | + +## Anti-Patterns Verdict + +**LLM assessment**: The site is competent but has visible AI-generation tells: + +1. **Identical card grids** (banned pattern): The "Why Choose Us" section on index, "Our Values" on about, and the projects grid all use the same icon + heading + text card repeated 3-6 times in an identical grid. This is the #1 AI slop tell. +2. **Repetitive hero pattern**: Every single page opens with the exact same structure: section badge (dot + uppercase text) → h1 with one accent-colored word → subtitle paragraph. Seven pages, seven identical compositions. A visitor browsing multiple pages will notice the formula. +3. **Glass navbar is purposeful** (not decorative glassmorphism): passes the "rare and purposeful" test. +4. **No gradient text**: clean. +5. **No side-stripe borders**: clean. +6. **Category-reflex check**: "tech agency → dark theme + warm gold" is a recognizable first-order reflex. The palette works but doesn't surprise. + +**Deterministic scan**: Unavailable (bundled detector not found in this environment). Manual review only. + +## Overall Impression + +The site is cohesive, warm, and technically well-built. The dark-warm palette and glass-effect navbar create genuine atmosphere. But the structural repetition across pages drains personality: every page feels stamped from the same template, and card grids dominate where more varied layouts would show craft. For an agency whose principle is "practice what you preach," the uniform layout undermines the claim of bespoke work. + +The single biggest opportunity: **break the layout monotony.** Vary section compositions across pages so each page feels designed, not generated. + +## What's Working + +1. **The hero section on index**: Floating testimonial cards flanking the headline create asymmetry and social proof simultaneously. The godrays effect adds atmospheric depth without being gimmicky. This is the strongest moment on the site. + +2. **The bento grid in services on index**: Mixing a tall 2-row card with shorter ones breaks the identical-grid pattern. The accent-colored "Strategy" card at the bottom adds variety. This approach should be expanded to other pages. + +3. **Contact form**: Well-structured with clear labels, progressive disclosure (optional fields second), honeypot spam protection, and proper field grouping. The sidebar with contact details provides good information architecture. + +## Priority Issues + +### [P1] Identical Card Grids Across All Pages +**What**: "Why Choose Us" (3 cards), "Our Values" (6 cards), Projects (3+ cards per tab), Products (3 cards), Pricing (6 step circles) all use the same icon-title-text card in a uniform grid. +**Why it matters**: This is the #1 AI-generation tell. An agency claiming craft cannot display the same card template 25+ times across its site. Visitors scanning multiple pages will subconsciously register "template." +**Fix**: Replace at least 3 of these grids with different compositions: a comparison table, a timeline, numbered steps with connecting lines, an accordion, a featured spotlight with supporting details, or asymmetric 2-column layouts. +**Suggested command**: `impeccable layout` + +### [P1] Every Page Hero Is Identical +**What**: All 7 pages open with: accent badge (dot + text) → extrabold h1 with one accent word → subtitle paragraph → centered alignment. The formula is visible. +**Why it matters**: Structural repetition across pages signals "generated from template." Real brand sites vary their openers: some lead with imagery, some with a provocative question, some with asymmetric layouts. +**Fix**: Keep the pattern for 2-3 inner pages, but vary at least the About and Projects heroes. About could lead with the story (no badge); Projects could open with a featured project hero image. Index already has variety with the testimonials. +**Suggested command**: `impeccable bolder` + +### [P2] About Page Stat Numbers Are Underwhelming +**What**: "2025 Officially Launched", "5+ Team Members", "10+ Projects", "10+ Customers" prominently displayed. +**Why it matters**: Small numbers displayed large draw attention to the company's youth. "10+ Customers" in a big accent-colored stat card could create doubt rather than confidence. These numbers will improve with time, but right now they're working against the "confident expert" brand. +**Fix**: Either remove the stat grid until numbers are more impressive, or reframe: "20+ Years Combined Experience" (already mentioned in copy), "100% Project Delivery Rate", qualitative achievements instead of quantity metrics. +**Suggested command**: `impeccable clarify` + +### [P2] Newsletter Section Is Deceptive +**What**: The email input appears to be a subscription form but the button is actually a link to Substack. The input does nothing. +**Why it matters**: This is an error-prevention failure (Heuristic 5). A user types their email, clicks "Subscribe," and leaves the site. Their typed email is lost. It violates "practice what you preach" by appearing functional but being decorative. +**Fix**: Either make it a real form that subscribes to Substack via API, or replace the input with a single clear CTA button: "Subscribe on Substack →". Don't fake form UX. +**Suggested command**: `impeccable harden` + +### [P2] Pricing Process Steps Violate the Ember Hierarchy Rule +**What**: The 6-step circle indicators alternate amber-gold (#C8956A) and maroon (#7A1C1C) with varying opacities (accent, accent/80, accent/60, primary, primary/80, accent). Gold and maroon touch directly in adjacent elements. +**Why it matters**: The DESIGN.md's Ember Hierarchy Rule states: "If gold is touching maroon directly, one of them is wrong." The alternating treatment creates visual noise rather than a clear progression. +**Fix**: Use a single color family for the progression (e.g., maroon at increasing opacity: /40 → /60 → /80 → /100), or all amber-gold. Not alternating. +**Suggested command**: `impeccable colorize` + +## Persona Red Flags + +**Sarah (Business Owner, first-time visitor)**: Arrives from Google, lands on index. Hero is strong, immediately understands what Acoruss does. Scrolls to "Why Choose Us": sees generic-looking cards and thinks "every agency says this." Clicks "Projects": sees a grid of cards with no screenshots or visuals. No imagery of actual work. Must click external links to see proof. High risk of abandoning without contacting. + +**David (CTO evaluating agencies)**: Goes to Pricing. Sees "$50 Discovery Call fee" immediately. No context on what the call covers, what deliverables come from it, or why it's worth paying for. Clicks Services: 7 tabs is high cognitive load. Tab content is long-form text with no visual hierarchy within each tab. Will skim and miss key differentiators. Wants to see a case study, not a feature list. + +**Amina (Startup founder, mobile)**: On index, floating testimonial cards are hidden (desktop only). Social proof disappears on mobile. Tab interfaces on Services/Projects require precise tapping. Long scrolling service panels on mobile with no way to jump between tabs without scrolling back up. + +## Minor Observations + +- The homepage has `font-extrabold` (800) while DESIGN.md specifies Display as 700. Minor inconsistency. +- Products page repeats xPerience Nairobi content that's also on the Projects page. Redundancy reduces each page's distinctiveness. +- Footer "Stay in the loop" section appears on every page including Contact (where someone already reaching out doesn't need newsletter prompting). +- Missing `aria-label` on several icon-only SVGs within cards. +- Tab panel transitions are instant (no animation). Given the system uses fade-in-up elsewhere, the jarring show/hide stands out. +- Some copy uses em-dashes implicitly via " - " (hyphen surrounded by spaces), which reads as an informal em-dash substitute. + +## Questions to Consider + +- What if each page had a genuinely different layout shape, proving Acoruss builds bespoke, not from templates? +- What if the Projects page showed screenshots or mockups instead of card descriptions? +- What if the About page led with the team's faces and personalities rather than a logo placeholder? +- What would pricing look like if it didn't try to list every service, but instead focused on the buyer's journey? diff --git a/.impeccable/design.json b/.impeccable/design.json new file mode 100644 index 0000000..ddd0a71 --- /dev/null +++ b/.impeccable/design.json @@ -0,0 +1,131 @@ +{ + "schemaVersion": 2, + "generatedAt": "2026-05-26T00:24:00.000Z", + "title": "Design System: Acoruss", + "extensions": { + "colorMeta": { + "warm-maroon": { "role": "primary", "displayName": "Warm Maroon", "canonical": "oklch(38% 0.12 25)", "tonalRamp": ["oklch(15% 0.06 25)", "oklch(22% 0.08 25)", "oklch(30% 0.10 25)", "oklch(38% 0.12 25)", "oklch(50% 0.14 25)", "oklch(62% 0.12 25)", "oklch(75% 0.08 25)", "oklch(90% 0.04 25)"] }, + "deep-ember": { "role": "secondary", "displayName": "Deep Ember", "canonical": "oklch(25% 0.06 25)", "tonalRamp": ["oklch(12% 0.03 25)", "oklch(18% 0.04 25)", "oklch(22% 0.05 25)", "oklch(25% 0.06 25)", "oklch(35% 0.07 25)", "oklch(48% 0.06 25)", "oklch(65% 0.04 25)", "oklch(82% 0.02 25)"] }, + "amber-gold": { "role": "tertiary", "displayName": "Amber Gold", "canonical": "oklch(72% 0.12 70)", "tonalRamp": ["oklch(25% 0.04 70)", "oklch(35% 0.06 70)", "oklch(48% 0.08 70)", "oklch(60% 0.10 70)", "oklch(72% 0.12 70)", "oklch(80% 0.10 70)", "oklch(88% 0.06 70)", "oklch(95% 0.03 70)"] }, + "charred-earth": { "role": "neutral", "displayName": "Charred Earth", "canonical": "oklch(12% 0.008 50)", "tonalRamp": ["oklch(8% 0.005 50)", "oklch(12% 0.008 50)", "oklch(18% 0.008 50)", "oklch(25% 0.008 50)", "oklch(35% 0.006 50)", "oklch(50% 0.005 50)", "oklch(70% 0.004 50)", "oklch(90% 0.003 50)"] }, + "warm-smoke": { "role": "neutral", "displayName": "Warm Smoke", "canonical": "oklch(18% 0.008 50)", "tonalRamp": ["oklch(10% 0.005 50)", "oklch(14% 0.007 50)", "oklch(18% 0.008 50)", "oklch(25% 0.008 50)", "oklch(35% 0.007 50)", "oklch(50% 0.005 50)", "oklch(70% 0.004 50)", "oklch(90% 0.003 50)"] }, + "warm-cream": { "role": "neutral", "displayName": "Warm Cream", "canonical": "oklch(96% 0.008 70)", "tonalRamp": ["oklch(30% 0.004 70)", "oklch(45% 0.005 70)", "oklch(60% 0.006 70)", "oklch(72% 0.007 70)", "oklch(82% 0.007 70)", "oklch(90% 0.008 70)", "oklch(94% 0.008 70)", "oklch(96% 0.008 70)"] } + }, + "typographyMeta": { + "display": { "displayName": "Display", "purpose": "Hero headlines only. Bold, tight, commanding." }, + "headline": { "displayName": "Headline", "purpose": "Section headings. Same weight as display, stepped down." }, + "title": { "displayName": "Title", "purpose": "Card headings, sub-section titles." }, + "body": { "displayName": "Body", "purpose": "Running text. Regular weight, generous leading for dark backgrounds." }, + "label": { "displayName": "Label", "purpose": "Section badges, pill labels, metadata. Uppercase, tracked out." } + }, + "shadows": [ + { "name": "card-hover", "value": "0 12px 40px rgba(0, 0, 0, 0.3)", "purpose": "Lift effect on card hover. Always paired with translateY(-4px)." }, + { "name": "navbar-ambient", "value": "0 1px 2px rgba(0, 0, 0, 0.1)", "purpose": "Minimal shadow on floating pill navbar. Barely perceptible." } + ], + "motion": [ + { "name": "ease-standard", "value": "cubic-bezier(0.4, 0, 0.2, 1)", "purpose": "Default easing for all state transitions (hover, sidebar collapse, nav)." }, + { "name": "fade-in-up", "value": "translateY(20px) → translateY(0), opacity 0 → 1, 0.6s ease-out", "purpose": "Scroll-triggered entrance animation for content sections." }, + { "name": "card-lift", "value": "translateY(-4px), 0.3s cubic-bezier(0.4, 0, 0.2, 1)", "purpose": "Card hover lift. Pairs with card-hover shadow." } + ], + "breakpoints": [ + { "name": "sm", "value": "640px" }, + { "name": "md", "value": "768px" }, + { "name": "lg", "value": "1024px" }, + { "name": "xl", "value": "1280px" } + ] + }, + "components": [ + { + "name": "Primary Button", + "kind": "button", + "refersTo": "button-primary", + "description": "Main CTA button. Pill-shaped, warm maroon fill, white text, trailing arrow icon.", + "html": "", + "css": ".ds-btn-primary { display: inline-flex; align-items: center; gap: 8px; background: #7A1C1C; color: #FFFFFF; padding: 10px 20px; border-radius: 9999px; font-family: Inter, ui-sans-serif, system-ui, sans-serif; font-size: 0.875rem; font-weight: 600; border: none; cursor: pointer; transition: background 0.2s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1); } .ds-btn-primary:hover { background: #8B2222; } .ds-btn-primary:focus-visible { outline: 2px solid #C8956A; outline-offset: 2px; }" + }, + { + "name": "Ghost Button", + "kind": "button", + "refersTo": "button-ghost", + "description": "Secondary navigation-style button. Transparent, reveals fill on hover.", + "html": "", + "css": ".ds-btn-ghost { display: inline-flex; align-items: center; background: transparent; color: #F5F0EB; padding: 8px 12px; border-radius: 12px; font-family: Inter, ui-sans-serif, system-ui, sans-serif; font-size: 0.875rem; font-weight: 500; border: none; cursor: pointer; transition: background 0.2s cubic-bezier(0.4, 0, 0.2, 1); } .ds-btn-ghost:hover { background: rgba(255, 255, 255, 0.1); } .ds-btn-ghost:focus-visible { outline: 2px solid #C8956A; outline-offset: 2px; }" + }, + { + "name": "Glass Card", + "kind": "card", + "refersTo": "card-surface", + "description": "Primary content container. Glass-effect surface floating on dark ground.", + "html": "

Custom Software

Tailored solutions that grow with your business.

", + "css": ".ds-glass-card { backdrop-filter: blur(16px) saturate(180%); -webkit-backdrop-filter: blur(16px) saturate(180%); background: rgba(26, 22, 18, 0.75); border: 1px solid rgba(232, 226, 218, 0.05); border-radius: 16px; padding: 20px; transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1); } .ds-glass-card:hover { transform: translateY(-4px); box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3); } .ds-card-title { font-size: 1.25rem; font-weight: 600; color: #F5F0EB; margin: 0 0 8px 0; } .ds-card-body { font-size: 1rem; color: rgba(232, 226, 218, 0.7); margin: 0; line-height: 1.6; }" + }, + { + "name": "Glass Navbar", + "kind": "nav", + "refersTo": "nav-pill", + "description": "Floating pill-shaped navigation bar with glass effect. Fixed at top.", + "html": "", + "css": ".ds-navbar { display: flex; align-items: center; justify-content: space-between; width: 100%; max-width: 72rem; backdrop-filter: blur(16px) saturate(180%); -webkit-backdrop-filter: blur(16px) saturate(180%); background: rgba(26, 22, 18, 0.75); border: 1px solid rgba(232, 226, 218, 0.05); border-radius: 9999px; padding: 12px 20px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); } .ds-nav-brand { font-size: 1.125rem; font-weight: 700; color: #F5F0EB; letter-spacing: -0.02em; } .ds-nav-links { display: flex; gap: 4px; } .ds-nav-link { padding: 8px 12px; border-radius: 12px; font-size: 0.875rem; font-weight: 500; color: #F5F0EB; text-decoration: none; transition: background 0.2s cubic-bezier(0.4, 0, 0.2, 1); } .ds-nav-link:hover { background: rgba(255, 255, 255, 0.1); } .ds-btn-sm { padding: 8px 16px; font-size: 0.8125rem; }" + }, + { + "name": "Section Badge", + "kind": "chip", + "refersTo": null, + "description": "Small uppercase pill that introduces a section. Amber dot indicator on left.", + "html": "OUR SERVICES", + "css": ".ds-section-badge { display: inline-flex; align-items: center; gap: 8px; font-family: Inter, ui-sans-serif, system-ui, sans-serif; font-size: 0.75rem; font-weight: 500; letter-spacing: 0.05em; text-transform: uppercase; color: rgba(232, 226, 218, 0.6); } .ds-badge-dot { width: 6px; height: 6px; border-radius: 9999px; background: #C8956A; }" + }, + { + "name": "Dashboard Card", + "kind": "card", + "refersTo": "card-surface", + "description": "Dashboard container with backdrop-blur. Used for stats, tables, and content panels.", + "html": "

Revenue

Monthly overview of payment activity.

", + "css": ".ds-dash-card { border-radius: 16px; border: 1px solid rgba(44, 37, 32, 0.5); background: rgba(15, 13, 11, 0.6); padding: 20px; backdrop-filter: blur(4px); } .ds-dash-card-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; } .ds-dash-card .ds-card-title { font-size: 1rem; font-weight: 600; color: #E8E2DA; margin: 0; } .ds-dash-card .ds-card-body { font-size: 0.875rem; color: rgba(232, 226, 218, 0.6); margin: 0; line-height: 1.5; }" + }, + { + "name": "Input Field", + "kind": "input", + "refersTo": "input-field", + "description": "Standard text input. Warm dark background, cream text, amber focus ring.", + "html": "", + "css": ".ds-input { width: 100%; background: #1A1612; color: #F5F0EB; border: 1px solid rgba(44, 37, 32, 0.8); border-radius: 12px; padding: 12px 16px; font-family: Inter, ui-sans-serif, system-ui, sans-serif; font-size: 1rem; transition: border-color 0.2s cubic-bezier(0.4, 0, 0.2, 1); } .ds-input::placeholder { color: rgba(232, 226, 218, 0.4); } .ds-input:focus { outline: none; border-color: #C8956A; box-shadow: 0 0 0 2px rgba(200, 149, 106, 0.2); } .ds-input:focus-visible { outline: 2px solid #C8956A; outline-offset: 2px; }" + } + ], + "narrative": { + "northStar": "The Fireside Counsel", + "overview": "A trusted advisor's space: warm, composed, assured. The interface evokes the feeling of sitting in a well-appointed study with someone who has solved this problem before. Every surface carries the warmth of dark timber and ember-glow accents. The system never shouts, never dazzles with cheap tricks; it earns trust through craft, consistency, and restraint in the right places.\n\nThis system rejects displaced or scattered designs, generic template aesthetics, flashy gimmickry, and cold corporate impersonality. It is an agency's own proof of work: if the site itself doesn't feel expertly made, nothing it claims matters.\n\nThe color strategy is Committed: warm maroon carries identity across dark surfaces, with amber-gold as a secondary voice for emphasis. The palette works in tight harmony; no color arrives without purpose.", + "keyCharacteristics": [ + "Dark warm ground with layered glass surfaces", + "Single-font system (Inter) using weight and scale for hierarchy", + "Pill-shaped primary CTAs that feel solid and inviting", + "Godrays and subtle radial gradients for atmospheric depth", + "Scroll-triggered fade animations at restrained energy", + "Glass-effect navbar floating above content" + ], + "rules": [ + { "name": "The Ember Hierarchy Rule", "body": "Maroon is identity. Gold is emphasis. The darks are structure. If gold is touching maroon directly, one of them is wrong. They address different emotional registers and should not compete in the same element.", "section": "colors" }, + { "name": "The Weight Gap Rule", "body": "Adjacent hierarchy levels must differ by at least one full weight step (e.g., 700 to 500, never 600 to 500). If two text elements feel the same weight at a glance, one of them is at the wrong level.", "section": "typography" }, + { "name": "The Flat-at-Rest Rule", "body": "Surfaces are flat at rest. No resting shadows. Shadows appear only as a response to interaction (hover, press, drag). If a card has a shadow without being hovered, the shadow is wrong.", "section": "elevation" } + ], + "dos": [ + "Do use the warm maroon (#7A1C1C) exclusively for CTAs and primary interactive elements. Its rarity is its power.", + "Do tint every \"black\" toward the warm hue. #0F0D0B, not #000000. The system has no true black or true white.", + "Do use the glass-effect (backdrop-blur 16px + saturate 180%) for floating navigation and elevated marketing surfaces.", + "Do maintain the weight gap between adjacent text levels (700 → 500 → 400, never adjacent values).", + "Do use scroll-triggered fade-in-up animations (0.6s ease-out) for content entering the viewport.", + "Do keep section spacing generous (80px between major sections) to let dark backgrounds breathe." + ], + "donts": [ + "Don't use displaced or scattered elements that feel like unrelated parts stitched together.", + "Don't use generic template patterns, stock imagery, or hollow marketing copy.", + "Don't use flashy gimmickry, excessive particle effects, or spectacle over substance.", + "Don't use cold, impersonal corporate styling. No clinical whites, no steel grays.", + "Don't use border-left or border-right greater than 1px as colored accent stripes.", + "Don't use gradient text (background-clip: text).", + "Don't use bounce or elastic easing. Ease-out with exponential curves only.", + "Don't use resting shadows. Shadows respond to interaction, never decorate at rest.", + "Don't use true #000000 or #FFFFFF anywhere. Every neutral is tinted warm." + ] + } +} diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 0000000..a73a739 --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,222 @@ +--- +name: Acoruss +description: Technology consulting agency empowering businesses through software, AI, and strategy. +colors: + warm-maroon: "#7A1C1C" + deep-ember: "#3D1C1C" + amber-gold: "#C8956A" + charred-earth: "#0F0D0B" + warm-smoke: "#1A1612" + ash-brown: "#2C2520" + warm-cream: "#F5F0EB" + parchment: "#E8E2DA" + soft-blue: "#5B9BD5" + muted-sage: "#5B9B6B" + warm-gold: "#D4A843" + ember-red: "#C94444" +typography: + display: + fontFamily: "Inter, ui-sans-serif, system-ui, sans-serif" + fontSize: "clamp(2.25rem, 5vw, 3.75rem)" + fontWeight: 700 + lineHeight: 1.1 + letterSpacing: "-0.02em" + headline: + fontFamily: "Inter, ui-sans-serif, system-ui, sans-serif" + fontSize: "clamp(1.5rem, 3vw, 2.25rem)" + fontWeight: 700 + lineHeight: 1.2 + letterSpacing: "-0.01em" + title: + fontFamily: "Inter, ui-sans-serif, system-ui, sans-serif" + fontSize: "1.25rem" + fontWeight: 600 + lineHeight: 1.4 + body: + fontFamily: "Inter, ui-sans-serif, system-ui, sans-serif" + fontSize: "1rem" + fontWeight: 400 + lineHeight: 1.6 + label: + fontFamily: "Inter, ui-sans-serif, system-ui, sans-serif" + fontSize: "0.75rem" + fontWeight: 500 + lineHeight: 1.25 + letterSpacing: "0.05em" +rounded: + sm: "8px" + md: "12px" + lg: "16px" + full: "9999px" +spacing: + sm: "8px" + md: "16px" + lg: "24px" + xl: "32px" + section: "80px" +components: + button-primary: + backgroundColor: "{colors.warm-maroon}" + textColor: "#FFFFFF" + rounded: "{rounded.full}" + padding: "10px 20px" + button-primary-hover: + backgroundColor: "#8B2222" + textColor: "#FFFFFF" + button-ghost: + backgroundColor: "transparent" + textColor: "{colors.warm-cream}" + rounded: "{rounded.md}" + padding: "8px 12px" + button-ghost-hover: + backgroundColor: "rgba(255, 255, 255, 0.1)" + textColor: "{colors.warm-cream}" + card-surface: + backgroundColor: "rgba(15, 13, 11, 0.6)" + textColor: "{colors.warm-cream}" + rounded: "{rounded.lg}" + padding: "20px" + card-surface-hover: + backgroundColor: "rgba(15, 13, 11, 0.7)" + nav-pill: + backgroundColor: "rgba(26, 22, 18, 0.75)" + textColor: "{colors.warm-cream}" + rounded: "{rounded.full}" + padding: "12px 20px" + input-field: + backgroundColor: "{colors.warm-smoke}" + textColor: "{colors.warm-cream}" + rounded: "{rounded.md}" + padding: "12px 16px" +--- + +# Design System: Acoruss + +## 1. Overview + +**Creative North Star: "The Fireside Counsel"** + +A trusted advisor's space: warm, composed, assured. The interface evokes the feeling of sitting in a well-appointed study with someone who has solved this problem before. Every surface carries the warmth of dark timber and ember-glow accents. The system never shouts, never dazzles with cheap tricks; it earns trust through craft, consistency, and restraint in the right places. + +This system rejects displaced or scattered designs, generic template aesthetics, flashy gimmickry, and cold corporate impersonality. It is an agency's own proof of work: if the site itself doesn't feel expertly made, nothing it claims matters. + +The color strategy is **Committed**: warm maroon carries identity across dark surfaces, with amber-gold as a secondary voice for emphasis. The palette works in tight harmony; no color arrives without purpose. + +**Key Characteristics:** +- Dark warm ground with layered glass surfaces +- Single-font system (Inter) using weight and scale for hierarchy +- Pill-shaped primary CTAs that feel solid and inviting +- Godrays and subtle radial gradients for atmospheric depth +- Scroll-triggered fade animations at restrained energy +- Glass-effect navbar floating above content + +## 2. Colors + +A palette of embers and ash: warm darks dominate, punctuated by maroon identity and amber-gold sparks. + +### Primary +- **Warm Maroon** (#7A1C1C): The brand voice. CTAs, headings, active states, and any element that says "this is Acoruss." Used sparingly on dark surfaces for maximum contrast and authority. + +### Secondary +- **Deep Ember** (#3D1C1C): Darker sibling of the primary. Card fills in variety contexts, section differentiation, and subtle tonal shifts. Never competes with primary; it recedes. + +### Tertiary +- **Amber Gold** (#C8956A): The warm accent. Featured elements, star ratings, emphasis text, hover highlights. Brings warmth and approachability to the maroon's authority. + +### Neutral +- **Charred Earth** (#0F0D0B): The deepest dark. Page background, footer ground. Almost black, but warm. +- **Warm Smoke** (#1A1612): Primary surface for cards and elevated containers. The "resting" background for interactive elements. +- **Ash Brown** (#2C2520): Borders, dividers, subtle separators. The lightest of the darks. +- **Warm Cream** (#F5F0EB): Primary text on dark. Off-white with warmth; never clinical. +- **Parchment** (#E8E2DA): Secondary text, body copy at reduced emphasis. Slightly muted. + +### Named Rules +**The Ember Hierarchy Rule.** Maroon is identity. Gold is emphasis. The darks are structure. If gold is touching maroon directly, one of them is wrong. They address different emotional registers and should not compete in the same element. + +## 3. Typography + +**Display Font:** Inter (with ui-sans-serif, system-ui fallback) +**Body Font:** Inter (same stack) + +**Character:** A single-font system that derives all personality from weight contrast and optical sizing. Inter's variable axis (opsz 14-32) keeps small text crisp and large text elegant. The system avoids typographic spectacle; authority comes from scale and weight, not decorative faces. + +### Hierarchy +- **Display** (700, clamp(2.25rem, 5vw, 3.75rem), line-height 1.1, tracking -0.02em): Hero headlines only. Bold, tight, commanding. +- **Headline** (700, clamp(1.5rem, 3vw, 2.25rem), line-height 1.2, tracking -0.01em): Section headings. Same weight as display, stepped down. +- **Title** (600, 1.25rem, line-height 1.4): Card headings, sub-section titles. Semibold, not bold. +- **Body** (400, 1rem, line-height 1.6, max 65-75ch): Running text. Regular weight, generous leading for readability on dark backgrounds. +- **Label** (500, 0.75rem, tracking 0.05em, uppercase): Section badges, pill labels, metadata. Small, tracked out, uppercase. + +### Named Rules +**The Weight Gap Rule.** Adjacent hierarchy levels must differ by at least one full weight step (e.g., 700 to 500, never 600 to 500). If two text elements feel the same weight at a glance, one of them is at the wrong level. + +## 4. Elevation + +This system uses **layered glass over warm darkness**. Depth is conveyed through translucent surfaces with backdrop-blur, not traditional drop shadows. The dark gradient ground (hero-gradient) establishes the base plane; glass-effect elements float above it with subtle borders at low opacity. + +Shadows appear only on hover as a state response, never at rest. The resting state is flat-with-blur; the active state lifts with shadow. + +### Shadow Vocabulary +- **Card hover lift** (`0 12px 40px rgba(0, 0, 0, 0.3)`): Applied via `.card-hover:hover`. Elements rise 4px on Y-axis simultaneously. +- **Navbar ambient** (`shadow-sm` via DaisyUI): Minimal shadow on the floating pill navbar. Barely perceptible; border does the heavy lifting. + +### Named Rules +**The Flat-at-Rest Rule.** Surfaces are flat at rest. No resting shadows. Shadows appear only as a response to interaction (hover, press, drag). If a card has a shadow without being hovered, the shadow is wrong. + +## 5. Components + +### Buttons +Solid and grounded. Buttons feel like they have weight. + +- **Shape:** Full pill radius (9999px) for primary CTAs; medium radius (12px) for ghost/nav buttons +- **Primary:** Warm maroon fill (#7A1C1C), white text, padding 10px 20px, font-semibold. Often includes a trailing arrow icon. +- **Hover / Focus:** Background lightens slightly (#8B2222), focus ring 2px solid amber-gold with 2px offset. No scale or bounce. +- **Ghost:** Transparent background, warm-cream text, 12px radius. Hover reveals white at 10% opacity. + +### Cards / Containers +Glass surfaces that float on the dark ground. + +- **Corner Style:** Generous curves (16px radius) +- **Background:** Base-100 at 60% opacity with 4px backdrop-blur (dashboard), or glass-effect (rgba(26,22,18,0.75) + 16px blur + saturate 180%) for marketing surfaces. +- **Border:** 1px, base-300 at 50% opacity (dashboard) or base-content at 5% opacity (marketing). Subtle; structure without division. +- **Internal Padding:** 20px standard, 16px for stat cards. +- **Hover:** translateY(-4px) + shadow (0 12px 40px rgba(0,0,0,0.3)). The card lifts toward you. + +### Inputs / Fields +Warm, recessive, ready. + +- **Style:** Warm-smoke background (#1A1612), warm-cream text, 12px radius, subtle border. +- **Focus:** 2px solid amber-gold outline with 2px offset. Unmistakable but not aggressive. +- **Error:** Ember-red (#C94444) border, red text below. + +### Navigation +A floating glass pill that feels permanent and trustworthy. + +- **Style:** Glass-effect background, full-width max 6xl, pill shape (rounded-full), fixed at top with 12-16px inset from edges. +- **Links:** Ghost buttons at 14px, medium weight. No active-state underline; relying on context. +- **Mobile:** Drawer overlay from left, same glass background. +- **CTA:** Primary button (pill, maroon fill) at navbar-end. "Get Started" with arrow icon. + +### Section Badges (signature component) +Small uppercase pills that introduce sections. Amber-gold dot indicator on the left, tracked-out text, base-content at muted opacity. They announce topic without demanding attention. + +## 6. Do's and Don'ts + +### Do: +- **Do** use the warm maroon (#7A1C1C) exclusively for CTAs and primary interactive elements. Its rarity is its power. +- **Do** tint every "black" toward the warm hue. #0F0D0B, not #000000. The system has no true black or true white. +- **Do** use the glass-effect (backdrop-blur 16px + saturate 180%) for floating navigation and elevated marketing surfaces. +- **Do** maintain the weight gap between adjacent text levels (700 → 500 → 400, never adjacent values). +- **Do** use scroll-triggered fade-in-up animations (0.6s ease-out) for content entering the viewport. +- **Do** keep section spacing generous (80px between major sections) to let dark backgrounds breathe. + +### Don't: +- **Don't** use displaced or scattered elements that feel like unrelated parts stitched together. Every section must feel like it belongs to the same warm room. +- **Don't** use generic template patterns, stock imagery, or hollow marketing copy. This site is proof of craft. +- **Don't** use flashy gimmickry, excessive particle effects, or spectacle over substance. +- **Don't** use cold, impersonal corporate styling. No clinical whites, no steel grays, no detachment. +- **Don't** use border-left or border-right greater than 1px as colored accent stripes. +- **Don't** use gradient text (background-clip: text). +- **Don't** use bounce or elastic easing. Ease-out with exponential curves only. +- **Don't** use resting shadows. Shadows respond to interaction, never decorate at rest. +- **Don't** use true #000000 or #FFFFFF anywhere. Every neutral is tinted warm. diff --git a/PRODUCT.md b/PRODUCT.md new file mode 100644 index 0000000..8fd13fd --- /dev/null +++ b/PRODUCT.md @@ -0,0 +1,36 @@ +# Product + +## Register + +brand + +## Users + +Startups, SMEs, and enterprises that need websites and custom software/apps. They find Acoruss when they need quality technology solutions without building an in-house team from scratch. Their context: evaluating agencies, looking for a partner who demonstrates technical competence through their own presence. + +## Product Purpose + +Acoruss is a technology consulting agency. The website exists to attract potential clients, establish credibility, communicate services, and convert visitors into leads. Success looks like: a visitor arrives, immediately perceives expertise and warmth, understands what Acoruss offers, and reaches out. + +## Brand Personality + +Confident, warm, expert. The voice is assured without being arrogant, approachable without being casual. Acoruss speaks as a trusted advisor who has done this many times before. Emotionally: visitors should feel they're in capable hands. + +## Anti-references + +- Displaced or scattered designs that feel like unrelated parts stitched together +- Generic template-looking agency sites with stock imagery and hollow copy +- Overly flashy or gimmicky sites that prioritize spectacle over substance +- Cold, corporate sites that feel impersonal and transactional + +## Design Principles + +1. **Practice what you preach** — The site itself is proof of craft. Every detail demonstrates the quality Acoruss delivers to clients. +2. **Grounded confidence** — Design choices are intentional and cohesive. Nothing feels accidental or default. +3. **Warm expertise** — Technical competence expressed through warmth, not coldness. The site invites rather than intimidates. +4. **Show, don't tell** — Demonstrate capability through the experience itself rather than relying on claims. +5. **Cohesion over novelty** — Every element belongs. No feature or section feels displaced from the whole. + +## Accessibility & Inclusion + +WCAG AA compliance. Ensure sufficient color contrast ratios, keyboard navigability, screen reader support, and reduced motion alternatives for all animations. diff --git a/src/apps/core/middleware.py b/src/apps/core/middleware.py index e9957ee..e2552a5 100644 --- a/src/apps/core/middleware.py +++ b/src/apps/core/middleware.py @@ -229,7 +229,6 @@ class MaliciousRequestBlockerMiddleware: # Minimal empty response — no body, no useful headers BLOCKED_RESPONSE = HttpResponse(status=403) BLOCKED_RESPONSE["Content-Length"] = "0" - BLOCKED_RESPONSE["Connection"] = "close" def __init__(self, get_response): self.get_response = get_response @@ -275,5 +274,5 @@ def __call__(self, request): return self.get_response(request) def _drop(self, request, ip: str, *, reason: str) -> HttpResponse: - """Return a minimal 403 with Connection: close.""" - return HttpResponse(status=403, headers={"Connection": "close", "Content-Length": "0"}) + """Return a minimal 403.""" + return HttpResponse(status=403, headers={"Content-Length": "0"}) diff --git a/src/static/css/main.css b/src/static/css/main.css index 621edb7..36f5a31 100644 --- a/src/static/css/main.css +++ b/src/static/css/main.css @@ -2507,6 +2507,14 @@ html { grid-auto-flow: column; overflow-x: auto; } +.steps { + display: inline-grid; + grid-auto-flow: column; + overflow: hidden; + overflow-x: auto; + counter-reset: step; + grid-auto-columns: 1fr; +} .steps .step { display: grid; grid-template-columns: repeat(1, minmax(0, 1fr)); @@ -3810,6 +3818,74 @@ details.collapse summary::-webkit-details-marker { .steps .step[data-content]:after { content: attr(data-content); } +.steps .step-neutral + .step-neutral:before, + .steps .step-neutral:after { + --tw-bg-opacity: 1; + background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity))); +} +.steps .step-primary + .step-primary:before, + .steps .step-primary:after { + --tw-bg-opacity: 1; + background-color: var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity))); +} +.steps .step-secondary + .step-secondary:before, + .steps .step-secondary:after { + --tw-bg-opacity: 1; + background-color: var(--fallback-s,oklch(var(--s)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-sc,oklch(var(--sc)/var(--tw-text-opacity))); +} +.steps .step-accent + .step-accent:before, + .steps .step-accent:after { + --tw-bg-opacity: 1; + background-color: var(--fallback-a,oklch(var(--a)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-ac,oklch(var(--ac)/var(--tw-text-opacity))); +} +.steps .step-info + .step-info:before { + --tw-bg-opacity: 1; + background-color: var(--fallback-in,oklch(var(--in)/var(--tw-bg-opacity))); +} +.steps .step-info:after { + --tw-bg-opacity: 1; + background-color: var(--fallback-in,oklch(var(--in)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity))); +} +.steps .step-success + .step-success:before { + --tw-bg-opacity: 1; + background-color: var(--fallback-su,oklch(var(--su)/var(--tw-bg-opacity))); +} +.steps .step-success:after { + --tw-bg-opacity: 1; + background-color: var(--fallback-su,oklch(var(--su)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity))); +} +.steps .step-warning + .step-warning:before { + --tw-bg-opacity: 1; + background-color: var(--fallback-wa,oklch(var(--wa)/var(--tw-bg-opacity))); +} +.steps .step-warning:after { + --tw-bg-opacity: 1; + background-color: var(--fallback-wa,oklch(var(--wa)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-wac,oklch(var(--wac)/var(--tw-text-opacity))); +} +.steps .step-error + .step-error:before { + --tw-bg-opacity: 1; + background-color: var(--fallback-er,oklch(var(--er)/var(--tw-bg-opacity))); +} +.steps .step-error:after { + --tw-bg-opacity: 1; + background-color: var(--fallback-er,oklch(var(--er)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-erc,oklch(var(--erc)/var(--tw-text-opacity))); +} .tabs-lifted > .tab:focus-visible { border-end-end-radius: 0; border-end-start-radius: 0; @@ -4708,6 +4784,9 @@ html:has(.drawer-toggle:checked) { .bottom-0 { bottom: 0px; } +.bottom-4 { + bottom: 1rem; +} .left-0 { left: 0px; } @@ -4717,6 +4796,9 @@ html:has(.drawer-toggle:checked) { .left-\[11px\] { left: 11px; } +.left-\[18px\] { + left: 18px; +} .right-0 { right: 0px; } @@ -4738,6 +4820,9 @@ html:has(.drawer-toggle:checked) { .top-3 { top: 0.75rem; } +.top-4 { + top: 1rem; +} .top-6 { top: 1.5rem; } @@ -4895,6 +4980,9 @@ html:has(.drawer-toggle:checked) { .h-10 { height: 2.5rem; } +.h-11 { + height: 2.75rem; +} .h-12 { height: 3rem; } @@ -4943,6 +5031,9 @@ html:has(.drawer-toggle:checked) { .h-full { height: 100%; } +.h-px { + height: 1px; +} .max-h-32 { max-height: 8rem; } @@ -4967,6 +5058,9 @@ html:has(.drawer-toggle:checked) { .w-10 { width: 2.5rem; } +.w-11 { + width: 2.75rem; +} .w-12 { width: 3rem; } @@ -5039,6 +5133,9 @@ html:has(.drawer-toggle:checked) { .max-w-3xl { max-width: 48rem; } +.max-w-4xl { + max-width: 56rem; +} .max-w-5xl { max-width: 64rem; } @@ -5172,6 +5269,13 @@ html:has(.drawer-toggle:checked) { .gap-8 { gap: 2rem; } +.gap-x-12 { + -moz-column-gap: 3rem; + column-gap: 3rem; +} +.gap-y-8 { + row-gap: 2rem; +} .-space-x-3 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(-0.75rem * var(--tw-space-x-reverse)); @@ -5244,6 +5348,9 @@ html:has(.drawer-toggle:checked) { text-overflow: ellipsis; white-space: nowrap; } +.whitespace-nowrap { + white-space: nowrap; +} .break-all { word-break: break-all; } @@ -5342,12 +5449,27 @@ html:has(.drawer-toggle:checked) { .bg-accent\/30 { background-color: var(--fallback-a,oklch(var(--a)/0.3)); } +.bg-accent\/40 { + background-color: var(--fallback-a,oklch(var(--a)/0.4)); +} +.bg-accent\/50 { + background-color: var(--fallback-a,oklch(var(--a)/0.5)); +} +.bg-accent\/55 { + background-color: var(--fallback-a,oklch(var(--a)/0.55)); +} .bg-accent\/60 { background-color: var(--fallback-a,oklch(var(--a)/0.6)); } +.bg-accent\/70 { + background-color: var(--fallback-a,oklch(var(--a)/0.7)); +} .bg-accent\/80 { background-color: var(--fallback-a,oklch(var(--a)/0.8)); } +.bg-accent\/85 { + background-color: var(--fallback-a,oklch(var(--a)/0.85)); +} .bg-base-100 { --tw-bg-opacity: 1; background-color: var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity, 1))); @@ -5436,9 +5558,6 @@ html:has(.drawer-toggle:checked) { .bg-primary\/30 { background-color: var(--fallback-p,oklch(var(--p)/0.3)); } -.bg-primary\/80 { - background-color: var(--fallback-p,oklch(var(--p)/0.8)); -} .bg-secondary { --tw-bg-opacity: 1; background-color: var(--fallback-s,oklch(var(--s)/var(--tw-bg-opacity, 1))); @@ -5476,6 +5595,9 @@ html:has(.drawer-toggle:checked) { .bg-white\/5 { background-color: rgb(255 255 255 / 0.05); } +.bg-gradient-to-b { + background-image: linear-gradient(to bottom, var(--tw-gradient-stops)); +} .bg-gradient-to-br { background-image: linear-gradient(to bottom right, var(--tw-gradient-stops)); } @@ -5484,6 +5606,11 @@ html:has(.drawer-toggle:checked) { --tw-gradient-to: rgb(255 255 255 / 0) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } +.from-accent\/40 { + --tw-gradient-from: var(--fallback-a,oklch(var(--a)/0.4)) var(--tw-gradient-from-position); + --tw-gradient-to: rgb(255 255 255 / 0) var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); +} .from-primary\/10 { --tw-gradient-from: var(--fallback-p,oklch(var(--p)/0.1)) var(--tw-gradient-from-position); --tw-gradient-to: rgb(255 255 255 / 0) var(--tw-gradient-to-position); @@ -5503,6 +5630,10 @@ html:has(.drawer-toggle:checked) { --tw-gradient-to: rgb(255 255 255 / 0) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-from), var(--fallback-a,oklch(var(--a)/0.1)) var(--tw-gradient-via-position), var(--tw-gradient-to); } +.via-accent\/20 { + --tw-gradient-to: rgb(255 255 255 / 0) var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--fallback-a,oklch(var(--a)/0.2)) var(--tw-gradient-via-position), var(--tw-gradient-to); +} .via-primary\/10 { --tw-gradient-to: rgb(255 255 255 / 0) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-from), var(--fallback-p,oklch(var(--p)/0.1)) var(--tw-gradient-via-position), var(--tw-gradient-to); @@ -5513,6 +5644,9 @@ html:has(.drawer-toggle:checked) { .to-base-300\/30 { --tw-gradient-to: var(--fallback-b3,oklch(var(--b3)/0.3)) var(--tw-gradient-to-position); } +.to-transparent { + --tw-gradient-to: transparent var(--tw-gradient-to-position); +} .object-contain { -o-object-fit: contain; object-fit: contain; @@ -5804,6 +5938,9 @@ html:has(.drawer-toggle:checked) { --tw-text-opacity: 1; color: var(--fallback-ac,oklch(var(--ac)/var(--tw-text-opacity, 1))); } +.text-accent\/40 { + color: var(--fallback-a,oklch(var(--a)/0.4)); +} .text-base-content { --tw-text-opacity: 1; color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity, 1))); @@ -6181,11 +6318,6 @@ a, button { --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.hover\:shadow-md:hover { - --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} .hover\:shadow-accent\/5:hover { --tw-shadow-color: var(--fallback-a,oklch(var(--a)/0.05)); --tw-shadow: var(--tw-shadow-colored); @@ -6391,14 +6523,6 @@ a, button { display: none; } - .md\:w-64 { - width: 16rem; - } - - .md\:w-auto { - width: auto; - } - .md\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } @@ -6426,6 +6550,14 @@ a, button { } @media (min-width: 1024px) { + .lg\:sticky { + position: sticky; + } + + .lg\:top-28 { + top: 7rem; + } + .lg\:col-span-1 { grid-column: span 1 / span 1; } @@ -6434,6 +6566,10 @@ a, button { grid-column: span 2 / span 2; } + .lg\:col-span-3 { + grid-column: span 3 / span 3; + } + .lg\:ml-\[260px\] { margin-left: 260px; } @@ -6471,10 +6607,18 @@ a, button { grid-template-columns: repeat(4, minmax(0, 1fr)); } + .lg\:grid-cols-5 { + grid-template-columns: repeat(5, minmax(0, 1fr)); + } + .lg\:grid-cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); } + .lg\:gap-12 { + gap: 3rem; + } + .lg\:gap-16 { gap: 4rem; } diff --git a/src/templates/about.html b/src/templates/about.html index bcbf0d3..18e7441 100644 --- a/src/templates/about.html +++ b/src/templates/about.html @@ -9,15 +9,9 @@ {% block content %}
-
-
-
- Who We Are -
-

About Acoruss

-

Learn about our mission, our team, and our commitment - to empowering businesses through technology.

+
+

We believe technology should work for you, not the other way around.

+

Acoruss exists to bridge the gap between ambitious businesses and the software that powers them. No bloated teams, no enterprise overhead; just focused expertise and relentless execution.

@@ -26,20 +20,20 @@

About
-

2025

-

Officially Launched

+

20+

+

Years Combined Experience

-

5+

-

Team Members

+

100%

+

Delivery Rate

10+

-

Projects

+

Projects Delivered

-

10+

-

Customers

+

5+

+

Industries Served

@@ -141,112 +135,51 @@

Our Values

Our Values

-

At Acoruss, our core values guide everything we - do, from - our customer interactions to our final handover.

+

The principles that guide every decision, interaction, and delivery at Acoruss.

-
-
-
- - - - - - - +
+
+ 01 +
+

Delight Our Customers

+

Create trust and lasting impact through exceptional service and results.

-

Delight Our Customers

-

Create trust and lasting impact through exceptional service and - results.

-
-
- - - - - - - +
+ 02 +
+

Team Is Key

+

Collaboration fuels growth and enables us to deliver better solutions.

-

Team Is Key

-

Collaboration fuels growth and enables us to deliver better - solutions.

-
-
- - - - - +
+ 03 +
+

Quality Over Quantity

+

Focus on depth and reliability rather than volume.

-

Quality Over Quantity

-

Focus on depth and reliability rather than volume.

-
-
- - - - - - - - +
+ 04 +
+

Simplicity Matters

+

Technology should simplify business and life, not complicate it.

-

Simplicity Matters

-

Technology should simplify business and life, not complicate it. -

-
-
- - - - - - +
+ 05 +
+

Innovation With Purpose

+

Empower people and solve real problems, not just showcase technology.

-

Innovation With Purpose

-

Empower people and solve real problems, not just showcase - technology.

-
-
- - - - - +
+ 06 +
+

Security By Default

+

OWASP-aligned practices and continuous risk reduction in everything we build.

-

Security By Default

-

OWASP-aligned practices and continuous risk reduction in - everything we build.

diff --git a/src/templates/base.html b/src/templates/base.html index 09ef0fa..c86fcea 100644 --- a/src/templates/base.html +++ b/src/templates/base.html @@ -138,24 +138,19 @@

Stay in the loop

-

Subscribe to our newsletter for - technology - insights, updates, and exclusive resources.

-
-
- - - Subscribe - - - - - +

Technology insights, updates, and exclusive resources delivered to your inbox via Substack.

+ + Subscribe on Substack + +
diff --git a/src/templates/contact.html b/src/templates/contact.html index a379c8e..2c3e483 100644 --- a/src/templates/contact.html +++ b/src/templates/contact.html @@ -41,12 +41,16 @@

Tell Us About Your Project

+ class="input input-bordered w-full rounded-xl" required + aria-describedby="name-error"> +
+ class="input input-bordered w-full rounded-xl" required + aria-describedby="email-error"> +
@@ -77,7 +81,9 @@

Tell Us About Your Project

+ class="textarea textarea-bordered w-full rounded-xl" required + aria-describedby="message-error"> +
+{% endblock %} + +{% block extra_js %} + {% endblock %} \ No newline at end of file diff --git a/src/templates/index.html b/src/templates/index.html index e2b08a9..041ccd0 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -196,72 +196,72 @@
-
-
-
- Why Choose Us -
-

The Acoruss Advantage

-

Deep experience, sharp domain knowledge, and - outstanding support - we deliver solutions you can stake your business on.

-
-
-
+
+ +
- - - - - + class="inline-flex items-center gap-2 bg-accent/10 border border-accent/20 rounded-full px-4 py-1.5 mb-4 text-accent text-xs font-semibold uppercase tracking-wider"> +
+ Why Choose Us
-

Production-grade Quality

-

We build to industry standards - secure, - hardened, and customised to fit your exact needs. No shortcuts.

-
-
-
- - - - - - - +

The Acoruss Advantage

+

Deep experience, sharp domain knowledge, and outstanding support. We deliver solutions you can stake your business on.

+
+ 20+ + years combined
experience
-

Experienced Experts

-

20+ cumulative years in top-tier corporates and - fast-moving startups. We've seen what works.

-
-
- - - - - - - + +
+
+
+ +
+
+

Production-grade Quality

+

Built to industry standards: secure, hardened, and customised to fit your exact needs. No shortcuts, no compromises.

+
+
+
+
+
+ +
+
+

Experienced Experts

+

Our team has worked across top-tier corporates and fast-moving startups. We know what works because we've shipped it before.

+
+
+
+
+
+ +
+
+

Complete Satisfaction

+

Your success is our reputation. We go beyond delivery to ensure lasting impact, reliability, and trust.

+
-

Customer Satisfaction

-

Your success is our reputation. We go the extra - mile - complete satisfaction and reliability, every single time.

@@ -454,85 +454,64 @@

How We -
-
- - 01 -

Reach Out

+ +
+ + + +
+
+ 01 +
+

Reach Out

+

Tell us about your goals and where you are today.

+ + Contact us + + +
-

Tell us about your goals and where you are - today.

- - Contact us - - - - - -
-
-
- - 02 -

Discovery Call

+
+ 02 +
+

Discovery Call

+

A 60-minute deep-dive into your needs, constraints, and success metrics.

+

$50 fee, credited if you proceed.

+
-

A 60-minute deep-dive into your needs, - constraints, - and success metrics.

-

$50 fee, credited if you proceed.

-
-
-
- - 03 -

Proposal & Plan

+
+ 03 +
+

Proposal & Plan

+

Scope, timeline, pricing, risks and mitigations laid out clearly.

+
-

Scope, timeline, pricing, risks & - mitigations - everything laid out clearly.

-
-
-
- - 04 -

Kickoff

+
+ 04 +
+

Kickoff

+

We finalise the agreement, deposit invoice, communication rhythm, and security baselines.

+
-

We finalise the SOW, deposit invoice, - communication rhythm, and security baselines.

-
-
-
- - 05 -

Build & Iterate

+
+ 05 +
+

Build & Iterate

+

Short sprints with demos. Security baked in: OWASP coding, dependency checks, CI/CD hardening.

+
-

Short sprints with demos. Security baked in - - - OWASP coding, dependency checks, CI/CD hardening.

-
-
-
- - 06 -

Delivery & Handover

+
+ 06 +
+

Delivery & Handover

+

UAT, documentation, training, and a thorough security review of access and data handling.

+
-

UAT, documentation, training, and a thorough - security - review of access & data handling.

diff --git a/src/templates/pricing.html b/src/templates/pricing.html index 850578b..6378abd 100644 --- a/src/templates/pricing.html +++ b/src/templates/pricing.html @@ -41,7 +41,7 @@

Transparent Pricing, Scoped

How Our Pricing Works

- +
How Our Pricing Works

+ class="w-12 h-12 bg-accent/85 text-accent-content rounded-full flex items-center justify-center mx-auto mb-3 font-bold"> 2
-

Scope & Estimate

+

Scope & Estimate

+ class="w-12 h-12 bg-accent/70 text-accent-content rounded-full flex items-center justify-center mx-auto mb-3 font-bold"> 3
-

Proposal & Milestones

+

Proposal & Milestones

+ class="w-12 h-12 bg-accent/55 text-accent-content rounded-full flex items-center justify-center mx-auto mb-3 font-bold"> 4
-

Build & QA

+

Build & QA

+ class="w-12 h-12 bg-accent/40 text-accent-content rounded-full flex items-center justify-center mx-auto mb-3 font-bold"> 5
-

Launch & Handover

+

Launch & Handover

+ class="w-12 h-12 bg-accent/30 text-accent-content rounded-full flex items-center justify-center mx-auto mb-3 font-bold"> 6
-

Support & Iteration

+

Support & Iteration

diff --git a/src/templates/projects.html b/src/templates/projects.html index 31ec7f5..3af903c 100644 --- a/src/templates/projects.html +++ b/src/templates/projects.html @@ -8,15 +8,9 @@ {% block content %}
-
-
-
- Portfolio -
-

Our Projects

-

Real work that demonstrates how we design, build, and - deliver solutions across different industries.

+
+

Work that speaks for itself

+

Real solutions, shipped and running. Browse what we've built across different industries and technologies.

@@ -81,6 +75,44 @@

Martin & Loice Wedding

+ + +
+
+
Web App
+

Zawadi Digital

+

Mobile-first group gifting platform for events and celebrations.

+
+

Outcome: Create events, share one link, track contributions in real time. 3% flat fee, instant receipts, full withdrawal visibility.

+
+ +
+
+ + +
+
+
Website
+

Feel At Home Interiors

+

Signature interior studio showcasing curtains, blinds, and window treatments across Kenya.

+
+

Outcome: Portfolio site with service showcase, featured projects gallery, client reviews, and styling tips section.

+
+ +
+
From ddbd8c32941a06a52188f7cc6bcaf07d76248747 Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Tue, 26 May 2026 08:43:03 +0300 Subject: [PATCH 2/2] feat: enhance accessibility and animations; add lazy loading for images --- src/static/css/main.css | 21 +++++++++++++++++---- src/static/js/main.js | 28 ++++++++++++++++++++++++---- src/templates/about.html | 4 ++-- src/templates/index.html | 39 ++++++++++++++++++++------------------- 4 files changed, 63 insertions(+), 29 deletions(-) diff --git a/src/static/css/main.css b/src/static/css/main.css index 36f5a31..6ba15b3 100644 --- a/src/static/css/main.css +++ b/src/static/css/main.css @@ -6208,15 +6208,19 @@ html:has(.drawer-toggle:checked) { animation: fade-in-up 0.6s ease-out forwards; } -[data-animate] { - opacity: 0; +@media (prefers-reduced-motion: no-preference) { + [data-animate] { + opacity: 0; + } } /* Tab active state */ /* Global styles */ -html { - scroll-behavior: smooth; +@media (prefers-reduced-motion: no-preference) { + html { + scroll-behavior: smooth; + } } /* Focus states for accessibility */ @@ -6233,6 +6237,15 @@ select:focus-visible { a, button { transition: color 0.2s ease, background-color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease; } + +/* Ensure minimum touch target size for tab buttons */ +.service-tab, +.project-tab { + min-height: 44px; + min-width: 44px; + padding-left: 1rem; + padding-right: 1rem; +} .hover\:badge-accent:hover { --tw-border-opacity: 1; border-color: var(--fallback-a,oklch(var(--a)/var(--tw-border-opacity))); diff --git a/src/static/js/main.js b/src/static/js/main.js index 1d47d9b..6e9498b 100644 --- a/src/static/js/main.js +++ b/src/static/js/main.js @@ -5,20 +5,28 @@ "use strict"; document.addEventListener("DOMContentLoaded", () => { - console.log("Acoruss web application loaded."); - // Mobile drawer: close on link click initMobileDrawer(); // Smooth scroll for hash links initSmoothScroll(); - // Scroll animations (intersection observer) - initScrollAnimations(); + // Scroll animations (intersection observer) — respects reduced motion + if (!window.matchMedia("(prefers-reduced-motion: reduce)").matches) { + initScrollAnimations(); + } else { + // Reveal all animated elements immediately + document.querySelectorAll("[data-animate]").forEach((el) => { + el.style.opacity = "1"; + }); + } // Tab system (services, projects) initTabs(); + // Accessibility: mark decorative SVGs + initA11y(); + // Blog posts from Substack RSS initBlogLoader(); @@ -26,6 +34,18 @@ document.addEventListener("DOMContentLoaded", () => { initCurrencyDisplay(); }); +/** + * Accessibility enhancements: mark decorative SVGs, ensure ARIA attributes. + */ +function initA11y() { + // Mark all inline SVGs without explicit role as decorative + document.querySelectorAll("svg:not([role])").forEach((svg) => { + if (!svg.querySelector("title") && !svg.getAttribute("aria-label")) { + svg.setAttribute("aria-hidden", "true"); + } + }); +} + /** * Close mobile drawer when a link inside it is clicked. */ diff --git a/src/templates/about.html b/src/templates/about.html index 18e7441..5fe0100 100644 --- a/src/templates/about.html +++ b/src/templates/about.html @@ -203,7 +203,7 @@

Our
- Martin Musale
@@ -241,7 +241,7 @@

Martin Musale

- Loice Andia
diff --git a/src/templates/index.html b/src/templates/index.html index 041ccd0..0876f2e 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -120,7 +120,7 @@

- From Nairobi to the world - we help ambitious businesses harness software, AI, and smart strategy + From Nairobi to the world, we help ambitious businesses harness software, AI, and smart strategy without breaking the bank.

@@ -280,7 +280,7 @@

Digital Solutions Th class="hidden sm:block"> Drive Results

-

From consultation to ongoing maintenance - +

From consultation to ongoing maintenance: complete solutions tailored to your needs.

@@ -379,7 +379,7 @@

Custom Software

AI & Automation

-

From chatbots to workflow automation - we +

From chatbots to workflow automation, we harness AI to save you time, cut costs, and make smarter decisions.

@@ -413,7 +413,7 @@

AI & Automation

Technology Strategy & Consulting

We assess your setup, identify the gaps, and design a - strategy that aligns with your goals - reducing risk and building a competitive edge.

+ strategy that aligns with your goals, reducing risk and building a competitive edge.

@@ -583,16 +583,14 @@

Our