/* global window, React */
// ─────────────────────────────────────────────────────────────────────────
// DEDICATED RESOURCES, single-screen inline flow
// ─────────────────────────────────────────────────────────────────────────
// Layout:
//   1. Time toggle             (Part-Time / Full-Time, segmented)
//   2. Roles section header    (title + Onboarding Availability widget)
//   3. Roles grid              (glass cards, multi-select)
//   4. Inline config panel     (one panel, switches between selected roles via tabs)
//        · PT: day-rate plan tiles (1 / 5 / 10 / Custom) + savings
//        · FT: location / seniority / tasks form
//   5. Deposit summary         (refundable deposit + per-role line items)
//
// Per-role configuration is stored in `selection.roleConfigs[roleId]`:
//   FT: { location, seniority, tasks }
//   PT: { days: number }            // base day-rate plan
// ─────────────────────────────────────────────────────────────────────────

const { useState: dfUseState, useEffect: dfUseEffect } = React;

const DEDICATED_DEPOSIT = 250;
window.DEDICATED_DEPOSIT = DEDICATED_DEPOSIT;

// Day-rate plans, fixed schedule of discounts off the role's base day rate.
// Custom = 11+ days, gets the deepest discount.
const DAY_PLANS = [
  { id: 'd1',     days: 1,  discount: 0,    label: '1 Day',  blurb: 'Ideal for urgent requests or small tasks' },
  { id: 'd5',     days: 5,  discount: 0.10, label: '5 Days', blurb: 'or a total of {total}, giving you {pct}% off' },
  { id: 'd10',    days: 10, discount: 0.12, label: '10 Days',blurb: 'or a total of {total}, giving you {pct}% off' },
  { id: 'custom', days: 11, discount: 0.15, label: 'Custom', blurb: 'Enter 11 days or more for tailored support' },
];

// Per-location range multipliers applied to a role's `hourlyFrom` baseline
// (which is the Philippines floor on each role card). The (lo, hi) pair spans
// junior → senior so a single per-country band is shown to the visitor.
// Final price is reconfirmed post-shortlist; these are indicative only.
const FT_LOCATIONS = [
  // 2026-05-26: hourlyFrom = fixed indicative regional floor shown on the
  // pill as "from £X/hour". Derived from the cheapest role's hourlyFrom (£8)
  // × the low multiplier of each region so no user sees a price increase
  // vs the previous per-role range.
  { id: 'uk',           label: 'United Kingdom', flag: '🇬🇧', cc: 'gb', multLo: 2.8, multHi: 4.0, hourlyFrom: 22 },
  { id: 'philippines',  label: 'Philippines',    flag: '🇵🇭', cc: 'ph', multLo: 1.0, multHi: 1.5, hourlyFrom: 8 },
  { id: 'south-africa', label: 'South Africa',   flag: '🇿🇦', cc: 'za', multLo: 1.3, multHi: 1.9, hourlyFrom: 10 },
];

// Compute the indicative hourly range for a given role × location combo.
// Returns null if the role has no `hourlyFrom` baseline. UI hides the range
// gracefully in that case.
function dfHourlyRange(role, locId) {
  if (!role || typeof role.hourlyFrom !== 'number') return null;
  const loc = FT_LOCATIONS.find(l => l.id === locId);
  if (!loc) return null;
  return {
    lo: Math.round(role.hourlyFrom * loc.multLo),
    hi: Math.round(role.hourlyFrom * loc.multHi),
  };
}

const FT_SENIORITY = [
  // 2026-05-26: `pos` = position within the location's range (0 = lo bound,
  // 1 = hi bound). Drives the per-seniority hourly rate displayed under
  // each tile. Junior anchors to the location pill "from £X/hr" floor.
  { id: 'junior', label: 'Junior',  blurb: '1-3 yrs experience',         pos: 0   },
  { id: 'mid',    label: 'Mid',     blurb: '3-6 yrs experience',         pos: 0.5 },
  { id: 'senior', label: 'Senior',  blurb: '6+ yrs · lead-capable',      pos: 1.0 },
];

// 2026-05-26: indicative hourly rate for role × location × seniority.
// Returns a positive integer £/hr, or null if either input is missing.
function dfSeniorityRate(role, locId, senId) {
  if (!role || typeof role.hourlyFrom !== 'number') return null;
  const loc = FT_LOCATIONS.find(l => l.id === locId);
  if (!loc) return null;
  const sen = FT_SENIORITY.find(s => s.id === senId);
  if (!sen) return null;
  const mult = loc.multLo + (loc.multHi - loc.multLo) * sen.pos;
  return Math.round(role.hourlyFrom * mult);
}
window.dfSeniorityRate = dfSeniorityRate;

window.DEDICATED_FT_LOCATIONS = FT_LOCATIONS;
window.DEDICATED_FT_SENIORITY = FT_SENIORITY;
window.DEDICATED_ROLE_RECS    = ROLE_RECS;

// Step status retained for compat with elsewhere in the app (sidebar/summary).
function dfStepStatus(selection) {
  const tier = selection?.tier;
  const roles = selection?.roles || [];
  const cfgs = selection?.roleConfigs || {};
  const s1 = !!tier;
  const s2 = s1 && roles.length > 0;
  const s3 = s2 && roles.every(rid => {
    const c = cfgs[rid] || {};
    if (tier === 'fulltime') return !!c.location && !!c.seniority;
    if (tier === 'parttime') return typeof c.days === 'number' && c.days >= 1;
    return false;
  });
  return [s1, s2, s3, s3];
}
window.dfStepStatus = dfStepStatus;

function dfRolesForTier(service, tier) {
  if (!service || !tier) return [];
  return service.roles?.[tier] || [];
}
function dfRoleById(service, tier, rid) {
  return dfRolesForTier(service, tier).find(r => r.id === rid) || null;
}
window.dfRolesForTier = dfRolesForTier;
window.dfRoleById = dfRoleById;

