---
format: typebulb/v1
name: Redlined
---

**code.tsx**

```tsx
import React, { useState } from "react";
import { createRoot } from "react-dom/client";

interface Annotation {
  snippet: string;
  explanation: string;
  short: string;
  category: "warning" | "info" | "tip";
}

interface Analysis {
  summary: string;
  annotations: Annotation[];
}

const CAT_COLORS: Record<Annotation["category"], string> = {
  warning: "#ef4444",
  info: "#3b82f6",
  tip: "#10b981",
};

const CAT_LABELS: Record<Annotation["category"], string> = {
  warning: "Watch Out",
  info: "Plain English",
  tip: "Good to Know",
};

interface TooltipState {
  visible: boolean;
  x: number;
  y: number;
  ann: Annotation | null;
}

function Tooltip({ state }: { state: TooltipState }) {
  if (!state.visible || !state.ann) return null;
  const color = CAT_COLORS[state.ann.category];
  return (
    <div className="tooltip" style={{ left: state.x, top: state.y, borderColor: color }}>
      <div className="tooltip-head">
        <span className="tooltip-dot" style={{ background: color }} />
        <span className="tooltip-cat" style={{ color }}>{CAT_LABELS[state.ann.category]}</span>
      </div>
      <div className="tooltip-body">{state.ann.explanation}</div>
    </div>
  );
}

function App() {
  const [analysis, setAnalysis] = useState<Analysis | null>(tb.insight<Analysis>());
  const [loading, setLoading] = useState(false);
  const [activeIndex, setActiveIndex] = useState<number | null>(null);
  const [tooltip, setTooltip] = useState<TooltipState>({ visible: false, x: 0, y: 0, ann: null });
  const runAnalysis = async () => {
    setLoading(true);
    try {
      const result = await tb.infer<Analysis>();
      if (result) setAnalysis(result);
    } finally {
      setLoading(false);
    }
  };

  const rawText = tb.data(0) || "";

  if (!analysis && !loading) {
    return (
      <div className="setup-screen">
        <h1 className="title">Redlined</h1>
        <p className="subtitle">Translate dense legalese into plain English</p>
        <button onClick={runAnalysis} disabled={loading} className="primary-btn">
          Analyze Document
        </button>
      </div>
    );
  }

  // Build highlighted text
  const renderText = () => {
    if (!analysis || !rawText) return <p>{rawText}</p>;
    const matches: { start: number; end: number; index: number }[] = [];
    analysis.annotations.forEach((ann, index) => {
      if (!ann.snippet) return;
      const pos = rawText.indexOf(ann.snippet);
      if (pos !== -1) matches.push({ start: pos, end: pos + ann.snippet.length, index });
    });
    matches.sort((a, b) => a.start - b.start);

    const result: React.ReactNode[] = [];
    let last = 0;
    for (const m of matches) {
      if (m.start < last) continue;
      if (m.start > last) result.push(<span key={`t${last}`}>{rawText.substring(last, m.start)}</span>);
      const cat = analysis.annotations[m.index].category;
      const isActive = activeIndex === m.index;
      result.push(
        <mark
          key={`h${m.index}`}
          className={`hl hl-${cat}${isActive ? " hl-active" : ""}`}
          onClick={(e) => {
            const next = activeIndex === m.index ? null : m.index;
            setActiveIndex(next);
            if (next !== null && analysis) {
              const rect = (e.target as HTMLElement).getBoundingClientRect();
              const vw = window.innerWidth;
              const tooltipW = Math.min(300, vw - 24);
              let x = rect.left;
              if (x + tooltipW > vw - 12) x = vw - tooltipW - 12;
              x = Math.max(12, x);
              setTooltip({ visible: true, x, y: rect.bottom + 8 + window.scrollY, ann: analysis.annotations[m.index] });
            } else {
              setTooltip(t => ({ ...t, visible: false }));
            }
          }}
        >
          {rawText.substring(m.start, m.end)}
          <span className="hl-num">{m.index + 1}</span>
        </mark>
      );
      last = m.end;
    }
    if (last < rawText.length) result.push(<span key={`t${last}`}>{rawText.substring(last)}</span>);
    return <>{result}</>;
  };

  return (
    <div className="container">
      <Tooltip state={tooltip} />
      <header className="main-header">
        <div>
          <h1>Redlined</h1>
          <p className="tagline">Legalese in, plain English out</p>
        </div>
        <button onClick={runAnalysis} disabled={loading} className="secondary-btn">
          {loading ? "Analyzing..." : "Analyze Another"}
        </button>
      </header>

      {analysis && (
        <>
          <div className="summary-box">
            <h3>Summary</h3>
            <p>{analysis.summary}</p>
          </div>

          <div className="editor-layout">
            <div className="doc-pane">
              {renderText()}
            </div>
            <div className="comments-pane">
              {analysis.annotations.map((ann, i) => {
                const isActive = activeIndex === i;
                return (
                  <div
                    key={i}
                    className={`bubble bubble-${ann.category}${isActive ? " bubble-active" : ""}`}
                    onClick={() => { if (window.getSelection()?.toString()) return; setActiveIndex(activeIndex === i ? null : i); }}
                  >
                    <div className="bubble-head">
                      <span className="bubble-num">{i + 1}</span>
                      <span className="bubble-cat" style={{ color: CAT_COLORS[ann.category] }}>{CAT_LABELS[ann.category]}</span>
                      <span className="bubble-short">{ann.short}</span>
                    </div>
                    {isActive && <>
                      <div className="bubble-quote">"{ann.snippet}"</div>
                      <div className="bubble-body">{ann.explanation}</div>
                    </>}
                  </div>
                );
              })}
            </div>
          </div>

          <div className="legend">
            {(Object.keys(CAT_COLORS) as Annotation["category"][]).map(cat => (
              <span key={cat} className="legend-item">
                <span className="legend-dot" style={{ background: CAT_COLORS[cat] }} />
                {CAT_LABELS[cat]}
              </span>
            ))}
          </div>

          <footer className="disclaimer">
            This is an AI-generated analysis for informational purposes only. It is not legal advice. Consult a qualified attorney for decisions based on legal documents.
          </footer>
        </>
      )}
    </div>
  );
}

const root = createRoot(document.getElementById("root")!);
root.render(<App />);
```
**styles.css**

