diff --git a/.opencode/init b/.opencode/init new file mode 100644 index 0000000..e69de29 diff --git a/.opencode/opencode.db b/.opencode/opencode.db new file mode 100644 index 0000000..4e86411 Binary files /dev/null and b/.opencode/opencode.db differ diff --git a/.opencode/opencode.db-shm b/.opencode/opencode.db-shm new file mode 100644 index 0000000..ba6df8f Binary files /dev/null and b/.opencode/opencode.db-shm differ diff --git a/.opencode/opencode.db-wal b/.opencode/opencode.db-wal new file mode 100644 index 0000000..bdb67af Binary files /dev/null and b/.opencode/opencode.db-wal differ diff --git a/OpenCode.md b/OpenCode.md new file mode 100644 index 0000000..3df9927 --- /dev/null +++ b/OpenCode.md @@ -0,0 +1,33 @@ +# Dealspace Coding Guide + +## Build & Test + +```bash +make build # Local build +make build-linux # Linux/amd64 with CGO + fts5 +make test # Run all tests +CGO_ENABLED=1 go test -tags fts5 ./lib -run TestPackUnpack -v # Single test +``` + +## Code Style + +- **Format**: `gofmt` (standard Go formatting) +- **Imports**: stdlib → third-party → internal (github.com/mish/dealspace) +- **Types**: Use JSON tags with `snake_case`, e.g., `EntryID string `json:"entry_id"`` +- **Naming**: PascalCase for exported, camelCase for unexported; constants use prefix like `TypeProject`, `StageDataroom` +- **Errors**: Wrap with `fmt.Errorf("context: %w", err)`; check sentinel errors with `==` + +## Architecture Rules + +**Database access ONLY through three choke points in `lib/dbcore.go`:** +- `EntryRead(db, cfg, actorID, projectID, filter)` — all reads +- `EntryWrite(db, cfg, actorID, entries...)` — all writes +- `EntryDelete(db, actorID, projectID, entryIDs...)` — all deletes + +**FORBIDDEN:** `db.Exec()`, `db.Query()`, `db.QueryRow()` outside dbcore.go; wrapper functions bypassing choke points; modifications to dbcore.go without explicit approval. + +`actorID=""` = system/internal access (always granted). RBAC enforced at DB level, not UI. + +## Tech Stack + +Go 1.24, SQLite with mattn/go-sqlite3 (CGO required), chi router, uuid, pdfcpu, excelize, golang.org/x/crypto diff --git a/portal/portal/emails/answer_approved.html b/portal/portal/emails/answer_approved.html deleted file mode 100644 index 3d47e58..0000000 --- a/portal/portal/emails/answer_approved.html +++ /dev/null @@ -1,85 +0,0 @@ -{{define "answer_approved.html"}} - - - - - - Your answer was approved ✓ - - - - - - -
- - - - - - - - - - - - - - - -
-

DEALSPACE

-
- -
-
- ✓ -
-
- -

- Your answer was approved -

- -

- Hi{{if .RecipientName}} {{.RecipientName}}{{end}}, -

- -

- Great news! Your answer for {{.RequestTitle}} has been approved. -

- - {{if .Published}} -
-

- 📁 Published to Data Room — Your response is now visible to authorized buyers. -

-
- {{end}} - - {{if .DataRoomURL}} - - - - - -
- View in Data Room -
- {{end}} - -

- Thank you for your prompt response. Keep up the excellent work! -

-
-

- Questions? Contact support@muskepo.com -

-

- © 2026 Dealspace · Privacy Policy · Terms of Service -

-
-
- - -{{end}} diff --git a/portal/portal/emails/answer_rejected.html b/portal/portal/emails/answer_rejected.html deleted file mode 100644 index 3a5da95..0000000 --- a/portal/portal/emails/answer_rejected.html +++ /dev/null @@ -1,76 +0,0 @@ -{{define "answer_rejected.html"}} - - - - - - Your answer needs revision - - - - - - -
- - - - - - - - - - - - - - - -
-

DEALSPACE

-
-

- Your answer needs revision -

- -

- Hi{{if .RecipientName}} {{.RecipientName}}{{end}}, -

- -

- Your answer for {{.RequestTitle}} requires some changes before it can be approved. -

- - - {{if .Reason}} -
-

Feedback

-

{{.Reason}}

-
- {{end}} - - - - - - -
- View Feedback -
- -

- Please update your response based on the feedback above. If you have any questions, you can reply directly in the request thread. -

-
-

- Questions? Contact support@muskepo.com -

-

- © 2026 Dealspace · Privacy Policy · Terms of Service -

