()
+  const [isSubmitting, setIsSubmitting] = useState(false)
+  const [wasSubmitted, setWasSubmitted] = useState(false)
+
+  const rangeError =
+    lowLimitProb !== undefined &&
+    highLimitProb !== undefined &&
+    lowLimitProb >= highLimitProb
+
+  const outOfRangeError =
+    (lowLimitProb !== undefined &&
+      (lowLimitProb <= 0 || lowLimitProb >= 100)) ||
+    (highLimitProb !== undefined &&
+      (highLimitProb <= 0 || highLimitProb >= 100))
+
+  const initialLow = initialProb * 0.9
+  const initialHigh = initialProb + (1 - initialProb) * 0.1
+  const lowPlaceholder = Math.round(
+    isPseudoNumeric ? getMappedValue(contract)(initialLow) : initialLow * 100
+  ).toString()
+  const highPlaceholder = Math.round(
+    isPseudoNumeric ? getMappedValue(contract)(initialHigh) : initialHigh * 100
+  ).toString()
+
+  const hasYesLimitBet = lowLimitProb !== undefined && !!betAmount
+  const hasNoLimitBet = highLimitProb !== undefined && !!betAmount
+  const hasTwoBets = hasYesLimitBet && hasNoLimitBet
+
+  const betDisabled =
+    isSubmitting ||
+    !betAmount ||
+    rangeError ||
+    outOfRangeError ||
+    error ||
+    (!hasYesLimitBet && !hasNoLimitBet)
+
+  const yesLimitProb =
+    lowLimitProb === undefined ? undefined : lowLimitProb / 100
+  const noLimitProb =
+    highLimitProb === undefined ? undefined : highLimitProb / 100
+
+  const shares =
+    yesLimitProb !== undefined && noLimitProb !== undefined
+      ? Math.min(
+          (betAmount ?? 0) / yesLimitProb,
+          (betAmount ?? 0) / (1 - noLimitProb)
+        )
+      : (betAmount ?? 0) / (yesLimitProb ?? 1 - (noLimitProb ?? 1))
+
+  const yesAmount = shares * (yesLimitProb ?? 1)
+  const noAmount = shares * (1 - (noLimitProb ?? 1))
+
+  const profitIfBothFilled = shares - (yesAmount + noAmount)
+
+  function onBetChange(newAmount: number | undefined) {
+    setWasSubmitted(false)
+    setBetAmount(newAmount)
+  }
+
+  async function submitBet() {
+    if (!user || betDisabled) return
+
+    setError(undefined)
+    setIsSubmitting(true)
+
+    const betsPromise = hasTwoBets
+      ? Promise.all([
+          placeBet({
+            outcome: 'YES',
+            amount: yesAmount,
+            limitProb: yesLimitProb,
+            contractId: contract.id,
+          }),
+          placeBet({
+            outcome: 'NO',
+            amount: noAmount,
+            limitProb: noLimitProb,
+            contractId: contract.id,
+          }),
+        ])
+      : placeBet({
+          outcome: hasYesLimitBet ? 'YES' : 'NO',
+          amount: betAmount,
+          contractId: contract.id,
+          limitProb: hasYesLimitBet ? yesLimitProb : noLimitProb,
+        })
+
+    betsPromise
+      .catch((e) => {
+        if (e instanceof APIError) {
+          setError(e.toString())
+        } else {
+          console.error(e)
+          setError('Error placing bet')
+        }
+        setIsSubmitting(false)
+      })
+      .then((r) => {
+        console.log('placed bet. Result:', r)
+        setIsSubmitting(false)
+        setWasSubmitted(true)
+        setBetAmount(undefined)
+        if (onBuySuccess) onBuySuccess()
+      })
+
+    if (hasYesLimitBet) {
+      track('bet', {
+        location: 'bet panel',
+        outcomeType: contract.outcomeType,
+        slug: contract.slug,
+        contractId: contract.id,
+        amount: yesAmount,
+        outcome: 'YES',
+        limitProb: yesLimitProb,
+        isLimitOrder: true,
+        isRangeOrder: hasTwoBets,
+      })
+    }
+    if (hasNoLimitBet) {
+      track('bet', {
+        location: 'bet panel',
+        outcomeType: contract.outcomeType,
+        slug: contract.slug,
+        contractId: contract.id,
+        amount: noAmount,
+        outcome: 'NO',
+        limitProb: noLimitProb,
+        isLimitOrder: true,
+        isRangeOrder: hasTwoBets,
+      })
+    }
+  }
+
+  const {
+    currentPayout: yesPayout,
+    currentReturn: yesReturn,
+    totalFees: yesFees,
+    newBet: yesBet,
+  } = getBinaryBetStats(
+    'YES',
+    yesAmount,
+    contract,
+    Math.min(yesLimitProb ?? initialLow, 0.999),
+    unfilledBets as LimitBet[]
+  )
+  const yesReturnPercent = formatPercent(yesReturn)
+
+  const {
+    currentPayout: noPayout,
+    currentReturn: noReturn,
+    totalFees: noFees,
+    newBet: noBet,
+  } = getBinaryBetStats(
+    'NO',
+    noAmount,
+    contract,
+    Math.max(noLimitProb ?? initialHigh, 0.01),
+    unfilledBets as LimitBet[]
+  )
+  const noReturnPercent = formatPercent(noReturn)
+
+  return (
+    
+      
+        Bet when the {isPseudoNumeric ? 'value' : 'probability'} reaches Low
+        and/or High limit.
+      
+
+      
+        
+          Low
+          
+        
+        
+          High
+          
+        
+      
+
+      {rangeError && (
+        
+          Low limit must be less than High limit
+        
+      )}
+      {outOfRangeError && (
+        
+          Limit is out of range
+        
+      )}
+
+      
+        Max amount*
+      
+      
+
+      
+        {(hasTwoBets || (hasYesLimitBet && yesBet.amount !== 0)) && (
+          
+            
+              {isPseudoNumeric ? (
+                
+              ) : (
+                
+              )}{' '}
+              current fill
+            
+            
+              {formatMoney(yesBet.amount)} of{' '}
+              {formatMoney(yesBet.orderAmount ?? 0)}
+            
+          
+        )}
+        {(hasTwoBets || (hasNoLimitBet && noBet.amount !== 0)) && (
+          
+            
+              {isPseudoNumeric ? (
+                
+              ) : (
+                
+              )}{' '}
+              current fill
+            
+            
+              {formatMoney(noBet.amount)} of{' '}
+              {formatMoney(noBet.orderAmount ?? 0)}
+            
+          
+        )}
+        {hasTwoBets && (
+          
+            
+              Profit if both orders filled
+            
+            
+              {formatMoney(profitIfBothFilled)}
+            
+          
+        )}
+        {hasYesLimitBet && !hasTwoBets && (
+          
+            
+              
+                {isPseudoNumeric ? (
+                  'Max payout'
+                ) : (
+                  <>
+                    Max  payout
+                  >
+                )}
+              
+              
+            
+            
+              
+                {formatMoney(yesPayout)}
+              
+              (+{yesReturnPercent})
+            
+          
+        )}
+        {hasNoLimitBet && !hasTwoBets && (
+          
+            
+              
+                {isPseudoNumeric ? (
+                  'Max payout'
+                ) : (
+                  <>
+                    Max  payout
+                  >
+                )}
+              
+              
+            
+            
+              
+                {formatMoney(noPayout)}
+              
+              (+{noReturnPercent})
+            
+          
+        )}
+      
+
+      {(hasYesLimitBet || hasNoLimitBet) && }
+
       {user && (
         
       )}
 
-      {wasSubmitted && (
-        {isLimitOrder ? 'Order' : 'Bet'} submitted!
-      )}
-    >
+      {wasSubmitted && Order submitted!
}
+    
   )
 }
 