```css
:root {
  --bg: #f8f9fa;
  --text: #1a1a2e;
  --border: #e2e8f0;
  --card: #ffffff;
  --primary: #4f46e5;
  --warn: #ef4444; --warn-bg: #fef2f2;
  --info: #3b82f6; --info-bg: #eff6ff;
  --tip: #10b981;  --tip-bg: #f0fdf4;
}
html[data-theme="dark"] {
  --bg: #121212;
  --text: #e0e0e0;
  --border: #2e2e2e;
  --card: #1e1e1e;
  --warn-bg: #2a1515; --info-bg: #1a1a1a; --tip-bg: #152015;
}

body { font-family: 'Inter', system-ui, sans-serif; background: var(--bg); color: var(--text); margin: 0; padding: 20px; }
.container { max-width: 1400px; margin: 0 auto; }

/* Header */
.main-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; }
.main-header h1 { margin: 0; font-size: 1.6rem; font-weight: 800; letter-spacing: -0.02em; }

/* Landing */
.setup-screen { text-align: center; padding: 120px 20px; }
.title { font-size: 3.5rem; font-weight: 900; margin-bottom: 0.75rem; letter-spacing: -0.03em; }
.subtitle { font-size: 1.15rem; opacity: 0.6; margin-bottom: 2rem; }
.primary-btn { background: var(--primary); color: #fff; border: none; padding: 14px 36px; font-size: 1.05rem; font-weight: 700; border-radius: 8px; cursor: pointer; transition: opacity 0.2s; }
.primary-btn:hover { opacity: 0.9; }
.secondary-btn { background: var(--card); border: 1px solid var(--border); color: var(--text); padding: 8px 16px; border-radius: 6px; font-weight: 600; cursor: pointer; }

/* Summary */
.summary-box { background: var(--card); border: 1px solid var(--border); border-radius: 12px; padding: 40px; margin-bottom: 24px; }
.summary-box h3 { margin: 0 0 8px; font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.05em; opacity: 0.5; }
.summary-box p { margin: 0; line-height: 1.7; }

/* Editor layout */
.editor-layout { display: grid; grid-template-columns: 3fr 2fr; gap: 0; align-items: start; }
@media (max-width: 900px) { .editor-layout { grid-template-columns: 1fr; } }

/* Document pane */
.doc-pane {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px 0 0 12px;
  padding: 40px 48px 40px 40px;
  font-size: 1.05rem;
  line-height: 2;
  white-space: pre-wrap;
  box-shadow: 0 4px 6px -1px rgba(0,0,0,0.04);
}
@media (max-width: 900px) {
  .doc-pane { border-radius: 12px 12px 0 0; padding: 24px; }
  .summary-box { padding: 24px; }
}

/* Highlights */
.hl {
  cursor: pointer;
  border-radius: 3px;
  padding: 1px 3px;
  margin: 0 -1px;
  transition: all 0.15s;
  position: relative;
  background: transparent;
  color: inherit;
}
.hl-warning { border-bottom: 2px solid var(--warn); background: var(--warn-bg); }
.hl-info    { border-bottom: 2px solid var(--info); background: var(--info-bg); }
.hl-tip     { border-bottom: 2px solid var(--tip);  background: var(--tip-bg);  }
.hl-active  { box-shadow: 0 2px 12px rgba(0,0,0,0.12); filter: brightness(0.95); }

.hl-num {
  position: absolute;
  top: -10px;
  right: -8px;
  width: 18px; height: 18px;
  border-radius: 50%;
  font-size: 10px;
  font-weight: 800;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  pointer-events: none;
  line-height: 1;
}
.hl-warning .hl-num { background: var(--warn); }
.hl-info .hl-num    { background: var(--info); }
.hl-tip .hl-num     { background: var(--tip); }

/* Comments pane */
.comments-pane {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 0 0 0 24px;
  align-self: start;
}
@media (max-width: 900px) {
  .comments-pane { padding: 24px 0 0 0; }
}

/* Bubbles */
.bubble {
  background: var(--card);
  border: 1px solid var(--border);
  border-left: 4px solid var(--border);
  border-radius: 8px;
  padding: 14px 16px;
  transition: all 0.2s;
  cursor: pointer;
  font-size: 0.9rem;
}
.bubble-warning { border-left-color: var(--warn); }
.bubble-info    { border-left-color: var(--info); }
.bubble-tip     { border-left-color: var(--tip); }
.bubble-active  { box-shadow: 0 4px 16px rgba(0,0,0,0.1); transform: scale(1.02); z-index: 10; position: relative; }

.bubble-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.bubble-num {
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--border); color: var(--text);
  font-size: 11px; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
}
.bubble-warning .bubble-num { background: var(--warn); color: #fff; }
.bubble-info .bubble-num    { background: var(--info); color: #fff; }
.bubble-tip .bubble-num     { background: var(--tip); color: #fff; }

.bubble-cat { font-weight: 700; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em; }
.bubble-short { font-size: 0.85rem; margin-left: auto; opacity: 0.7; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bubble-active .bubble-short { display: none; }
.bubble-quote { font-style: italic; opacity: 0.5; font-size: 0.8rem; margin-bottom: 8px; }
.bubble-body { line-height: 1.55; }

/* Legend */
.legend { display: flex; gap: 24px; justify-content: center; margin-top: 32px; opacity: 0.6; font-size: 0.85rem; font-weight: 600; }
.legend-item { display: flex; align-items: center; gap: 6px; }
.legend-dot { width: 10px; height: 10px; border-radius: 50%; }

/* Tagline */
.tagline { margin: 2px 0 0; font-size: 0.8rem; opacity: 0.5; font-weight: 500; }

/* Disclaimer */
.disclaimer { text-align: center; margin-top: 32px; padding: 16px; font-size: 0.75rem; opacity: 0.4; line-height: 1.5; }

/* Tooltip (mobile only) */
.tooltip {
  display: none;
  position: absolute;
  z-index: 100;
  background: var(--card);
  border: 2px solid;
  border-radius: 10px;
  padding: 12px 14px;
  max-width: 300px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.15);
  animation: tooltipIn 0.15s ease-out;
}
@keyframes tooltipIn {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: translateY(0); }
}
.tooltip-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.tooltip-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.tooltip-cat { font-weight: 700; font-size: 0.75rem; text-transform: uppercase; }
.tooltip-body { font-size: 0.85rem; line-height: 1.5; }
@media (max-width: 900px) {
  .tooltip { display: block; }
}
```
**index.html**