-
-
- - -{{end}} diff --git a/portal/portal/emails/answer_submitted.html b/portal/portal/emails/answer_submitted.html deleted file mode 100644 index a496ead..0000000 --- a/portal/portal/emails/answer_submitted.html +++ /dev/null @@ -1,92 +0,0 @@ -{{define "answer_submitted.html"}} - - - - - - {{.AnswererName}} submitted an answer for: {{.RequestTitle}} - - - - - - -
- - - - - - - - - - - - - - - -
-

DEALSPACE

-
-
- ACTION REQUIRED -
- -

- New answer submitted for review -

- -

- Hi{{if .RecipientName}} {{.RecipientName}}{{end}}, -

- -

- {{.AnswererName}} has submitted an answer that needs your review. -

- - - - - - -
-

Request

-

{{.RequestTitle}}

- - {{if .WorkstreamName}} -

Workstream

-

{{.WorkstreamName}}

- {{end}} - - {{if .AnswerPreview}} -

Preview

-

"{{truncate .AnswerPreview 200}}"

- {{end}} -
- - - - - - -
- Review Answer -
- -

- Once approved, this answer will be published to the data room and visible to authorized buyers. -

-
-

- Questions? Contact support@muskepo.com -

-

- © 2026 Dealspace · Privacy Policy · Terms of Service -

-
-
- - -{{end}} diff --git a/portal/portal/emails/invite.html b/portal/portal/emails/invite.html deleted file mode 100644 index 3ba8281..0000000 --- a/portal/portal/emails/invite.html +++ /dev/null @@ -1,76 +0,0 @@ -{{define "invite.html"}} - - - - - - You're invited to {{.ProjectName}} - - - - - - -
- - - - - - - - - - - - - - - -
-

DEALSPACE

-
-

- You've been invited to join {{.ProjectName}} -

- -

- Hi{{if .RecipientName}} {{.RecipientName}}{{end}}, -

- -

- {{.InviterName}} from {{.InviterOrg}} has invited you to join the due diligence process for {{.ProjectName}}. -

- - - - - - -
- Accept Invitation -
- - -
-

What is Dealspace?

-

- Dealspace is a secure platform for managing M&A due diligence. All documents are encrypted and watermarked. You control what gets shared and when. -

-
- -

- ⏱ This invitation expires in {{if .ExpiresIn}}{{.ExpiresIn}}{{else}}7 days{{end}}. -

-
-

- Questions? Contact support@muskepo.com -

-

- © 2026 Dealspace · Privacy Policy · Terms of Service -

-
-
- - -{{end}} diff --git a/portal/portal/emails/request_forwarded.html b/portal/portal/emails/request_forwarded.html deleted file mode 100644 index 317d184..0000000 --- a/portal/portal/emails/request_forwarded.html +++ /dev/null @@ -1,85 +0,0 @@ -{{define "request_forwarded.html"}} - - - - - - {{.SenderName}} forwarded a request to you - - - - - - -
- - - - - - - - - - - - - - - -
-

DEALSPACE

-
-

- Request forwarded to you -

- -

- Hi{{if .RecipientName}} {{.RecipientName}}{{end}}, -

- -

- {{.SenderName}} has forwarded a request to you for your input. -

- - - - - - -
-

Request

-

{{.RequestTitle}}

- - {{if .HasDueDate}} -
-

Due Date

-

{{.DueDate}}

-
- {{end}} -
- - - - - - -
- View Request -
- -

- You can respond to this request directly in Dealspace. Your response will be routed back to {{.SenderName}} for review. -

-
-

- Questions? Contact support@muskepo.com -

-

- © 2026 Dealspace · Privacy Policy · Terms of Service -

-
-
- - -{{end}} diff --git a/portal/portal/emails/tasks_assigned.html b/portal/portal/emails/tasks_assigned.html deleted file mode 100644 index 7f73ca3..0000000 --- a/portal/portal/emails/tasks_assigned.html +++ /dev/null @@ -1,87 +0,0 @@ -{{define "tasks_assigned.html"}} - - - - - - You have {{.Count}} new task{{if gt .Count 1}}s{{end}} on {{.ProjectName}} - - - - - - -
- - - - - - - - - - - - - - - -
-

DEALSPACE

-
-

- You have {{.Count}} new task{{if gt .Count 1}}s{{end}} on {{.ProjectName}} -

- -

- Hi{{if .RecipientName}} {{.RecipientName}}{{end}}, -

- -

- The following request{{if gt .Count 1}}s have{{else}} has{{end}} been assigned to you: -

- - - - {{range $i, $task := .Tasks}} - {{if lt $i 5}} - - - - - {{end}} - {{end}} -
-

{{$task.Title}}

- {{if $task.DueDate}} -

Due: {{$task.DueDate}}{{if eq $task.Priority "high"}} · High Priority{{end}}