diff --git a/web/components/bucket-input.tsx b/web/components/bucket-input.tsx
index 195032dc..19dacd65 100644
--- a/web/components/bucket-input.tsx
+++ b/web/components/bucket-input.tsx
@@ -9,8 +9,9 @@ export function BucketInput(props: {
   contract: NumericContract | PseudoNumericContract
   isSubmitting?: boolean
   onBucketChange: (value?: number, bucket?: string) => void
+  placeholder?: string
 }) {
-  const { contract, isSubmitting, onBucketChange } = props
+  const { contract, isSubmitting, onBucketChange, placeholder } = props
 
   const [numberString, setNumberString] = useState('')
 
@@ -39,7 +40,7 @@ export function BucketInput(props: {
       error={undefined}
       disabled={isSubmitting}
       numberString={numberString}
-      label="Value"
+      placeholder={placeholder}
     />
   )
 }
diff --git a/web/components/number-input.tsx b/web/components/number-input.tsx
index d7159fab..0b48df6e 100644
--- a/web/components/number-input.tsx
+++ b/web/components/number-input.tsx
@@ -9,8 +9,8 @@ export function NumberInput(props: {
   numberString: string
   onChange: (newNumberString: string) => void
   error: string | undefined
-  label: string
   disabled?: boolean
+  placeholder?: string
   className?: string
   inputClassName?: string
   // Needed to focus the amount input
@@ -21,8 +21,8 @@ export function NumberInput(props: {
     numberString,
     onChange,
     error,
-    label,
     disabled,
+    placeholder,
     className,
     inputClassName,
     inputRef,
@@ -32,16 +32,17 @@ export function NumberInput(props: {
   return (