```html
<div id="root"></div>

```
**data.txt**

```txt
The Department of War may use the AI System for all lawful purposes, consistent with applicable law, operational requirements, and well-established safety and oversight protocols. The AI System will not be used to independently direct autonomous weapons in any case where law, regulation, or Department policy requires human control, nor will it be used to assume other high-stakes decisions that require approval by a human decisionmaker under the same authorities. Per DoD Directive 3000.09 (dtd 25 January 2023), any use of AI in autonomous and semi-autonomous systems must undergo rigorous verification, validation, and testing to ensure they perform as intended in realistic environments before deployment.

 For intelligence activities, any handling of private information will comply with the Fourth Amendment, the National Security Act of 1947 and the Foreign Intelligence and Surveillance Act of 1978, Executive Order 12333, and applicable DoD directives requiring a defined foreign intelligence purpose. The AI System shall not be used for unconstrained monitoring of U.S. persons' private information as consistent with these authorities. The system shall also not be used for domestic law-enforcement activities except as permitted by the Posse Comitatus Act and other applicable law.
```
**infer.md**

````md
You are a plain-English legal analyst. Analyze the provided legal text.

Your job: find every clause that a non-lawyer would misunderstand, miss the implications of, or be surprised by — and explain it clearly.

For each annotation:
- `snippet`: an exact verbatim substring from the source text (must match character-for-character for highlighting to work)
- `short`: a punchy 3-6 word summary shown as a label (e.g. "Only bans what's already banned", "Has emergency exceptions")
- `explanation`: 1-3 sentences in plain, conversational English. No jargon. Explain what this actually means in practice, not just what it says.
- `category`:
  - `warning`: clause that is weaker than it appears, contains a hidden escape hatch, or could be used against the party it seems to protect
  - `info`: standard legal language translated plainly — not dangerous, just opaque
  - `tip`: clause that genuinely protects rights or limits power in a meaningful way