- {{end}} -
- - {{if gt .Count 5}} -

- ...and {{sub .Count 5}} more -

- {{end}} - - - - - - -
- View My Tasks -
-
-

- You're receiving this because you're assigned to requests in {{.ProjectName}}. -

-

- © 2026 Dealspace · Manage Notifications · Unsubscribe -

-
-
- - -{{end}} diff --git a/portal/portal/emails/welcome.html b/portal/portal/emails/welcome.html deleted file mode 100644 index 2f08a32..0000000 --- a/portal/portal/emails/welcome.html +++ /dev/null @@ -1,61 +0,0 @@ -{{define "welcome.html"}} - - - - - - Welcome to Dealspace - - - - - - -
- - - - - - - - - - -
-

DEALSPACE

-
-

- Welcome to Dealspace{{if .RecipientName}}, {{.RecipientName}}{{end}}! 🎉 -

-

- You're all set up and ready to go. Here are three quick tips to get you started: -

-
-

📥 Your inbox is your home

-

Everything assigned to you appears in your task inbox. Start there each day to see what needs your attention.

-
-
-

📋 Requests, not folders

-

We organize by requests, not file folders. Each request tracks its own status, comments, and documents — all in one place.

-
-
-

🤖 Ask Aria

-

Not sure where something is? Ask Aria, our AI assistant. She can find documents, answer questions, and guide you through the process.

-
- - - - -
- Go to My Tasks -
-

We're excited to have you on board. Let's make this deal happen! 🚀

-
-

Need help? Contact support@muskepo.com

-

© 2026 Dealspace · Privacy Policy · Terms of Service