// Helper: format £ with commas, no decimals.
function dfMoney(n) {
  return '£' + Math.round(n).toLocaleString('en-GB');
}

// ── TOP TIME TOGGLE ────────────────────────────────────────────────────────────────
function DFTimeToggle({ service, tier, onTier, hasSelection }) {
  if (!service.tiers || service.tiers.length < 2) return null;
  return (
    <div className="df-time-toggle" role="tablist" aria-label="Engagement type">
      {service.tiers.map(t => {
        const on = tier === t.id;
        const isFT = t.id === 'fulltime';
        return (
          <button
            key={t.id}
            type="button"
            role="tab"
            aria-selected={on}
            className={`df-time-toggle__btn ${on ? 'df-time-toggle__btn--on' : ''}`}
            onClick={() => onTier(t.id)}
          >
            <span className="df-time-toggle__icon" aria-hidden="true">
              {isFT ? (
                <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
                  <rect x="3" y="7" width="18" height="13" rx="2" />
                  <path d="M8 7V5a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
                </svg>
              ) : (
                <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
                  <rect x="3" y="5" width="18" height="16" rx="2" />
                  <path d="M3 10h18M8 3v4M16 3v4" />
                </svg>
              )}
            </span>
            <div className="df-time-toggle__text">
              <div className="df-time-toggle__name">{t.name}</div>
              <div className="df-time-toggle__price">
                {isFT ? 'Custom · monthly subscription' : 'From £175/day · flexible'}
              </div>
            </div>
            {on && hasSelection && (
              <span className="df-time-toggle__check" aria-hidden="true">
                <window.Check size={12} />
              </span>
            )}
          </button>
        );
      })}
    </div>
  );
}

// ── PER-ROLE LOCATION RECOMMENDATIONS ─────────────────────────────────────────────────────
// Philippines = delivery / creative / technical roles (cost-efficient, strong talent pool).
// UK          = client-facing / sales roles (native English, same time zone as UK clients).
const ROLE_RECS = {
  'pt-2d':        { cc: 'ph', label: 'Philippines' },
  'pt-copy':      { cc: 'ph', label: 'Philippines' },
  'pt-video':     { cc: 'ph', label: 'Philippines' },
  'pt-motion':    { cc: 'ph', label: 'Philippines' },
  'pt-3d':        { cc: 'ph', label: 'Philippines' },
  'pt-web':       { cc: 'ph', label: 'Philippines' },
  'pt-ai':        { cc: 'ph', label: 'Philippines' },
  'pt-va':        { cc: 'ph', label: 'Philippines' },
  'pt-marketer':  { cc: 'ph', label: 'Philippines' },
  'pt-seo':       { cc: 'ph', label: 'Philippines' },
  'pt-appt':      { cc: 'ph', label: 'Philippines' },
  'ft-mkt-ops':   { cc: 'ph', label: 'Philippines' },
  'ft-graphic':   { cc: 'ph', label: 'Philippines' },
  'ft-copy':      { cc: 'ph', label: 'Philippines' },
  'ft-video':     { cc: 'ph', label: 'Philippines' },
  'ft-fullstack': { cc: 'ph', label: 'Philippines' },
  'ft-ai':        { cc: 'ph', label: 'Philippines' },
  'ft-data':      { cc: 'ph', label: 'Philippines' },
  'ft-devops':    { cc: 'ph', label: 'Philippines' },
  'ft-uiux':      { cc: 'ph', label: 'Philippines' },
  'ft-3d':        { cc: 'ph', label: 'Philippines' },
  'ft-vmotion':   { cc: 'ph', label: 'Philippines' },
  'ft-exec':      { cc: 'ph', label: 'Philippines' },
  'ft-va':        { cc: 'ph', label: 'Philippines' },
  'pt-sales':     { cc: 'gb', label: 'United Kingdom' },
  'ft-sdr':       { cc: 'za', label: 'South Africa' },
  'ft-csm':       { cc: 'gb', label: 'United Kingdom' },
  'ft-am':        { cc: 'gb', label: 'United Kingdom' },
};

