A partnership conversation for WCF Insurance

People Matter™.
So Does Their Health.

For 108 years, WCF Insurance has built its reputation on the simple, trademarked promise that People Matter™. That's the same compass The Force for Health® Network is built on — turning every person, family, and community into a Force for Health for themselves and the people around them. This page is a conversation starter for what a partnership across your six-state footprint could look like.

$2.2M
Given back to communities by WCF in 2024
6 States
Western P&C footprint
108 yrs
Workers' comp leadership since 1917
$50K
Phase 1 dual-state pilot — AZ + UT, head-to-head
Why we're already aligned

We've done our homework on WCF.

Before we ever ask, we listen. Here's what we already know about WCF Insurance — and why FFH is built to amplify, not duplicate, what you're doing.

PEOPLE MATTER

Charismatic, mission-led CEO

Matthew Lyon trademarked People Matter because that's how WCF actually thinks — about employees, policyholders, injured workers, and the communities you all live in.

Workers' comp at the core

Born in 1917 as the Workers Compensation Fund of Utah. P&C across six western states today, with offices in four. That heritage is a workforce-health superpower for what we want to build together.

Generosity is policy

$2.2M back to communities last year, plus a board that says yes to causes that matter (thank you, Jan, for the $7,500 to Tucson Jazz Society as a flagship sponsor).

Geography of opportunity

Strongest where you live (Utah HQ); lightest in Arizona. That gap is where a public partnership with FFH can move the needle on visibility AND community impact at the same time.

The Western Footprint

Six states. One People-Matter promise.

FFH proposes a phased, geographically smart rollout: Arizona & Utah first — the state where you have the lightest presence and the state where you're headquartered — then expand based on what we learn together.

IDAHO CALIFORNIA NEVADA UTAH COLORADO ARIZONA PHASE 1 PILOT PHASE 1 PILOT N
WCF service area (P&C)
Phase 1 pilot focus
Active pilot badge
The Value Proposition

Three reasons WCF wins by leaning in.

We've stress-tested this with a property & casualty hat on. Each of these three angles stands on its own — together, they give WCF a defensible community-impact playbook the rest of the P&C industry can't match.

1
Philanthropy with Purpose

Turn $2.2M of giveback into measurable community wellness.

WCF's community giving is already sizable and sincere. FFH gives that giving a visible, branded delivery system — one that lets WCF show up at high schools, chambers, and city halls in every state you serve, not just the ones where you have offices.

  • Branded "WCF People Matter" presence at FFH community activations
  • Naming on STEAM teams, Reality Health Games tournaments, and Chamber of Health convenings
  • Earned media: schools, students, families, local press already follow these activations
  • Aligned with WCF's existing CSR posture — we extend reach, you extend trust
P&C lens: philanthropy that lives on the ground in your loss-control geographies builds the kind of brand affinity that makes agents' jobs easier on every renewal.
2
PHIT Score & Risk Resilience

A workforce-health signal you've never had access to before.