-
-
- - -{{end}} diff --git a/portal/portal/static/themes.css b/portal/portal/static/themes.css deleted file mode 100644 index e51d614..0000000 --- a/portal/portal/static/themes.css +++ /dev/null @@ -1,744 +0,0 @@ -/** - * Dealspace Theme System - * - * All colors are CSS custom properties. Zero hardcoded values in templates. - * Switch themes by changing the class on : theme-light, theme-dark, theme-contrast - * Per-project overrides use data-project attribute. - */ - -/* ========================================================================== - BASE TOKENS (shared across themes) - ========================================================================== */ - -:root { - /* Spacing */ - --space-xs: 0.25rem; /* 4px */ - --space-sm: 0.5rem; /* 8px */ - --space-md: 1rem; /* 16px */ - --space-lg: 1.5rem; /* 24px */ - --space-xl: 2rem; /* 32px */ - --space-2xl: 3rem; /* 48px */ - - /* Border radius */ - --radius-sm: 0.25rem; /* 4px */ - --radius-md: 0.5rem; /* 8px */ - --radius-lg: 0.75rem; /* 12px */ - --radius-full: 9999px; - - /* Typography */ - --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; - --font-mono: "SF Mono", Consolas, "Liberation Mono", Menlo, monospace; - - --text-xs: 0.75rem; /* 12px */ - --text-sm: 0.875rem; /* 14px */ - --text-base: 1rem; /* 16px */ - --text-lg: 1.125rem; /* 18px */ - --text-xl: 1.25rem; /* 20px */ - --text-2xl: 1.5rem; /* 24px */ - - --leading-tight: 1.25; - --leading-normal: 1.5; - --leading-relaxed: 1.75; - - /* Transitions */ - --transition-fast: 150ms ease; - --transition-normal: 250ms ease; - - /* Z-index scale */ - --z-dropdown: 100; - --z-modal: 200; - --z-toast: 300; -} - - -/* ========================================================================== - LIGHT THEME (default) - ========================================================================== */ - -.theme-light, -:root { - /* Surfaces */ - --color-bg-primary: #ffffff; - --color-bg-secondary: #f9fafb; - --color-bg-tertiary: #f3f4f6; - --color-bg-inverse: #1f2937; - --color-bg-hover: #f3f4f6; - --color-bg-selected: #eff6ff; - - /* Text */ - --color-text-primary: #111827; - --color-text-secondary: #6b7280; - --color-text-tertiary: #9ca3af; - --color-text-inverse: #ffffff; - --color-text-link: #2563eb; - --color-text-link-hover: #1d4ed8; - - /* Borders */ - --color-border-primary: #e5e7eb; - --color-border-secondary: #f3f4f6; - --color-border-focus: #2563eb; - - /* Semantic colors */ - --color-accent: #2563eb; - --color-accent-hover: #1d4ed8; - --color-accent-light: #dbeafe; - --color-success: #059669; - --color-success-light: #d1fae5; - --color-warning: #d97706; - --color-warning-light: #fef3c7; - --color-error: #dc2626; - --color-error-light: #fee2e2; - --color-info: #0284c7; - --color-info-light: #e0f2fe; - - /* Priority indicators */ - --color-priority-high: #dc2626; - --color-priority-normal: #d97706; - --color-priority-low: #9ca3af; - - /* Status badges */ - --color-status-open: #6b7280; - --color-status-open-bg: #f3f4f6; - --color-status-assigned: #2563eb; - --color-status-assigned-bg: #dbeafe; - --color-status-answered: #d97706; - --color-status-answered-bg: #fef3c7; - --color-status-vetted: #7c3aed; - --color-status-vetted-bg: #ede9fe; - --color-status-published: #059669; - --color-status-published-bg: #d1fae5; - --color-status-closed: #9ca3af; - --color-status-closed-bg: #f3f4f6; - - /* Components */ - --color-header-bg: #ffffff; - --color-header-text: #111827; - --color-header-border: #e5e7eb; - --color-card-bg: #ffffff; - --color-card-border: #e5e7eb; - --color-card-shadow: rgba(0, 0, 0, 0.05); - --color-input-bg: #ffffff; - --color-input-border: #d1d5db; - --color-input-focus: #2563eb; - --color-input-placeholder: #9ca3af; - --color-badge-bg: #ef4444; - --color-badge-text: #ffffff; - - /* Shadows */ - --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); - --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); - --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); - --shadow-focus: 0 0 0 3px rgba(37, 99, 235, 0.2); -} - - -/* ========================================================================== - DARK THEME - ========================================================================== */ - -.theme-dark { - /* Surfaces */ - --color-bg-primary: #111827; - --color-bg-secondary: #1f2937; - --color-bg-tertiary: #374151; - --color-bg-inverse: #f9fafb; - --color-bg-hover: #374151; - --color-bg-selected: #1e3a5f; - - /* Text */ - --color-text-primary: #f9fafb; - --color-text-secondary: #9ca3af; - --color-text-tertiary: #6b7280; - --color-text-inverse: #111827; - --color-text-link: #60a5fa; - --color-text-link-hover: #93c5fd; - - /* Borders */ - --color-border-primary: #374151; - --color-border-secondary: #4b5563; - --color-border-focus: #60a5fa; - - /* Semantic colors */ - --color-accent: #3b82f6; - --color-accent-hover: #60a5fa; - --color-accent-light: #1e3a5f; - --color-success: #10b981; - --color-success-light: #064e3b; - --color-warning: #f59e0b; - --color-warning-light: #78350f; - --color-error: #ef4444; - --color-error-light: #7f1d1d; - --color-info: #0ea5e9; - --color-info-light: #0c4a6e; - - /* Priority indicators */ - --color-priority-high: #ef4444; - --color-priority-normal: #f59e0b; - --color-priority-low: #6b7280; - - /* Status badges */ - --color-status-open: #9ca3af; - --color-status-open-bg: #374151; - --color-status-assigned: #60a5fa; - --color-status-assigned-bg: #1e3a5f; - --color-status-answered: #f59e0b; - --color-status-answered-bg: #78350f; - --color-status-vetted: #a78bfa; - --color-status-vetted-bg: #4c1d95; - --color-status-published: #10b981; - --color-status-published-bg: #064e3b; - --color-status-closed: #6b7280; - --color-status-closed-bg: #374151; - - /* Components */ - --color-header-bg: #1f2937; - --color-header-text: #f9fafb; - --color-header-border: #374151; - --color-card-bg: #1f2937; - --color-card-border: #374151; - --color-card-shadow: rgba(0, 0, 0, 0.3); - --color-input-bg: #374151; - --color-input-border: #4b5563; - --color-input-focus: #60a5fa; - --color-input-placeholder: #6b7280; - --color-badge-bg: #ef4444; - --color-badge-text: #ffffff; - - /* Shadows */ - --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3); - --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3); - --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5), 0 4px 6px -2px rgba(0, 0, 0, 0.3); - --shadow-focus: 0 0 0 3px rgba(96, 165, 250, 0.3); -} - - -/* ========================================================================== - HIGH CONTRAST THEME - ========================================================================== */ - -.theme-contrast { - /* Surfaces */ - --color-bg-primary: #000000; - --color-bg-secondary: #1a1a1a; - --color-bg-tertiary: #333333; - --color-bg-inverse: #ffffff; - --color-bg-hover: #333333; - --color-bg-selected: #003366; - - /* Text */ - --color-text-primary: #ffffff; - --color-text-secondary: #e0e0e0; - --color-text-tertiary: #b0b0b0; - --color-text-inverse: #000000; - --color-text-link: #66b3ff; - --color-text-link-hover: #99ccff; - - /* Borders */ - --color-border-primary: #ffffff; - --color-border-secondary: #808080; - --color-border-focus: #ffff00; - - /* Semantic colors */ - --color-accent: #66b3ff; - --color-accent-hover: #99ccff; - --color-accent-light: #003366; - --color-success: #00ff00; - --color-success-light: #003300; - --color-warning: #ffff00; - --color-warning-light: #333300; - --color-error: #ff3333; - --color-error-light: #330000; - --color-info: #00ffff; - --color-info-light: #003333; - - /* Priority indicators */ - --color-priority-high: #ff3333; - --color-priority-normal: #ffff00; - --color-priority-low: #808080; - - /* Status badges */ - --color-status-open: #ffffff; - --color-status-open-bg: #333333; - --color-status-assigned: #66b3ff; - --color-status-assigned-bg: #003366; - --color-status-answered: #ffff00; - --color-status-answered-bg: #333300; - --color-status-vetted: #cc99ff; - --color-status-vetted-bg: #330066; - --color-status-published: #00ff00; - --color-status-published-bg: #003300; - --color-status-closed: #808080; - --color-status-closed-bg: #1a1a1a; - - /* Components */ - --color-header-bg: #000000; - --color-header-text: #ffffff; - --color-header-border: #ffffff; - --color-card-bg: #1a1a1a; - --color-card-border: #ffffff; - --color-card-shadow: none; - --color-input-bg: #1a1a1a; - --color-input-border: #ffffff; - --color-input-focus: #ffff00; - --color-input-placeholder: #808080; - --color-badge-bg: #ff3333; - --color-badge-text: #ffffff; - - /* Shadows - disabled for clarity */ - --shadow-sm: none; - --shadow-md: none; - --shadow-lg: none; - --shadow-focus: 0 0 0 3px #ffff00; -} - -/* High contrast specific: underline all links */ -.theme-contrast a { - text-decoration: underline; -} - -.theme-contrast a:focus { - outline: 3px solid var(--color-border-focus); - outline-offset: 2px; -} - - -/* ========================================================================== - PER-PROJECT BRAND OVERRIDES - ========================================================================== */ - -/* Project overrides cascade on top of the selected theme */ -/* Example: data-project="alpha" */ - -[data-project="alpha"] { - --color-accent: #7c3aed; /* Purple accent */ - --color-accent-hover: #6d28d9; - --color-header-bg: #7c3aed; - --color-header-text: #ffffff; -} - -[data-project="beta"] { - --color-accent: #059669; /* Emerald accent */ - --color-accent-hover: #047857; - --color-header-bg: #059669; - --color-header-text: #ffffff; -} - - -/* ========================================================================== - COMPONENT STYLES (using theme variables) - ========================================================================== */ - -/* Base reset */ -*, *::before, *::after { - box-sizing: border-box; -} - -body { - font-family: var(--font-sans); - font-size: var(--text-base); - line-height: var(--leading-normal); - color: var(--color-text-primary); - background-color: var(--color-bg-primary); - margin: 0; - padding: 0; -} - -/* Header */ -.global-header { - display: flex; - align-items: center; - gap: var(--space-lg); - padding: var(--space-md) var(--space-lg); - background: var(--color-header-bg); - border-bottom: 1px solid var(--color-header-border); -} - -.global-header .logo { - font-size: var(--text-xl); - font-weight: 700; - color: var(--color-header-text); -} - -/* Project selector */ -.project-select { - flex: 1; - max-width: 400px; - padding: var(--space-sm) var(--space-md); - font-size: var(--text-sm); - color: var(--color-text-primary); - background: var(--color-input-bg); - border: 1px solid var(--color-input-border); - border-radius: var(--radius-md); - cursor: pointer; -} - -.project-select:focus { - outline: none; - border-color: var(--color-input-focus); - box-shadow: var(--shadow-focus); -} - -/* Workstream tabs */ -.workstream-tabs { - display: flex; - gap: var(--space-xs); - padding: 0 var(--space-lg); - background: var(--color-bg-secondary); - border-bottom: 1px solid var(--color-border-primary); -} - -.workstream-tabs a { - display: inline-flex; - align-items: center; - gap: var(--space-sm); - padding: var(--space-md) var(--space-lg); - font-size: var(--text-sm); - font-weight: 500; - color: var(--color-text-secondary); - text-decoration: none; - border-bottom: 2px solid transparent; - transition: color var(--transition-fast), border-color var(--transition-fast); -} - -.workstream-tabs a:hover { - color: var(--color-text-primary); -} - -.workstream-tabs a.active { - color: var(--color-accent); - border-bottom-color: var(--color-accent); -} - -/* Badge */ -.badge { - display: inline-flex; - align-items: center; - justify-content: center; - min-width: 1.25rem; - height: 1.25rem; - padding: 0 var(--space-xs); - font-size: var(--text-xs); - font-weight: 600; - color: var(--color-badge-text); - background: var(--color-badge-bg); - border-radius: var(--radius-full); -} - -.badge-muted { - background: var(--color-bg-tertiary); - color: var(--color-text-secondary); -} - -/* Task card */ -.task-card { - display: block; - padding: var(--space-md) var(--space-lg); - background: var(--color-card-bg); - border: 1px solid var(--color-card-border); - border-radius: var(--radius-lg); - box-shadow: var(--shadow-sm); - text-decoration: none; - color: inherit; - transition: box-shadow var(--transition-fast), border-color var(--transition-fast); -} - -.task-card:hover { - border-color: var(--color-border-focus); - box-shadow: var(--shadow-md); -} - -.task-card-header { - display: flex; - align-items: flex-start; - gap: var(--space-md); - margin-bottom: var(--space-sm); -} - -.task-card-priority { - width: 0.625rem; - height: 0.625rem; - border-radius: var(--radius-full); - flex-shrink: 0; - margin-top: 0.375rem; -} - -.task-card-priority.high { background: var(--color-priority-high); } -.task-card-priority.normal { background: var(--color-priority-normal); } -.task-card-priority.low { background: var(--color-priority-low); } - -.task-card-ref { - font-size: var(--text-sm); - font-weight: 600; - color: var(--color-text-secondary); - font-family: var(--font-mono); -} - -.task-card-title { - flex: 1; - font-size: var(--text-base); - font-weight: 600; - color: var(--color-text-primary); -} - -.task-card-due { - font-size: var(--text-sm); - color: var(--color-text-secondary); - white-space: nowrap; -} - -.task-card-due.overdue { - color: var(--color-error); - font-weight: 600; -} - -.task-card-due.today { - color: var(--color-warning); - font-weight: 600; -} - -.task-card-meta { - font-size: var(--text-sm); - color: var(--color-text-secondary); - margin-bottom: var(--space-sm); -} - -.task-card-preview { - font-size: var(--text-sm); - color: var(--color-text-tertiary); - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -/* Status badge */ -.status-badge { - display: inline-flex; - align-items: center; - padding: var(--space-xs) var(--space-sm); - font-size: var(--text-xs); - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.025em; - border-radius: var(--radius-sm); -} - -.status-badge.open { color: var(--color-status-open); background: var(--color-status-open-bg); } -.status-badge.assigned { color: var(--color-status-assigned); background: var(--color-status-assigned-bg); } -.status-badge.answered { color: var(--color-status-answered); background: var(--color-status-answered-bg); } -.status-badge.vetted { color: var(--color-status-vetted); background: var(--color-status-vetted-bg); } -.status-badge.published { color: var(--color-status-published); background: var(--color-status-published-bg); } -.status-badge.closed { color: var(--color-status-closed); background: var(--color-status-closed-bg); } - -/* Buttons */ -.btn { - display: inline-flex; - align-items: center; - justify-content: center; - gap: var(--space-sm); - padding: var(--space-sm) var(--space-md); - font-size: var(--text-sm); - font-weight: 500; - text-decoration: none; - border-radius: var(--radius-md); - border: 1px solid transparent; - cursor: pointer; - transition: all var(--transition-fast); -} - -.btn-primary { - color: var(--color-text-inverse); - background: var(--color-accent); - border-color: var(--color-accent); -} - -.btn-primary:hover { - background: var(--color-accent-hover); - border-color: var(--color-accent-hover); -} - -.btn-secondary { - color: var(--color-text-primary); - background: var(--color-bg-secondary); - border-color: var(--color-border-primary); -} - -.btn-secondary:hover { - background: var(--color-bg-tertiary); -} - -.btn:focus { - outline: none; - box-shadow: var(--shadow-focus); -} - -/* Form inputs */ -.input, .textarea { - width: 100%; - padding: var(--space-sm) var(--space-md); - font-size: var(--text-base); - color: var(--color-text-primary); - background: var(--color-input-bg); - border: 1px solid var(--color-input-border); - border-radius: var(--radius-md); -} - -.input::placeholder, .textarea::placeholder { - color: var(--color-input-placeholder); -} - -.input:focus, .textarea:focus { - outline: none; - border-color: var(--color-input-focus); - box-shadow: var(--shadow-focus); -} - -.textarea { - min-height: 100px; - resize: vertical; -} - -/* Thread messages */ -.thread-message { - padding: var(--space-md); - background: var(--color-card-bg); - border: 1px solid var(--color-card-border); - border-radius: var(--radius-lg); - margin-bottom: var(--space-md); -} - -.thread-message-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: var(--space-sm); -} - -.thread-message-author { - font-weight: 600; - color: var(--color-text-primary); -} - -.thread-message-time { - font-size: var(--text-sm); - color: var(--color-text-tertiary); -} - -.thread-message-body { - color: var(--color-text-primary); - line-height: var(--leading-relaxed); -} - -.thread-message-attachment { - display: inline-flex; - align-items: center; - gap: var(--space-sm); - margin-top: var(--space-sm); - padding: var(--space-sm) var(--space-md); - background: var(--color-bg-tertiary); - border-radius: var(--radius-md); - font-size: var(--text-sm); - color: var(--color-text-link); - text-decoration: none; -} - -.thread-message-attachment:hover { - color: var(--color-text-link-hover); -} - -/* Routing chain */ -.routing-chain { - display: flex; - align-items: center; - gap: var(--space-md); - padding: var(--space-md); - background: var(--color-bg-secondary); - border-radius: var(--radius-lg); - overflow-x: auto; -} - -.routing-step { - display: flex; - align-items: center; - gap: var(--space-sm); - white-space: nowrap; - font-size: var(--text-sm); - color: var(--color-text-secondary); -} - -.routing-step.current { - font-weight: 600; - color: var(--color-accent); -} - -.routing-arrow { - color: var(--color-text-tertiary); -} - -/* Empty state */ -.empty-state { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: var(--space-2xl); - text-align: center; -} - -.empty-state-icon { - font-size: 3rem; - margin-bottom: var(--space-md); -} - -.empty-state-title { - font-size: var(--text-xl); - font-weight: 600; - color: var(--color-text-primary); - margin-bottom: var(--space-sm); -} - -.empty-state-text { - color: var(--color-text-secondary); -} - - -/* ========================================================================== - UTILITY CLASSES - ========================================================================== */ - -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border: 0; -} - -.container { - max-width: 1200px; - margin: 0 auto; - padding: 0 var(--space-lg); -} - -.flex { display: flex; } -.flex-col { flex-direction: column; } -.items-center { align-items: center; } -.justify-between { justify-content: space-between; } -.gap-sm { gap: var(--space-sm); } -.gap-md { gap: var(--space-md); } -.gap-lg { gap: var(--space-lg); } - -.mt-sm { margin-top: var(--space-sm); } -.mt-md { margin-top: var(--space-md); } -.mt-lg { margin-top: var(--space-lg); } -.mb-sm { margin-bottom: var(--space-sm); } -.mb-md { margin-bottom: var(--space-md); } -.mb-lg { margin-bottom: var(--space-lg); } - -.text-sm { font-size: var(--text-sm); } -.text-lg { font-size: var(--text-lg); } -.text-muted { color: var(--color-text-secondary); } -.font-semibold { font-weight: 600; } diff --git a/portal/portal/templates/admin/dashboard.html b/portal/portal/templates/admin/dashboard.html deleted file mode 100644 index 988f20b..0000000 --- a/portal/portal/templates/admin/dashboard.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - Admin — Dealspace - - - - - -
- Dealspace -
- Super Admin - - -
-
-
- -
-

Admin Dashboard

-

Platform overview and management.

- -
-
-
Users
-
-
-
-
Projects
-
-
-
-
Organizations
-
-
-
-
Active Sessions
-
-
-
- -
-
-

All Users

-
-
Loading...
-
-
-
- - - - diff --git a/portal/portal/templates/app/orgs.html b/portal/portal/templates/app/orgs.html deleted file mode 100644 index a445794..0000000 --- a/portal/portal/templates/app/orgs.html +++ /dev/null @@ -1,154 +0,0 @@ - - - - - Organizations — Dealspace - - - - - -
- Dealspace -
- - -
-
-
- -
-
-
-

Organizations

-

Company directory — parties eligible to participate in deals.

-
- -
-
-
Loading...
-
- -
-
- - - - - - - diff --git a/portal/portal/templates/app/project.html b/portal/portal/templates/app/project.html deleted file mode 100644 index 5445b18..0000000 --- a/portal/portal/templates/app/project.html +++ /dev/null @@ -1,494 +0,0 @@ - - - - - Project — Dealspace - - - - - -
-
- Dealspace - / - Projects - / - Loading... -
-
- - -
-
-
- -
-
-
-
-

Loading...

- -
-

-
-
- - -
-
-
- - - -
-
-
Loading requests...
- -
- - -
-
- - - - - - - diff --git a/portal/portal/templates/app/projects.html b/portal/portal/templates/app/projects.html deleted file mode 100644 index 10669c8..0000000 --- a/portal/portal/templates/app/projects.html +++ /dev/null @@ -1,155 +0,0 @@ - - - - - Projects — Dealspace - - - - - -
- Dealspace -
- - -
-
-
- -
-
-
-

Projects

-

All deals you have access to.

-
- -
-
-
Loading projects...
-
- -
-
- - - - - - - diff --git a/portal/portal/templates/app/request.html b/portal/portal/templates/app/request.html deleted file mode 100644 index 635835c..0000000 --- a/portal/portal/templates/app/request.html +++ /dev/null @@ -1,204 +0,0 @@ - - - - - Request — Dealspace - - - - - -
-
- Dealspace - / - Projects - / - Project - / - Request -
-
- - -
-
-
- -
- -
-
-
-

Loading...

-

-
- -
-
- - -
-
- - -
-

Response

-
-
-
📎
-

Drop files here or click to upload

-

PDF, DOCX, XLSX, images

- -
-
-
- - -
-

Comments

-
-
- - -
-
-
-
- - - - diff --git a/portal/portal/templates/app/tasks.html b/portal/portal/templates/app/tasks.html deleted file mode 100644 index 74b8343..0000000 --- a/portal/portal/templates/app/tasks.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - My Tasks — Dealspace - - - - - - - -
-
- - Dealspace - - -
-
- - -
-
- -
- - - - -
- -
-

-

Here are your pending tasks.

-
- - -
-
Loading tasks...
-
- - - -
-
- - - - diff --git a/portal/portal/templates/auth/login.html b/portal/portal/templates/auth/login.html deleted file mode 100644 index eaf9b07..0000000 --- a/portal/portal/templates/auth/login.html +++ /dev/null @@ -1,206 +0,0 @@ - - - - - - Login — Dealspace - - - - - - -
- -
-

- Dealspace -

-

Secure M&A deal management

-
- - -
-

Sign in

-

Enter your email to receive a login code.

- - - -
-
- - -
- -
-
- - - - -

- Don’t have an account? Dealspace is invite-only.
- Request access on muskepo.com -

-

© 2026 Muskepo B.V. — Amsterdam

-
- - - - diff --git a/portal/portal/templates/auth/setup.html b/portal/portal/templates/auth/setup.html deleted file mode 100644 index f5c827c..0000000 --- a/portal/portal/templates/auth/setup.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - Setup — Dealspace - - - - - - -
- -
-

- Dealspace -

-

First-time setup

-
- - -
-

Create admin account

-

This will be the first administrator account for your Dealspace instance.

- - - - -
-
- - -
-
- - -
-
- - -

Minimum 8 characters

-
- -
-
- -

© 2026 Muskepo B.V. — Amsterdam

-
- - - - diff --git a/portal/portal/templates/request-detail.html b/portal/portal/templates/request-detail.html deleted file mode 100644 index c3579a6..0000000 --- a/portal/portal/templates/request-detail.html +++ /dev/null @@ -1,572 +0,0 @@ - - - - - - FIN-042: Audited financials FY2024 — Dealspace - - - - -
- - - - -
- - - ← Back to Inbox - - - -
-
-
- FIN-042 - Assigned -
-

Audited financials FY2024

-

Project Alpha • Finance • Due: March 15, 2026

-
-
- - High Priority -
-
- -
-
- -
-

Routing

-
- -
- When done, returns to: M. Chen (CFO) -
-
- - -
-
-
- - -
-

Thread

-
- -
-
- J. Smith (IB) - -
-
-

Please provide audited financial statements for FY2024.

-

We need the following documents:

-
    -
  • Income statement (P&L)
  • -
  • Balance sheet
  • -
  • Cash flow statement
  • -
  • Auditor's opinion letter
  • -
-

Please ensure these are the final audited versions, not draft.

-
-
- - -
-
- M. Chen (CFO) - -
-
-

@accountant Can you pull these from the ERP? The audit was finalized last month.

-

Attaching last year's format for reference so we maintain consistency.

-
- - 📎 fy2023-financials-format.xlsx - -
- - -
-
- S. Johnson (You) - -
-
-

On it. Just waiting for the auditor to send the final signed opinion letter. Should have everything by EOD Thursday.

-
-
-
-
- - -
-

Your Response

-
- -
-
- - -
-
- - -
-
-
-
-
- - -
-
-
- - -
- - - -
- - diff --git a/portal/portal/templates/task-inbox.html b/portal/portal/templates/task-inbox.html deleted file mode 100644 index 995cf91..0000000 --- a/portal/portal/templates/task-inbox.html +++ /dev/null @@ -1,258 +0,0 @@ - - - - - - My Tasks — Dealspace - - - - -
- - - - -
-
-

My Tasks

- -
- - -
-
- - -
- - - -
- - - - -