=== SSC Career Hub ===
Contributors: ssc
Tags: security jobs, cv review, careers, woocommerce
Requires at least: 6.0
Requires PHP: 7.4
Stable tag: 1.4.8
License: GPLv2 or later

Curated NY/NJ security job directory, CSV/Google Sheet sync, saved-job activity, CV paste/upload review queue with shareable readiness reports, attribution tracking, optional OpenRouter LLM enrichment for paid reviews, and admin pages for SSC Security Guard Training.

V1.4.8 post-submission flow + analyzing UX:
* Redesigned the post-submission state from a small text card into a proper transactional confirmation panel (Stripe / Linear / Wise pattern). Shows: tone-coded status icon (green check for scored, amber clock for queued), big headline, SSC-CV-#NNNN reference number, "saved for [email]" account context, 3-step visual timeline (Saved → Reviewed → Report ready) with pulsing active dot, primary actions (Open report / Copy share link), and 4 next-step tiles (My CVs / Dashboard / Browse jobs / Submit another).
* Form is now hidden when the page renders in submission state — the user knows the action completed and is given clear next moves instead of an empty form. "Submit another" tile reloads the bare URL to bring the form back.
* New "Scored by" badge on every result: blue "Auto-scored by SSC readiness engine" for free local submissions, red "Local engine score · AI review running" when credits-spent priority review fires the OpenRouter cron, amber "Queued for human reviewer" for manual-review fallback. Users always know what evaluated their CV.
* When AI review isn't active (no key configured OR no credits spent), the success panel now shows an explicit upgrade prompt with a direct top-up link, so users know AI review is an option they can unlock.
* New full-page "Analyzing your CV…" overlay during form submission — animated three-dot pulse, cycling status messages ("Reading your submission / Extracting key signals / Scoring readiness / Saving to your account"), backdrop blur. Pure UX feedback (no AJAX); disappears naturally when the browser navigates to the success page.
* CV Optimizer hero h2 dialed down from clamp(32px,5vw,58px) to clamp(26px,3.4vw,38px) — the page is transactional, not marketing, so a 58px header was overwhelming.

V1.4.7 logic + navigation pass:
* Fixed success-card after CV submission. The v1.4.3 guard required score>0 to show the "scored" card; a legitimate 0/100 was falling through to the "manual review" message and confusing users into thinking their CV wasn't saved. New guard tests for the presence of ?cv= and ?t= in the URL (which only the upload handler sets when scoring actually happened). All branches now explicitly say "saved to your account" so the user knows the data persisted regardless of which message displays.
* Fixed CV analyzer keyword matching. The v1.4.0 tight word-boundary regex required BOTH sides of a keyword to be non-alphanumeric, so "guards" (plural), "patrolling", "licensed", "supervisors" all failed to match — artificially deflating scores. New regex requires only the start-of-word boundary; matches morphological variants but still blocks substring false positives like "rearguard" matching "guard".
* Cities + Training filters now grouped by state inside their collapsible panels — "New York" sub-section above "New Jersey" sub-section, with small uppercase headers. State filter hides the entire opposite-state sub-section (previously it only hid individual chips, leaving an orphaned section title).
* New account-nav tab bar (Dashboard / Jobs / Submit CV / My CVs / Credits) rendered at the top of every member shortcode. One consistent place to navigate; current page gets a solid SSC-blue pill. Horizontally scrollable on mobile.
* Dashboard upgraded to a real account hub:
  - Quick Actions row: "Submit a new CV" (primary gradient), "Browse jobs", "Top up credits" — clickable tiles with icon + title + subtitle.
  - New "Recent CVs" cards grid below the score trend. Each card shows score with tone-coloured number (green/amber/red), status pill, role, date, plus [View report] and [Copy link] buttons. Pending/manual-review CVs show an "Awaiting manual review" note.
* New generic data-ssc-copy-link clipboard handler. Used by Recent-CVs cards and the post-submission success card. Native Clipboard API with hidden-textarea fallback; brief "✓ Copied" confirmation flash.

V1.4.6 CV form vertical stretch fix:
* The form card was rendering ~1200px tall with only ~370px of content, producing huge dead space between the wizard chips, the step heading, the fields, and the Continue button. Root cause: the parent .ssc-ch-cv-shell is a 2-column grid (form + aside) with default align-items:stretch, so the form was being stretched to match the taller aside (credit balance + 4 top-up cards). The form is itself display:grid, so it then distributed the extra height across its internal rows — pushing chips, legend, fields, and nav far apart.
* Fix: align-items:start on the parent shell (form sizes to its own content), plus align-self:start + align-content:start on the form (defensive, pack rows at top regardless of container height). Both gaps collapse to the intended 14px row gap.