The PHIT™ Score (Population Health Intelligence Tracker) aggregates community- and cohort-level health literacy, daily-action consistency, and prevention-behavior trends. For a workers' comp and commercial P&C carrier, that's upstream loss data nobody else in the industry currently sees.

  • Underwriting signal: de-identified PHIT trends by ZIP/employer cohort inform safer-workforce pricing and loss-control offerings
  • Claims duration: comorbidity awareness (diabetes, hypertension, mental health) is the #1 lever on workers' comp claim length — FFH educates patients before they're ever a claimant
  • Return-to-work: Certified Patient pathways (Dr. Rob's program) give injured workers the literacy and adherence tools that shorten claim tails
  • Mental-health rising: #1 growth category in WC severity — FFH's Coach Lucy + mental-health bingo cards address it without expanding your medical-bill exposure
P&C lens: every 1% improvement in claim duration or frequency in a book your size pays for the entire program many times over — and FFH gives you a community-facing brand story while it does it.
3
Giveback Tracking Dashboard

Prove every dollar of community investment, in real time.

WCF gives back $2.2M a year. The hard part isn't writing the checks — it's showing what they produced. FFH's Capital Command Center is a private, branded dashboard that closes the loop from dollar in → activation funded → students reached → PHIT Score lift in the community.

  • Live ledger of every WCF-funded activation, tied to dollar amount and date
  • Community-level outcome metrics (students engaged, coins earned, badges issued, PHIT lift)
  • Year-end CSR/ESG report generated automatically — ready for board, regulators, AM Best, employees
  • Investor- and rating-agency-friendly social-impact narrative
P&C lens: AM Best, Moody's, employees, and brokers all increasingly ask for measurable social impact. FFH gives WCF the receipts that turn "People Matter" from a slogan into a scoreboard.
The Data Behind the Pitch

PHIT™ pulls the public-health stack most carriers don't even buy.

Workers' comp pricing accuracy lives in the math: Frequency × Severity × Duration. FFH's PHIT™ system already aggregates federal & national data sources that move the needle on severity and duration — and three closable gaps would make it underwriting-grade for frequency too. Here's what's wired today, what's closing, and what's FFH-native.

Workplace Injury & Safety (Frequency drivers)

The most direct frequency signal a workers' comp carrier sees. Closing this gap is gap #1 in our P&C readiness plan.

Closing gapOSHA Establishment DataRecordable injury 300A reports for high-hazard industries
Closing gapOSHA Severe Injury ReportsAmputations, hospitalizations — by employer since 2017
Closing gapBLS SOII & CFOISurvey of Occupational Injuries & Census of Fatal Occupational Injuries
Closing gapNIOSH FACE & Worker Health Charts200+ occupational health metrics by industry & occupation
Closing gapState WC Bureau Loss CostsNCCI states + independent bureaus (CA, MI, NJ, NY)
Closing gapLiberty Mutual Workplace Safety IndexTop causes of disabling work injuries by industry

Workforce Health & Behavior (Severity & Duration drivers)

FFH's strongest current zone. Comorbidity prevalence, mental health, smoking, behavioral risk — the variables that drive how bad a claim will be and how long it will run.

LiveCDC PLACES36 health measures at census tract
LiveCDC WONDERMortality data — deaths of despair, cardiovascular, MH
LiveCDC SUDORS & DOSEToxicology overdose; weekly ED syndromic surveillance
LiveHRSA HPSAHealth Professional Shortage Areas — access to care
LiveCMS & CCWMedicare/Medicaid + Chronic Condition Warehouse
LiveNPPES · NPI RegistryProvider directory — access density
Closing gapCDC BRFSS DirectSleep, MH days, alcohol/drug, social isolation
Closing gapCDC NHIS-OHSOccupational Health Supplement to NHIS
Closing gapHERO ScorecardEmployer wellness program benchmarking
🌎

Workplace Environment & Exposure

Air, water, chemical, and built-environment exposures — respiratory and chronic-disease drivers that show up in workers' comp duration.

LiveEPA AirNowReal-time air quality at workplace ZIP
LiveEPA TRIToxics Release Inventory — chemical releases
LiveEPA EJScreen12 environmental + 6 demographic indicators
LiveCDC EPHTEnvironmental Public Health Tracking
👥

Workforce Composition & Economics

Industry mix, pay structure, education, language, commute — the supply-side of any workforce risk profile.

LiveBLS QCEWEstablishment counts by NAICS
LiveBLS OESOccupational Employment by SOC
LiveCensus ACSEducation, age, language, commute
Closing gapAHRQ MEPS-ICEmployer-Sponsored Insurance utilization

FFH-Native Cohort Intelligence (the unique layer)

This is where WCF goes from "buying public data" to "seeing what no other carrier sees." Cohort-level wellness signal at the employer roster level.

FFH-nativeWorkforce Wellness IndexComposite score per employer cohort
FFH-nativeLIVE It Tracker StreaksActivity, weight, vitals (self-reported)
FFH-nativeRHG League EngagementGame competition rates, leaderboard ranks
FFH-nativePre/Post Wellness BaselineOnboarding + quarterly pulse surveys
FFH-nativeCoach Lucy AI UtilizationTopic distribution, follow-through (de-id)
FFH-nativeBingo Card Completion RatesBy body system, by employer cohort
Coming Q3Terra API WearablesSleep, activity, HRV (de-identified)
Coming Q3Capital Command CenterBranded employer dashboards & ROI attribution
Open the full Healthy Workplace Hub →
Two Ways to Engage — Or Both

Pick the door that fits.

FFH offers WCF two distinct, complementary paths into partnership. They aren't mutually exclusive — many partners start with the philanthropic anchor and graduate to co-development. Pick one, pick both, or sequence them.

A
Philanthropic Play

Foundational Community Sponsor

Brand visibility + measurable community impact, anchored across two states. Lowest commitment, fastest activation, most aligned with WCF's existing $2.2M giveback posture.

$50,000 (Year 1)
$25K Arizona + $25K Utah, parallel pilots
  • 10 AZ STEAM teams + 5 UT STEAM teams
  • Foundational Partner naming on both Chamber of Health pages
  • Inaugural Utah Chamber convening
  • Capital Command Center reporting on both states
  • Pure community-impact play — no internal data integration required
See Option A details ↓
B
Co-Development · Investment Play

Underwriting Intelligence Design Partner

WCF as the design partner who shapes a healthy-workplace + workers' comp intelligence layer. Internal RHG leagues for WCF employees. Exclusive vertical access. Long-term, defensible moat.

$250K Year 1 · scaling
3-year horizon, with right of first refusal in WC vertical
  • Everything in Option A, plus:
  • Internal RHG Leagues for WCF employees (closed/public/hybrid modes)
  • Co-development: close the 3 PHIT data gaps with WCF input
  • Exclusive WC-vertical access for a defined window
  • Branded Capital Command Center for WCF underwriting + CSR teams
  • Co-marketing rights — PHIT × WCF "People Matter"™ positioning
See Option B details ↓
And/Or: the cleanest path is often A in 2026 → B starting 2027. The philanthropic anchor proves the community ROI; co-development builds on the proof.
Option A · Philanthropic Play

$25K × 2 — anchor Arizona AND Utah, head to head.

Two states. Two parallel $25K commitments. One coordinated launch. Arizona is the visibility play (lightest WCF presence, biggest brand-elevation upside). Utah is the home-state play (HQ, smallest state, highest internal-stakeholder support). Together, they give WCF a defensible foundation for everything that follows in California, Colorado, Idaho, and Nevada.

Phase 1 · Visibility
Arizona
Foundational AZ Chamber of Health Partner
$25,000
AZ pilot sponsorship
Match the Banner University Family Care / My Healthy Arizona positioning — at a fraction of the spend, and with a measurable 10-team return.
  • 10 high school STEAM teams across AZ at $2,500/team
  • Statewide WCF "People Matter" presence at every activation
  • Peer-positioning vs Banner UFC on My Healthy Arizona
  • Capital Command Center reporting — live PHIT outcome dashboard
  • Pathway to Chamber of Health AZ — foundational partner naming
Open the Arizona Chamber of Health →
Phase 1 · Home State
Utah
Foundational UT Chamber of Health Partner
$25,000
UT pilot sponsorship
Anchor the Utah Chamber of Health as Founding Partner — in WCF's home state, where every employee, agent, and policyholder will see it.
  • 5 high school STEAM teams across the three Utah Super-Regions
  • Inaugural Utah Chamber convening with Founding Partner naming
  • First seat at the Utah Director's Table — statewide policy convener
  • Quarterly Utah PHIT brief — branded Capital Command Center reports
  • Right of first refusal on Phase 2 expansion to CA/CO/ID/NV
Open the Utah Chamber of Health →
Option B · Co-Development · Investment Partner

Be the carrier who co-defines healthy-workplace underwriting.

For a multi-year, design-partner relationship, WCF stops being a sponsor and becomes the carrier who shapes the product. Internal Reality Health Game leagues for WCF employees. Exclusive vertical access. The closest thing the workers' comp industry has to a defensible data moat.

$250K+
Year 1 design-partner commitment
Three-year horizon. Tier scales with cohort additions and use-case depth. Co-defined scope — nothing prescriptive until WCF risk & CSR teams help shape it.
Year 1 · $250K design partner
Year 2 · ~$500K cohort scale
Year 3 · ~$750K platform-wide
~$1.5M total · 3-year horizon
Numbers are anchoring estimates — not committed. Final scope co-defined with WCF.
1

Co-Development of the Underwriting Layer

WCF helps close the three identified PHIT gaps (OSHA + NIOSH direct, BRFSS direct, Terra wearable + cohort dashboard). WCF input shapes how the data shows up — what fields the dashboard surfaces, what aggregations matter, what triggers alerts.

2

Exclusive Workers' Comp Vertical Window

Right of first refusal on FFH workers' comp / P&C carrier partnerships for a defined window (typically 24 months). No other WC carrier gets this access during the exclusivity window.

3

Branded Capital Command Center

WCF gets a private, branded dashboard for cohort PHIT trends, RHG league performance, and ROI attribution. Internal use for risk & CSR teams; optional public-facing slice for AM Best / broker / employee storytelling.

4

Co-Marketing Rights

Joint positioning of "PHIT™ powered by WCF People Matter™" on AZ + UT activations, expansion states, and FFH-side content. WCF gets named in every Capital Command Center brief, every season-end RHG report, every Director's Table communication.

5

Network Aggregate Access

Anonymized, k-anonymized cohort intelligence across the entire FFH Network — not just WCF's policyholder cohorts, but the broader anchor data set. Underwriting context no other carrier sees.

Internal Activation Bonus

Reality Health Game Leagues for WCF employees.

The "amplifier" inside Option B. Turn WCF's own offices into a season-long Reality Health Game league — office-vs-office, region-vs-region, or full company-wide. Employee engagement, measurable wellness lift, and a story you can tell every WCF policyholder, broker, and AM Best analyst.

Mode A · Closed
Internal Office League

Closed leaderboards across WCF's Utah, AZ, NV, ID, CO, and CA offices. HR + Wellness team gets the dashboard. Pure internal engagement play.

Mode B · Public
Public-Facing Sponsor League

WCF offices play in a public-facing season alongside community teams. Earned media at every milestone, full season-end PHIT impact report.

Mode C · Hybrid
Internal + Community League

Closed internal scoreboard for engagement + a public-facing one for brand. Best of both. Most likely the right starting mode for WCF.

The Rollout

Phase 1 in 2026, Phase 2 builds on what works.

Geographically smart, financially conservative, and fully measured. WCF doesn't commit to anything beyond Phase 1 until the data says yes.

Phase 1 — 2026

$25K × 2 — Foundational AZ + UT Chambers

Arizona for the visibility and brand-elevation play. Utah because it's home — smallest state, biggest internal-stakeholder upside, and the natural place to test the Capital Command Center reporting alongside your existing CSR team.

Deliverables: 10 AZ STEAM teams + 5 UT STEAM teams, inaugural Utah Chamber convening with Founding Partner naming, full Capital Command Center PHIT dashboard for both states.

Phase 2 — 2027

Scale to California, Colorado, Idaho, Nevada

🟦 California 🟦 Colorado 🟦 Idaho 🟦 Nevada

Once Phase 1 metrics validate the model, replicate state-by-state with WCF leading or supporting Chamber of Health activations in markets where you're already underwriting. Idaho can move forward quickly given its size and your existing relationships.

Result: a six-state community-health platform that travels with the WCF book of business.

Next Step

A 30-minute walkthrough with Matthew & team.

Lucy already ran Jan through PHIT Score and the systems, and Jan thinks Matthew needs to see this. We'd love to put 30 minutes on the calendar for a live walkthrough with the WCF executive team.

Who's at the table

Lucy Howell — CEO, The Force for Health Network
Dr. Robert Gillio — Co-founder & CMO (retired pulmonologist)
Jan — WCF Board Member & FFH champion
Matthew Lyon — CEO, WCF Insurance
Plus your CSR / philanthropy lead and risk/data lead, if available.

* to any FFH page. No other changes required. * * Edit-mode triggers (any one will activate): * - URL contains ?edit=1 or #edit * - localStorage 'ffh_edit_mode' === 'on' (persists across page loads) * - Click the floating toggle button * * Author: Coach Lucy + Claude * Version: 1.0 (2026-04-25) * ────────────────────────────────────────────────────────────────────────── */ (function() { 'use strict'; // Avoid double-loading if (window.__FFH_EDITOR_LOADED__) return; window.__FFH_EDITOR_LOADED__ = true; // ── State ────────────────────────────────────────────────────────────── var STORE_KEY_MODE = 'ffh_edit_mode'; var STORE_KEY_EDITS = 'ffh_pending_edits'; var pendingEdits = []; // {before, after, tag, snippet} var editMode = false; var currentEditEl = null; var currentBeforeText = null; // Page metadata — try hard to figure out the source file path function getPageMeta() { var path = window.location.pathname; // Strip trailing slashes / index.html var clean = path.replace(/index\.html$/i, '').replace(/\/$/, '') || '/'; // Best-guess source file path inside Deploy Ready var slug = clean.replace(/^\//, '').replace(/\/$/, '') || 'index'; return { url: clean, sourceFile: 'Deploy Ready/' + slug + '/index.html', title: document.title || 'FFH Page' }; } // ── Mode detection ───────────────────────────────────────────────────── function detectModeFromURL() { var qs = window.location.search; var hash = window.location.hash; if (qs.indexOf('edit=1') !== -1) return true; if (hash.indexOf('edit') !== -1) return true; return null; // null = use stored value } function loadEditMode() { var fromUrl = detectModeFromURL(); if (fromUrl !== null) return fromUrl; return localStorage.getItem(STORE_KEY_MODE) === 'on'; } function saveEditMode(on) { if (on) localStorage.setItem(STORE_KEY_MODE, 'on'); else localStorage.removeItem(STORE_KEY_MODE); } function loadPendingEdits() { try { var raw = localStorage.getItem(STORE_KEY_EDITS); return raw ? JSON.parse(raw) : []; } catch (e) { return []; } } function savePendingEdits() { try { localStorage.setItem(STORE_KEY_EDITS, JSON.stringify(pendingEdits)); } catch (e) { /* ignore quota */ } } // ── Styles ───────────────────────────────────────────────────────────── function injectStyles() { if (document.getElementById('ffh-editor-styles')) return; var css = ` .ffh-edit-toggle { position: fixed; bottom: 18px; right: 18px; z-index: 9999; background: #0f2044; color: #fff; border: 2px solid #fff; border-radius: 28px; padding: 10px 18px; font-size: 13px; font-weight: 700; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; box-shadow: 0 6px 20px rgba(15,32,68,.35); cursor: pointer; transition: all .2s; display: flex; align-items: center; gap: 8px; } .ffh-edit-toggle:hover { background: #e8450a; transform: translateY(-2px); } .ffh-edit-toggle.on { background: #16a34a; border-color: #fff; } .ffh-edit-toggle.on:hover { background: #dc2626; } .ffh-edit-banner { position: fixed; top: 0; left: 0; right: 0; z-index: 9998; background: linear-gradient(135deg, #16a34a 0%, #0f766e 100%); color: #fff; text-align: center; padding: 6px 12px; font-size: 12px; font-weight: 700; font-family: -apple-system, sans-serif; letter-spacing: .04em; box-shadow: 0 2px 10px rgba(0,0,0,.2); } body.ffh-edit-on { padding-top: 28px !important; } /* Hover highlight + pencil */ .ffh-editable-hover { outline: 2px dashed rgba(232, 69, 10, .55) !important; outline-offset: 3px !important; cursor: pointer !important; position: relative !important; } .ffh-pencil-btn { position: absolute; top: -10px; right: -10px; z-index: 100; width: 28px; height: 28px; border-radius: 50%; background: #e8450a; color: #fff; border: 2px solid #fff; box-shadow: 0 2px 8px rgba(0,0,0,.25); cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 14px; line-height: 1; transition: transform .15s; } .ffh-pencil-btn:hover { transform: scale(1.12); background: #c73a08; } /* In-place editing */ .ffh-editing { outline: 3px solid #16a34a !important; outline-offset: 4px !important; background: rgba(22, 163, 74, .07) !important; cursor: text !important; } .ffh-edit-toolbar { position: absolute; background: #0f2044; color: #fff; border-radius: 8px; padding: 4px; box-shadow: 0 6px 18px rgba(0,0,0,.25); display: flex; gap: 4px; z-index: 9997; font-family: -apple-system, sans-serif; } .ffh-edit-toolbar button { background: transparent; border: none; color: #fff; padding: 6px 12px; border-radius: 6px; font-size: 12px; font-weight: 700; cursor: pointer; font-family: inherit; } .ffh-edit-toolbar button.save { background: #16a34a; } .ffh-edit-toolbar button.save:hover { background: #15803d; } .ffh-edit-toolbar button.cancel { background: #dc2626; } .ffh-edit-toolbar button.cancel:hover { background: #b91c1c; } /* Edits panel (bottom-right above toggle) */ .ffh-edits-panel { position: fixed; bottom: 76px; right: 18px; z-index: 9996; width: 360px; max-height: 60vh; background: #fff; border: 2px solid #0f2044; border-radius: 14px; box-shadow: 0 12px 32px rgba(15,32,68,.3); font-family: -apple-system, sans-serif; display: none; flex-direction: column; overflow: hidden; } .ffh-edits-panel.open { display: flex; } .ffh-edits-panel-header { background: #0f2044; color: #fff; padding: 12px 16px; display: flex; align-items: center; justify-content: space-between; } .ffh-edits-panel-header h4 { margin: 0; font-size: 14px; font-weight: 800; color: #fff; } .ffh-edits-panel-count { background: #e8450a; color: #fff; border-radius: 12px; padding: 2px 10px; font-size: 11px; font-weight: 800; } .ffh-edits-panel-list { flex: 1; overflow-y: auto; padding: 8px 12px; } .ffh-edit-row { background: #f4f6fa; border: 1px solid #e2e8f0; border-radius: 8px; padding: 10px 12px; margin-bottom: 8px; font-size: 12px; color: #0f2044; position: relative; } .ffh-edit-row .row-tag { font-size: 9px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; color: #6b7a99; margin-bottom: 4px; } .ffh-edit-row .row-before, .ffh-edit-row .row-after { background: #fff; border: 1px solid #e2e8f0; border-radius: 4px; padding: 4px 8px; margin-bottom: 4px; font-family: ui-monospace, 'SF Mono', monospace; font-size: 11px; overflow-wrap: break-word; word-break: break-word; line-height: 1.35; } .ffh-edit-row .row-after { background: #dcfce7; border-color: #86efac; } .ffh-edit-row .row-before { background: #fee2e2; border-color: #fca5a5; } .ffh-edit-row .row-remove { position: absolute; top: 4px; right: 4px; background: transparent; border: none; color: #dc2626; cursor: pointer; font-size: 14px; padding: 4px; border-radius: 4px; } .ffh-edit-row .row-remove:hover { background: rgba(220,38,38,.1); } .ffh-edits-panel-footer { padding: 12px; border-top: 1px solid #e2e8f0; display: flex; gap: 8px; flex-direction: column; } .ffh-copy-btn { background: #e8450a; color: #fff; border: none; border-radius: 22px; padding: 12px 16px; font-size: 13px; font-weight: 800; cursor: pointer; transition: all .2s; font-family: inherit; display: flex; align-items: center; justify-content: center; gap: 8px; } .ffh-copy-btn:hover { background: #c73a08; } .ffh-copy-btn.copied { background: #16a34a; } .ffh-clear-btn { background: transparent; color: #6b7a99; border: 1px solid #e2e8f0; border-radius: 16px; padding: 6px 12px; font-size: 11px; font-weight: 700; cursor: pointer; font-family: inherit; } .ffh-clear-btn:hover { color: #dc2626; border-color: #dc2626; } .ffh-empty-state { text-align: center; padding: 20px; color: #6b7a99; font-size: 12px; } /* Modal toast */ .ffh-toast { position: fixed; top: 50px; left: 50%; transform: translateX(-50%); background: #0f2044; color: #fff; padding: 12px 24px; border-radius: 28px; font-size: 13px; font-weight: 700; box-shadow: 0 8px 24px rgba(0,0,0,.3); z-index: 10000; font-family: -apple-system, sans-serif; opacity: 0; transition: opacity .25s; pointer-events: none; } .ffh-toast.show { opacity: 1; } /* Skip elements that should never be editable */ .ffh-no-edit, .ffh-edit-toggle, .ffh-edits-panel, .ffh-edit-banner, .ffh-edit-toolbar, .ffh-pencil-btn, .ffh-toast, .nav-bar, .nav-logo, nav, footer, script, style, head { /* These are excluded from edit hover detection in JS */ } `; var styleEl = document.createElement('style'); styleEl.id = 'ffh-editor-styles'; styleEl.textContent = css; document.head.appendChild(styleEl); } // ── Editable element detection ───────────────────────────────────────── function isElementEditable(el) { if (!el || el.nodeType !== 1) return false; // Skip our own UI if (el.closest('.ffh-edit-toggle, .ffh-edits-panel, .ffh-edit-banner, .ffh-edit-toolbar, .ffh-pencil-btn, .ffh-toast')) return false; // Skip nav and footer chrome if (el.closest('nav.nav-bar, footer.site-footer, footer')) return false; // Skip inputs and form elements var tag = el.tagName.toLowerCase(); if (['input','textarea','select','button','script','style','svg','path','image','img'].indexOf(tag) !== -1) return false; if (el.closest('svg')) return false; // Need text content var text = (el.textContent || '').trim(); if (!text || text.length < 2) return false; // Ideal targets: leaf text elements (no element children, or only inline formatting children) var inlineFormatting = ['b','i','em','strong','u','span','br','a','small','sub','sup','code','mark']; var hasNonInlineChildren = false; for (var i = 0; i < el.children.length; i++) { var childTag = el.children[i].tagName.toLowerCase(); if (inlineFormatting.indexOf(childTag) === -1) { hasNonInlineChildren = true; break; } } if (hasNonInlineChildren) return false; // Filter: only keep "text-bearing" tags var allowedTags = ['p','h1','h2','h3','h4','h5','h6','li','td','th','span','strong','em','figcaption','blockquote','dt','dd','div','a','small']; if (allowedTags.indexOf(tag) === -1) return false; // Skip very short or whitespace-only or layout-only divs if (tag === 'div' && el.children.length > 0) return false; return true; } // ── UI ───────────────────────────────────────────────────────────────── var toggleBtn, editsPanel, editsList, editsCount, banner; function injectUI() { // Floating toggle toggleBtn = document.createElement('button'); toggleBtn.className = 'ffh-edit-toggle'; toggleBtn.innerHTML = '✏ Edit Mode'; toggleBtn.addEventListener('click', toggleEditMode); document.body.appendChild(toggleBtn); // Edits panel editsPanel = document.createElement('div'); editsPanel.className = 'ffh-edits-panel'; editsPanel.innerHTML = `

Pending Edits

0
`; document.body.appendChild(editsPanel); editsList = editsPanel.querySelector('.ffh-edits-panel-list'); editsCount = editsPanel.querySelector('.ffh-edits-panel-count'); editsPanel.querySelector('.ffh-copy-btn').addEventListener('click', copyEditsToClipboard); editsPanel.querySelector('.ffh-clear-btn').addEventListener('click', clearEdits); } function showBanner() { if (banner) return; banner = document.createElement('div'); banner.className = 'ffh-edit-banner'; banner.innerHTML = '✏ Edit Mode is ON — hover any text to reveal the edit pencil'; document.body.appendChild(banner); document.body.classList.add('ffh-edit-on'); } function hideBanner() { if (banner) { banner.remove(); banner = null; } document.body.classList.remove('ffh-edit-on'); } function toast(msg) { var t = document.createElement('div'); t.className = 'ffh-toast'; t.textContent = msg; document.body.appendChild(t); setTimeout(function() { t.classList.add('show'); }, 10); setTimeout(function() { t.classList.remove('show'); }, 2200); setTimeout(function() { t.remove(); }, 2600); } // ── Hover handling ───────────────────────────────────────────────────── var hoverEl = null, pencilBtn = null; function clearHover() { if (hoverEl) { hoverEl.classList.remove('ffh-editable-hover'); hoverEl = null; } if (pencilBtn) { pencilBtn.remove(); pencilBtn = null; } } function attachPencil(el) { clearHover(); if (!editMode || currentEditEl) return; if (!isElementEditable(el)) return; el.classList.add('ffh-editable-hover'); // Make sure positioning works var origPos = window.getComputedStyle(el).position; if (origPos === 'static') el.style.position = 'relative'; // Pencil button pencilBtn = document.createElement('button'); pencilBtn.className = 'ffh-pencil-btn'; pencilBtn.innerHTML = '✏'; pencilBtn.title = 'Edit this text'; pencilBtn.addEventListener('mousedown', function(e) { e.preventDefault(); e.stopPropagation(); startEdit(el); }); el.appendChild(pencilBtn); hoverEl = el; } function onMouseOver(e) { if (!editMode || currentEditEl) return; var target = e.target; // Walk up to find nearest editable ancestor var maxDepth = 5, depth = 0, el = target; while (el && depth < maxDepth) { if (isElementEditable(el)) { attachPencil(el); return; } el = el.parentElement; depth++; } clearHover(); } function onMouseOut(e) { // Only clear if we're truly leaving the hovered element if (!hoverEl) return; var related = e.relatedTarget; if (related && (hoverEl.contains(related) || related.classList && related.classList.contains('ffh-pencil-btn'))) return; // small delay so the pencil button is clickable setTimeout(function() { if (!pencilBtn || !pencilBtn.matches(':hover')) clearHover(); }, 80); } // ── Edit lifecycle ───────────────────────────────────────────────────── function startEdit(el) { clearHover(); currentEditEl = el; currentBeforeText = (el.innerText || el.textContent || '').replace(/\s+/g, ' ').trim(); el.contentEditable = 'true'; el.classList.add('ffh-editing'); el.spellcheck = true; el.focus(); // Place cursor at end var range = document.createRange(); range.selectNodeContents(el); range.collapse(false); var sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); // Toolbar var toolbar = document.createElement('div'); toolbar.className = 'ffh-edit-toolbar'; toolbar.innerHTML = ''; document.body.appendChild(toolbar); positionToolbar(toolbar, el); toolbar.querySelector('.save').addEventListener('mousedown', function(e) { e.preventDefault(); finishEdit(true, toolbar); }); toolbar.querySelector('.cancel').addEventListener('mousedown', function(e) { e.preventDefault(); finishEdit(false, toolbar); }); // Esc cancels el.addEventListener('keydown', function ek(ev) { if (ev.key === 'Escape') { ev.preventDefault(); finishEdit(false, toolbar); el.removeEventListener('keydown', ek); } else if (ev.key === 'Enter' && (ev.metaKey || ev.ctrlKey)) { ev.preventDefault(); finishEdit(true, toolbar); el.removeEventListener('keydown', ek); } }); } function positionToolbar(toolbar, el) { var rect = el.getBoundingClientRect(); var top = rect.top + window.scrollY - 44; if (top < window.scrollY + 36) top = rect.bottom + window.scrollY + 8; var left = rect.left + window.scrollX; toolbar.style.top = top + 'px'; toolbar.style.left = left + 'px'; } function finishEdit(save, toolbar) { if (!currentEditEl) return; var el = currentEditEl; var afterText = (el.innerText || el.textContent || '').replace(/\s+/g, ' ').trim(); el.contentEditable = 'false'; el.classList.remove('ffh-editing'); if (toolbar && toolbar.parentNode) toolbar.remove(); if (save && afterText && afterText !== currentBeforeText) { var edit = { tag: el.tagName.toLowerCase(), snippet: shortSnippet(currentBeforeText), before: currentBeforeText, after: afterText, timestamp: new Date().toISOString() }; pendingEdits.push(edit); savePendingEdits(); renderEditsPanel(); toast('Edit captured (' + pendingEdits.length + ' pending)'); } else if (!save) { // Restore el.innerText = currentBeforeText; } currentEditEl = null; currentBeforeText = null; } function shortSnippet(s) { if (!s) return ''; if (s.length <= 60) return s; return s.slice(0, 57) + '…'; } // ── Edits panel rendering ────────────────────────────────────────────── function renderEditsPanel() { editsCount.textContent = String(pendingEdits.length); if (pendingEdits.length === 0) { editsList.innerHTML = '
No edits yet. Click any pencil to start.
'; editsPanel.classList.remove('open'); } else { editsList.innerHTML = pendingEdits.map(function(e, i) { return `
[${i+1}] <${e.tag}> · ${shortSnippet(e.snippet)}
${escapeHtml(e.before)}
${escapeHtml(e.after)}
`; }).join(''); editsPanel.classList.add('open'); editsList.querySelectorAll('.row-remove').forEach(function(btn) { btn.addEventListener('click', function() { var idx = parseInt(btn.dataset.idx, 10); pendingEdits.splice(idx, 1); savePendingEdits(); renderEditsPanel(); }); }); } } function escapeHtml(s) { return String(s).replace(/&/g, '&').replace(//g, '>'); } function clearEdits() { if (pendingEdits.length === 0) return; if (!confirm('Discard all ' + pendingEdits.length + ' pending edit' + (pendingEdits.length > 1 ? 's' : '') + '?')) return; pendingEdits = []; savePendingEdits(); renderEditsPanel(); toast('Edits cleared'); } function copyEditsToClipboard() { if (pendingEdits.length === 0) { toast('No edits to copy'); return; } var meta = getPageMeta(); var lines = []; lines.push('=== FFH INLINE EDITS ==='); lines.push('File: ' + meta.sourceFile); lines.push('URL: ' + meta.url); lines.push('Page Title: ' + meta.title); lines.push('Captured: ' + new Date().toISOString()); lines.push('Edits: ' + pendingEdits.length); lines.push(''); pendingEdits.forEach(function(e, i) { lines.push('[' + (i+1) + '] <' + e.tag + '>'); lines.push('--- BEFORE ---'); lines.push(e.before); lines.push('--- AFTER ---'); lines.push(e.after); lines.push(''); }); lines.push('=== END EDITS ==='); var payload = lines.join('\n'); function fallbackCopy() { var ta = document.createElement('textarea'); ta.value = payload; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); try { document.execCommand('copy'); } catch (e) { /* ignore */ } ta.remove(); } if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(payload).then(function() { onCopySuccess(); }, function() { fallbackCopy(); onCopySuccess(); }); } else { fallbackCopy(); onCopySuccess(); } } function onCopySuccess() { var btn = editsPanel.querySelector('.ffh-copy-btn'); var orig = btn.innerHTML; btn.innerHTML = '✓ Copied! Paste into Cowork chat'; btn.classList.add('copied'); toast('Copied ' + pendingEdits.length + ' edit' + (pendingEdits.length > 1 ? 's' : '') + ' to clipboard'); setTimeout(function() { btn.innerHTML = orig; btn.classList.remove('copied'); }, 2400); } // ── Mode toggle ──────────────────────────────────────────────────────── function setEditMode(on) { editMode = on; saveEditMode(on); if (on) { toggleBtn.classList.add('on'); toggleBtn.innerHTML = '✗ Exit Edit Mode'; showBanner(); renderEditsPanel(); } else { toggleBtn.classList.remove('on'); toggleBtn.innerHTML = '✏ Edit Mode'; hideBanner(); clearHover(); editsPanel.classList.remove('open'); } } function toggleEditMode() { setEditMode(!editMode); if (editMode) toast('Edit mode ON — hover any text to edit'); else toast('Edit mode OFF'); } // ── Init ─────────────────────────────────────────────────────────────── function init() { injectStyles(); injectUI(); pendingEdits = loadPendingEdits(); renderEditsPanel(); // Hover listeners (always attached, gated by editMode flag inside) document.addEventListener('mouseover', onMouseOver); document.addEventListener('mouseout', onMouseOut); // Activate if mode was on var startOn = loadEditMode(); if (startOn) setEditMode(true); else setEditMode(false); // Re-position toolbar on scroll/resize during edit var repositionPending = false; function rep() { if (currentEditEl && !repositionPending) { repositionPending = true; requestAnimationFrame(function() { var tb = document.querySelector('.ffh-edit-toolbar'); if (tb && currentEditEl) positionToolbar(tb, currentEditEl); repositionPending = false; }); } } window.addEventListener('scroll', rep, { passive: true }); window.addEventListener('resize', rep); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();