/**
 * SDRI Adjust Timing overlay — Explore Flow Plan only.
 * UNLOCK_UI_GOLD: Explore SDRI activity-card + overlay surface (Aaron 2026-09-13).
 * Requires: window.SF_SDRI_EXPLORE_TIMING · window.SylvanFlowAuth · window.SF_API_BASE
 */
(function () {
  'use strict';

  const { useEffect, useLayoutEffect, useRef, useState, useCallback } = React;

  function H() {
    return window.SF_SDRI_EXPLORE_TIMING;
  }

  const COPY_FALLBACK = {
    adjustTiming: 'Adjust timing',
    whenFinish: 'When will you finish?',
    confirmPrefix: 'Confirm',
    checkingDay: 'Checking the rest of your day…',
    recheckingDay: 'Rechecking your day…',
    proposedPlan: 'Proposed Flow Plan',
    acceptChanges: 'Accept changes',
    keepCurrent: 'Keep current plan',
    cancel: 'Cancel',
    rePropose: 'Re-propose',
    customTime: 'Custom time',
    changedByYou: 'Changed by you',
    adjustedBySylvan: 'Adjusted by SylvanFlow',
    unchanged: 'Unchanged',
    protectedLbl: 'Protected',
    tight: 'Tight',
    editedByYou: 'Edited by you',
    committing: 'Saving your plan…',
    refreshing: 'Updating Flow Plan…',
    refreshFailed:
      'Your change was saved, but Flow Plan could not reload. Please retry.',
    retryRefresh: 'Retry refresh',
    noSafeRecovery: 'SylvanFlow cannot produce a safe recovery for this change.',
    errorGeneric: 'Something went wrong. Your Flow Plan was not changed.',
    close: 'Close',
  };

  function useCopy(lang) {
    const [copy, setCopy] = useState(COPY_FALLBACK);

    useEffect(() => {
      let cancelled = false;

      async function resolveSys(key, fallback) {
        try {
          if (typeof window.getSysMessage === 'function') {
            const v = await window.getSysMessage(key, lang || 'en');
            if (v && String(v).trim() && String(v) !== key) return String(v);
          }
        } catch (_) {}
        return fallback;
      }

      (async () => {
        const next = {
          adjustTiming: await resolveSys('ui:sdri_adjust_timing', COPY_FALLBACK.adjustTiming),
          whenFinish: await resolveSys('ui:sdri_when_finish', COPY_FALLBACK.whenFinish),
          confirmPrefix: await resolveSys('ui:sdri_confirm_prefix', COPY_FALLBACK.confirmPrefix),
          checkingDay: await resolveSys('ui:sdri_checking_day', COPY_FALLBACK.checkingDay),
          recheckingDay: await resolveSys('ui:sdri_rechecking_day', COPY_FALLBACK.recheckingDay),
          proposedPlan: await resolveSys('ui:sdri_proposed_plan', COPY_FALLBACK.proposedPlan),
          acceptChanges: await resolveSys('ui:sdri_accept_changes', COPY_FALLBACK.acceptChanges),
          keepCurrent: await resolveSys('ui:sdri_keep_current', COPY_FALLBACK.keepCurrent),
          cancel: await resolveSys('ui:sdri_cancel', COPY_FALLBACK.cancel),
          rePropose: await resolveSys('ui:sdri_repropose', COPY_FALLBACK.rePropose),
          customTime: await resolveSys('ui:sdri_custom_time', COPY_FALLBACK.customTime),
          changedByYou: await resolveSys('ui:sdri_changed_by_you', COPY_FALLBACK.changedByYou),
          adjustedBySylvan: await resolveSys(
            'ui:sdri_adjusted_by_sylvan',
            COPY_FALLBACK.adjustedBySylvan
          ),
          unchanged: await resolveSys('ui:sdri_unchanged', COPY_FALLBACK.unchanged),
          protectedLbl: await resolveSys('ui:sdri_protected', COPY_FALLBACK.protectedLbl),
          tight: await resolveSys('ui:sdri_tight', COPY_FALLBACK.tight),
          editedByYou: await resolveSys('ui:sdri_edited_by_you', COPY_FALLBACK.editedByYou),
          committing: await resolveSys('ui:sdri_committing', COPY_FALLBACK.committing),
          refreshing: await resolveSys('ui:sdri_refreshing', COPY_FALLBACK.refreshing),
          refreshFailed: await resolveSys('ui:sdri_refresh_failed', COPY_FALLBACK.refreshFailed),
          retryRefresh: await resolveSys('ui:sdri_retry_refresh', COPY_FALLBACK.retryRefresh),
          noSafeRecovery: await resolveSys('ui:sdri_no_safe_recovery', COPY_FALLBACK.noSafeRecovery),
          errorGeneric: await resolveSys('ui:sdri_error_generic', COPY_FALLBACK.errorGeneric),
          close: await resolveSys('ui:sdri_close', COPY_FALLBACK.close),
        };
        if (!cancelled) setCopy(next);
      })();

      return () => {
        cancelled = true;
      };
    }, [lang]);

    return copy;
  }

  function presentationText(key, copy) {
    if (key === 'changed_by_you') return copy.changedByYou;
    if (key === 'adjusted') return copy.adjustedBySylvan;
    if (key === 'protected') return copy.protectedLbl;
    if (key === 'tight') return copy.tight;
    if (key === 'edited_by_you') return copy.editedByYou;
    return copy.unchanged;
  }

  function SdriAdjustTimingOverlay(props) {
    const {
      open,
      tripKey,
      dayKey,
      activity,
      activityTitle,
      activityByKey,
      lang,
      onClose,
      onCommittedRefresh,
    } = props;

    const helpers = H();
    const PHASE = helpers.PHASE;
    const copy = useCopy(lang);

    const [phase, setPhase] = useState(PHASE.CLOSED);
    const [stagedEnd, setStagedEnd] = useState(null);
    const [customEnd, setCustomEnd] = useState('');
    const [validProposal, setValidProposal] = useState(null);
    const [draftRows, setDraftRows] = useState([]);
    const [travellerConstraints, setTravellerConstraints] = useState({});
    const [errorMsg, setErrorMsg] = useState(null);
    const [busyHint, setBusyHint] = useState(null);
    const [lastCommitIntent, setLastCommitIntent] = useState(null);

    const reqGenRef = useRef(0);
    const abortRef = useRef(null);
    const openRef = useRef(false);
    const scrollLockRef = useRef(null);
    const sessionIdentityRef = useRef(null);

    const title =
      activityTitle || (activity && (activity.title || activity.Title)) || 'Activity';
    const triggerKey = helpers.resolveActivityKey(activity);
    const startHhmm = helpers.resolveActivityStart(activity);

    const endOpts = useCallback(
      (endHhmm) => {
        const now = new Date();
        return {
          dayKey,
          startHhmm,
          clientDayKey: helpers.formatClientDayKeyLocal(now),
          clientLocalHhmm: helpers.formatClientLocalHhmm(now),
          endHhmm: endHhmm || undefined,
          now,
        };
      },
      [dayKey, startHhmm, helpers]
    );

    const cancelInFlight = useCallback(() => {
      reqGenRef.current += 1;
      if (abortRef.current) {
        try {
          abortRef.current.abort();
        } catch (_) {}
        abortRef.current = null;
      }
    }, []);

    const resetLocal = useCallback(() => {
      setPhase(PHASE.CLOSED);
      setStagedEnd(null);
      setCustomEnd('');
      setValidProposal(null);
      setDraftRows([]);
      setTravellerConstraints({});
      setErrorMsg(null);
      setBusyHint(null);
      setLastCommitIntent(null);
    }, [PHASE]);

    const dismissBlocked =
      phase === PHASE.REFRESHING || phase === PHASE.REFRESH_FAILED;

    const finishAfterRefresh = useCallback(
      (intent) => {
        cancelInFlight();
        resetLocal();
        openRef.current = false;
        sessionIdentityRef.current = null;
        if (typeof onClose === 'function') {
          onClose({ committed: true, intent: intent || lastCommitIntent });
        }
      },
      [cancelInFlight, resetLocal, onClose, lastCommitIntent]
    );

    const runPostCommitRefresh = useCallback(
      async (gen, previewId, intent) => {
        setErrorMsg(null);
        setBusyHint(copy.refreshing);
        setPhase(PHASE.REFRESHING);
        let refreshed = false;
        if (typeof onCommittedRefresh === 'function') {
          try {
            refreshed = !!(await onCommittedRefresh({ tripKey, dayKey, previewId }));
          } catch (_) {
            refreshed = false;
          }
        }
        if (gen !== reqGenRef.current || !openRef.current) return;
        setBusyHint(null);
        if (refreshed) {
          finishAfterRefresh(intent);
        } else {
          setPhase(PHASE.REFRESH_FAILED);
          setErrorMsg(copy.refreshFailed);
        }
      },
      [PHASE, copy, onCommittedRefresh, tripKey, dayKey, finishAfterRefresh]
    );

    const runRetryRefresh = useCallback(async () => {
      const gen = ++reqGenRef.current;
      setErrorMsg(null);
      setBusyHint(copy.refreshing);
      setPhase(PHASE.REFRESHING);
      let refreshed = false;
      if (typeof onCommittedRefresh === 'function') {
        try {
          refreshed = !!(await onCommittedRefresh({ tripKey, dayKey }));
        } catch (_) {
          refreshed = false;
        }
      }
      if (gen !== reqGenRef.current || !openRef.current) return;
      setBusyHint(null);
      if (refreshed) {
        finishAfterRefresh(lastCommitIntent);
      } else {
        setPhase(PHASE.REFRESH_FAILED);
        setErrorMsg(copy.refreshFailed);
      }
    }, [
      PHASE,
      copy,
      onCommittedRefresh,
      tripKey,
      dayKey,
      finishAfterRefresh,
      lastCommitIntent,
    ]);

    const handleCancel = useCallback(() => {
      if (dismissBlocked) return;
      cancelInFlight();
      resetLocal();
      openRef.current = false;
      sessionIdentityRef.current = null;
      if (typeof onClose === 'function') onClose({ committed: false });
    }, [dismissBlocked, cancelInFlight, resetLocal, onClose]);

    useEffect(() => {
      if (open) {
        openRef.current = true;
        cancelInFlight();
        setErrorMsg(null);
        setValidProposal(null);
        setDraftRows([]);
        setTravellerConstraints({});
        setBusyHint(null);
        setLastCommitIntent(null);
        const earliest = helpers.earliestValidEndHhmm(endOpts());
        setStagedEnd(earliest);
        setCustomEnd(earliest || '');
        setPhase(PHASE.TIME_SELECT);
        sessionIdentityRef.current = [
          String(tripKey || ''),
          String(dayKey || ''),
          String(helpers.resolveActivityKey(activity) || ''),
        ].join('|');
      } else if (openRef.current) {
        cancelInFlight();
        resetLocal();
        openRef.current = false;
        sessionIdentityRef.current = null;
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [open]);

    useEffect(() => {
      if (!open || !openRef.current) return;
      const next = [
        String(tripKey || ''),
        String(dayKey || ''),
        String(helpers.resolveActivityKey(activity) || ''),
      ].join('|');
      const prev = sessionIdentityRef.current;
      if (prev && next !== prev) handleCancel();
    }, [open, tripKey, dayKey, activity, helpers, handleCancel]);

    useLayoutEffect(() => {
      if (!open) {
        if (scrollLockRef.current) {
          document.documentElement.style.overflow = scrollLockRef.current.html;
          document.body.style.overflow = scrollLockRef.current.body;
          scrollLockRef.current = null;
        }
        return undefined;
      }
      scrollLockRef.current = {
        html: document.documentElement.style.overflow,
        body: document.body.style.overflow,
      };
      document.documentElement.style.overflow = 'hidden';
      document.body.style.overflow = 'hidden';
      return () => {
        if (scrollLockRef.current) {
          document.documentElement.style.overflow = scrollLockRef.current.html;
          document.body.style.overflow = scrollLockRef.current.body;
          scrollLockRef.current = null;
        }
      };
    }, [open]);

    const selectEnd = useCallback(
      (hhmm) => {
        const n = helpers.normalizeHhmm(hhmm);
        if (!n) return;
        if (!helpers.isValidCustomEnd(endOpts(n))) return;
        setErrorMsg(null);
        setStagedEnd(n);
        setCustomEnd(n);
        setPhase(PHASE.END_SELECTED);
      },
      [helpers, endOpts, PHASE]
    );

    const postJson = useCallback(async (path, body, gen) => {
      const controller = new AbortController();
      abortRef.current = controller;
      const base = window.SF_API_BASE || '';
      const url = `${base}${path}`;
      const auth = window.SylvanFlowAuth;
      if (!auth || typeof auth.authenticatedFetch !== 'function') {
        throw new Error('SylvanFlowAuth.authenticatedFetch unavailable');
      }
      const res = await auth.authenticatedFetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
        signal: controller.signal,
      });
      if (typeof auth.handleAuthResponse === 'function') {
        auth.handleAuthResponse(res);
      }
      let data = null;
      try {
        data = await res.json();
      } catch (_) {
        data = null;
      }
      if (gen !== reqGenRef.current || !openRef.current) return { stale: true };
      return { stale: false, res, data };
    }, []);

    const runImpactPreview = useCallback(
      async (rePropose) => {
        if (!triggerKey || !stagedEnd || !tripKey || !dayKey) return;
        const gen = ++reqGenRef.current;
        setErrorMsg(null);
        setBusyHint(rePropose ? copy.recheckingDay : copy.checkingDay);
        setPhase(rePropose ? PHASE.ANALYSING_REPROPOSE : PHASE.ANALYSING);

        const now = new Date();
        const timingConstraints = rePropose
          ? helpers.travellerConstraintsToArray(travellerConstraints)
          : null;

        const body = helpers.buildImpactPreviewBody({
          tripKey,
          dayKey,
          clientDayKey: helpers.formatClientDayKeyLocal(now),
          clientLocalHhmm: helpers.formatClientLocalHhmm(now),
          triggerActivityKey: triggerKey,
          newEndHhmm: stagedEnd,
          supersedesPreviewId:
            rePropose && validProposal
              ? validProposal.preview_id || validProposal.previewId || null
              : null,
          timingConstraints: rePropose ? timingConstraints : null,
        });
        if (!helpers.assertNoClientOpSet(body)) {
          setErrorMsg(copy.errorGeneric);
          setBusyHint(null);
          setPhase(rePropose ? PHASE.DIRTY_EDIT : PHASE.END_SELECTED);
          return;
        }

        try {
          const out = await postJson('/api/sdri/impact-preview', body, gen);
          if (out.stale) return;
          setBusyHint(null);
          const data = out.data || {};
          if (!out.res.ok || data.ok === false) {
            const code = String(data.code || data.error || '');
            const infeasible = /INFEASIBLE|NO_SAFE|HARD_PROTECTED|PROTECTED|ERR_SDRI/i.test(code);
            setErrorMsg(infeasible ? copy.noSafeRecovery : data.message || copy.errorGeneric);
            setPhase(rePropose ? PHASE.DIRTY_EDIT : PHASE.END_SELECTED);
            return;
          }
          const status = data.proposal_status || data.status;
          if (status === 'infeasible' || status === 'no_safe_recovery') {
            setErrorMsg(copy.noSafeRecovery);
            setPhase(rePropose ? PHASE.DIRTY_EDIT : PHASE.END_SELECTED);
            return;
          }
          const rows = Array.isArray(data.rows) ? data.rows : [];
          const proposal = {
            preview_id: data.preview_id || data.previewId,
            proposal_status: status,
            proposal_provenance: data.proposal_provenance || data.provenance,
            proposal_revision: data.proposal_revision,
            rows,
          };
          setValidProposal(helpers.cloneJson(proposal));
          setDraftRows(
            rows.map((r) => ({
              ...helpers.cloneJson(r),
              __dirty: false,
              __draftStart: (r.proposed && r.proposed.start) || r.start_hhmm || null,
              __draftEnd: (r.proposed && r.proposed.end) || r.end_hhmm || null,
            }))
          );
          setPhase(rePropose ? PHASE.PROPOSAL_VALID_NEW : PHASE.PROPOSAL_VALID);
        } catch (e) {
          if (gen !== reqGenRef.current || !openRef.current) return;
          if (e && e.name === 'AbortError') return;
          setBusyHint(null);
          setErrorMsg(copy.errorGeneric);
          setPhase(rePropose ? PHASE.DIRTY_EDIT : PHASE.END_SELECTED);
        }
      },
      [
        triggerKey,
        stagedEnd,
        tripKey,
        dayKey,
        copy,
        PHASE,
        travellerConstraints,
        validProposal,
        helpers,
        postJson,
      ]
    );

    const onDirtyEditRow = useCallback(
      (activityKey, field, value) => {
        const n = helpers.normalizeHhmm(value);
        let nextStart = null;
        let nextEnd = null;
        setDraftRows((prev) =>
          prev.map((row) => {
            const ak = row.activity_key || row.activityKey;
            if (String(ak) !== String(activityKey)) return row;
            const next = { ...row, __dirty: true };
            const proposed = { ...(row.proposed || {}) };
            if (field === 'start') {
              next.__draftStart = n || value;
              if (n) proposed.start = n;
            } else {
              next.__draftEnd = n || value;
              if (n) proposed.end = n;
            }
            next.proposed = proposed;
            next.presentation = 'edited_by_you';
            nextStart = next.__draftStart;
            nextEnd = next.__draftEnd;
            return next;
          })
        );
        setTravellerConstraints((tcPrev) =>
          helpers.mergeTravellerConstraint(tcPrev, activityKey, nextStart, nextEnd)
        );
        setPhase(PHASE.DIRTY_EDIT);
        setErrorMsg(null);
      },
      [helpers, PHASE]
    );

    const runCommit = useCallback(
      async (intent) => {
        const previewId =
          validProposal && (validProposal.preview_id || validProposal.previewId);
        if (!previewId) return;
        if (phase === PHASE.DIRTY_EDIT) return;
        const gen = ++reqGenRef.current;
        setErrorMsg(null);
        setBusyHint(copy.committing);
        setLastCommitIntent(intent);
        setPhase(
          intent === helpers.COMMIT_KEEP_END_ONLY
            ? PHASE.COMMITTING_KEEP
            : PHASE.COMMITTING_ACCEPT
        );
        const body = helpers.buildCommitBody({
          previewId,
          commitIntent: intent,
        });
        if (!helpers.assertNoClientOpSet(body)) {
          setErrorMsg(copy.errorGeneric);
          setBusyHint(null);
          setPhase(PHASE.PROPOSAL_VALID);
          return;
        }
        try {
          const out = await postJson('/api/sdri/commit', body, gen);
          if (out.stale) return;
          setBusyHint(null);
          const data = out.data || {};
          if (!out.res.ok || data.ok === false) {
            setErrorMsg(data.message || copy.errorGeneric);
            setPhase(PHASE.PROPOSAL_VALID);
            return;
          }
          await runPostCommitRefresh(gen, previewId, intent);
        } catch (e) {
          if (gen !== reqGenRef.current || !openRef.current) return;
          if (e && e.name === 'AbortError') return;
          setBusyHint(null);
          setErrorMsg(copy.errorGeneric);
          setPhase(PHASE.PROPOSAL_VALID);
        }
      },
      [
        validProposal,
        phase,
        PHASE,
        copy,
        helpers,
        postJson,
        runPostCommitRefresh,
      ]
    );

    if (!open || phase === PHASE.CLOSED) return null;

    const quick = helpers.quickEndChoices(endOpts(), 4);
    const analysing =
      phase === PHASE.ANALYSING || phase === PHASE.ANALYSING_REPROPOSE;
    const committing =
      phase === PHASE.COMMITTING_ACCEPT || phase === PHASE.COMMITTING_KEEP;
    const refreshing = phase === PHASE.REFRESHING;
    const refreshFailed = phase === PHASE.REFRESH_FAILED;
    const showProposal =
      phase === PHASE.PROPOSAL_VALID ||
      phase === PHASE.PROPOSAL_VALID_NEW ||
      phase === PHASE.DIRTY_EDIT ||
      committing ||
      refreshing ||
      refreshFailed;
    const dirty = phase === PHASE.DIRTY_EDIT;
    const confirmEnabled =
      !!stagedEnd &&
      helpers.isValidCustomEnd(endOpts(stagedEnd)) &&
      (phase === PHASE.TIME_SELECT || phase === PHASE.END_SELECTED) &&
      !analysing;
    const acceptEnabled =
      showProposal &&
      !dirty &&
      !committing &&
      !refreshing &&
      !refreshFailed &&
      !!validProposal &&
      !!(validProposal.preview_id || validProposal.previewId);

    const glass = {
      backgroundColor: 'rgba(10, 14, 22, 0.88)',
      backdropFilter: 'blur(18px) saturate(1.35)',
      WebkitBackdropFilter: 'blur(18px) saturate(1.35)',
    };

    return (
      <div
        className="fixed inset-0 z-[260] flex items-end justify-center sm:items-center"
        data-sdri-overlay="1"
        role="dialog"
        aria-modal="true"
        aria-label={copy.adjustTiming}
      >
        <button
          type="button"
          className="absolute inset-0 bg-black/70 backdrop-blur-sm"
          aria-label={copy.close}
          data-sdri-action="backdrop-cancel"
          disabled={dismissBlocked}
          onClick={dismissBlocked ? undefined : handleCancel}
        />
        <div
          className="relative z-[1] flex max-h-[min(92dvh,40rem)] w-full max-w-lg flex-col overflow-hidden rounded-t-2xl border border-[#2DE2C5]/25 shadow-[0_0_48px_-12px_rgba(45,226,197,0.35)] sm:mx-4 sm:rounded-2xl"
          style={glass}
          onClick={(e) => e.stopPropagation()}
        >
          <div className="flex items-start justify-between gap-3 border-b border-white/10 px-4 pb-3 pt-[max(0.85rem,env(safe-area-inset-top))]">
            <div className="min-w-0">
              <p className="font-mono text-[10px] font-semibold uppercase tracking-[0.14em] text-[#2DE2C5]/90">
                {copy.adjustTiming}
              </p>
              <h2 className="mt-1 truncate text-base font-semibold text-white sm:text-lg">
                {title}
              </h2>
            </div>
            <button
              type="button"
              className="flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-full border border-white/15 text-slate-300 active:bg-white/10 disabled:opacity-40"
              aria-label={copy.close}
              data-sdri-action="x-cancel"
              disabled={dismissBlocked}
              onClick={dismissBlocked ? undefined : handleCancel}
            >
              ×
            </button>
          </div>

          <div className="min-h-0 flex-1 overflow-y-auto px-4 py-4">
            {errorMsg ? (
              <div
                className="mb-3 rounded-xl border border-amber-500/35 bg-amber-950/40 px-3 py-2 text-sm text-amber-100"
                role="alert"
                data-sdri-error="1"
              >
                {errorMsg}
              </div>
            ) : null}

            {(phase === PHASE.TIME_SELECT || phase === PHASE.END_SELECTED) && !analysing ? (
              <div data-sdri-panel="time-select">
                <p className="mb-3 text-sm text-slate-200">{copy.whenFinish}</p>
                <div className="mb-3 flex flex-wrap gap-2">
                  {quick.map((t) => (
                    <button
                      key={t}
                      type="button"
                      className={
                        'min-h-[40px] rounded-xl border px-3 py-2 font-mono text-sm ' +
                        (stagedEnd === t
                          ? 'border-[#2DE2C5]/70 bg-[#2DE2C5]/15 text-[#2DE2C5]'
                          : 'border-white/15 bg-black/30 text-slate-200 active:border-[#2DE2C5]/40')
                      }
                      data-sdri-quick={t}
                      onClick={() => selectEnd(t)}
                    >
                      {t}
                    </button>
                  ))}
                </div>
                <label className="mb-1 block font-mono text-[10px] uppercase tracking-[0.12em] text-slate-400">
                  {copy.customTime}
                </label>
                <input
                  type="time"
                  step="60"
                  className="mb-4 w-full rounded-xl border border-white/15 bg-black/40 px-3 py-2.5 font-mono text-base text-white outline-none focus:border-[#2DE2C5]/55"
                  value={customEnd || ''}
                  data-sdri-custom-end="1"
                  onChange={(e) => {
                    const v = e.target.value;
                    setCustomEnd(v);
                    if (helpers.normalizeHhmm(v)) selectEnd(v);
                  }}
                />
              </div>
            ) : null}

            {analysing || committing || refreshing ? (
              <div
                className="flex flex-col items-center justify-center gap-3 py-10 text-center"
                data-sdri-panel="loading"
              >
                <div
                  className="h-10 w-10 animate-pulse rounded-full border-2 border-[#2DE2C5]/35 border-t-[#2DE2C5]"
                  aria-hidden
                />
                <p className="text-sm text-slate-200">
                  {busyHint ||
                    (refreshing
                      ? copy.refreshing
                      : committing
                        ? copy.committing
                        : copy.checkingDay)}
                </p>
              </div>
            ) : null}

            {showProposal && !analysing && !refreshing ? (
              <div data-sdri-panel="proposal">
                <p className="mb-3 font-mono text-[10px] font-semibold uppercase tracking-[0.14em] text-[#2DE2C5]/90">
                  {copy.proposedPlan}
                </p>
                <ul className="space-y-2">
                  {(draftRows || []).map((row, idx) => {
                    const ak = row.activity_key || row.activityKey || `row-${idx}`;
                    const labelKey = row.__dirty
                      ? 'edited_by_you'
                      : helpers.presentationLabelKey(row.presentation);
                    const editable =
                      !committing &&
                      !refreshFailed &&
                      helpers.isProposalRowEditable(row, activityByKey || null);
                    const startVal =
                      (row.proposed && row.proposed.start) || row.__draftStart || '';
                    const endVal = (row.proposed && row.proposed.end) || row.__draftEnd || '';
                    const priorToProposed = helpers.formatPriorToProposed(row);
                    const timingDisplay =
                      priorToProposed ||
                      (startVal && endVal
                        ? `${startVal}–${endVal}`
                        : endVal || startVal || '—');
                    const rowTitle =
                      row.title ||
                      row.Title ||
                      (activityByKey &&
                        activityByKey[ak] &&
                        (activityByKey[ak].title || activityByKey[ak].Title)) ||
                      ak;
                    return (
                      <li
                        key={ak}
                        className="rounded-xl border border-white/10 bg-black/35 px-3 py-2.5"
                        data-sdri-row={ak}
                        data-sdri-editable={editable ? '1' : '0'}
                        data-sdri-prior-proposed={priorToProposed ? '1' : '0'}
                      >
                        <div className="flex items-start justify-between gap-2">
                          <div className="min-w-0">
                            <p className="truncate text-sm font-semibold text-white">{rowTitle}</p>
                            <p className="mt-0.5 font-mono text-[10px] uppercase tracking-[0.1em] text-slate-400">
                              {presentationText(labelKey, copy)}
                            </p>
                          </div>
                          {!editable ? (
                            <p
                              className="flex-shrink-0 font-mono text-xs text-[#2DE2C5]/85"
                              data-sdri-timing-display="1"
                            >
                              {timingDisplay}
                            </p>
                          ) : null}
                        </div>
                        {editable ? (
                          <div className="mt-2">
                            {priorToProposed ? (
                              <p
                                className="mb-1.5 font-mono text-xs text-[#2DE2C5]/85"
                                data-sdri-timing-display="1"
                              >
                                {priorToProposed}
                              </p>
                            ) : null}
                            <div className="flex gap-2">
                              <input
                                type="time"
                                step="60"
                                className="min-h-[40px] flex-1 rounded-lg border border-white/15 bg-black/40 px-2 py-1.5 font-mono text-sm text-white"
                                value={startVal || ''}
                                data-sdri-edit-start={ak}
                                onChange={(e) => onDirtyEditRow(ak, 'start', e.target.value)}
                              />
                              <input
                                type="time"
                                step="60"
                                className="min-h-[40px] flex-1 rounded-lg border border-white/15 bg-black/40 px-2 py-1.5 font-mono text-sm text-white"
                                value={endVal || ''}
                                data-sdri-edit-end={ak}
                                onChange={(e) => onDirtyEditRow(ak, 'end', e.target.value)}
                              />
                            </div>
                          </div>
                        ) : null}
                      </li>
                    );
                  })}
                </ul>
              </div>
            ) : null}
          </div>

          <div className="flex flex-col gap-2 border-t border-white/10 px-4 py-3 pb-[max(0.85rem,env(safe-area-inset-bottom))]">
            {(phase === PHASE.TIME_SELECT || phase === PHASE.END_SELECTED) && !analysing ? (
              <button
                type="button"
                className="min-h-[44px] w-full rounded-xl bg-gradient-to-r from-teal-400 to-teal-300 px-4 py-2.5 text-sm font-semibold text-black disabled:cursor-not-allowed disabled:opacity-40"
                data-sdri-action="confirm-preview"
                disabled={!confirmEnabled}
                onClick={() => runImpactPreview(false)}
              >
                {copy.confirmPrefix} {stagedEnd || ''}
              </button>
            ) : null}

            {showProposal && !analysing && !refreshing ? (
              refreshFailed ? (
                <button
                  type="button"
                  className="min-h-[44px] w-full rounded-xl bg-gradient-to-r from-teal-400 to-teal-300 px-4 py-2.5 text-sm font-semibold text-black"
                  data-sdri-action="retry-refresh"
                  onClick={runRetryRefresh}
                >
                  {copy.retryRefresh}
                </button>
              ) : dirty ? (
                <button
                  type="button"
                  className="min-h-[44px] w-full rounded-xl bg-gradient-to-r from-teal-400 to-teal-300 px-4 py-2.5 text-sm font-semibold text-black disabled:opacity-40"
                  data-sdri-action="repropose"
                  disabled={committing}
                  onClick={() => runImpactPreview(true)}
                >
                  {copy.rePropose}
                </button>
              ) : (
                <>
                  <button
                    type="button"
                    className="min-h-[44px] w-full rounded-xl bg-gradient-to-r from-teal-400 to-teal-300 px-4 py-2.5 text-sm font-semibold text-black disabled:cursor-not-allowed disabled:opacity-40"
                    data-sdri-action="accept"
                    disabled={!acceptEnabled}
                    onClick={() => runCommit(helpers.COMMIT_ACCEPT_FULL)}
                  >
                    {copy.acceptChanges}
                  </button>
                  <button
                    type="button"
                    className="min-h-[44px] w-full rounded-xl border border-[#2DE2C5]/35 bg-black/40 px-4 py-2.5 text-sm font-semibold text-[#2DE2C5] disabled:opacity-40"
                    data-sdri-action="keep-current"
                    disabled={!acceptEnabled}
                    onClick={() => runCommit(helpers.COMMIT_KEEP_END_ONLY)}
                  >
                    {copy.keepCurrent}
                  </button>
                </>
              )
            ) : null}

            {!committing && !refreshing && !refreshFailed ? (
              <button
                type="button"
                className="min-h-[40px] w-full rounded-xl px-4 py-2 text-sm text-slate-400 active:bg-white/5"
                data-sdri-action="cancel"
                onClick={handleCancel}
              >
                {copy.cancel}
              </button>
            ) : null}
          </div>
        </div>
      </div>
    );
  }

  if (typeof window !== 'undefined') {
    window.SdriAdjustTimingOverlay = SdriAdjustTimingOverlay;
  }
})();