V1.4.5 dashboard hero + KPI layout fix:
* The dashboard hero was rendering "My Security Career Dashboard" as four stacked words ("My / Security / Career / Dashboard") at giant size — root cause: the hero is a 2-column grid (minmax(0,1fr) 320px) but the template loose-leafed three direct children (kicker, h2, reminder p), so the h2 landed in the 320px-wide column and word-wrapped.
* Restructured dashboard.php to match the Jobs hero pattern — content wrapped in a <div> + new <aside class="ssc-ch-hero-card"> that holds the stats (tracked / applied / CV reviews / credits) and the pathway chips. Now they live INSIDE the dark hero where the existing white-on-dark styling actually works.
* Added defensive CSS: any hero without an aside/hero-card child collapses to a single column (fixes [ssc_my_credits], [ssc_my_cvs], and the logged-out dashboard, all of which have no aside).
* Forced kicker pill to sizeof-content with higher specificity in case a parent theme applies "p { width: 100% }".
* Saved/tracked jobs table got proper styling — uppercase muted column headers, hover state, status pill in SSC blue, "View" link in SSC blue instead of inheriting the theme's anchor red.
* Stats grid switched to 2x2 inside the hero aside so the 4th stat doesn't orphan.

V1.4.4 jobs-page filter strip visual fix:
* Filter labels (State track / Role type / Training) were rendering as white-on-white because the v1.4.0 chip styles assumed the filter strip was on the dark hero gradient (legacy 1.3.x layout). Rewrote the entire chip/label/collapse block for the actual light background — labels are now uppercase muted ink, chips are blue-ink-on-white pills with solid SSC blue when active, collapsible City/Training panels have a clean +/− toggle.
* Broke the legacy 6-column grid (.ssc-ch-filters at line 425) for chip-mode forms — the chip form is now a clean vertical flex column so State / City / Role / Training / Search-Clear stack naturally instead of sprawling across the row.
* Search/Clear actions row has a top border + proper button styling so it reads as the form's commit zone.
* Improved focus state on inputs/selects (3px blue outline + ink border).

V1.4.3 spacing + UX patch on the CV Optimizer form:
* Fixed ~150px of dead vertical space inside the wizard fieldset by resetting Chrome's default fieldset min-inline-size and the legend's implicit top anchoring. Wizard steps now sit flush below the progress chips.
* Tightened wizard progress chips bottom spacing (was 22+24+border, now 14+16+border).
* Empty submit-row container no longer takes vertical space on non-last wizard steps (hidden via data-wizard-last="0").
* Success card no longer renders "Your CV scored 0/100" when the URL has ?submitted=1 without a real score. Falls through to a generic "received" message unless cv, t, and a positive score are all present.

V1.4.2 adds secure OpenRouter integration:
* New SSC_CH_OpenRouter helper. The API key is read ONLY from a wp-config.php constant (SSC_CH_OPENROUTER_KEY) — never from wp_options, so it does not appear in DB backups (JetBackup → Google Drive in this hosting setup). Optional SSC_CH_OPENROUTER_MODEL constant overrides the default model (anthropic/claude-haiku-4.5). Optional SSC_CH_OPENROUTER_HOST for self-hosted gateways.
* When a candidate spends credits for an ultimate CV review (status → priority_review), a WP-cron event fires SSC_CH_OpenRouter::run_for_cv() which calls OpenRouter, stores the draft narrative in cv_reviews.ai_narrative, and logs token usage + cost in ssc_ch_ai_usage.
* Admin gate: the AI draft is NEVER auto-published. It appears as an admin-only details panel on the CV Reviews row with a "Use this as candidate feedback" button that copies the draft into the candidate_feedback textarea. The admin reviews, edits, and saves before anything reaches the candidate.
* Per-call cost cap (openrouter_cost_cap_usd setting) is enforced as a 100× daily ceiling. If today's cumulative AI cost exceeds the ceiling, requests are skipped and logged to abuse_events.
* Settings page shows "Configured via wp-config.php (…last4)" or "Not configured" — the key value itself is never echoed to the page.
* Prompt-injection defence: CV text is wrapped in explicit ===CV BEGINS=== / ===CV ENDS=== markers, system prompt fixes the role, output is capped at 600 tokens, and the model is instructed not to mention being AI.
* New columns on ssc_ch_cv_reviews: ai_narrative, ai_narrative_at. Existing CVs are unaffected.
* If the constant is absent, the plugin degrades to the prior behaviour (local heuristic + human-fulfilled priority reviews). No errors, no half-broken state.