**Calibration guidelines:**
- If a restriction only restates what existing law already requires, that's a `warning` — it adds no new protection and disappears if the law changes.
- If a prohibition is qualified by phrases like "as consistent with," "except as permitted by," or "in any case where [law] requires," flag the qualifier specifically. These phrases are where the real flexibility lives.
- Don't just explain what the text says. Explain what it *doesn't* say — what's left open, what's ambiguous, what could be read two ways.
- Be specific about which laws are being referenced and what they actually permit, not just that they exist.

After annotations, provide a `summary`: 2-3 sentences on the document's overall strength as a protection. Is it a real constraint, or does it mostly restate existing law? Would a change in underlying policy or law hollow it out?

Output valid JSON matching:
```json
{
  "summary": "...",
  "annotations": [
    { "snippet": "...", "short": "...", "explanation": "...", "category": "warning" }
  ]
}
```
````
**insight.json**

```json
{
  "summary": "This contract clause permits the military to use the AI system for essentially anything legal, while appearing to set hard limits on autonomous weapons and surveillance. In practice, nearly every restriction is a restatement of existing law — it prohibits only what's already prohibited. If underlying laws, directives, or executive orders change, most of these protections vanish automatically.",
  "annotations": [
    {
      "snippet": "for all lawful purposes",
      "short": "Permits any legal use",
      "explanation": "This is the real operative phrase of the whole document. Everything after it is qualification, but this upfront grants permission for any use that isn't explicitly illegal. It's extremely broad.",
      "category": "warning"
    },
    {
      "snippet": "in any case where law, regulation, or Department policy requires human control",
      "short": "Only bans what's already banned",
      "explanation": "This is the key escape hatch. The AI isn't banned from directing autonomous weapons outright — only in cases where existing rules already require a human. If the DoD updates its policy to allow more autonomy, this restriction shrinks automatically. It's not a red line; it's a mirror of whatever the current rules happen to say.",
      "category": "warning"
    },
    {
      "snippet": "nor will it be used to assume other high-stakes decisions that require approval by a human decisionmaker under the same authorities",
      "short": "Disappears if procedures change",
      "explanation": "Same pattern: the AI can't make decisions that already require human sign-off. But if the definition of 'high-stakes' narrows or the approval requirements change, so does this protection. It protects nothing beyond current procedure.",
      "category": "warning"
    },
    {
      "snippet": "Per DoD Directive 3000.09 (dtd 25 January 2023)",
      "short": "Pinned to a specific version",
      "explanation": "This pins to a specific dated version of the directive on autonomous weapons. That's actually meaningful — even if the directive is rewritten later, this contract references the January 2023 version. However, it only applies to the testing requirement in this sentence, not to the broader weapons prohibition above.",
      "category": "tip"
    },
    {
      "snippet": "rigorous verification, validation, and testing to ensure they perform as intended in realistic environments before deployment",
      "short": "Real safety testing required",
      "explanation": "Before putting the AI into real military use, it has to pass thorough safety testing. This is a genuine procedural safeguard — it can't be quietly deployed without checks.",
      "category": "tip"
    },
    {
      "snippet": "comply with the Fourth Amendment, the National Security Act of 1947 and the Foreign Intelligence and Surveillance Act of 1978, Executive Order 12333, and applicable DoD directives",
      "short": "Just restates existing law",
      "explanation": "This lists existing surveillance laws the military must already follow. It sounds like a wall of protection, but it adds nothing new — these laws already apply whether or not this contract mentions them. Note: Executive Order 12333 can be revoked by any president unilaterally.",
      "category": "info"
    },
    {
      "snippet": "unconstrained monitoring of U.S. persons' private information",
      "short": "'Unconstrained' is the escape hatch",
      "explanation": "The word 'unconstrained' is doing heavy lifting. It bans mass, rule-free surveillance — but any surveillance with targeting criteria, however broad, could be argued to be 'constrained.' This doesn't ban monitoring Americans; it bans monitoring them without any rules at all.",
      "category": "warning"
    },
    {
      "snippet": "as consistent with these authorities",
      "short": "Tied to current law, not beyond it",
      "explanation": "This qualifier ties the surveillance ban to whatever the referenced laws currently permit. FISA already allows significant surveillance of U.S. persons under certain conditions. This clause doesn't go further than FISA — it just says 'follow FISA.'",
      "category": "warning"
    },
    {
      "snippet": "except as permitted by the Posse Comitatus Act and other applicable law",
      "short": "Has emergency exceptions",
      "explanation": "The Posse Comitatus Act generally bans military involvement in domestic law enforcement — but it has exceptions for insurrection, disaster, and other emergencies. The phrase 'and other applicable law' is an open-ended catch-all that could include future legislation.",
      "category": "warning"
    }
  ]
}

```
**config.json**

```json
{
  "description": "Translate legalese into plain English and surface the hidden risks you need to watch out for.",
  "inference": {
    "title": "Redlined",
    "dataTitle": "Paste legal text, a contract, or terms of service",
    "submitTitle": "Translate to English"
  },
  "dependencies": {
    "react": "^19.2.3",
    "react-dom": "^19.2.3"
  }
}
```