// ── ROLE CARD (glass) ────────────────────────────────────────────────────────────────────
// 2026-05-28 Batch 2 (#32 + #35):
//   #32 — HoverPortalTip pricing tooltip on each card. PT explains tiered day rates;
//          FT explains indicative hourly rate, confirmed after shortlist.
//   #35 — Outer <button> converted to <div role="checkbox"> so a real <button> remove
//          can be nested inside. Explicit × appears when the card is selected (on=true),
//          matching the × already present on summary-panel role lines.
function DFRoleCard({ role, on, isFocused, onToggle, onFocus, isFT, rec }) {
  const className = [
    'df-role-card',
    on && 'df-role-card--on',
    isFocused && 'df-role-card--focused',
    !on && 'df-role-card--dim',
  ].filter(Boolean).join(' ');

  // #32: tooltip text — PT shows tiered day rates; FT explains indicative hourly
  const tipText = isFT
    ? 'Hourly rate is indicative for the recommended location. Final monthly fee is confirmed after we shortlist candidates to your brief. Rates vary by location and seniority.'
    : (() => {
        const d1 = (role.dayRates && role.dayRates.d1) || role.price;
        const d5 = role.dayRates && role.dayRates.d5;
        const d10 = role.dayRates && role.dayRates.d10;
        const cust = role.dayRates && role.dayRates.custom;
        if (d1 && d5 && d10 && cust) {
          return `1 day: £${d1}/day · 5 days: £${d5}/day (10% off) · 10 days: £${d10}/day (12% off) · 11+ days: £${cust}/day (15% off). Final pricing confirmed on your scoping call.`;
        }
        return 'Day rate at 1-day rate. Discounts: 5-day block 10% off · 10-day block 12% off · 11+ days 15% off. Final pricing confirmed on your scoping call.';
      })();

  return (
    // #35: <div role="checkbox"> allows nesting a real <button> remove inside
    <div
      className={className}
      role="checkbox"
      aria-checked={on}
      tabIndex={0}
      onClick={() => onToggle()}
      onKeyDown={e => { if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); onToggle(); } }}
    >
      {/* #35: explicit × remove, only shown when card is selected */}
      {on && (
        <button
          type="button"
          className="df-role-card__remove"
          aria-label={`Remove ${role.name}`}
          onClick={e => { e.stopPropagation(); onToggle(); }}
        >
          <svg viewBox="0 0 12 12" width="8" height="8" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" aria-hidden="true">
            <line x1="2" y1="2" x2="10" y2="10"/>
            <line x1="10" y1="2" x2="2" y2="10"/>
          </svg>
        </button>
      )}
      <span className={`df-role-card__check ${on ? 'is-on' : ''}`} aria-hidden="true">
        {on && <window.Check size={11} />}
      </span>
      <div className="df-role-card__name">
        {role.name}
        {/* #32: pricing info tooltip */}
        {window.HoverPortalTip && (
          <window.HoverPortalTip
            wrapClassName="df-role-tip-wrap"
            wrapStyle={{marginLeft: '4px', display: 'inline-flex', verticalAlign: 'middle'}}
            tipClassName="dis-tip dis-tip--above"
            tip={tipText}
            placement="above"
          >
            <window.InfoIcon
              className="df-role-card__tip-icon"
              title={`About ${role.name} pricing`}
              onClick={(e) => e.stopPropagation()}
            />
          </window.HoverPortalTip>
        )}
      </div>
      <div className="df-role-card__price">{role.priceLabel}</div>
      {rec && (
        <div className="df-role-card__rec">
          <span>Recommended: </span>
          <img
            src={`https://flagcdn.com/${rec.cc}.svg`}
            alt={rec.label}
            className="df-role-card__rec-flag"
            width="14"
            height="10"
            loading="lazy"
          />
        </div>
      )}
      <span className="df-role-card__glass" aria-hidden="true"></span>
    </div>
  );
}

// ── PT DAY-RATE PLAN TILES ──────────────────────────────────────────────────────────────
// ── Per-role commitment toggle (3 / 6 / 12 mo) ──
// Reuses the .svc__commit-bar visual treatment (pill row, brand-blue
// selected state, orange save chip) so the per-role pills match the
// service-level commit toggle pixel-for-pixel. Lives inline in the
// role-form header.
function DFCommitToggle({ cfg, onPatch }) {
  const selected = cfg && cfg.commitId ? String(cfg.commitId) : '12';
  const COMMITS = (window.COMMITS || [
    { id: '3',  months: 3,  save: 0  },
    { id: '6',  months: 6,  save: 20 },
    { id: '12', months: 12, save: 40 },
  ]);
  return (
    <div className="svc__commit-bar df-commit-bar" role="radiogroup" aria-label="Role commitment length">
      {COMMITS.map(c => {
        const on = selected === c.id;
        return (
          <button
            key={c.id}
            type="button"
            role="radio"
            aria-checked={on}
            className={`svc__commit-bar-btn ${on ? 'is-on' : ''}`}
            onClick={() => onPatch({ commitId: c.id })}
          >
            <span className="svc__commit-bar-text">{c.months} mo</span>
          </button>
        );
      })}
    </div>
  );
}