V1.4.1 sanity-check pass on top of 1.4.0:
* CV form wizard is now progressive enhancement — without JS the form renders as a single page with a working submit button; with JS the multi-step nav + per-step validation kicks in.
* [ssc_my_cvs] cards now expose a "View report" button per scored CV (was missing the link in v1.4.0).
* Candidate confirmation email goes out automatically after CV submission, with the shareable report link and clear NY/NJ disclaimer.
* New candidate_feedback field on CV reviews — admins can write public-facing reviewer notes (rendered on the CV report) separately from internal admin_notes, and can tick "Email the candidate" to push the update.
* Candidate dashboard now includes a "CV score trend" bar chart of the last 5 reviews, with score-delta vs previous and a one-click link to the latest report.
* Chart.js admin enqueue keeps the CDN dependency but the placeholder SRI was removed (a wrong digest would brick the charts); doc-comment explains how to pin the real hash post-install.
* New DB columns on ssc_ch_cv_reviews: candidate_feedback, candidate_notified_at.

V1.4.0 was a major design + capability pass:
* Shareable token-based CV report at [ssc_cv_report] — full score breakdown, six dimension bars, strengths, next-step checklist, recommendation CTA, score-over-time delta, and OG/Twitter share-card metadata.
* Pure-PHP PDF and DOCX text extraction (no Composer deps, no shelling out) — text-based uploads now get scored automatically; only scanned/encrypted PDFs fall through to manual review.
* UTM/source attribution capture (cookie-based, sendBeacon ingest) joins to CV submissions and credit purchases, surfacing a "where candidates come from" widget on the analytics page.
* Admin analytics rebuilt: date-range filter with 7/30/90/all presets, Chart.js daily activity + credits-purchased charts, conversion funnel (saves → applied → CV → credits), CSV export of the credit ledger, and tone-coded ledger rows.
* Mobile CV form is now a 3-step wizard with progress chips and per-step validation.
* Mobile jobs filter swaps native multi-select for tap-friendly chip groups in collapsible details panels.
* Bug fixes: word-boundary keyword matching in the CV analyzer (no more "patrol" inside "patrol-style"), removed all three unused legacy CSS files, dropped legacy 0000-00-00 deleted_at fallbacks, hardened error reflection on the CV form.
* New DB tables: ssc_ch_attribution (UTM/referrer/device per session) and ssc_ch_report_views (CV report engagement). New columns on ssc_ch_cv_reviews: share_token, share_views, share_first_viewed_at, extraction_source, attribution_id. Existing CVs are backfilled with share tokens on upgrade.

V1.3.4 added admin manual credit adjustments, a fuller analytics control room, recent credit ledger visibility, CV status breakdowns, and stronger candidate dashboard stats. V1.3.3 tightened the CV/credit flow review: empty submissions are blocked, file-only CVs are queued for manual review, priority credit spend uses the logged-in account identity. V1.3.2 preserved manually uploaded WooCommerce product images. V1.3.1 fixed WooCommerce variation checkout links. V1.3.0 added credit top-ups, My Credits/My CVs shortcodes, CV scoring, safer PDF/DOCX/TXT uploads, credit analytics, and API-cost tracking.

== Description ==
SSC Career Hub provides shortcodes:
* [ssc_jobs] — searchable job directory from local DB synced from CSV/published Google Sheet.
* [ssc_job_dashboard] — simple seeker dashboard for saved/applied activity.
* [ssc_cv_optimizer] — three-step CV intake wizard with readiness score and admin review.
* [ssc_cv_report] — public token-shareable CV readiness report (place on its own page, e.g. /cv-report/).
* [ssc_my_credits] — logged-in candidate credit balance and smooth top-up cards.
* [ssc_my_cvs] — logged-in candidate CV review tracker.

Important: SSC provides training and career preparation support. Job listings are informational and employment is not guaranteed. New York DCJS training and New Jersey SORA are distinct requirements.

== Installation ==
Upload/activate the plugin, place the shortcodes on pages, configure CSV URL under SSC Career Hub > Sync Jobs, then run Manual Sync.

== CSV Columns ==
Supports common headers: id, title/job_title, company/employer, city/location, state, job_type/type, pay/pay_text, schedule, training_requirement/training, tags, summary/description, requirements, apply_url/url, source_name, source_url, verified_at, expires_at.

== Security ==
Uses nonces/capabilities, fixed file allowlist (txt/pdf/docx only; legacy .doc is blocked), private upload folder protection, hashed IP/email for rate/abuse events, formula-safe CSV helper, and WooCommerce buyer detection only when WooCommerce functions exist.
