/* app.css -- relocated from index.html inline <style> blocks so the
   CSP style-src no longer needs 'unsafe-inline' (0.100.3). */
    body { font-family: 'Inter', 'Assistant', system-ui, sans-serif; }
    ::-webkit-scrollbar { width: 6px; height: 6px; }
    ::-webkit-scrollbar-track { background: #f1f5f9; }
    ::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; }
    ::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
    .rtl-disable { direction: ltr !important; text-align: left !important; }
    :focus-visible { outline: 2px solid #14b8a6; outline-offset: 2px; border-radius: 6px; }
    /* Skip-to-content link (WCAG 2.4.1): off-screen until keyboard-focused.
       Hand-rolled because the prebuilt Tailwind bundle lacks focus:not-sr-only. */
    .skip-link { position: absolute; left: 8px; top: -48px; z-index: 100;
      background: #0f766e; color: #fff; padding: 8px 14px; border-radius: 6px;
      font-size: 13px; font-weight: 600; transition: top .15s ease; }
    .skip-link:focus { top: 8px; }
    /* Swiss/functional refinements (additive -- no Tailwind rebuild needed):
       tabular figures so the live KPI numbers align in a column, and honour the
       OS "reduce motion" setting by neutralising decorative transitions
       (WCAG 2.3.3 Animation from Interactions). */
    #kpi-strip { font-variant-numeric: tabular-nums; }
    @media (prefers-reduced-motion: reduce) {
      *, *::before, *::after {
        animation-duration: .001ms !important; animation-iteration-count: 1 !important;
        transition-duration: .001ms !important; scroll-behavior: auto !important;
      }
    }

    /* RTL chrome support (interface language switcher). The shell is built
       from direction-agnostic flex/grid + gap utilities, so native
       dir="rtl" on <html> mirrors the whole layout. These rules cover the
       few physical-direction utilities the chrome still uses, activate the
       pre-built rtl: icon variants without a Tailwind rebuild, and keep
       code / URLs / numbers / monospace runs LTR inside an RTL page. */
    [dir="rtl"] .rtl\:hidden { display: none !important; }
    [dir="rtl"] .rtl\:block  { display: block !important; }
    [dir="rtl"] .text-left   { text-align: right; }
    [dir="rtl"] .text-right  { text-align: left; }
    [dir="rtl"] input:not(.rtl-disable),
    [dir="rtl"] textarea:not(.rtl-disable),
    [dir="rtl"] select { text-align: right; }
    [dir="rtl"] .font-mono,
    [dir="rtl"] code,
    [dir="rtl"] kbd,
    [dir="rtl"] .rtl-disable { direction: ltr; text-align: left; unicode-bidi: isolate; }
    [dir="rtl"] .lang-dir-flip { transform: scaleX(-1); }
    /* Positioned chrome elements: mirror the few pinned to a physical side. */
    [dir="rtl"] #toast-notif { right: auto; left: 1.25rem; }
    [dir="rtl"] #kw-url-status,
    [dir="rtl"] #br-url-status { right: auto; left: 0.5rem; }
    [dir="rtl"] .pr-9 { padding-right: 0.5rem; padding-left: 2.25rem; }

    /* Progress-bar internals for progressBar() (index.html). The prebuilt
       Tailwind bundle is content-scanned, so the few width/transition
       utilities the bars need live here as plain CSS rather than as classes
       that may not have been emitted. */
    /* Determinate fill: animate width changes so a job's bar glides as it
       drains instead of snapping. */
    .progress-fill { transition: width 0.5s ease-out; }
    /* Indeterminate stripe -- for jobs with no known total (e.g. a live site
       crawl). A short fill sweeps the track to signal "work is happening"
       without implying a precise percentage. Mirrors cleanly under RTL. */
    .progress-indeterminate { width: 40%; animation: progress-sweep 1.3s ease-in-out infinite; }
    @keyframes progress-sweep {
      0%   { transform: translateX(-120%); }
      100% { transform: translateX(320%); }
    }
    [dir="rtl"] .progress-indeterminate { animation-direction: reverse; }
    @media (prefers-reduced-motion: reduce) {
      .progress-indeterminate { animation: none; width: 100%; opacity: 0.6; }
    }

    /* iOS focus-zoom guard. Mobile Safari zooms the viewport whenever a
       focused form control computes to < 16px, which is jarring for an
       operator checking the workbench from a phone. The desktop UI is
       intentionally dense (text-sm / text-xs inputs), so raise the floor to
       16px only on small viewports -- desktop density is untouched. The
       !important is required because Tailwind's .text-sm/.text-xs class
       selectors outrank a bare element rule. (Mobile audit S7.) */
    @media (max-width: 640px) {
      input, select, textarea { font-size: 16px !important; }
    }

    /* Touch targets (mobile). The left-rail nav buttons are intentionally
       dense (py-1.5) for desktop; on a phone raise them to the ~44px
       comfortable tap size. (Mobile audit S4 / ISSUE_TRACKER M-09.) */
    @media (max-width: 640px) {
      #tabs-container button,
      aside nav button { min-height: 44px; }
    }
    /* Dense per-row action controls (Edit / Delete / Approve / Reject / Retry /
       Inspect / Publish ...) render ~25px tall at desktop density; on a phone
       raise them to a comfortable 44px tap target. Scoped to interactive
       controls inside the data table + the AI/biz data panels; md+ desktop
       density is untouched (this @media doesn't apply there). Tables stay
       overflow-x-auto, so the wider hit area just scrolls.
       (ISSUE_TRACKER M-09 -- table-row tap-target sweep.) */
    @media (max-width: 640px) {
      #dynamic-table button, #dynamic-table a[onclick],
      #biz-business-panel button, #biz-business-panel a[onclick] {
        min-height: 44px;
        min-width: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
      }
    }

    /* Off-canvas navigation drawer on mobile (M-09 / CLAUDE UI rule #2:
       first-visible content is data). Below md the two-column layout would
       stack the nav rail above the KPI strip + table; instead the rail becomes
       a slide-in drawer toggled by the header hamburger, and the data column
       fills the width underneath. On md+ the aside stays the static sticky
       rail (these rules don't apply), so desktop is unchanged. Uses logical
       inset so it mirrors automatically under dir="rtl". */
    @media (max-width: 767px) {
      main > div > aside {
        position: fixed;
        inset-block: 0;
        inset-inline-start: 0;
        z-index: 50;
        width: 17rem;
        max-width: 85vw;
        padding: 0.75rem;
        overflow-y: auto;
        background: #f8fafc;                 /* slate-50, matches body */
        box-shadow: 0 10px 30px rgba(15, 23, 42, 0.25);
        transform: translateX(-100%);
        transition: transform 0.25s ease;
      }
      [dir="rtl"] main > div > aside { transform: translateX(100%); }
      body.nav-open main > div > aside { transform: translateX(0); }
      #nav-backdrop { position: fixed; inset: 0; z-index: 40; background: rgba(15, 23, 42, 0.5); }
    }
    /* The hamburger is mobile-only. `md:hidden` is not in the prebuilt Tailwind
       bundle (nothing else used that variant), so hide it explicitly on md+ and
       keep the backdrop out of the desktop flow. */
    @media (min-width: 768px) {
      #nav-toggle { display: none; }
      #nav-backdrop { display: none; }
      /* Desktop collapsible drawer (#2): the collapse toggle is desktop-only;
         collapsing fully hides the left rail so the content area spans full width.
         State is persisted per-browser (localStorage 'nav-rail-collapsed'). */
      #nav-collapse { display: inline-flex; }
      body.nav-collapsed #nav-rail { display: none; }
    }
    /* The desktop collapse toggle is meaningless on mobile (the rail is an
       off-canvas drawer there, driven by #nav-toggle) -- hide it under md. */
    @media (max-width: 767px) {
      #nav-collapse { display: none; }
    }
    @media (prefers-reduced-motion: reduce) {
      main > div > aside { transition: none; }
    }

    /* CLS reserve (M-10). The active panel fills asynchronously after the
       data fetch; on first paint it is empty, so the page is shorter than the
       viewport and the footer renders in view -- then content lands and shoves
       the footer down through the viewport, scoring a large layout shift.
       Reserving a viewport-proportional minimum height makes the page exceed
       the viewport at first paint, so the footer starts below the fold and its
       later movement no longer counts toward CLS. Content taller than this
       expands normally. */
    #active-panel { min-height: 70vh; }

    /* Global base font-size bump. Tailwind's text-*, spacing, and sizing
       utilities are rem-based off the root, so raising the root font-size
       scales the whole UI up proportionally (the canonical "increase the base
       font size for all UI elements"). px-based rules (tap-target minimums,
       the kbd chip) are intentionally left fixed. */
    html { font-size: 17px; }

    /* Full-width layout. The header, main, and footer share a centered
       max-w-7xl (80rem) cap; release it so the UI occupies 100% of the
       horizontal space. The mx-auto + px-* gutters stay (full width, not
       edge-to-edge), so content fills the screen without touching the edges. */
    .max-w-7xl { max-width: 100%; }
  