function DFDayRateTiles({ role, cfg, onPatch }) {
  const baseRate = role.price || 0;
  const days = typeof cfg.days === 'number' ? cfg.days : null;
  let selectedPlanId = null;
  if (days === 1) selectedPlanId = 'd1';
  else if (days === 5) selectedPlanId = 'd5';
  else if (days === 10) selectedPlanId = 'd10';
  else if (typeof days === 'number' && days >= 11) selectedPlanId = 'custom';
  const isCustom = selectedPlanId === 'custom';

  return (
    <div className="df-plan">
      <div className="df-plan__header">
        <div className="df-plan__title">
          How many days would you like to collaborate with our {role.name}?
          <span className="df-plan__info" aria-hidden="true" tabIndex={-1}>
            <svg viewBox="0 0 16 16" width="13" height="13" fill="none" stroke="currentColor" strokeWidth="1.6">
              <circle cx="8" cy="8" r="6.5"/>
              <path d="M8 11V7M8 5h0" strokeLinecap="round"/>
            </svg>
          </span>
        </div>
        <div className="df-plan__sub">Choose from the following plans:</div>
      </div>

      <div className="df-plan__rate-label">
        Day rate
        <span className="df-plan__info" aria-hidden="true">
          <svg viewBox="0 0 16 16" width="11" height="11" fill="none" stroke="currentColor" strokeWidth="1.6">
            <circle cx="8" cy="8" r="6.5"/>
            <path d="M8 11V7M8 5h0" strokeLinecap="round"/>
          </svg>
        </span>
      </div>

      <div className="df-plan__tiles">
        {DAY_PLANS.map(plan => {
          const on = selectedPlanId === plan.id;
          const explicit = role.dayRates && typeof role.dayRates[plan.id] === 'number'
            ? role.dayRates[plan.id]
            : null;
          const dayRate = explicit != null
            ? explicit
            : Math.round(baseRate * (1 - plan.discount));
          const total = dayRate * (plan.id === 'custom' ? Math.max(11, days || 11) : plan.days);
          const baseDayRate = (role.dayRates && typeof role.dayRates.d1 === 'number')
            ? role.dayRates.d1
            : baseRate;
          const pct = baseDayRate > 0
            ? Math.round((1 - dayRate / baseDayRate) * 100)
            : Math.round(plan.discount * 100);
          let blurb = plan.blurb;
          if (plan.id === 'd5' || plan.id === 'd10') {
            blurb = blurb.replace('{total}', dfMoney(total)).replace('{pct}', pct);
          }
          return (
            <button
              key={plan.id}
              type="button"
              className={`df-plan-tile ${on ? 'df-plan-tile--on' : ''} ${plan.id === 'custom' ? 'df-plan-tile--custom' : ''}`}
              onClick={() => {
                if (plan.id === 'custom') {
                  onPatch({ days: (typeof days === 'number' && days >= 11) ? days : 11 });
                } else {
                  onPatch({ days: plan.days });
                }
              }}
              aria-pressed={on}
            >
              <div className="df-plan-tile__head">
                <span className="df-plan-tile__name">{plan.label}</span>
                <span className={`df-plan-tile__radio ${on ? 'is-on' : ''}`} aria-hidden="true">
                  {on && <window.Check size={10} />}
                </span>
              </div>
              <div className="df-plan-tile__price">
                <span className="df-plan-tile__amt">{dfMoney(dayRate)}</span>
                <span className="df-plan-tile__unit">/day</span>
              </div>
              <div className="df-plan-tile__blurb">{blurb}</div>
            </button>
          );
        })}
      </div>

      {isCustom && (
        <div className="df-plan__custom">
          <label className="df-plan__custom-label" htmlFor={`custom-days-${role.id}`}>
            How many days per month?
          </label>
          <div className="df-plan__custom-input-wrap">
            <button
              type="button"
              className="df-plan__custom-step"
              onClick={() => onPatch({ days: Math.max(11, (days || 11) - 1) })}
              aria-label="Decrease days"
            >−</button>
            <input
              id={`custom-days-${role.id}`}
              type="number"
              min="11"
              max="22"
              className="df-plan__custom-input"
              value={days || 11}
              onChange={e => onPatch({ days: Math.max(11, Math.min(22, Math.floor(Number(e.target.value) || 11))) })}
            />
            <button
              type="button"
              className="df-plan__custom-step"
              onClick={() => onPatch({ days: Math.min(22, (days || 11) + 1) })}
              aria-label="Increase days"
            >+</button>
            <span className="df-plan__custom-suffix">
              days/month · {dfMoney((role.dayRates && role.dayRates.custom) || Math.round(baseRate * (1 - 0.15)))}/day · total {dfMoney(((role.dayRates && role.dayRates.custom) || Math.round(baseRate * (1 - 0.15))) * (days || 11))}
            </span>
          </div>
        </div>
      )}
    </div>
  );
}

// ── FT FORM ────────────────────────────────────────────────────────────────────────────────
function DFFullTimeForm({ role, cfg, onPatch }) {
  const recEntry = ROLE_RECS[role.id];
  const recLocId = recEntry
    ? (FT_LOCATIONS.find(l => l.cc === recEntry.cc) || {}).id
    : null;
  return (
    <div className="df-ft-form">
      <div className="df-ft-form__head">
        <div className="df-ft-form__title">Configure your {role.name} placement</div>
        <DFCommitToggle cfg={cfg} onPatch={onPatch} />
      </div>
      <div className="df-field">
        <label className="df-field__label">
          Location
          {window.HoverPortalTip && (
            <window.HoverPortalTip
              wrapClassName="df-loc-tip-wrap"
              wrapStyle={{marginLeft: '6px', display: 'inline-flex', verticalAlign: 'middle'}}
              tipClassName="dis-tip dis-tip--above"
              tip={"Floor rate for this location. Final monthly fee is confirmed after we shortlist candidates to your brief."}
              placement="above"
            >
              <span className="df-loc-tip-icon" aria-label="About these rates">i</span>
            </window.HoverPortalTip>
          )}
        </label>
        <div className="df-field__sub">Where should this specialist be based?</div>
        {/* df-radio-row--loc gives all location pills uniform top padding so content aligns */}
        <div className="df-radio-row df-radio-row--loc">
          {FT_LOCATIONS.map(loc => {
            const on = cfg.location === loc.id;
            const range = dfHourlyRange(role, loc.id);
            const isRec = recLocId === loc.id;
            return (
              <button
                key={loc.id}
                type="button"
                className={`df-radio-pill df-radio-pill--loc ${on ? 'df-radio-pill--on' : ''}`}
                onClick={() => onPatch({ location: loc.id })}
                aria-pressed={on}
              >
                <span style={{display:'flex',alignItems:'center',gap:'8px'}}>
                  <span className="df-radio-pill__flag" aria-hidden="true">
                    <img
                      src={`https://flagcdn.com/${loc.cc}.svg`}
                      alt=""
                      className="df-radio-pill__flag-img"
                      width="20"
                      height="14"
                      loading="lazy"
                    />
                  </span>
                  <span>{loc.label}</span>
                </span>
                <span className="df-radio-pill__range">
                  from £{loc.hourlyFrom}/hour
                </span>
                {isRec && (
                  <img
                    src="assets/badges/recommended.webp"
                    alt="Recommended"
                    className="df-location-rec-ribbon"
                    aria-hidden="true"
                  />
                )}
              </button>
            );
          })}
        </div>
        <div className="df-field__sub" style={{marginTop:'8px',fontStyle:'italic',fontSize:'12px',opacity:0.8}}>
          Floor rate shown. Final monthly fee confirmed after shortlist, once we review the brief and seniority match.
        </div>
      </div>

      <div className="df-field">
        <label className="df-field__label">Seniority</label>
        <div className="df-field__sub">We'll match candidates to this experience tier.</div>
        <div className="df-radio-row">
          {FT_SENIORITY.map(s => {
            const on = cfg.seniority === s.id;
            const rate = dfSeniorityRate(role, cfg.location, s.id);
            return (
              <button
                key={s.id}
                type="button"
                className={`df-radio-pill df-radio-pill--col ${on ? 'df-radio-pill--on' : ''}`}
                onClick={() => onPatch({ seniority: s.id })}
                aria-pressed={on}
              >
                <span className="df-radio-pill__name">{s.label}</span>
                <span className="df-radio-pill__blurb">{s.blurb}</span>
                {rate != null && (
                  <span className="df-radio-pill__rate">from £{rate}/hour</span>
                )}
              </button>
            );
          })}
        </div>
      </div>

      <div className="df-field">
        <label className="df-field__label">What tasks do you want them to do? <span className="df-field__opt">(optional)</span></label>
        <div className="df-field__sub">A short brief helps us match the right candidates and price the role accurately.</div>
        <textarea
          className="df-textarea"
          rows={3}
          placeholder="e.g. Cold outreach to UK SaaS founders, ~50 emails/day; running discovery calls; CRM hygiene…"
          value={cfg.tasks || ''}
          onChange={e => onPatch({ tasks: e.target.value })}
        />
      </div>
    </div>
  );
}

