2682 lines
79 KiB
Vue
2682 lines
79 KiB
Vue
<template>
|
|
<div>
|
|
<!-- Wizard Subnav -->
|
|
<WizardSubnav />
|
|
|
|
<div
|
|
class="template-wrapper bg-white dark:bg-neutral-950 text-neutral-900 dark:text-neutral-100">
|
|
<!-- Export Controls -->
|
|
<div class="max-w-4xl mx-auto no-print no-pdf mb-8 py-4">
|
|
<div class="flex justify-end">
|
|
<div class="flex items-center gap-4">
|
|
<UButton
|
|
variant="outline"
|
|
color="gray"
|
|
size="lg"
|
|
@click="exportPDF">
|
|
<UIcon name="i-heroicons-document-arrow-down" class="mr-2" />
|
|
PDF
|
|
</UButton>
|
|
<UButton
|
|
variant="outline"
|
|
color="gray"
|
|
size="lg"
|
|
@click="handlePrint">
|
|
<UIcon name="i-heroicons-printer" class="mr-2" />
|
|
Print
|
|
</UButton>
|
|
<UButton
|
|
variant="outline"
|
|
color="gray"
|
|
size="lg"
|
|
@click="exportText">
|
|
<UIcon name="i-heroicons-document-text" class="mr-2" />
|
|
Text
|
|
</UButton>
|
|
<UButton
|
|
variant="outline"
|
|
color="gray"
|
|
size="lg"
|
|
@click="exportMarkdown">
|
|
<UIcon name="i-heroicons-arrow-down-tray" class="mr-2" />
|
|
Markdown
|
|
</UButton>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Document Container -->
|
|
<div class="document-page">
|
|
<div class="template-content">
|
|
<!-- Document Title -->
|
|
<div class="text-center mb-8">
|
|
<h1
|
|
class="text-3xl md:text-5xl font-bold uppercase text-neutral-900 dark:text-white m-0 py-4 border-t-2 border-b-2 border-neutral-900 dark:border-neutral-100"
|
|
:data-coop-name="
|
|
formData.cooperativeName || 'Worker Cooperative'
|
|
">
|
|
MEMBERSHIP AGREEMENT
|
|
</h1>
|
|
</div>
|
|
|
|
<!-- Section 1: Who We Are -->
|
|
<div class="section-card">
|
|
<h2
|
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
|
1. Who We Are
|
|
</h2>
|
|
|
|
<div class="space-y-8">
|
|
<UFormField label="Cooperative Name" class="form-group-large">
|
|
<UInput
|
|
v-model="formData.cooperativeName"
|
|
placeholder="Enter cooperative name"
|
|
size="xl"
|
|
class="w-full"
|
|
@input="debouncedAutoSave"
|
|
@change="autoSave" />
|
|
</UFormField>
|
|
|
|
<UFormField label="Date Established" class="form-group-large">
|
|
<UInput
|
|
v-model="formData.dateEstablished"
|
|
type="date"
|
|
size="xl"
|
|
class="large-field"
|
|
@change="autoSave" />
|
|
</UFormField>
|
|
|
|
<UFormField label="Our Purpose" class="form-group-large">
|
|
<UTextarea
|
|
v-model="formData.purpose"
|
|
:rows="3"
|
|
placeholder="Write 1-2 sentences about what your cooperative does and why it exists"
|
|
size="xl"
|
|
class="large-field"
|
|
@input="debouncedAutoSave"
|
|
@change="autoSave" />
|
|
</UFormField>
|
|
|
|
<UFormField label="Our Core Values" class="form-group-large">
|
|
<UTextarea
|
|
v-model="formData.coreValues"
|
|
:rows="4"
|
|
placeholder="List 3-5 values that guide everything you do. Examples: mutual care, creative sustainability, economic justice, collective liberation"
|
|
size="xl"
|
|
class="large-field"
|
|
@input="debouncedAutoSave"
|
|
@change="autoSave" />
|
|
</UFormField>
|
|
|
|
<div class="form-group-large">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<label
|
|
class="text-lg font-semibold text-neutral-900 dark:text-neutral-100"
|
|
>Current Members</label
|
|
>
|
|
<UButton
|
|
@click="addMember"
|
|
size="sm"
|
|
color="primary"
|
|
variant="outline"
|
|
icon="i-heroicons-plus">
|
|
Add Member
|
|
</UButton>
|
|
</div>
|
|
|
|
<div class="space-y-4">
|
|
<div
|
|
v-for="(member, index) in formData.members"
|
|
:key="index"
|
|
class="border border-neutral-600 rounded-lg p-4">
|
|
<div class="flex items-start justify-between mb-3">
|
|
<h4
|
|
class="font-medium text-neutral-900 dark:text-neutral-100">
|
|
Member {{ index + 1 }}
|
|
</h4>
|
|
<UButton
|
|
v-if="formData.members.length > 1"
|
|
@click="removeMember(index)"
|
|
size="sm"
|
|
color="red"
|
|
variant="ghost"
|
|
icon="i-heroicons-trash">
|
|
</UButton>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<UFormField label="Full Name" class="form-group-large">
|
|
<UInput
|
|
v-model="member.name"
|
|
placeholder="Enter full name"
|
|
size="xl"
|
|
class="large-field"
|
|
@input="debouncedAutoSave"
|
|
@change="autoSave" />
|
|
</UFormField>
|
|
|
|
<UFormField label="Email" class="form-group-large">
|
|
<UInput
|
|
v-model="member.email"
|
|
type="email"
|
|
placeholder="Enter email address"
|
|
size="xl"
|
|
class="large-field"
|
|
@input="debouncedAutoSave"
|
|
@change="autoSave" />
|
|
</UFormField>
|
|
|
|
<UFormField label="Join Date" class="form-group-large">
|
|
<UInput
|
|
v-model="member.joinDate"
|
|
type="date"
|
|
size="xl"
|
|
class="large-field"
|
|
@change="autoSave" />
|
|
</UFormField>
|
|
|
|
<UFormField
|
|
label="Current Role (Optional)"
|
|
class="form-group-large">
|
|
<UInput
|
|
v-model="member.role"
|
|
placeholder="e.g., Coordinator, Developer, etc."
|
|
size="xl"
|
|
class="large-field"
|
|
@input="debouncedAutoSave"
|
|
@change="autoSave" />
|
|
</UFormField>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section 2: Membership -->
|
|
<div class="section-card">
|
|
<h2
|
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
|
2. Membership
|
|
</h2>
|
|
|
|
<div class="space-y-4">
|
|
<div>
|
|
<h3
|
|
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
|
Who Can Be a Member
|
|
</h3>
|
|
<p class="content-paragraph mb-3 leading-relaxed text-left">
|
|
Any person who:
|
|
</p>
|
|
<ul class="content-list my-2 pl-6 list-disc">
|
|
<li>Shares our values and purpose</li>
|
|
<li>
|
|
Contributes labour to the cooperative (by doing actual work,
|
|
not just investing money)
|
|
</li>
|
|
<li>Commits to collective decision-making</li>
|
|
<li>Participates in governance responsibilities</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div>
|
|
<h3
|
|
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
|
Becoming a Member
|
|
</h3>
|
|
|
|
<p class="content-paragraph">
|
|
New members join through a consent process, which means
|
|
existing members must agree that adding this person won't harm
|
|
the cooperative.
|
|
</p>
|
|
|
|
<ol class="content-list numbered my-2 pl-6 list-decimal">
|
|
<li class="flex items-baseline gap-2 flex-wrap">
|
|
Trial period of
|
|
<UInput
|
|
v-model="formData.trialPeriodMonths"
|
|
type="number"
|
|
placeholder="3"
|
|
class="inline-field number-field"
|
|
@change="autoSave" />
|
|
months working together
|
|
</li>
|
|
<li>Values alignment conversation</li>
|
|
<li>Consent decision by current members</li>
|
|
<li class="flex items-baseline gap-2 flex-wrap">
|
|
Optional - Equal buy-in contribution of $<UInput
|
|
v-model="formData.buyInAmount"
|
|
type="number"
|
|
placeholder="1000"
|
|
class="inline-field number-field"
|
|
@change="autoSave" />
|
|
(can be paid over time or waived based on need)
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
|
|
<div>
|
|
<h3
|
|
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
|
Leaving the Cooperative
|
|
</h3>
|
|
|
|
<p
|
|
class="content-paragraph flex items-baseline gap-2 flex-wrap">
|
|
Members can leave anytime with
|
|
<UInput
|
|
v-model="formData.noticeDays"
|
|
type="number"
|
|
placeholder="30"
|
|
class="inline-field number-field"
|
|
@change="autoSave" />
|
|
days notice. The cooperative will:
|
|
</p>
|
|
|
|
<ul class="content-list my-2 pl-6 list-disc">
|
|
<li class="flex items-baseline gap-2 flex-wrap">
|
|
Pay out their share of any surplus within
|
|
<UInput
|
|
v-model="formData.surplusPayoutDays"
|
|
type="number"
|
|
placeholder="30"
|
|
class="inline-field number-field"
|
|
@change="autoSave" />
|
|
days
|
|
</li>
|
|
<li class="flex items-baseline gap-2 flex-wrap">
|
|
Return their buy-in contribution within
|
|
<UInput
|
|
v-model="formData.buyInReturnDays"
|
|
type="number"
|
|
placeholder="90"
|
|
class="inline-field number-field"
|
|
@change="autoSave" />
|
|
days
|
|
</li>
|
|
<li>
|
|
Maintain respectful ongoing relationships when possible
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section 3: How We Make Decisions -->
|
|
<div class="section-card">
|
|
<h2
|
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
|
3. How We Make Decisions
|
|
</h2>
|
|
|
|
<div class="space-y-4">
|
|
<div>
|
|
<h3
|
|
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
|
Consent-Based Decisions
|
|
</h3>
|
|
<p class="content-paragraph mb-3 leading-relaxed text-left">
|
|
We use consent, not consensus. This means we move forward when
|
|
no one has a principled objection that would harm the
|
|
cooperative. An objection must explain how the proposal would
|
|
contradict our values or threaten our sustainability.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<h3
|
|
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
|
Day-to-Day Decisions
|
|
</h3>
|
|
<p
|
|
class="content-paragraph mb-3 leading-relaxed text-left flex items-baseline gap-2 flex-wrap">
|
|
Decisions under $<UInput
|
|
v-model="formData.dayToDayLimit"
|
|
type="number"
|
|
placeholder="100"
|
|
class="inline-field number-field"
|
|
@change="autoSave" />
|
|
can be made by any member. Just tell others what you did at
|
|
the next meeting.
|
|
</p>
|
|
</div>
|
|
|
|
<div>
|
|
<h3
|
|
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
|
Regular Decisions
|
|
</h3>
|
|
<p
|
|
class="content-paragraph mb-3 leading-relaxed text-left flex items-baseline gap-2 flex-wrap">
|
|
Decisions between $<UInput
|
|
v-model="formData.regularDecisionMin"
|
|
type="number"
|
|
placeholder="100"
|
|
class="inline-field number-field"
|
|
@change="autoSave" />
|
|
and $<UInput
|
|
v-model="formData.regularDecisionMax"
|
|
type="number"
|
|
placeholder="1000"
|
|
class="inline-field number-field"
|
|
@change="autoSave" />
|
|
need consent from members present at a meeting (minimum 2
|
|
members).
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<h3
|
|
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
|
Major Decisions
|
|
</h3>
|
|
<p class="content-paragraph mb-3 leading-relaxed text-left">
|
|
These require consent from all members:
|
|
</p>
|
|
<ul class="content-list my-2 pl-6 list-disc">
|
|
<li>Adding or removing members</li>
|
|
<li>Changing this agreement</li>
|
|
<li class="flex items-baseline gap-2 flex-wrap">
|
|
Taking on debt over $<UInput
|
|
v-model="formData.majorDebtThreshold"
|
|
type="number"
|
|
placeholder="5000"
|
|
class="inline-field number-field"
|
|
@change="autoSave" />
|
|
</li>
|
|
<li>Fundamental changes to our purpose or structure</li>
|
|
<li>Dissolution of the cooperative</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div>
|
|
<h3
|
|
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
|
Meeting Structure
|
|
</h3>
|
|
<ul class="content-list my-2 pl-6 list-disc">
|
|
<li class="flex items-baseline gap-2 flex-wrap">
|
|
Regular meetings happen
|
|
<UInput
|
|
v-model="formData.meetingFrequency"
|
|
placeholder="weekly"
|
|
class="inline-field"
|
|
@change="autoSave" />
|
|
</li>
|
|
<li class="flex items-baseline gap-2 flex-wrap">
|
|
Emergency meetings need
|
|
<UInput
|
|
v-model="formData.emergencyNoticeHours"
|
|
type="number"
|
|
placeholder="24"
|
|
class="inline-field number-field"
|
|
@change="autoSave" />
|
|
hours notice
|
|
</li>
|
|
<li>We rotate who facilitates meetings</li>
|
|
<li>
|
|
Decisions and reasoning get documented in shared notes
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section 4: Money and Labour -->
|
|
<div class="section-card">
|
|
<h2
|
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
|
4. Money and Labour
|
|
</h2>
|
|
|
|
<div class="space-y-4">
|
|
<div>
|
|
<h3
|
|
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
|
Equal Ownership
|
|
</h3>
|
|
<p class="content-paragraph mb-3 leading-relaxed text-left">
|
|
Each member owns an equal share of the cooperative, regardless
|
|
of hours worked or tenure.
|
|
</p>
|
|
</div>
|
|
|
|
<div>
|
|
<h3
|
|
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
|
Paying Ourselves
|
|
</h3>
|
|
<ul class="content-list my-2 pl-6 list-disc">
|
|
<li class="flex items-baseline gap-2 flex-wrap">
|
|
Base rate: $<UInput
|
|
v-model="formData.baseRate"
|
|
type="number"
|
|
placeholder="25"
|
|
class="inline-field number-field"
|
|
@change="autoSave" />/hour for all members
|
|
</li>
|
|
<li class="flex items-baseline gap-2 flex-wrap">
|
|
Or: Equal monthly draw of $<UInput
|
|
v-model="formData.monthlyDraw"
|
|
type="number"
|
|
placeholder="2000"
|
|
class="inline-field number-field"
|
|
@change="autoSave" />
|
|
per member
|
|
</li>
|
|
<li class="flex items-baseline gap-2 flex-wrap">
|
|
Paid on the
|
|
<USelect
|
|
v-model="formData.paymentDay"
|
|
:items="dayOptions"
|
|
placeholder="15"
|
|
class="inline-field"
|
|
@change="autoSave" />
|
|
of each month
|
|
</li>
|
|
<li class="flex items-baseline gap-2 flex-wrap">
|
|
Surplus (profit) distributed equally every
|
|
<UInput
|
|
v-model="formData.surplusFrequency"
|
|
placeholder="quarter"
|
|
class="inline-field"
|
|
@change="autoSave" />
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<h3
|
|
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
|
Work Expectations
|
|
</h3>
|
|
<ul class="content-list my-2 pl-6 list-disc">
|
|
<li class="flex items-baseline gap-2 flex-wrap">
|
|
Target hours per week:
|
|
<UInput
|
|
v-model="formData.targetHours"
|
|
type="number"
|
|
placeholder="40"
|
|
class="inline-field number-field"
|
|
@change="autoSave" />
|
|
(flexible based on capacity)
|
|
</li>
|
|
<li>We explicitly reject crunch culture</li>
|
|
<li>Members communicate their capacity openly</li>
|
|
<li>
|
|
We adjust workload collectively when someone needs reduced
|
|
hours
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div>
|
|
<h3
|
|
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
|
Financial Transparency
|
|
</h3>
|
|
<ul class="content-list my-2 pl-6 list-disc">
|
|
<li>
|
|
All members can access all financial records anytime
|
|
</li>
|
|
<li>Monthly financial check-ins at meetings</li>
|
|
<li>
|
|
Quarterly reviews of our runway (how many months we can
|
|
operate)
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section 5: Roles and Responsibilities -->
|
|
<div class="section-card">
|
|
<h2
|
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
|
5. Roles and Responsibilities
|
|
</h2>
|
|
|
|
<div class="space-y-4">
|
|
<div>
|
|
<h3
|
|
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
|
Rotating Roles
|
|
</h3>
|
|
<p
|
|
class="content-paragraph mb-3 leading-relaxed text-left flex items-baseline gap-2 flex-wrap">
|
|
We rotate operational roles every
|
|
<UInput
|
|
v-model="formData.roleRotationMonths"
|
|
type="number"
|
|
placeholder="6"
|
|
class="inline-field number-field"
|
|
@change="autoSave" />
|
|
months. Current roles include:
|
|
</p>
|
|
<ul class="content-list">
|
|
<li>
|
|
Financial coordinator (handles bookkeeping, not financial
|
|
decisions)
|
|
</li>
|
|
<li>Meeting facilitator</li>
|
|
<li>External communications</li>
|
|
<li>Others</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div>
|
|
<h3
|
|
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
|
Shared Responsibilities
|
|
</h3>
|
|
<p class="content-paragraph mb-3 leading-relaxed text-left">
|
|
All members participate in:
|
|
</p>
|
|
<ul class="content-list my-2 pl-6 list-disc">
|
|
<li>Governance and decision-making</li>
|
|
<li>Strategic planning</li>
|
|
<li>Mutual support and care</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section 6: Conflict and Care -->
|
|
<div class="section-card">
|
|
<h2
|
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
|
6. Conflict and Care
|
|
</h2>
|
|
|
|
<div class="space-y-4">
|
|
<div>
|
|
<h3
|
|
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
|
When Conflict Happens
|
|
</h3>
|
|
<ol class="content-list numbered my-2 pl-6 list-decimal">
|
|
<li>Direct conversation between parties (if comfortable)</li>
|
|
<li>Mediation with another member</li>
|
|
<li>Full group discussion with structured process</li>
|
|
<li>External mediation if needed</li>
|
|
</ol>
|
|
</div>
|
|
|
|
<div>
|
|
<h3
|
|
class="subsection-title text-xl font-semibold text-neutral-700 dark:text-neutral-200 border-b border-neutral-200 dark:border-neutral-600 pb-1 mb-3">
|
|
Care Commitments
|
|
</h3>
|
|
<ul class="content-list my-2 pl-6 list-disc">
|
|
<li>We check in about capacity and wellbeing regularly</li>
|
|
<li>We honour diverse access needs</li>
|
|
<li>We maintain flexibility for life circumstances</li>
|
|
<li>
|
|
We contribute to mutual aid when members face hardship
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section 7: Changing This Agreement -->
|
|
<div class="section-card">
|
|
<h2
|
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
|
7. Changing This Agreement
|
|
</h2>
|
|
|
|
<p
|
|
class="content-paragraph mb-3 leading-relaxed text-left flex items-baseline gap-2 flex-wrap">
|
|
This is a living document. We review it every
|
|
<UInput
|
|
v-model="formData.reviewFrequency"
|
|
placeholder="year"
|
|
class="inline-field"
|
|
@change="autoSave" />
|
|
and update it through our consent process. Small clarifications
|
|
can happen anytime; structural changes need full member consent.
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Section 8: If We Need to Close -->
|
|
<div class="section-card">
|
|
<h2
|
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
|
8. If We Need to Close
|
|
</h2>
|
|
|
|
<div class="space-y-4">
|
|
<p class="content-paragraph mb-3 leading-relaxed text-left">
|
|
If the cooperative dissolves:
|
|
</p>
|
|
<ol class="content-list numbered my-2 pl-6 list-decimal">
|
|
<li>Pay all debts and obligations</li>
|
|
<li>Return member contributions</li>
|
|
<li>Distribute remaining assets equally among members</li>
|
|
<li class="flex items-baseline gap-2 flex-wrap">
|
|
Or donate remaining assets to
|
|
<UInput
|
|
v-model="formData.assetDonationTarget"
|
|
placeholder="Enter organization name"
|
|
class="inline-field wide-field" />
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section 9: Legal Bits -->
|
|
<div class="section-card">
|
|
<h2
|
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
|
9. Legal Bits
|
|
</h2>
|
|
|
|
<div class="space-y-4">
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<UFormField label="Legal Structure" class="form-group-block">
|
|
<UInput
|
|
v-model="formData.legalStructure"
|
|
size="xl"
|
|
class="w-full"
|
|
placeholder="Cooperative corporation, LLC, partnership, etc." />
|
|
</UFormField>
|
|
|
|
<UFormField label="Registered in" class="form-group-inline">
|
|
<UInput
|
|
v-model="formData.registeredLocation"
|
|
placeholder="State/Province"
|
|
size="xl"
|
|
class="inline-field w-full"
|
|
@change="autoSave" />
|
|
</UFormField>
|
|
|
|
<div class="fiscal-year-group">
|
|
<UFormField label="Fiscal Year-End" class="form-group-inline">
|
|
<div class="flex gap-2 items-center">
|
|
<USelect
|
|
v-model="formData.fiscalYearEndMonth"
|
|
:items="monthOptions"
|
|
placeholder="Month"
|
|
size="xl"
|
|
class="w-60"
|
|
@change="autoSave" />
|
|
<USelect
|
|
v-model="formData.fiscalYearEndDay"
|
|
:items="dayOptions"
|
|
placeholder="Day"
|
|
size="xl"
|
|
class="w-40"
|
|
@change="autoSave" />
|
|
</div>
|
|
</UFormField>
|
|
</div>
|
|
</div>
|
|
|
|
<p class="content-paragraph mb-3 leading-relaxed text-left">
|
|
This agreement works alongside but doesn't replace our legal
|
|
incorporation documents. Where they conflict, we follow the law
|
|
but work to align our legal structure with our values.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section 10: Agreement Review -->
|
|
<div class="section-card">
|
|
<h2
|
|
class="section-title text-2xl font-extrabold text-neutral-900 dark:text-neutral-100 mb-4">
|
|
10. Agreement Review
|
|
</h2>
|
|
|
|
<div class="space-y-4">
|
|
<p class="content-paragraph mb-3 leading-relaxed text-left">
|
|
By using this agreement, we commit to these principles and to
|
|
showing up for each other.
|
|
</p>
|
|
|
|
<div
|
|
class="bg-neutral-50 dark:bg-neutral-900 p-4 rounded-md border-l-4 border-emerald-300">
|
|
<p
|
|
class="content-paragraph mb-3 leading-relaxed text-left flex items-baseline gap-2 flex-wrap">
|
|
This agreement was last updated on
|
|
<UInput
|
|
v-model="formData.lastUpdated"
|
|
type="date"
|
|
class="inline-field"
|
|
@change="autoSave" />. We commit to reviewing it on
|
|
<UInput
|
|
v-model="formData.nextReview"
|
|
type="date"
|
|
class="inline-field"
|
|
@change="autoSave" />
|
|
or sooner if circumstances require.
|
|
</p>
|
|
</div>
|
|
|
|
<div
|
|
class="signature-space mt-8 p-8 border border-dashed border-neutral-300 rounded-md bg-neutral-50 dark:bg-neutral-950">
|
|
<p
|
|
class="content-paragraph mb-3 leading-relaxed text-center text-neutral-600 italic">
|
|
[Space for member signatures when printed]
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, watch } from "vue";
|
|
|
|
definePageMeta({
|
|
layout: false,
|
|
});
|
|
|
|
// Import PDF export composable
|
|
const { exportToPDF } = usePdfExportBasic();
|
|
|
|
const monthOptions = [
|
|
"January",
|
|
"February",
|
|
"March",
|
|
"April",
|
|
"May",
|
|
"June",
|
|
"July",
|
|
"August",
|
|
"September",
|
|
"October",
|
|
"November",
|
|
"December",
|
|
];
|
|
|
|
const dayOptions = Array.from({ length: 31 }, (_, i) => (i + 1).toString());
|
|
|
|
const formData = ref({
|
|
cooperativeName: "",
|
|
dateEstablished: "",
|
|
purpose: "",
|
|
coreValues: "",
|
|
members: [{ name: "", email: "", joinDate: "", role: "" }],
|
|
trialPeriodMonths: 3,
|
|
buyInAmount: "",
|
|
noticeDays: 30,
|
|
surplusPayoutDays: 30,
|
|
buyInReturnDays: 90,
|
|
dayToDayLimit: 100,
|
|
regularDecisionMin: 100,
|
|
regularDecisionMax: 1000,
|
|
majorDebtThreshold: 5000,
|
|
meetingFrequency: "weekly",
|
|
emergencyNoticeHours: 24,
|
|
baseRate: 25,
|
|
monthlyDraw: "",
|
|
paymentDay: 15,
|
|
surplusFrequency: "quarter",
|
|
targetHours: 40,
|
|
roleRotationMonths: 6,
|
|
reviewFrequency: "year",
|
|
assetDonationTarget: "",
|
|
legalStructure: "",
|
|
registeredLocation: "",
|
|
fiscalYearEndMonth: "December",
|
|
fiscalYearEndDay: 31,
|
|
lastUpdated: new Date().toISOString().split("T")[0],
|
|
nextReview: "",
|
|
});
|
|
|
|
// Load saved data immediately (before watchers)
|
|
const loadSavedData = () => {
|
|
const saved = localStorage.getItem("membership-agreement-data");
|
|
if (saved) {
|
|
try {
|
|
const parsedData = JSON.parse(saved);
|
|
formData.value = { ...formData.value, ...parsedData };
|
|
console.log("Loaded saved data:", parsedData);
|
|
} catch (error) {
|
|
console.error("Error loading saved data:", error);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Load data immediately
|
|
loadSavedData();
|
|
|
|
// Auto-save to localStorage (removed immediate to prevent overwriting)
|
|
watch(
|
|
formData,
|
|
(newData) => {
|
|
localStorage.setItem("membership-agreement-data", JSON.stringify(newData));
|
|
console.log("Auto-saved data");
|
|
},
|
|
{ deep: true }
|
|
);
|
|
|
|
// Also ensure data is loaded on mount as backup
|
|
onMounted(() => {
|
|
loadSavedData();
|
|
});
|
|
|
|
// Auto-save individual field changes immediately
|
|
const autoSave = () => {
|
|
localStorage.setItem(
|
|
"membership-agreement-data",
|
|
JSON.stringify(formData.value)
|
|
);
|
|
console.log("Manual auto-save triggered:", formData.value);
|
|
};
|
|
|
|
// Debounced auto-save for better performance
|
|
const debouncedAutoSave = debounce(autoSave, 300);
|
|
|
|
// Helper function for debouncing
|
|
function debounce(func, wait) {
|
|
let timeout;
|
|
return function executedFunction(...args) {
|
|
const later = () => {
|
|
clearTimeout(timeout);
|
|
func(...args);
|
|
};
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(later, wait);
|
|
};
|
|
}
|
|
|
|
// Member management functions
|
|
const addMember = () => {
|
|
formData.value.members.push({ name: "", email: "", joinDate: "", role: "" });
|
|
debouncedAutoSave();
|
|
};
|
|
|
|
const removeMember = (index) => {
|
|
if (formData.value.members.length > 1) {
|
|
formData.value.members.splice(index, 1);
|
|
debouncedAutoSave();
|
|
}
|
|
};
|
|
|
|
// Print function with proper form value handling
|
|
const handlePrint = () => {
|
|
// Create print-friendly version by replacing inputs with their values from formData
|
|
const inputs = document.querySelectorAll("input, textarea, select");
|
|
const printValues = [];
|
|
|
|
// Also create signature section replacement
|
|
const signatureSpace = document.querySelector(".signature-space");
|
|
let signatureReplacement = null;
|
|
|
|
if (signatureSpace) {
|
|
const signatureDiv = document.createElement("div");
|
|
signatureDiv.className = "print-signatures";
|
|
signatureDiv.innerHTML = `
|
|
<p style="font-weight: bold; margin-bottom: 12pt; color: #000;">Member Signatures</p>
|
|
<p style="margin-bottom: 16pt; color: #000;">By signing below, we agree to these terms and commit to working together as equals in this cooperative.</p>
|
|
`;
|
|
|
|
// Add signature lines for each member
|
|
const membersWithNames =
|
|
formData.value.members?.filter((m) => m.name) || [];
|
|
const numSignatures = Math.max(
|
|
2,
|
|
Math.min(8, membersWithNames.length || 4)
|
|
);
|
|
|
|
for (let i = 0; i < numSignatures; i++) {
|
|
const memberName = membersWithNames[i]?.name || "";
|
|
const sigDiv = document.createElement("div");
|
|
sigDiv.style.marginBottom = "24pt";
|
|
sigDiv.innerHTML = `
|
|
<p style="margin-bottom: 8pt; font-weight: bold; color: #000;">${
|
|
memberName || `Member ${i + 1}:`
|
|
}</p>
|
|
<div style="border-bottom: 1pt solid #000; width: 300pt; height: 16pt; margin-bottom: 4pt;"></div>
|
|
<p style="font-size: 9pt; color: #666;">Signature Date: ___________</p>
|
|
`;
|
|
signatureDiv.appendChild(sigDiv);
|
|
}
|
|
|
|
signatureReplacement = signatureDiv;
|
|
signatureSpace.style.display = "none";
|
|
signatureSpace.parentNode.insertBefore(signatureDiv, signatureSpace);
|
|
}
|
|
|
|
inputs.forEach((input, index) => {
|
|
// Get value from the actual formData reactive object instead of DOM
|
|
let value = "";
|
|
|
|
// Try to match the input to formData properties
|
|
if (input.closest('[label="Cooperative Name"]'))
|
|
value = formData.value.cooperativeName;
|
|
else if (input.closest('[label="Date Established"]'))
|
|
value = formData.value.dateEstablished;
|
|
else if (input.closest('[label="Our Purpose"]'))
|
|
value = formData.value.purpose;
|
|
else if (input.closest('[label="Our Core Values"]'))
|
|
value = formData.value.coreValues;
|
|
else if (input.closest('[label="Legal Structure"]'))
|
|
value = formData.value.legalStructure;
|
|
else if (input.closest('[label="Registered in"]'))
|
|
value = formData.value.registeredLocation;
|
|
else if (input.closest('[label="Fiscal Year-End"]')) {
|
|
if (input.tagName === "SELECT" || input.type === "select-one") {
|
|
value = formData.value.fiscalYearEndMonth;
|
|
} else {
|
|
value = formData.value.fiscalYearEndDay;
|
|
}
|
|
}
|
|
// Handle member fields
|
|
else if (input.closest(".border-neutral-200")) {
|
|
const memberCard = input.closest(".border-neutral-200");
|
|
const memberIndex = Array.from(memberCard.parentNode.children).indexOf(
|
|
memberCard
|
|
);
|
|
const member = formData.value.members?.[memberIndex];
|
|
if (member) {
|
|
if (input.closest('[label="Full Name"]')) value = member.name;
|
|
else if (input.closest('[label="Email"]')) value = member.email;
|
|
else if (input.closest('[label="Join Date"]')) value = member.joinDate;
|
|
else if (input.closest('[label="Current Role (Optional)"]'))
|
|
value = member.role;
|
|
}
|
|
}
|
|
// Fallback to input.value
|
|
else {
|
|
value = input.value?.trim() || "";
|
|
}
|
|
|
|
// Create a span element to replace the input for print
|
|
const printSpan = document.createElement("span");
|
|
printSpan.className = "print-value";
|
|
|
|
if (value) {
|
|
// Has a value - show it in bold
|
|
printSpan.textContent = value;
|
|
printSpan.style.fontWeight = "bold";
|
|
} else {
|
|
// Empty field - show as blank line
|
|
printSpan.innerHTML = " ";
|
|
printSpan.setAttribute("data-empty", "true");
|
|
}
|
|
|
|
printSpan.setAttribute("data-original-index", index);
|
|
|
|
// Store original element info for restoration
|
|
printValues.push({
|
|
element: input,
|
|
parent: input.parentNode,
|
|
nextSibling: input.nextSibling,
|
|
replacement: printSpan,
|
|
});
|
|
|
|
// Replace input with span for print
|
|
input.style.display = "none";
|
|
input.parentNode.insertBefore(printSpan, input);
|
|
});
|
|
|
|
// Trigger print
|
|
setTimeout(() => {
|
|
window.print();
|
|
|
|
// Restore original inputs after print dialog
|
|
setTimeout(() => {
|
|
printValues.forEach((item) => {
|
|
item.element.style.display = "";
|
|
if (item.replacement.parentNode) {
|
|
item.replacement.parentNode.removeChild(item.replacement);
|
|
}
|
|
});
|
|
|
|
// Restore signature section
|
|
if (signatureReplacement && signatureSpace) {
|
|
signatureSpace.style.display = "";
|
|
if (signatureReplacement.parentNode) {
|
|
signatureReplacement.parentNode.removeChild(signatureReplacement);
|
|
}
|
|
}
|
|
}, 100);
|
|
}, 100);
|
|
};
|
|
|
|
// Export functions
|
|
const exportPDF = async () => {
|
|
// Only run on client side
|
|
if (process.server || typeof window === "undefined") {
|
|
console.warn("PDF export attempted on server side");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
console.log("Starting PDF export...");
|
|
|
|
// Get the document title for filename if available
|
|
const cooperativeName = formData.value.cooperativeName || "document";
|
|
const filename = `${cooperativeName.replace(
|
|
/[^a-zA-Z0-9]/g,
|
|
"_"
|
|
)}_membership_agreement.pdf`;
|
|
|
|
console.log("Generated filename:", filename);
|
|
|
|
await exportToPDF(".document-page", filename);
|
|
|
|
console.log("PDF export completed successfully");
|
|
} catch (error) {
|
|
console.error("PDF export failed:", error);
|
|
|
|
// Show more specific error message
|
|
const errorMessage = error?.message || "Unknown error occurred";
|
|
alert(
|
|
`PDF generation failed: ${errorMessage}\n\nFalling back to print dialog.`
|
|
);
|
|
|
|
// Fallback to print dialog if PDF generation fails
|
|
window.print();
|
|
}
|
|
};
|
|
|
|
const exportText = () => {
|
|
const content = extractTextContent();
|
|
downloadFile(content, "membership_agreement.txt", "text/plain");
|
|
};
|
|
|
|
const exportMarkdown = () => {
|
|
const content = convertToMarkdown();
|
|
downloadFile(content, "membership_agreement.md", "text/markdown");
|
|
};
|
|
|
|
const extractTextContent = () => {
|
|
// Format date helper
|
|
const formatDate = (dateStr) => {
|
|
if (!dateStr) return "[_____]";
|
|
return new Date(dateStr).toLocaleDateString();
|
|
};
|
|
|
|
// Build the document content with actual data
|
|
const content = `
|
|
MEMBERSHIP AGREEMENT
|
|
====================
|
|
|
|
1. Who We Are
|
|
-------------
|
|
|
|
Cooperative Name: ${formData.value.cooperativeName || "[Cooperative Name]"}
|
|
Date Established: ${formatDate(formData.value.dateEstablished)}
|
|
|
|
Our Purpose: ${formData.value.purpose || "[Purpose]"}
|
|
|
|
Our Core Values: ${formData.value.coreValues || "[Core Values]"}
|
|
|
|
Current Members:
|
|
${
|
|
formData.value.members && formData.value.members.some((m) => m.name)
|
|
? formData.value.members
|
|
.map((member, index) =>
|
|
member.name
|
|
? `${index + 1}. ${member.name}${
|
|
member.email ? ` (${member.email})` : ""
|
|
}${
|
|
member.joinDate
|
|
? ` - Joined: ${formatDate(member.joinDate)}`
|
|
: ""
|
|
}${member.role ? ` - Role: ${member.role}` : ""}`
|
|
: ""
|
|
)
|
|
.filter(Boolean)
|
|
.join("\n")
|
|
: "[No members added yet]"
|
|
}
|
|
|
|
2. Membership
|
|
-------------
|
|
|
|
Who Can Be a Member
|
|
|
|
Any person who:
|
|
|
|
• Shares our values and purpose
|
|
• Contributes labour to the cooperative (by doing actual work, not just investing money)
|
|
• Commits to collective decision-making
|
|
• Participates in governance responsibilities
|
|
|
|
Becoming a Member
|
|
|
|
New members join through a consent process, which means existing members must agree that adding this person won't harm the cooperative.
|
|
|
|
1. Trial period of ${
|
|
formData.value.trialPeriodMonths || "[___]"
|
|
} months working together
|
|
2. Values alignment conversation
|
|
3. Consent decision by current members
|
|
4. Optional - Equal buy-in contribution of $${
|
|
formData.value.buyInAmount || "[___]"
|
|
} (can be paid over time or waived based on need)
|
|
|
|
Leaving the Cooperative
|
|
|
|
Members can leave anytime with ${
|
|
formData.value.noticeDays || "[___]"
|
|
} days notice. The cooperative will:
|
|
|
|
• Pay out their share of any surplus within ${
|
|
formData.value.surplusPayoutDays || "[___]"
|
|
} days
|
|
• Return their buy-in contribution within ${
|
|
formData.value.buyInReturnDays || "[___]"
|
|
} days
|
|
• Maintain respectful ongoing relationships when possible
|
|
|
|
3. How We Make Decisions
|
|
------------------------
|
|
|
|
Consent-Based Decisions
|
|
|
|
We use consent, not consensus. This means we move forward when no one has a principled objection that would harm the cooperative. An objection must explain how the proposal would contradict our values or threaten our sustainability.
|
|
|
|
Day-to-Day Decisions
|
|
|
|
Decisions under $${
|
|
formData.value.dayToDayLimit || "[___]"
|
|
} can be made by any member. Just tell others what you did at the next meeting.
|
|
|
|
Regular Decisions
|
|
|
|
Decisions between $${formData.value.regularDecisionMin || "[___]"} and $${
|
|
formData.value.regularDecisionMax || "[___]"
|
|
} need consent from members present at a meeting (minimum 2 members).
|
|
|
|
Major Decisions
|
|
|
|
These require consent from all members:
|
|
• Adding or removing members
|
|
• Changing this agreement
|
|
• Taking on debt over $${formData.value.majorDebtThreshold || "[___]"}
|
|
• Fundamental changes to our purpose or structure
|
|
• Dissolution of the cooperative
|
|
|
|
Meeting Structure
|
|
|
|
• We meet ${
|
|
formData.value.meetingFrequency || "[___]"
|
|
} to make decisions together
|
|
• Emergency meetings need ${
|
|
formData.value.emergencyNoticeHours || "[___]"
|
|
} hours notice
|
|
• All members can add items to the agenda
|
|
• We keep simple records of what we decide
|
|
|
|
4. Money and Labour
|
|
-------------------
|
|
|
|
Equal Ownership
|
|
|
|
Each member owns an equal share of the cooperative, regardless of when they joined or how much money they put in.
|
|
|
|
Paying Ourselves
|
|
|
|
• Base hourly rate: $${formData.value.baseRate || "[___]"}/hour for all members
|
|
• Monthly draw: $${
|
|
formData.value.monthlyDraw || "[___]"
|
|
} per month (if applicable)
|
|
• Payment date: ${formData.value.paymentDay || "[___]"}th of each month
|
|
• Surplus sharing: ${
|
|
formData.value.surplusFrequency || "[___]"
|
|
}ly based on hours worked
|
|
|
|
Work Expectations
|
|
|
|
• Target hours per week: ${formData.value.targetHours || "[___]"} hours
|
|
• All work counts equally - admin, client work, business development
|
|
• We track hours honestly and transparently
|
|
• Flexible scheduling based on personal needs and business requirements
|
|
|
|
Financial Transparency
|
|
|
|
• All members can access all financial records anytime
|
|
• Monthly financial updates shared with everyone
|
|
• Annual financial review conducted together
|
|
• No secret salaries or hidden expenses
|
|
|
|
5. Roles and Responsibilities
|
|
-----------------------------
|
|
|
|
Rotating Roles
|
|
|
|
We rotate operational roles every ${
|
|
formData.value.roleRotationMonths || "[___]"
|
|
} months to share knowledge and prevent burnout. Current roles include:
|
|
|
|
• Financial coordinator (bookkeeping, invoicing, payments)
|
|
• Client relationship manager (main point of contact)
|
|
• Operations coordinator (scheduling, project management)
|
|
• Business development (marketing, new client outreach)
|
|
|
|
Shared Responsibilities
|
|
|
|
All members participate in:
|
|
• Weekly planning and check-in meetings
|
|
• Monthly financial review
|
|
• Annual strategic planning
|
|
• Conflict resolution when needed
|
|
• Onboarding new members
|
|
|
|
6. Conflict and Care
|
|
--------------------
|
|
|
|
When Conflict Happens
|
|
|
|
1. Direct conversation between parties (if comfortable)
|
|
2. Bring in a neutral member as mediator
|
|
3. Full group conversation if needed
|
|
4. External mediation if we can't resolve it ourselves
|
|
5. As a last resort, consent process about membership
|
|
|
|
Care Commitments
|
|
|
|
• We check in about capacity and wellbeing regularly
|
|
• We adjust workload when someone is struggling
|
|
• We celebrate successes and support through failures
|
|
• We maintain boundaries between work and personal relationships
|
|
• We commit to direct, kind communication
|
|
|
|
7. Changing This Agreement
|
|
--------------------------
|
|
|
|
This agreement gets reviewed every ${
|
|
formData.value.reviewFrequency || "[___]"
|
|
} and can be changed anytime with consent from all members. We'll update it as we learn what works for us.
|
|
|
|
8. If We Need to Close
|
|
----------------------
|
|
|
|
If the cooperative dissolves:
|
|
• Pay all debts and obligations first
|
|
• Return member buy-ins
|
|
• Donate remaining assets to ${
|
|
formData.value.assetDonationTarget || "[organization to be determined]"
|
|
}
|
|
• Close all legal and financial accounts
|
|
• Celebrate what we built together
|
|
|
|
9. Legal Bits
|
|
-------------
|
|
|
|
Legal Structure: ${formData.value.legalStructure || "[To be determined]"}
|
|
Registered Location: ${
|
|
formData.value.registeredLocation || "[To be determined]"
|
|
}
|
|
Fiscal Year End: ${formData.value.fiscalYearEndMonth || "December"} ${
|
|
formData.value.fiscalYearEndDay || "31"
|
|
}
|
|
|
|
10. Agreement Review
|
|
--------------------
|
|
|
|
Last Updated: ${formatDate(formData.value.lastUpdated)}
|
|
Next Review: ${formatDate(formData.value.nextReview) || "[To be scheduled]"}
|
|
|
|
Member Signatures
|
|
-----------------
|
|
|
|
By signing below, we agree to these terms and commit to working together as equals in this cooperative.
|
|
|
|
${
|
|
formData.value.members && formData.value.members.some((m) => m.name)
|
|
? formData.value.members
|
|
.map((member, index) =>
|
|
member.name
|
|
? `${index + 1}. ${
|
|
member.name
|
|
}\n Signature: ___________________________ Date: ___________\n`
|
|
: ""
|
|
)
|
|
.filter(Boolean)
|
|
.join("\n")
|
|
: "Member signatures:\n\n1. ___________________________ Date: ___________\n\n2. ___________________________ Date: ___________\n"
|
|
}
|
|
`;
|
|
|
|
return content.trim();
|
|
};
|
|
|
|
const convertToMarkdown = () => {
|
|
// Format date helper
|
|
const formatDate = (dateStr) => {
|
|
if (!dateStr) return "[_____]";
|
|
return new Date(dateStr).toLocaleDateString();
|
|
};
|
|
|
|
// Build the document content with actual data in Markdown format
|
|
const content = `# MEMBERSHIP AGREEMENT
|
|
|
|
## 1. Who We Are
|
|
|
|
**Cooperative Name:** ${
|
|
formData.value.cooperativeName || "[Cooperative Name]"
|
|
}
|
|
**Date Established:** ${formatDate(formData.value.dateEstablished)}
|
|
|
|
**Our Purpose:** ${formData.value.purpose || "[Purpose]"}
|
|
|
|
**Our Core Values:** ${formData.value.coreValues || "[Core Values]"}
|
|
|
|
### Current Members
|
|
|
|
${
|
|
formData.value.members && formData.value.members.some((m) => m.name)
|
|
? formData.value.members
|
|
.map((member, index) =>
|
|
member.name
|
|
? `${index + 1}. **${member.name}**${
|
|
member.email ? ` (${member.email})` : ""
|
|
}${
|
|
member.joinDate
|
|
? ` \n Joined: ${formatDate(member.joinDate)}`
|
|
: ""
|
|
}${member.role ? ` \n Role: ${member.role}` : ""}`
|
|
: ""
|
|
)
|
|
.filter(Boolean)
|
|
.join("\n\n")
|
|
: "*No members added yet*"
|
|
}
|
|
|
|
## 2. Membership
|
|
|
|
### Who Can Be a Member
|
|
|
|
Any person who:
|
|
|
|
- Shares our values and purpose
|
|
- Contributes labour to the cooperative (by doing actual work, not just investing money)
|
|
- Commits to collective decision-making
|
|
- Participates in governance responsibilities
|
|
|
|
### Becoming a Member
|
|
|
|
New members join through a consent process, which means existing members must agree that adding this person won't harm the cooperative.
|
|
|
|
1. Trial period of **${
|
|
formData.value.trialPeriodMonths || "[___]"
|
|
}** months working together
|
|
2. Values alignment conversation
|
|
3. Consent decision by current members
|
|
4. Optional - Equal buy-in contribution of **$${
|
|
formData.value.buyInAmount || "[___]"
|
|
}** (can be paid over time or waived based on need)
|
|
|
|
### Leaving the Cooperative
|
|
|
|
Members can leave anytime with **${
|
|
formData.value.noticeDays || "[___]"
|
|
}** days notice. The cooperative will:
|
|
|
|
- Pay out their share of any surplus within **${
|
|
formData.value.surplusPayoutDays || "[___]"
|
|
}** days
|
|
- Return their buy-in contribution within **${
|
|
formData.value.buyInReturnDays || "[___]"
|
|
}** days
|
|
- Maintain respectful ongoing relationships when possible
|
|
|
|
## 3. How We Make Decisions
|
|
|
|
### Consent-Based Decisions
|
|
|
|
We use consent, not consensus. This means we move forward when no one has a principled objection that would harm the cooperative. An objection must explain how the proposal would contradict our values or threaten our sustainability.
|
|
|
|
### Day-to-Day Decisions
|
|
|
|
Decisions under **$${
|
|
formData.value.dayToDayLimit || "[___]"
|
|
}** can be made by any member. Just tell others what you did at the next meeting.
|
|
|
|
### Regular Decisions
|
|
|
|
Decisions between **$${formData.value.regularDecisionMin || "[___]"}** and **$${
|
|
formData.value.regularDecisionMax || "[___]"
|
|
}** need consent from members present at a meeting (minimum 2 members).
|
|
|
|
### Major Decisions
|
|
|
|
These require consent from all members:
|
|
- Adding or removing members
|
|
- Changing this agreement
|
|
- Taking on debt over **$${formData.value.majorDebtThreshold || "[___]"}**
|
|
- Fundamental changes to our purpose or structure
|
|
- Dissolution of the cooperative
|
|
|
|
### Meeting Structure
|
|
|
|
- We meet **${
|
|
formData.value.meetingFrequency || "[___]"
|
|
}** to make decisions together
|
|
- Emergency meetings need **${
|
|
formData.value.emergencyNoticeHours || "[___]"
|
|
}** hours notice
|
|
- All members can add items to the agenda
|
|
- We keep simple records of what we decide
|
|
|
|
## 4. Money and Labour
|
|
|
|
### Equal Ownership
|
|
|
|
Each member owns an equal share of the cooperative, regardless of when they joined or how much money they put in.
|
|
|
|
### Paying Ourselves
|
|
|
|
- Base hourly rate: **$${
|
|
formData.value.baseRate || "[___]"
|
|
}/hour** for all members
|
|
- Monthly draw: **$${
|
|
formData.value.monthlyDraw || "[___]"
|
|
}** per month (if applicable)
|
|
- Payment date: **${formData.value.paymentDay || "[___]"}th** of each month
|
|
- Surplus sharing: **${
|
|
formData.value.surplusFrequency || "[___]"
|
|
}ly** based on hours worked
|
|
|
|
### Work Expectations
|
|
|
|
- Target hours per week: **${formData.value.targetHours || "[___]"}** hours
|
|
- All work counts equally - admin, client work, business development
|
|
- We track hours honestly and transparently
|
|
- Flexible scheduling based on personal needs and business requirements
|
|
|
|
### Financial Transparency
|
|
|
|
- All members can access all financial records anytime
|
|
- Monthly financial updates shared with everyone
|
|
- Annual financial review conducted together
|
|
- No secret salaries or hidden expenses
|
|
|
|
## 5. Roles and Responsibilities
|
|
|
|
### Rotating Roles
|
|
|
|
We rotate operational roles every **${
|
|
formData.value.roleRotationMonths || "[___]"
|
|
}** months to share knowledge and prevent burnout. Current roles include:
|
|
|
|
- Financial coordinator (bookkeeping, invoicing, payments)
|
|
- Client relationship manager (main point of contact)
|
|
- Operations coordinator (scheduling, project management)
|
|
- Business development (marketing, new client outreach)
|
|
|
|
### Shared Responsibilities
|
|
|
|
All members participate in:
|
|
- Weekly planning and check-in meetings
|
|
- Monthly financial review
|
|
- Annual strategic planning
|
|
- Conflict resolution when needed
|
|
- Onboarding new members
|
|
|
|
## 6. Conflict and Care
|
|
|
|
### When Conflict Happens
|
|
|
|
1. Direct conversation between parties (if comfortable)
|
|
2. Bring in a neutral member as mediator
|
|
3. Full group conversation if needed
|
|
4. External mediation if we can't resolve it ourselves
|
|
5. As a last resort, consent process about membership
|
|
|
|
### Care Commitments
|
|
|
|
- We check in about capacity and wellbeing regularly
|
|
- We adjust workload when someone is struggling
|
|
- We celebrate successes and support through failures
|
|
- We maintain boundaries between work and personal relationships
|
|
- We commit to direct, kind communication
|
|
|
|
## 7. Changing This Agreement
|
|
|
|
This agreement gets reviewed every **${
|
|
formData.value.reviewFrequency || "[___]"
|
|
}** and can be changed anytime with consent from all members. We'll update it as we learn what works for us.
|
|
|
|
## 8. If We Need to Close
|
|
|
|
If the cooperative dissolves:
|
|
- Pay all debts and obligations first
|
|
- Return member buy-ins
|
|
- Donate remaining assets to **${
|
|
formData.value.assetDonationTarget || "[organization to be determined]"
|
|
}**
|
|
- Close all legal and financial accounts
|
|
- Celebrate what we built together
|
|
|
|
## 9. Legal Bits
|
|
|
|
**Legal Structure:** ${formData.value.legalStructure || "[To be determined]"}
|
|
**Registered Location:** ${
|
|
formData.value.registeredLocation || "[To be determined]"
|
|
}
|
|
**Fiscal Year End:** ${formData.value.fiscalYearEndMonth || "December"} ${
|
|
formData.value.fiscalYearEndDay || "31"
|
|
}
|
|
|
|
## 10. Agreement Review
|
|
|
|
**Last Updated:** ${formatDate(formData.value.lastUpdated)}
|
|
**Next Review:** ${formatDate(formData.value.nextReview) || "[To be scheduled]"}
|
|
|
|
## Member Signatures
|
|
|
|
By signing below, we agree to these terms and commit to working together as equals in this cooperative.
|
|
|
|
${
|
|
formData.value.members && formData.value.members.some((m) => m.name)
|
|
? formData.value.members
|
|
.map((member, index) =>
|
|
member.name
|
|
? `**${index + 1}. ${
|
|
member.name
|
|
}** \nSignature: ___________________________ Date: ___________\n`
|
|
: ""
|
|
)
|
|
.filter(Boolean)
|
|
.join("\n")
|
|
: "**Member signatures:**\n\n**1.** ___________________________ \nSignature: ___________________________ Date: ___________\n\n**2.** ___________________________ \nSignature: ___________________________ Date: ___________\n"
|
|
}
|
|
`;
|
|
|
|
return content.trim();
|
|
};
|
|
|
|
const downloadFile = (content, filename, mimeType) => {
|
|
const blob = new Blob([content], { type: mimeType });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement("a");
|
|
a.href = url;
|
|
a.download = filename;
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
URL.revokeObjectURL(url);
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* Ubuntu font import */
|
|
@import url("https://fonts.googleapis.com/css2?family=Ubuntu:wght@300;400;500;700&family=Ubuntu+Mono:wght@400;700&display=swap");
|
|
@reference "tailwindcss";
|
|
|
|
.template-content {
|
|
max-width: none;
|
|
line-height: 1.6;
|
|
color: #1f2937;
|
|
}
|
|
|
|
/* Section styling */
|
|
.section-card {
|
|
@apply border border-neutral-200 dark:border-neutral-800 rounded-lg p-5 mb-8;
|
|
}
|
|
|
|
.section-card:last-child::after {
|
|
display: none;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 1.75rem;
|
|
font-weight: 800;
|
|
color: #111827;
|
|
margin: 0 0 1rem 0;
|
|
padding: 0;
|
|
letter-spacing: -0.025em;
|
|
}
|
|
|
|
.subsection-title {
|
|
font-size: 1.25rem;
|
|
font-weight: 600;
|
|
color: #374151;
|
|
margin: 0 0 0.75rem 0;
|
|
text-decoration: none;
|
|
border-bottom: 1px solid #e5e7eb;
|
|
padding-bottom: 0.25rem;
|
|
}
|
|
|
|
/* Content styling */
|
|
.content-paragraph {
|
|
margin-bottom: 0.75rem;
|
|
line-height: 1.6;
|
|
text-align: left;
|
|
}
|
|
|
|
.content-list {
|
|
margin: 0.5rem 0;
|
|
padding-left: 1.5rem;
|
|
}
|
|
|
|
.content-list li {
|
|
margin-bottom: 0.5rem;
|
|
line-height: 1.5;
|
|
display: list-item;
|
|
list-style-position: outside;
|
|
}
|
|
|
|
.content-list.numbered {
|
|
list-style-type: decimal;
|
|
counter-reset: list-counter;
|
|
}
|
|
|
|
.content-list.numbered li {
|
|
list-style-type: decimal;
|
|
display: list-item;
|
|
}
|
|
|
|
.content-list:not(.numbered) {
|
|
list-style-type: disc;
|
|
}
|
|
|
|
.content-list:not(.numbered) li {
|
|
list-style-type: disc;
|
|
display: list-item;
|
|
}
|
|
|
|
/* Ensure bullets are visible even with flex items */
|
|
.content-list li.flex {
|
|
display: list-item;
|
|
}
|
|
|
|
.content-list li .flex {
|
|
display: flex;
|
|
width: 100%;
|
|
}
|
|
|
|
/* Fix flex list items to show bullets */
|
|
.content-list li[class*="flex"] {
|
|
display: list-item !important;
|
|
list-style-position: outside !important;
|
|
}
|
|
|
|
/* Ensure numbered lists show numbers even with flex */
|
|
.content-list.numbered li[class*="flex"] {
|
|
list-style-type: decimal !important;
|
|
}
|
|
|
|
/* Ensure bullet lists show bullets even with flex */
|
|
.content-list:not(.numbered) li[class*="flex"] {
|
|
list-style-type: disc !important;
|
|
}
|
|
|
|
.form-group-inline .inline-field:focus {
|
|
background: #f3f4f6;
|
|
outline: 1px solid #3b82f6;
|
|
outline-offset: -1px;
|
|
}
|
|
|
|
.form-group-block .block-field {
|
|
display: block;
|
|
width: 100%;
|
|
margin-top: 0.25rem;
|
|
border: none;
|
|
background: #f9fafb;
|
|
padding: 0.5rem;
|
|
border-radius: 0.25rem;
|
|
}
|
|
|
|
.form-group-block .block-field:focus {
|
|
background: #f3f4f6;
|
|
outline: 1px solid #3b82f6;
|
|
outline-offset: -1px;
|
|
}
|
|
|
|
.form-group-large {
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.form-group-large .large-field {
|
|
@apply block w-full mt-2 text-lg rounded-md border-none transition-colors duration-150 ease-in-out;
|
|
}
|
|
|
|
.form-group-large .large-field:focus {
|
|
background: #f3f4f6;
|
|
box-shadow: none;
|
|
outline: 2px solid #3b82f6;
|
|
outline-offset: -2px;
|
|
}
|
|
|
|
.number-field {
|
|
min-width: 80px !important;
|
|
text-align: center;
|
|
}
|
|
|
|
.wide-field {
|
|
min-width: 250px !important;
|
|
}
|
|
|
|
/* Fiscal year group styling */
|
|
.fiscal-year-group {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.fiscal-year-group .flex {
|
|
align-items: center;
|
|
}
|
|
|
|
/* Signature space styling */
|
|
.signature-space {
|
|
margin-top: 2rem;
|
|
padding: 2rem 1rem;
|
|
border: 1px dashed #d1d5db;
|
|
border-radius: 0.375rem;
|
|
background: #f9fafb;
|
|
min-height: 4rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
/* Review dates styling */
|
|
.review-dates {
|
|
background: #f9fafb;
|
|
padding: 1rem;
|
|
border-radius: 0.375rem;
|
|
border-left: 3px solid #3b82f6;
|
|
}
|
|
|
|
/* Hide elements from print */
|
|
.no-print {
|
|
display: block;
|
|
}
|
|
|
|
/* Print optimizations */
|
|
@media print {
|
|
.no-print {
|
|
display: none !important;
|
|
}
|
|
|
|
.template-content {
|
|
font-size: 10pt;
|
|
line-height: 1.3;
|
|
}
|
|
|
|
.document-title {
|
|
font-size: 16pt;
|
|
background: none;
|
|
padding: 0.5rem 0;
|
|
border-width: 1px;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 14pt;
|
|
}
|
|
|
|
.section-card {
|
|
box-shadow: none;
|
|
border: none;
|
|
break-inside: avoid;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.section-card::after {
|
|
height: 1px;
|
|
background: #000;
|
|
margin: 1rem 0;
|
|
}
|
|
|
|
.signature-space {
|
|
border: 1px solid #000;
|
|
background: none;
|
|
min-height: 3rem;
|
|
padding: 1rem;
|
|
}
|
|
|
|
.review-dates {
|
|
background: none;
|
|
border: 1px solid #000;
|
|
padding: 0.5rem;
|
|
}
|
|
|
|
.large-field,
|
|
.inline-field,
|
|
.block-field {
|
|
background: none !important;
|
|
border: none !important;
|
|
outline: 1px solid #000 !important;
|
|
padding: 0.25rem !important;
|
|
}
|
|
|
|
.font-selector {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
/* Font selector styling */
|
|
.font-selector {
|
|
position: fixed;
|
|
top: 1rem;
|
|
right: 1rem;
|
|
z-index: 1000;
|
|
background: white;
|
|
padding: 0.75rem;
|
|
border-radius: 6px;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
border: 1px solid #d1d5db;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.font-selector label {
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
color: #374151;
|
|
margin: 0;
|
|
}
|
|
|
|
.font-select {
|
|
min-width: 140px;
|
|
}
|
|
|
|
/* Font families */
|
|
.template-content.font-source-serif,
|
|
.template-content.font-source-serif * {
|
|
font-family: "Source Serif 4", "Source Serif Pro", Georgia, serif !important;
|
|
}
|
|
|
|
.template-content.font-ubuntu,
|
|
.template-content.font-ubuntu * {
|
|
font-family: "Ubuntu", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
sans-serif !important;
|
|
}
|
|
|
|
.template-content.font-inter,
|
|
.template-content.font-inter * {
|
|
font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
sans-serif !important;
|
|
}
|
|
|
|
/* Template wrapper and document styling */
|
|
/* rely on Tailwind bg utilities applied on wrapper */
|
|
.template-wrapper {
|
|
min-height: 100vh;
|
|
padding: 2rem;
|
|
font-family: "Ubuntu", monospace;
|
|
position: relative;
|
|
}
|
|
.template-wrapper::before {
|
|
content: "";
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-image: radial-gradient(
|
|
circle at 25% 25%,
|
|
black 1px,
|
|
transparent 1px
|
|
),
|
|
radial-gradient(circle at 75% 75%, black 1px, transparent 1px);
|
|
background-size: 8px 8px, 8px 8px;
|
|
background-position: 0 0, 4px 4px;
|
|
opacity: 0.1;
|
|
pointer-events: none;
|
|
z-index: -1;
|
|
}
|
|
|
|
.document-page::before {
|
|
content: "";
|
|
position: absolute;
|
|
top: 4px;
|
|
left: 4px;
|
|
right: -4px;
|
|
bottom: -4px;
|
|
background: black;
|
|
background-image: radial-gradient(white 1px, transparent 1px);
|
|
background-size: 2px 2px;
|
|
z-index: -1;
|
|
}
|
|
.document-page::after {
|
|
content: "";
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
border: 1px solid black;
|
|
z-index: 1;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* Export controls */
|
|
.export-controls {
|
|
max-width: 8.5in;
|
|
margin: 0 auto 1.5rem;
|
|
background: white;
|
|
border: 1px solid black;
|
|
padding: 1rem;
|
|
position: relative;
|
|
}
|
|
.export-controls::before {
|
|
content: "";
|
|
position: absolute;
|
|
top: 2px;
|
|
left: 2px;
|
|
right: -2px;
|
|
bottom: -2px;
|
|
background: black;
|
|
background-image: radial-gradient(white 1px, transparent 1px);
|
|
background-size: 2px 2px;
|
|
z-index: -1;
|
|
}
|
|
|
|
.export-content {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 1.5rem;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.export-section {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.75rem;
|
|
align-items: center;
|
|
flex: 1;
|
|
}
|
|
|
|
.export-buttons {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.75rem;
|
|
align-items: center;
|
|
}
|
|
|
|
.export-title {
|
|
font-weight: 600;
|
|
color: #374151;
|
|
margin: 0 1rem 0 0;
|
|
font-size: 0.875rem;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.separator {
|
|
width: 1px;
|
|
height: 2rem;
|
|
background: #d1d5db;
|
|
margin: 0 0.5rem;
|
|
}
|
|
|
|
.font-section {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.font-label {
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
color: #374151;
|
|
margin: 0;
|
|
}
|
|
|
|
.export-btn {
|
|
background: white;
|
|
border: 1px solid black;
|
|
padding: 0.5rem 1rem;
|
|
font-size: 0.875rem;
|
|
color: black;
|
|
cursor: pointer;
|
|
transition: all 0.1s ease;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
font-family: "Ubuntu Mono", monospace;
|
|
text-transform: uppercase;
|
|
font-weight: bold;
|
|
letter-spacing: 0.5px;
|
|
}
|
|
|
|
.export-btn:hover {
|
|
background: black;
|
|
color: white;
|
|
transform: translateY(-1px) translateX(-1px);
|
|
}
|
|
|
|
.export-btn.primary {
|
|
background: black;
|
|
color: white;
|
|
}
|
|
|
|
.export-btn.primary:hover {
|
|
background: black;
|
|
transform: translateY(-1px) translateX(-1px);
|
|
}
|
|
|
|
/* Bitmap aesthetic overrides - remove all rounded corners */
|
|
* {
|
|
border-radius: 0 !important;
|
|
font-family: "Ubuntu", monospace !important;
|
|
}
|
|
|
|
/* Form fields with bitmap styling */
|
|
input,
|
|
textarea,
|
|
select {
|
|
border: 1px solid black !important;
|
|
background: white !important;
|
|
color: black !important;
|
|
font-family: "Ubuntu Mono", monospace !important;
|
|
}
|
|
|
|
input:focus,
|
|
textarea:focus,
|
|
select:focus {
|
|
outline: 2px solid black !important;
|
|
outline-offset: -2px !important;
|
|
background: white !important;
|
|
}
|
|
|
|
/* Dark mode form fields */
|
|
html.dark input,
|
|
html.dark textarea,
|
|
html.dark select {
|
|
border: 1px solid white !important;
|
|
background: #0a0a0a !important;
|
|
color: white !important;
|
|
}
|
|
|
|
html.dark input:focus,
|
|
html.dark textarea:focus,
|
|
html.dark select:focus {
|
|
outline: 2px solid white !important;
|
|
background: #0a0a0a !important;
|
|
}
|
|
|
|
/* Buttons with bitmap styling */
|
|
button:not(.export-btn) {
|
|
background: white !important;
|
|
border: 1px solid black !important;
|
|
color: black !important;
|
|
font-family: "Ubuntu Mono", monospace !important;
|
|
text-transform: uppercase !important;
|
|
font-weight: bold !important;
|
|
letter-spacing: 0.5px !important;
|
|
}
|
|
|
|
button:not(.export-btn):hover {
|
|
background: black !important;
|
|
color: white !important;
|
|
transform: translateY(-1px) translateX(-1px) !important;
|
|
}
|
|
|
|
/* Remove any card styling roundness */
|
|
.section-card,
|
|
.form-group-large {
|
|
border-radius: 0 !important;
|
|
}
|
|
|
|
/* All text */
|
|
p,
|
|
span,
|
|
div {
|
|
font-family: "Ubuntu", monospace !important;
|
|
}
|
|
|
|
/* Mobile responsiveness */
|
|
@media (max-width: 768px) {
|
|
.template-wrapper {
|
|
padding: 1rem;
|
|
}
|
|
|
|
.export-content {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.export-section {
|
|
justify-content: center;
|
|
}
|
|
|
|
.separator {
|
|
width: 100%;
|
|
height: 1px;
|
|
margin: 0;
|
|
}
|
|
|
|
.export-buttons {
|
|
justify-content: center;
|
|
}
|
|
}
|
|
|
|
/* Professional Print Styles - Match PDF Export Quality */
|
|
@media print {
|
|
/* Page setup - professional document margins */
|
|
@page {
|
|
size: letter;
|
|
margin: 0.75in;
|
|
}
|
|
|
|
/* Global print reset */
|
|
* {
|
|
-webkit-print-color-adjust: exact !important;
|
|
print-color-adjust: exact !important;
|
|
}
|
|
|
|
/* Hide everything except the document content */
|
|
body > *:not(.template-wrapper),
|
|
#__nuxt > *:not(.template-wrapper),
|
|
.export-controls,
|
|
.no-print,
|
|
.no-pdf,
|
|
header,
|
|
nav,
|
|
footer,
|
|
.nuxt-loading,
|
|
[data-testid],
|
|
.nuxt-icon,
|
|
.app-header,
|
|
.page-header,
|
|
.brand,
|
|
.logo,
|
|
h1:contains("Urgent Tools"),
|
|
*:contains("Urgent Tools"):not(.document-title):not(.template-content *) {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Specifically hide any element that contains "Urgent Tools" text but isn't part of our document */
|
|
body *:not(.template-wrapper):not(.template-wrapper *) {
|
|
visibility: hidden !important;
|
|
}
|
|
|
|
.template-wrapper,
|
|
.template-wrapper * {
|
|
visibility: visible !important;
|
|
}
|
|
|
|
/* Document structure - clean and professional */
|
|
.template-wrapper {
|
|
background: white !important;
|
|
padding: 0 !important;
|
|
min-height: auto !important;
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
"Helvetica Neue", Arial, sans-serif !important;
|
|
font-size: 11pt !important;
|
|
line-height: 1.6 !important;
|
|
color: #000000 !important;
|
|
}
|
|
|
|
.document-page {
|
|
max-width: none !important;
|
|
width: 100% !important;
|
|
margin: 0 !important;
|
|
padding: 0 !important;
|
|
box-shadow: none !important;
|
|
border-radius: 0 !important;
|
|
background: white !important;
|
|
min-height: auto !important;
|
|
}
|
|
|
|
.template-content {
|
|
background: white !important;
|
|
padding: 0 !important;
|
|
max-width: none !important;
|
|
}
|
|
|
|
/* Professional header with black background - matching PDF but smaller */
|
|
.document-page::before {
|
|
content: "";
|
|
display: block;
|
|
width: 100%;
|
|
height: 0.8in;
|
|
background: #000000 !important;
|
|
margin: 0 0 0.15in 0;
|
|
position: relative;
|
|
-webkit-print-color-adjust: exact !important;
|
|
print-color-adjust: exact !important;
|
|
}
|
|
|
|
/* Document title styling - white text on black background */
|
|
.document-title {
|
|
position: relative !important;
|
|
z-index: 1 !important;
|
|
margin-top: -0.8in !important;
|
|
margin-bottom: 0.15in !important;
|
|
padding: 0.2in 0 0.1in 0 !important;
|
|
color: white !important;
|
|
background: transparent !important;
|
|
border: none !important;
|
|
font-size: 16pt !important;
|
|
font-weight: bold !important;
|
|
text-align: center !important;
|
|
text-transform: uppercase !important;
|
|
letter-spacing: 1pt !important;
|
|
page-break-after: avoid !important;
|
|
-webkit-print-color-adjust: exact !important;
|
|
print-color-adjust: exact !important;
|
|
}
|
|
|
|
/* Add cooperative name below title */
|
|
.document-title::after {
|
|
content: attr(data-coop-name);
|
|
display: block;
|
|
font-size: 10pt;
|
|
font-weight: normal;
|
|
margin-top: 0.1in;
|
|
color: white !important;
|
|
text-transform: none;
|
|
letter-spacing: normal;
|
|
-webkit-print-color-adjust: exact !important;
|
|
print-color-adjust: exact !important;
|
|
}
|
|
|
|
/* Section headers with professional gray background */
|
|
.section-title {
|
|
font-size: 14pt !important;
|
|
font-weight: bold !important;
|
|
margin: 20pt 0 12pt 0 !important;
|
|
padding: 6pt 10pt !important;
|
|
background: #f0f0f0 !important;
|
|
border-radius: 3pt !important;
|
|
color: #000000 !important;
|
|
page-break-after: avoid !important;
|
|
-webkit-print-color-adjust: exact !important;
|
|
print-color-adjust: exact !important;
|
|
}
|
|
|
|
/* Subsection headers */
|
|
.subsection-title {
|
|
font-size: 12pt !important;
|
|
font-weight: bold !important;
|
|
margin: 14pt 0 8pt 0 !important;
|
|
color: #000000 !important;
|
|
border-bottom: 0.5pt solid #cccccc !important;
|
|
padding-bottom: 2pt !important;
|
|
page-break-after: avoid !important;
|
|
}
|
|
|
|
/* Content paragraphs */
|
|
.content-paragraph,
|
|
p {
|
|
margin: 8pt 0 !important;
|
|
text-align: justify !important;
|
|
line-height: 1.5 !important;
|
|
color: #000000 !important;
|
|
font-size: 11pt !important;
|
|
orphans: 2 !important;
|
|
widows: 2 !important;
|
|
}
|
|
|
|
/* Lists with proper spacing */
|
|
.content-list,
|
|
ul,
|
|
ol {
|
|
margin: 8pt 0 !important;
|
|
padding-left: 20pt !important;
|
|
color: #000000 !important;
|
|
}
|
|
|
|
.content-list li,
|
|
li {
|
|
margin: 4pt 0 !important;
|
|
line-height: 1.4 !important;
|
|
color: #000000 !important;
|
|
font-size: 11pt !important;
|
|
page-break-inside: avoid !important;
|
|
}
|
|
|
|
/* Section cards */
|
|
.section-card {
|
|
margin: 16pt 0 !important;
|
|
padding: 0 !important;
|
|
border: none !important;
|
|
border-radius: 0 !important;
|
|
background: white !important;
|
|
page-break-inside: avoid !important;
|
|
}
|
|
|
|
.section-card::after {
|
|
display: none !important;
|
|
}
|
|
|
|
/* CRITICAL: Form inputs styled to look like filled-in text */
|
|
input[type="text"],
|
|
input[type="number"],
|
|
input[type="date"],
|
|
input[type="email"],
|
|
textarea,
|
|
select,
|
|
.inline-field,
|
|
.large-field,
|
|
.block-field,
|
|
.number-field,
|
|
.wide-field {
|
|
/* Remove all input styling */
|
|
background: transparent !important;
|
|
border: none !important;
|
|
border-bottom: 0.75pt solid #000000 !important;
|
|
color: #000000 !important;
|
|
font-family: inherit !important;
|
|
font-size: inherit !important;
|
|
font-weight: bold !important;
|
|
padding: 0 2pt !important;
|
|
margin: 0 1pt !important;
|
|
outline: none !important;
|
|
box-shadow: none !important;
|
|
-webkit-appearance: none !important;
|
|
appearance: none !important;
|
|
display: inline !important;
|
|
vertical-align: baseline !important;
|
|
min-width: 80pt !important;
|
|
height: auto !important;
|
|
line-height: inherit !important;
|
|
}
|
|
|
|
/* Special handling for empty inputs - show as underlined blanks */
|
|
input:placeholder-shown:not([value]),
|
|
input[value=""]:not(:focus),
|
|
textarea:placeholder-shown:not([value]),
|
|
textarea[value=""]:not(:focus) {
|
|
border-bottom: 0.75pt solid #000000 !important;
|
|
min-width: 100pt !important;
|
|
height: 11pt !important;
|
|
display: inline-block !important;
|
|
}
|
|
|
|
/* Filled inputs should look like handwritten text */
|
|
input:not(:placeholder-shown),
|
|
input[value]:not([value=""]),
|
|
textarea:not(:placeholder-shown),
|
|
textarea[value]:not([value=""]),
|
|
select:not([value=""]) {
|
|
border-bottom: none !important;
|
|
font-weight: bold !important;
|
|
background: transparent !important;
|
|
}
|
|
|
|
/* Ensure input values are visible in print by using CSS content */
|
|
input[data-print-value]:after {
|
|
content: attr(data-print-value) !important;
|
|
font-weight: bold !important;
|
|
color: #000000 !important;
|
|
}
|
|
|
|
/* Textarea specific styling */
|
|
textarea {
|
|
border: none !important;
|
|
padding: 2pt !important;
|
|
margin: 0 !important;
|
|
resize: none !important;
|
|
border-radius: 0 !important;
|
|
min-height: auto !important;
|
|
line-height: 1.5 !important;
|
|
font-weight: normal !important;
|
|
vertical-align: top !important;
|
|
overflow: hidden !important;
|
|
}
|
|
|
|
/* Select dropdowns */
|
|
select {
|
|
-webkit-appearance: none !important;
|
|
appearance: none !important;
|
|
background-image: none !important;
|
|
border-bottom: none !important;
|
|
}
|
|
|
|
/* Form labels */
|
|
.form-group-large label,
|
|
label {
|
|
font-weight: bold !important;
|
|
color: #000000 !important;
|
|
display: block !important;
|
|
margin-bottom: 3pt !important;
|
|
font-size: 10pt !important;
|
|
}
|
|
|
|
.form-group-large {
|
|
margin: 10pt 0 !important;
|
|
page-break-inside: avoid !important;
|
|
}
|
|
|
|
/* Layout simplification for print */
|
|
.grid {
|
|
display: block !important;
|
|
}
|
|
|
|
.grid > div {
|
|
margin: 6pt 0 !important;
|
|
padding: 2pt 0 !important;
|
|
}
|
|
|
|
.flex {
|
|
display: block !important;
|
|
}
|
|
|
|
.flex.items-baseline {
|
|
display: inline !important;
|
|
}
|
|
|
|
.flex.items-baseline > * {
|
|
display: inline !important;
|
|
margin: 0 2pt !important;
|
|
}
|
|
|
|
.flex > *:not(.flex.items-baseline > *) {
|
|
display: block !important;
|
|
margin: 3pt 0 !important;
|
|
}
|
|
|
|
/* Spacing utilities */
|
|
.space-y-4 > * + *,
|
|
.space-y-6 > * + *,
|
|
.space-y-8 > * + * {
|
|
margin-top: 10pt !important;
|
|
}
|
|
|
|
/* Hide all buttons and UI controls */
|
|
button,
|
|
.export-btn,
|
|
.font-select,
|
|
.export-controls,
|
|
[class*="button"],
|
|
[type="button"],
|
|
[role="button"],
|
|
.no-print,
|
|
.no-pdf {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Hide the "Add Member" button specifically */
|
|
button:contains("Add Member"),
|
|
[icon="i-heroicons-plus"] {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Member management sections */
|
|
.border-neutral-200 {
|
|
border: none !important;
|
|
background: transparent !important;
|
|
padding: 0 !important;
|
|
margin: 10pt 0 !important;
|
|
page-break-inside: avoid !important;
|
|
}
|
|
|
|
/* Hide member management UI elements */
|
|
.border-neutral-200 button,
|
|
.border-neutral-200 .flex button,
|
|
[icon*="heroicons"],
|
|
.flex.items-start.justify-between h4,
|
|
.border-neutral-200 h4 {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Member cards layout - convert to simple blocks */
|
|
.border-neutral-200 .grid {
|
|
display: block !important;
|
|
}
|
|
|
|
.border-neutral-200 .grid > * {
|
|
display: block !important;
|
|
margin: 5pt 0 !important;
|
|
}
|
|
|
|
/* Member card titles and management elements */
|
|
.border-neutral-200 .flex.items-start.justify-between {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Style member information as clean blocks */
|
|
.border-neutral-200 .form-group-large {
|
|
margin: 6pt 0 !important;
|
|
}
|
|
|
|
.border-neutral-200 .form-group-large label {
|
|
font-size: 10pt !important;
|
|
font-weight: bold !important;
|
|
margin-bottom: 2pt !important;
|
|
}
|
|
|
|
/* Special areas styling */
|
|
.signature-space {
|
|
display: none !important;
|
|
}
|
|
|
|
.print-signatures {
|
|
margin-top: 20pt !important;
|
|
padding: 0 !important;
|
|
background: transparent !important;
|
|
color: #000000 !important;
|
|
}
|
|
|
|
.print-signatures p {
|
|
color: #000000 !important;
|
|
font-family: inherit !important;
|
|
line-height: 1.5 !important;
|
|
}
|
|
|
|
.print-signatures div {
|
|
page-break-inside: avoid !important;
|
|
}
|
|
|
|
.review-dates {
|
|
background: #f8f8f8 !important;
|
|
padding: 8pt !important;
|
|
border-radius: 3pt !important;
|
|
border-left: 2pt solid #3b82f6 !important;
|
|
margin: 10pt 0 !important;
|
|
-webkit-print-color-adjust: exact !important;
|
|
print-color-adjust: exact !important;
|
|
}
|
|
|
|
/* Page break controls */
|
|
.page-break-before {
|
|
page-break-before: always !important;
|
|
}
|
|
.page-break-after {
|
|
page-break-after: always !important;
|
|
}
|
|
.page-break-inside-avoid {
|
|
page-break-inside: avoid !important;
|
|
}
|
|
}
|
|
/* Dark mode enhancements for readability and contrast */
|
|
html.dark .template-content {
|
|
color: #e5e7eb;
|
|
}
|
|
|
|
html.dark .document-title {
|
|
color: #f9fafb;
|
|
border-top-color: #f9fafb;
|
|
border-bottom-color: #f9fafb;
|
|
background: linear-gradient(135deg, #111827 0%, #1f2937 100%);
|
|
}
|
|
|
|
html.dark .section-card::after {
|
|
background: linear-gradient(90deg, #444 0%, #333 50%, #444 100%);
|
|
}
|
|
|
|
html.dark .section-title {
|
|
color: #f9fafb;
|
|
}
|
|
html.dark .subsection-title {
|
|
color: #e5e7eb;
|
|
border-bottom-color: #4b5563;
|
|
}
|
|
html.dark .content-paragraph {
|
|
color: #e5e7eb;
|
|
}
|
|
html.dark .content-list,
|
|
html.dark .content-list li {
|
|
color: #e5e7eb;
|
|
}
|
|
|
|
html.dark .signature-space {
|
|
border-color: #374151;
|
|
background: #0a0a0a;
|
|
}
|
|
html.dark .review-dates {
|
|
background: #0f172a;
|
|
border-left-color: #60a5fa;
|
|
}
|
|
|
|
/* Dither overlay inversion */
|
|
html.dark .template-wrapper::before {
|
|
background-image: radial-gradient(
|
|
circle at 25% 25%,
|
|
white 1px,
|
|
transparent 1px
|
|
),
|
|
radial-gradient(circle at 75% 75%, white 1px, transparent 1px);
|
|
opacity: 0.12;
|
|
}
|
|
|
|
/* Document page inversion for dark */
|
|
html.dark .document-page {
|
|
background: #0a0a0a;
|
|
}
|
|
html.dark .document-page::before {
|
|
background: white;
|
|
background-image: radial-gradient(black 1px, transparent 1px);
|
|
}
|
|
html.dark .document-page::after {
|
|
border-color: white;
|
|
}
|
|
|
|
/* Export controls */
|
|
html.dark .export-controls {
|
|
background: #0a0a0a;
|
|
border-color: white;
|
|
}
|
|
html.dark .export-controls::before {
|
|
background: white;
|
|
background-image: radial-gradient(black 1px, transparent 1px);
|
|
}
|
|
html.dark .export-title,
|
|
html.dark .font-label {
|
|
color: #e5e7eb;
|
|
}
|
|
|
|
/* Buttons in dark */
|
|
html.dark .export-btn {
|
|
background: #0a0a0a;
|
|
border-color: white;
|
|
color: white;
|
|
}
|
|
html.dark .export-btn:hover {
|
|
background: white;
|
|
color: black;
|
|
}
|
|
html.dark .export-btn.primary {
|
|
background: white;
|
|
color: black;
|
|
}
|
|
html.dark .export-btn.primary:hover {
|
|
background: white;
|
|
}
|
|
</style>
|