.kbd{background:#f1f5f9;border:1px solid #cbd5e1;border-bottom-width:2px;color:#334155;font-family:ui-monospace,Menlo,monospace;font-size:11px;padding:1px 5px;border-radius:4px;}

/* WCAG AA text contrast (1.4.3): white text on the -600 action-button shades
   measured below 4.5:1 (emerald 3.77, teal 3.74, amber 3.19, cyan 3.68,
   sky 4.10, orange 3.56). Darken just those white-text buttons to the -700
   value (>=5:1 resting); :hover steps to the old -600 (transient, and still an
   improvement over the previous -500 hover). Scoped via [class~] so badges /
   borders that merely use a -600 background WITHOUT white text are untouched.
   rose / fuchsia / violet / indigo / blue / slate -600 already pass with white
   text (>=4.7:1) and are intentionally left alone. (0.100.7) */
[class~="bg-emerald-600"][class~="text-white"]{background-color:#047857;}
[class~="bg-emerald-600"][class~="text-white"]:hover{background-color:#059669;}
[class~="bg-teal-600"][class~="text-white"]{background-color:#0f766e;}
[class~="bg-teal-600"][class~="text-white"]:hover{background-color:#0d9488;}
[class~="bg-amber-600"][class~="text-white"]{background-color:#b45309;}
[class~="bg-amber-600"][class~="text-white"]:hover{background-color:#d97706;}
[class~="bg-cyan-600"][class~="text-white"]{background-color:#0e7490;}
[class~="bg-cyan-600"][class~="text-white"]:hover{background-color:#0891b2;}
[class~="bg-sky-600"][class~="text-white"]{background-color:#0369a1;}
[class~="bg-sky-600"][class~="text-white"]:hover{background-color:#0284c7;}
[class~="bg-orange-600"][class~="text-white"]{background-color:#c2410c;}
[class~="bg-orange-600"][class~="text-white"]:hover{background-color:#ea580c;}
/* yellow-600 white-text buttons/badges also fail (2.94:1) -> yellow-700 (4.9:1). */
[class~="bg-yellow-600"][class~="text-white"]{background-color:#a16207;}
[class~="bg-yellow-600"][class~="text-white"]:hover{background-color:#ca8a04;}
/* Muted secondary text: text-slate-400 on white/slate-50 measured 2.45-2.56:1.
   Bump to slate-600 (#475569), which passes AA on white, slate-50, slate-100 and
   slate-200 tints while still reading as secondary. Single source-of-truth override;
   slate-400 in this app is only ever used on light surfaces. (0.100.7) */
[class~="text-slate-400"]{color:#475569;}
/* Modal-header gradient `from-teal-600 to-emerald-600` carries text-base/text-lg
   bold white titles (16-18px -> below the large-text bar), so it needs 4.5:1 but
   measured 3.74:1. Darken the two stops to -700 (white >=5:1). Matches the bundle's
   position-var syntax; loaded after tailwind.css so it wins on source order. The
   amber/orange header gradients use text-xl bold (large text, 3:1) and already pass,
   so they're left alone. (0.100.7) */
[class~="from-teal-600"]{--tw-gradient-from:#0f766e var(--tw-gradient-from-position);}
[class~="to-emerald-600"]{--tw-gradient-to:#047857 var(--tw-gradient-to-position);}
/* Accent TEXT colors: text-*-600 used as colored text (scores, status, issue
   pills, links) on white/tinted backgrounds measured below 4.5:1 (emerald 3.77,
   teal 3.74, amber 3.19, cyan 3.68, sky 4.10, orange 3.56, yellow 2.94; rose 4.28
   on rose-50). Darken to the -700 value (>=4.7:1 on white, and higher contrast on
   the matching -50 tint pills). Hue is preserved. (0.100.7) */
[class~="text-emerald-600"]{color:#047857;}
[class~="text-teal-600"]{color:#0f766e;}
[class~="text-amber-600"]{color:#b45309;}
[class~="text-cyan-600"]{color:#0e7490;}
[class~="text-sky-600"]{color:#0369a1;}
[class~="text-orange-600"]{color:#c2410c;}
[class~="text-yellow-600"]{color:#a16207;}
[class~="text-rose-600"]{color:#be123c;}
/* Count chips: bg-slate-100 text-slate-500 @10px = 4.34:1 (just under). Darken
   the text to slate-600 on that specific tint (6.8:1). */
[class~="text-slate-500"]{color:#475569;}