// ── ONBOARDING AVAILABILITY ────────────────────────────────────────────────
function DFAvailability({ tier }) {
  // §3.6, qualifier-aware capacity status. urgency=now shifts to Limited
  // (proxy for the spec's hiringTime='within-14-days'). Falls back to the
  // legacy addonAvailability helper when getDrFtTalentCapacity isn't loaded
  // (initial render race) or when tier is PT.
  const isFT = tier === 'fulltime';
  let status = 'open';
  let caption = 'We currently have capacity to onboard new clients for this service. We recommend scheduling a call soon to secure your spot, as we will move to a waiting list once our capacity limit is reached to ensure quality for our existing clients.';
  if (isFT && typeof window.getDrFtTalentCapacity === 'function') {
    const cap = window.getDrFtTalentCapacity(window.__lastBuildPageState);
    status = cap.status || 'open';
    caption = cap.caption || caption;
  } else if (window.addonAvailability) {
    const cap = window.addonAvailability({ id: 'dedicated-resources', badge: 'recommended' });
    status = cap.status || 'open';
  }
  return (
    <div className={`df-avail capacity capacity--${status}`}>
      <div className="df-avail__head">
        <span className="df-avail__title">Onboarding Availability:</span>
        <span className="df-avail__status">
          {status === 'open' && (
            <svg viewBox="0 0 16 16" width="13" height="13" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
              <circle cx="8" cy="8" r="6.5" />
              <path d="M5 8.5l2 2L11.5 6" />
            </svg>
          )}
          {status === 'limited' && (
            <svg viewBox="0 0 16 16" width="13" height="13" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
              <circle cx="8" cy="8" r="6.5" />
              <line x1="8" y1="5" x2="8" y2="9" strokeLinecap="round" />
              <circle cx="8" cy="11.5" r="0.6" fill="currentColor" stroke="none" />
            </svg>
          )}
          {status === 'closed' && (
            <svg viewBox="0 0 16 16" width="13" height="13" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
              <circle cx="8" cy="8" r="6.5" />
              <line x1="5" y1="5" x2="11" y2="11" strokeLinecap="round" />
              <line x1="11" y1="5" x2="5" y2="11" strokeLinecap="round" />
            </svg>
          )}
          <span className="df-avail__status-text">
            {status === 'open' && 'Open'}
            {status === 'limited' && 'Limited'}
            {status === 'nearly-full' && 'Nearly Full'}
            {status === 'full' && 'Full'}
            {status === 'closed' && 'Closed'}
          </span>
        </span>
      </div>
      <div className="df-avail__track">
        {window.CapacityVideo ? <window.CapacityVideo status={status} /> : null}
      </div>
      <div className="df-avail__copy">{caption}</div>
    </div>
  );
}

// ── MAIN COMPONENT ─────────────────────────────────────────────────────────────────────────
function DedicatedFlow({ service, selection, onSelect, onTier, onToggleRole, onSetRoleConfig }) {
  const active = !!selection;
  const tier = selection?.tier || service.tiers?.[0]?.id || 'parttime';
  const isFT = tier === 'fulltime';
  const selectedRoles = selection?.roles || [];
  const cfgs = selection?.roleConfigs || {};
  const roles = dfRolesForTier(service, tier);

  const [focusedRoleId, setFocusedRoleId] = dfUseState(null);
  dfUseEffect(() => {
    if (selectedRoles.length === 0) {
      if (focusedRoleId !== null) setFocusedRoleId(null);
      return;
    }
    if (!focusedRoleId || !selectedRoles.includes(focusedRoleId)) {
      setFocusedRoleId(selectedRoles[selectedRoles.length - 1]);
    }
  }, [selectedRoles.join('|')]);

  const handleTier = (tid) => {
    if (active && tier === tid) { onSelect(false); return; }
    if (!active) onSelect(true);
    onTier(tid);
  };

  const handleToggleRole = (rid) => {
    const isRemoving = active && selectedRoles.includes(rid);
    const isLastRole = isRemoving && selectedRoles.length === 1;
    // Activating dedicated-ft via a role-tile click: SET_SERVICE auto-seeds
    // the qualifier-driven default roles (founders-talent §5). If the clicked
    // role is among those defaults, TOGGLE_ROLE here would immediately remove
    // it. Detect that case and skip the toggle, the seed already includes it.
    const isFirstActivation = !active;
    let skipToggleAfterSeed = false;
    if (isFirstActivation && service?.id === 'dedicated-ft' && tier === 'fulltime') {
      const defaults = window.getDrFtDefaultRoles
        ? window.getDrFtDefaultRoles(window.__lastBuildPageState)
        : [];
      if (defaults.includes(rid)) skipToggleAfterSeed = true;
    }
    if (isFirstActivation && service?.id === 'dedicated-pt' && tier === 'parttime') {
      const defaults = window.getDrPtDefaultRoles
        ? window.getDrPtDefaultRoles(window.__lastBuildPageState)
        : [];
      if (defaults.includes(rid)) skipToggleAfterSeed = true;
    }
    if (!active) onSelect(true);
    if (isLastRole) { onSelect(false); return; }
    if (!skipToggleAfterSeed) onToggleRole(rid);
    if (!isRemoving) {
      setFocusedRoleId(rid);
      const role = dfRoleById(service, tier, rid);
      if (role) {
        if (tier === 'parttime' && !cfgs[rid]?.days) {
          onSetRoleConfig(rid, { days: 5 });
        } else if (tier === 'fulltime') {
          // Set the recommended location as the default when a FT role is first selected.
          // ROLE_RECS and FT_LOCATIONS are local to this file, no window lookup needed.
          const recEntry = ROLE_RECS[rid];
          const recLoc = recEntry ? FT_LOCATIONS.find(l => l.cc === recEntry.cc) : null;
          const recLocId = recLoc ? recLoc.id : 'philippines';
          onSetRoleConfig(rid, { location: recLocId, seniority: 'mid', tasks: '' });
        }
      }
    }
  };

  const focusedRole = focusedRoleId ? dfRoleById(service, tier, focusedRoleId) : null;
  const focusedCfg = focusedRoleId ? (cfgs[focusedRoleId] || {}) : {};

  let ptMonthly = 0;
  if (!isFT) {
    selectedRoles.forEach(rid => {
      const role = dfRoleById(service, tier, rid);
      const days = cfgs[rid]?.days || 0;
      if (!role || !role.price) return;
      let dayRate;
      if (role.dayRates) {
        if (days === 1) dayRate = role.dayRates.d1;
        else if (days === 5) dayRate = role.dayRates.d5;
        else if (days === 10) dayRate = role.dayRates.d10;
        else if (days >= 11) dayRate = role.dayRates.custom;
        else dayRate = role.dayRates.d1;
      } else {
        let discount = 0;
        if (days === 5) discount = 0.10;
        else if (days === 10) discount = 0.12;
        else if (days >= 11) discount = 0.15;
        dayRate = Math.round(role.price * (1 - discount));
      }
      ptMonthly += dayRate * days;
    });
  }

  // Preserve the original order of role cards regardless of selection state.
  // Previously we hoisted selected roles to the front, but that mid-flow
  // reflow confused users, selecting a role made the rest of the list jump.
  const sortedRoles = roles;

  // §3.3, 2-column trust grid. Verbatim copy from the talent spec. Only
  // surfaces on FT (PT has a simpler single-line trust line).
  const FT_TRUST_LEFT = [
    { label: '90-Day Performance Guarantee',                                 tip: "If a placed specialist isn't the right fit within the first 90 days. We replace them at no charge. The performance bar is set on the kick-off call so both sides know what 'right fit' means before day one." },
    { label: 'Algorithmic Skill Matching & Practical Assessments',           tip: 'Every specialist is scored across the brief hard-skill requirements via a structured test bank, then a 30-minute video panel with the GoGorilla talent team. You receive 2-3 shortlisted candidates with the test scores attached.' },
    { label: 'GorillaMatrix Performance Tracking',                           tip: 'Every placed specialist is tracked in GorillaMatrix: output velocity, quality scores, brief-completion rates. You see the dashboard. Performance reviews happen at month 1, 3, 6, and 12.' },
    { label: 'Dedicated Account Management',                                 tip: 'A UK-based AM owns the relationship. Weekly check-ins, escalation routing, performance reviews, brief refinement.' },
    { label: 'GorillaPerks Investor Portal & Bundle Discounts',              tip: 'Every active Talent engagement unlocks the GorillaPerks portal: investor-network access, multi-service bundle discounts, partner tooling discounts, founder/investor flywheel introductions.' },
  ];
  const FT_TRUST_RIGHT = [
    { label: 'Access to Global Talent',                                      tip: 'We recruit from over 130 countries with a particular focus on the UK, South Africa, and the Philippines. We can advise which country is likely to provide access to the best talent for each role whilst driving optimal capital efficiency.' },
    { label: 'Full HR & Payroll Administration',                             tip: 'We handle hiring, contracts, payroll, leave management, performance reviews, and offboarding. You manage the work output; we manage the employment relationship.' },
    { label: 'International Compliance Handled',                             tip: 'Local employment law, tax compliance, employer social-cost equivalents, data-protection requirements (GDPR / POPIA / Data Privacy Act) all handled in the specialist home jurisdiction by our local entities or trusted EOR partners.' },
    { label: 'Ongoing Training & Development',                               tip: 'Our specialists receive ongoing training and development to ensure they remain at the forefront of their fields.' },
    { label: 'Talent Buyout Option',                                         tip: 'Transition a specialist to a direct employee. The fee is a declining multiple of the monthly management fee based on tenure: 4x at 12 to 18 months, 3x at 18 to 24 months, and 2x at 24 months and beyond. Pre-agreed pathway means there are no surprise costs when you are ready to bring them in-house.' },
  ];

  return (
    <div className="df">
      <DFTimeToggle service={service} tier={selection?.tier} onTier={handleTier} hasSelection={active} />

      {isFT && (
        <div className="df-trust-grid" role="list" aria-label="What you get with embedded full-time talent">
          <div className="df-trust-grid__col">
            <div className="df-trust-grid__title">Talent Acquisition</div>
            <ul className="df-trust-grid__list">
              {FT_TRUST_LEFT.map((p, i) => (
                <li key={'l'+i} className="df-trust-grid__item" role="listitem">
                  <svg className="df-trust-grid__check" viewBox="0 0 16 16" width="13" height="13" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                    <polyline points="3 8.5 6.5 12 13 4.5"/>
                  </svg>
                  <span className="df-trust-grid__label">{p.label}</span>
                  {window.HoverPortalTip ? (
                    <window.HoverPortalTip
                      wrapClassName="df-trust-grid__info-wrap"
                      tipClassName="dis-tip dis-tip--above"
                      placement="above"
                      tip={p.tip}
                    >
                      <button type="button" className="df-trust-grid__info" aria-label={`About ${p.label}`} tabIndex={0}>
                        <svg viewBox="0 0 16 16" width="11" height="11" fill="none" stroke="currentColor" strokeWidth="1.6" aria-hidden="true">
                          <circle cx="8" cy="8" r="6.5"/>
                          <line x1="8" y1="11" x2="8" y2="7" strokeLinecap="round"/>
                          <circle cx="8" cy="5" r="0.5" fill="currentColor"/>
                        </svg>
                      </button>
                    </window.HoverPortalTip>
                  ) : (
                    <span className="df-trust-grid__info" title={p.tip} aria-label={`About ${p.label}`}>i</span>
                  )}
                </li>
              ))}
            </ul>
          </div>
          <div className="df-trust-grid__col">
            <div className="df-trust-grid__title">Talent Operations</div>
            <ul className="df-trust-grid__list">
              {FT_TRUST_RIGHT.map((p, i) => (
                <li key={'r'+i} className="df-trust-grid__item" role="listitem">
                  <svg className="df-trust-grid__check" viewBox="0 0 16 16" width="13" height="13" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                    <polyline points="3 8.5 6.5 12 13 4.5"/>
                  </svg>
                  <span className="df-trust-grid__label">{p.label}</span>
                  {window.HoverPortalTip ? (
                    <window.HoverPortalTip
                      wrapClassName="df-trust-grid__info-wrap"
                      tipClassName="dis-tip dis-tip--above"
                      placement="above"
                      tip={p.tip}
                    >
                      <button type="button" className="df-trust-grid__info" aria-label={`About ${p.label}`} tabIndex={0}>
                        <svg viewBox="0 0 16 16" width="11" height="11" fill="none" stroke="currentColor" strokeWidth="1.6" aria-hidden="true">
                          <circle cx="8" cy="8" r="6.5"/>
                          <line x1="8" y1="11" x2="8" y2="7" strokeLinecap="round"/>
                          <circle cx="8" cy="5" r="0.5" fill="currentColor"/>
                        </svg>
                      </button>
                    </window.HoverPortalTip>
                  ) : (
                    <span className="df-trust-grid__info" title={p.tip} aria-label={`About ${p.label}`}>i</span>
                  )}
                </li>
              ))}
            </ul>
          </div>
        </div>
      )}

      <div className="df-section__head df-section__head--stacked">
        <DFAvailability tier={selection?.tier} />
        <div className="df-section__head-left">
          <div className="df-section__title">
            Roles
            <span className="df-section__info" aria-hidden="true">
              <svg viewBox="0 0 16 16" width="13" height="13" fill="none" stroke="currentColor" strokeWidth="1.6">
                <circle cx="8" cy="8" r="6.5"/>
                <path d="M8 11V7M8 5h0" strokeLinecap="round"/>
              </svg>
            </span>
          </div>
          <div className="df-section__sub">
            Choose from the following {tier === 'fulltime' ? 'full time' : 'part time'} roles:
          </div>
        </div>
      </div>

      {/* §13, soft "too early for FT" warning. Surfaces only for
          pre-revenue founders with sub-£1k ACV. Reads the global
          BuildPage state since DedicatedFlow doesn't receive qualifier
          as a prop. Pure render, no state changes from the warning. */}
      {tier === 'fulltime' && window.isDrFtTooEarlyWarning && window.isDrFtTooEarlyWarning(window.__lastBuildPageState) && (
        <div className="df-too-early-warning" role="note">
          <svg className="df-too-early-warning__icon" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
            <path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>
            <line x1="12" y1="9" x2="12" y2="13"/>
            <circle cx="12" cy="17" r="0.9" fill="currentColor" stroke="none"/>
          </svg>
          <span>
            Full-time embeds start around <strong>£3,000/mo</strong>. At your stage, a Part-Time block or a managed retainer is often a better fit. You can still proceed. We will calibrate scope at kick-off.
          </span>
        </div>
      )}

      {tier === 'fulltime' && (
        <div className="df-deposit-notice">
          <svg className="df-deposit-notice__icon" viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
            <rect x="2" y="4" width="12" height="9" rx="2"/>
            <path d="M5 4V3a3 3 0 0 1 6 0v1"/>
            <circle cx="8" cy="8.5" r="1" fill="currentColor" stroke="none"/>
          </svg>
          <span>
            A <strong>£{DEDICATED_DEPOSIT} refundable deposit</strong> is required per role, due today to progress your search. Billed at checkout, returned if no placement is made.
          </span>
        </div>
      )}

      <div className="df-roles-wrap">
        <div className="df-role-grid">
          {sortedRoles.map(role => {
            const on = selectedRoles.includes(role.id);
            return (
              <DFRoleCard
                key={role.id}
                role={role}
                on={on}
                isFocused={role.id === focusedRoleId}
                onToggle={() => handleToggleRole(role.id)}
                onFocus={() => setFocusedRoleId(role.id)}
                isFT={isFT}
                rec={isFT ? ROLE_RECS[role.id] : null}
              />
            );
          })}
        </div>
      </div>

      {/* 2026-05-26: inline-config lifted OUT of df-roles-wrap so it is a
          direct sibling of df-deposit-card + df-forecast. Lets the
          sibling-selector + :has() merge CSS visually combine the three. */}
      {selectedRoles.length > 0 && focusedRole && (
          <div className="df-inline-config">
            {selectedRoles.length > 1 && (
              <div className="df-tab-strip" role="tablist">
                {selectedRoles.map(rid => {
                  const r = dfRoleById(service, tier, rid);
                  if (!r) return null;
                  const tabOn = rid === focusedRoleId;
                  return (
                    <button
                      key={rid}
                      type="button"
                      role="tab"
                      aria-selected={tabOn}
                      className={`df-tab ${tabOn ? 'df-tab--on' : ''}`}
                      onClick={() => setFocusedRoleId(rid)}
                    >
                      {r.name}
                    </button>
                  );
                })}
              </div>
            )}

            <div className="df-inline-config__body" key={focusedRoleId}>
              {isFT ? (
                <DFFullTimeForm
                  role={focusedRole}
                  cfg={focusedCfg}
                  onPatch={patch => onSetRoleConfig(focusedRoleId, patch)}
                />
              ) : (
                <DFDayRateTiles
                  role={focusedRole}
                  cfg={focusedCfg}
                  onPatch={patch => onSetRoleConfig(focusedRoleId, patch)}
                />
              )}
            </div>
          </div>
        )}

      {selectedRoles.length > 0 && (
        <div className="df-deposit-card">
          {isFT ? (
            <>
              <div className="df-deposit-card__row df-deposit-card__row--main">
                <div>
                  <div className="df-deposit-card__label">Estimated monthly per role</div>
                  <div className="df-deposit-card__sub">Range shown on each role card · confirmed after shortlist</div>
                </div>
                <div className="df-deposit-card__amt">Custom</div>
              </div>
              <div className="df-deposit-card__row df-deposit-card__row--deposit">
                <div>
                  <div className="df-deposit-card__label df-deposit-card__label--deposit">
                    Placement deposit{selectedRoles.length > 1 ? ` × ${selectedRoles.length} roles` : ''}
                  </div>
                  <div className="df-deposit-card__sub">£{DEDICATED_DEPOSIT}/role · refundable · due today · added to your total</div>
                </div>
                <div className="df-deposit-card__amt df-deposit-card__amt--deposit">£{DEDICATED_DEPOSIT * selectedRoles.length}</div>
              </div>
            </>
          ) : (
            <>
              <div className="df-deposit-card__row df-deposit-card__row--main">
                <div>
                  <div className="df-deposit-card__label">Estimated monthly</div>
                  <div className="df-deposit-card__sub">Based on day rates × days/month</div>
                </div>
                <div className="df-deposit-card__amt">{ptMonthly > 0 ? window.fmt(Math.round(ptMonthly)) : '—'}</div>
              </div>
            </>
          )}
          <div className="df-deposit-card__foot">
            <window.Lock size={12} /> {isFT ? 'Monthly fee confirmed after candidate shortlist · billed on placement. Deposit is fully refundable if no placement is made.' : 'Estimate only, final pricing confirmed on shortlist.'}
          </div>
        </div>
      )}

      {/* §3.7, Collapsible "in-house cost comparison" forecast panel. Only
          for FT (PT compares against UK freelance day rates, different lookup).
          Reads window.drFtForecast(state) which uses DR_FT_UK_BASE_SALARY × 1.4
          for the in-house side and hourlyFrom × hours × commit multiplier for
          the GoGorilla side. */}
      {isFT && selectedRoles.length > 0 && window.drFtForecast && (() => {
        const fc = window.drFtForecast(window.__lastBuildPageState);
        if (fc.gorilla.total === 0) return null;
        return (
          <details className="df-forecast">
            <summary className="df-forecast__trigger">
              <span className="df-forecast__trigger-label">See the in-house cost comparison</span>
              <svg className="df-forecast__chevron" viewBox="0 0 12 12" width="11" height="11" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                <polyline points="3 4.5 6 8 9 4.5"/>
              </svg>
            </summary>
            <div className="df-forecast__panel">
              <div className="df-forecast__cols">
                <div className="df-forecast__col df-forecast__col--gorilla">
                  <div className="df-forecast__col-head">GoGorilla · 12 months</div>
                  <ul className="df-forecast__rows">
                    {fc.gorilla.rows.map(r => (
                      <li key={r.roleId}>
                        <span>{r.name}</span>
                        <span>{window.fmt(r.annual)}</span>
                      </li>
                    ))}
                  </ul>
                  <div className="df-forecast__total">{window.fmt(fc.gorilla.total)}</div>
                </div>
                <div className="df-forecast__col df-forecast__col--inhouse">
                  <div className="df-forecast__col-head">In-house UK · 12 months</div>
                  <ul className="df-forecast__rows">
                    {fc.inhouse.rows.map(r => (
                      <li key={r.roleId}>
                        <span>{r.name}</span>
                        <span>{window.fmt(r.annual)}</span>
                      </li>
                    ))}
                  </ul>
                  <div className="df-forecast__total">{window.fmt(fc.inhouse.total)}</div>
                </div>
              </div>
              {fc.savings > 0 && (
                <div className="df-forecast__savings">
                  Save <strong>{window.fmt(fc.savings)}</strong> over 12 months by going with GoGorilla.
                </div>
              )}
              <div className="df-forecast__disclaimer">
                Indicative comparison. GoGorilla pricing uses commit-length rates across Philippines, South Africa, and UK location mix; in-house side uses UK loaded cost (base salary × 1.4 for NI, pension, benefits, equipment, and recruitment). Final numbers confirmed at kickoff.
              </div>
            </div>
          </details>
        );
      })()}
    </div>
  );
}

window.DedicatedFlow = DedicatedFlow;
