diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md
index cb838a49cb1..ad5f19c4215 100644
--- a/.github/CHANGELOG.md
+++ b/.github/CHANGELOG.md
@@ -140,6 +140,8 @@
 1. [EFB] Set EFB Auto Brightness to default to On - @MrJigs7 (MrJigs)
 1. [FMS] Allow airport to be loaded as fixes in instrument procedures - @tracernz (Mike)
 1. [A380X/ND] Fix Terr text wrong position on terrain radar - @MrJigs7 (MrJigs.)
+1. [A380X/BTV] Add EXIT MISSED indication on FMA and aural triple click - @flogross89 (floridude)
+1. [A380X/OANS] Add flags/crosses capability, change cursor to magenta, implement ARPT NAV reset button - @flogross89 (floridude)
 
 ## 0.12.0
 
diff --git a/fbw-a32nx/src/systems/instruments/src/EFB/index.tsx b/fbw-a32nx/src/systems/instruments/src/EFB/index.tsx
index 3c73ee13f29..200a16179c8 100644
--- a/fbw-a32nx/src/systems/instruments/src/EFB/index.tsx
+++ b/fbw-a32nx/src/systems/instruments/src/EFB/index.tsx
@@ -60,6 +60,7 @@ render(
           registrationDecal: true,
           wheelChocks: true,
           cabinLighting: false,
+          oansPerformanceMode: false,
         },
         throttle: {
           numberOfAircraftThrottles: 2,
diff --git a/fbw-a380x/src/base/flybywire-aircraft-a380-842/SimObjects/AirPlanes/FlyByWire_A380_842/model/A380_COCKPIT.xml b/fbw-a380x/src/base/flybywire-aircraft-a380-842/SimObjects/AirPlanes/FlyByWire_A380_842/model/A380_COCKPIT.xml
index 1e1b9771bb1..544e7157575 100644
--- a/fbw-a380x/src/base/flybywire-aircraft-a380-842/SimObjects/AirPlanes/FlyByWire_A380_842/model/A380_COCKPIT.xml
+++ b/fbw-a380x/src/base/flybywire-aircraft-a380-842/SimObjects/AirPlanes/FlyByWire_A380_842/model/A380_COCKPIT.xml
@@ -4982,6 +4982,9 @@
                 </Component>
 
                 <Component ID="Overhead_Reset_Panel">
+                <UseTemplate Name="FBW_Airbus_RESET_PANEL_BUTTON">
+                        <NAME>ARPT_NAV</NAME>
+                    </UseTemplate>
                     <UseTemplate Name="FBW_Airbus_RESET_PANEL_BUTTON">
                         <NAME>FMC_A</NAME>
                     </UseTemplate>
diff --git a/fbw-a380x/src/base/flybywire-aircraft-a380-842/html_ui/Images/fbw-a380x/oans/oans-cross.png b/fbw-a380x/src/base/flybywire-aircraft-a380-842/html_ui/Images/fbw-a380x/oans/oans-cross.png
new file mode 100644
index 00000000000..05051858ab1
Binary files /dev/null and b/fbw-a380x/src/base/flybywire-aircraft-a380-842/html_ui/Images/fbw-a380x/oans/oans-cross.png differ
diff --git a/fbw-a380x/src/base/flybywire-aircraft-a380-842/html_ui/Images/fbw-a380x/oans/oans-flag.png b/fbw-a380x/src/base/flybywire-aircraft-a380-842/html_ui/Images/fbw-a380x/oans/oans-flag.png
new file mode 100644
index 00000000000..1c6688fc694
Binary files /dev/null and b/fbw-a380x/src/base/flybywire-aircraft-a380-842/html_ui/Images/fbw-a380x/oans/oans-flag.png differ
diff --git a/fbw-a380x/src/images/oans/oans-cross.svg b/fbw-a380x/src/images/oans/oans-cross.svg
new file mode 100644
index 00000000000..2cd52aedb76
--- /dev/null
+++ b/fbw-a380x/src/images/oans/oans-cross.svg
@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" version="1.1" viewBox="163.055 83.355 54.707 51.783">
+  <defs>
+    <radialGradient gradientUnits="userSpaceOnUse" cx="327.5" cy="243.75" r="36.5" id="gradient-0">
+      <stop offset="0" style="stop-color: rgb(255, 182, 182);"/>
+      <stop offset="1" style="stop-color: rgb(255, 0, 0);"/>
+    </radialGradient>
+  </defs>
+  <circle style="stroke: rgb(0, 0, 0); fill: url(&quot;#gradient-0&quot;); fill-rule: nonzero; stroke-width: 3.16437px;" transform="matrix(0.65445, 0, 0, 0.609625, -37.958115, -49.774086)" cx="348.5" cy="262" r="36.5"/>
+  <polygon style="stroke: rgb(0, 0, 0); stroke-width: 0px; fill: rgb(255, 255, 255);" points="180.582 94.82 189.748 104.302 199.969 95.03 206.185 101.562 196.071 110.308 205.131 119.37 198.494 125.164 189.327 115.893 179.738 124.426 173.417 117.789 182.794 109.043 174.154 100.298"/>
+</svg>
diff --git a/fbw-a380x/src/images/oans/oans-flag.svg b/fbw-a380x/src/images/oans/oans-flag.svg
new file mode 100644
index 00000000000..ba79384e2dc
--- /dev/null
+++ b/fbw-a380x/src/images/oans/oans-flag.svg
@@ -0,0 +1,14 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" version="1.1" viewBox="125.128 151.914 39.804 59.914">
+  <defs>
+    <linearGradient id="gradient-2">
+      <stop style="stop-color: rgb(75, 193, 70);" offset="0"/>
+      <stop offset="0.257" style="stop-color: rgb(213, 238, 214);"/>
+      <stop offset="0.449" style="stop-color: rgb(184, 226, 184);"/>
+      <stop style="stop-color: rgb(0, 119, 3);" offset="0.971"/>
+      <stop offset="1" style="stop-color: rgb(204, 239, 200);"/>
+    </linearGradient>
+  </defs>
+  <g transform="matrix(1, 0, 0, 1, 186.60524, 161.414047)"/>
+  <rect x="126.526" y="161.974" width="2.443" height="48.65" style="fill: rgb(213, 213, 213); stroke: rgb(0, 0, 0); stroke-width: 0.5px;" rx="2.012" ry="2.012"/>
+  <path style="stroke: rgb(0, 0, 0); paint-order: fill; fill-rule: nonzero; fill: url(&quot;#gradient-2&quot;); stroke-width: 0.5px;" d="M 128.532 185.718 C 128.532 185.718 131.43 187.593 133.412 183.186 C 135.394 178.779 136.38 175.496 141.501 176.044 C 146.622 176.592 143.234 185.384 148.172 185.384 C 153.11 185.384 163.901 182.126 163.901 182.126 L 163.718 161.608 C 163.718 161.608 157.994 165.491 153.97 165.857 C 149.946 166.223 148.51 165.491 147.667 161.83 C 146.824 158.169 146.598 157.668 144.586 154.742 C 142.574 151.816 137.045 152.901 133.753 156.559 C 130.461 160.217 128.237 162.157 128.237 162.157 L 128.532 185.718 Z"/>
+</svg>
diff --git a/fbw-a380x/src/systems/instruments/src/AtcMailbox/AtcMailbox.tsx b/fbw-a380x/src/systems/instruments/src/AtcMailbox/AtcMailbox.tsx
index 57c394aff8b..f1824432f36 100644
--- a/fbw-a380x/src/systems/instruments/src/AtcMailbox/AtcMailbox.tsx
+++ b/fbw-a380x/src/systems/instruments/src/AtcMailbox/AtcMailbox.tsx
@@ -31,6 +31,7 @@ export class AtcMailbox extends DisplayComponent<AtcMailboxProps> {
 
   destroy(): void {
     this.topRef.getOrDefault()?.removeEventListener('mousemove', this.onMouseMoveHandler);
+    this.mouseCursorRef.getOrDefault()?.destroy();
 
     super.destroy();
   }
diff --git a/fbw-a380x/src/systems/instruments/src/EFB/index.tsx b/fbw-a380x/src/systems/instruments/src/EFB/index.tsx
index f9b00f56a4c..f40dcbeab04 100644
--- a/fbw-a380x/src/systems/instruments/src/EFB/index.tsx
+++ b/fbw-a380x/src/systems/instruments/src/EFB/index.tsx
@@ -57,6 +57,7 @@ render(
           registrationDecal: false, // TODO FIXME: Enable when dynamic registration decal is completed
           wheelChocks: false,
           cabinLighting: true,
+          oansPerformanceMode: true,
         },
         throttle: {
           numberOfAircraftThrottles: 4,
diff --git a/fbw-a380x/src/systems/instruments/src/MFD/MFD.tsx b/fbw-a380x/src/systems/instruments/src/MFD/MFD.tsx
index cd60b114481..226be5a8efd 100644
--- a/fbw-a380x/src/systems/instruments/src/MFD/MFD.tsx
+++ b/fbw-a380x/src/systems/instruments/src/MFD/MFD.tsx
@@ -328,6 +328,8 @@ export class MfdComponent extends DisplayComponent<MfdComponentProps> implements
 
   destroy(): void {
     this.topRef.getOrDefault()?.removeEventListener('mousemove', this.onMouseMoveHandler);
+    this.mouseCursorRef.getOrDefault()?.destroy();
+    this.duplicateNamesRef.getOrDefault()?.destroy();
 
     super.destroy();
   }
diff --git a/fbw-a380x/src/systems/instruments/src/MsfsAvionicsCommon/UiWidgets/MouseCursor.tsx b/fbw-a380x/src/systems/instruments/src/MsfsAvionicsCommon/UiWidgets/MouseCursor.tsx
index 6b5e296411f..8bc6ad6fa73 100644
--- a/fbw-a380x/src/systems/instruments/src/MsfsAvionicsCommon/UiWidgets/MouseCursor.tsx
+++ b/fbw-a380x/src/systems/instruments/src/MsfsAvionicsCommon/UiWidgets/MouseCursor.tsx
@@ -7,22 +7,36 @@ import {
   FSComponent,
   Subject,
   Subscribable,
+  SubscribableUtils,
   Subscription,
   VNode,
 } from '@microsoft/msfs-sdk';
 
+export enum MouseCursorColor {
+  Yellow,
+  Magenta,
+}
+
 interface MouseCursorProps extends ComponentProps {
   side: Subscribable<'CAPT' | 'FO'>;
   isDoubleScreenMfd?: boolean;
   visible?: Subject<boolean>;
+  color?: Subscribable<MouseCursorColor> | MouseCursorColor;
 }
 
 export class MouseCursor extends DisplayComponent<MouseCursorProps> {
-  private subs: Subscription[] = [];
+  private readonly subs: Subscription[] = [];
 
   private readonly divRef = FSComponent.createRef<HTMLSpanElement>();
 
-  private readonly fillColor = '#ffff00'; // or ff94ff = purple, but not sure where that is used
+  private readonly color: Subscribable<MouseCursorColor> = SubscribableUtils.toSubscribable(
+    this.props.color ?? MouseCursorColor.Yellow,
+    true,
+  );
+
+  private readonly fillColor = this.color.map((c) => (c === MouseCursorColor.Magenta ? '#ff94ff' : '#ffff00'));
+
+  private readonly rotation = this.props.side.map((side) => `rotate(${side === 'FO' ? 90 : 0} 40 40)`);
 
   private hideTimer: ReturnType<typeof setTimeout> | undefined = undefined;
 
@@ -60,17 +74,25 @@ export class MouseCursor extends DisplayComponent<MouseCursorProps> {
     if (this.props.visible) {
       this.subs.push(this.props.visible.sub((vis) => (vis ? this.show() : this.hide()), true));
     }
+
+    this.subs.push(this.fillColor, this.rotation);
+  }
+
+  destroy(): void {
+    for (const s of this.subs) {
+      s.destroy();
+    }
   }
 
   render(): VNode {
     return (
       <div ref={this.divRef} class="mfd-mouse-cursor">
         <svg width="80" height="80" xmlns="http://www.w3.org/2000/svg">
-          <g transform={this.props.side.map((side) => `rotate(${side === 'FO' ? 90 : 0} 40 40)`)}>
-            <polyline points="0,0 40,35 80,0" style={`fill: none; stroke: ${this.fillColor}; stroke-width: 3`} />
-            <line x1="40" y1="39" x2="40" y2="41" style={`stroke: ${this.fillColor}; stroke-width: 2`} />
-            <line x1="39" y1="40" x2="41" y2="40" style={`stroke: ${this.fillColor}; stroke-width: 2`} />
-            <polyline points="0,80 40,45 80,80" style={`fill: none; stroke: ${this.fillColor}; stroke-width: 3`} />
+          <g transform={this.rotation}>
+            <polyline points="0,0 40,35 80,0" style={{ fill: 'none', stroke: this.fillColor, 'stroke-width': '3' }} />
+            <line x1="40" y1="39" x2="40" y2="41" style={{ stroke: this.fillColor, 'stroke-width': '2' }} />
+            <line x1="39" y1="40" x2="41" y2="40" style={{ stroke: this.fillColor, 'stroke-width': '2' }} />
+            <polyline points="0,80 40,45 80,80" style={{ fill: 'none', stroke: this.fillColor, 'stroke-width': '3' }} />
           </g>
         </svg>
       </div>
diff --git a/fbw-a380x/src/systems/instruments/src/MsfsAvionicsCommon/providers/ResetPanelPublisher.tsx b/fbw-a380x/src/systems/instruments/src/MsfsAvionicsCommon/providers/ResetPanelPublisher.tsx
index 5a2a98a24b7..880ae550188 100644
--- a/fbw-a380x/src/systems/instruments/src/MsfsAvionicsCommon/providers/ResetPanelPublisher.tsx
+++ b/fbw-a380x/src/systems/instruments/src/MsfsAvionicsCommon/providers/ResetPanelPublisher.tsx
@@ -9,6 +9,7 @@ import { EventBus, SimVarDefinition, SimVarValueType, SimVarPublisher } from '@m
  * Functionally, these behave similarly to circuit breakers, however they only interrupt software. If pulled out, execution of SW is halted.
  */
 export type ResetPanelSimvars = {
+  a380x_reset_panel_arpt_nav: boolean;
   a380x_reset_panel_fmc_a: boolean;
   a380x_reset_panel_fmc_b: boolean;
   a380x_reset_panel_fmc_c: boolean;
@@ -16,6 +17,7 @@ export type ResetPanelSimvars = {
 
 export class ResetPanelSimvarPublisher extends SimVarPublisher<ResetPanelSimvars> {
   private static simvars = new Map<keyof ResetPanelSimvars, SimVarDefinition>([
+    ['a380x_reset_panel_arpt_nav', { name: 'L:A32NX_RESET_PANEL_ARPT_NAV', type: SimVarValueType.Bool }],
     ['a380x_reset_panel_fmc_a', { name: 'L:A32NX_RESET_PANEL_FMC_A', type: SimVarValueType.Bool }],
     ['a380x_reset_panel_fmc_b', { name: 'L:A32NX_RESET_PANEL_FMC_B', type: SimVarValueType.Bool }],
     ['a380x_reset_panel_fmc_c', { name: 'L:A32NX_RESET_PANEL_FMC_C', type: SimVarValueType.Bool }],
diff --git a/fbw-a380x/src/systems/instruments/src/ND/OANSRunwayInfoBox.tsx b/fbw-a380x/src/systems/instruments/src/ND/OANSRunwayInfoBox.tsx
index c52741abff9..baef653c351 100644
--- a/fbw-a380x/src/systems/instruments/src/ND/OANSRunwayInfoBox.tsx
+++ b/fbw-a380x/src/systems/instruments/src/ND/OANSRunwayInfoBox.tsx
@@ -3,10 +3,10 @@
 
 import { DisplayComponent, FSComponent, Subscribable, VNode } from '@microsoft/msfs-sdk';
 import './oans-style.scss';
-import { EntityTypes } from './OansControlPanel';
+import { ControlPanelMapDataSearchMode } from '@flybywiresim/oanc';
 
 interface OansRunwayInfoBoxProps {
-  rwyOrStand: Subscribable<EntityTypes | null>;
+  rwyOrStand: Subscribable<ControlPanelMapDataSearchMode | null>;
   selectedEntity: Subscribable<string | null>;
   tora: Subscribable<string | null>;
   lda: Subscribable<string | null>;
@@ -22,10 +22,10 @@ export class OansRunwayInfoBox extends DisplayComponent<OansRunwayInfoBoxProps>
     this.rwyDivRef.instance.style.display = 'none';
     this.standDivRef.instance.style.display = 'none';
 
-    if (this.props.rwyOrStand.get() === EntityTypes.RWY && this.props.selectedEntity.get()) {
+    if (this.props.rwyOrStand.get() === ControlPanelMapDataSearchMode.Runway && this.props.selectedEntity.get()) {
       this.rwyDivRef.instance.style.display = 'grid';
       this.standDivRef.instance.style.display = 'none';
-    } else if (this.props.rwyOrStand.get() === EntityTypes.STAND && this.props.selectedEntity.get()) {
+    } else if (this.props.rwyOrStand.get() === ControlPanelMapDataSearchMode.Stand && this.props.selectedEntity.get()) {
       this.rwyDivRef.instance.style.display = 'none';
       this.standDivRef.instance.style.display = 'flex';
     } else {
diff --git a/fbw-a380x/src/systems/instruments/src/ND/OansControlPanel.tsx b/fbw-a380x/src/systems/instruments/src/ND/OansControlPanel.tsx
index bf8db36a391..015e59bfe1d 100644
--- a/fbw-a380x/src/systems/instruments/src/ND/OansControlPanel.tsx
+++ b/fbw-a380x/src/systems/instruments/src/ND/OansControlPanel.tsx
@@ -8,12 +8,12 @@ import {
   ArraySubject,
   ClockEvents,
   ComponentProps,
+  ConsumerSubject,
   DisplayComponent,
   EventBus,
   FSComponent,
   MapSubject,
   MappedSubject,
-  MappedSubscribable,
   SimVarValueType,
   Subject,
   Subscribable,
@@ -22,6 +22,7 @@ import {
 } from '@microsoft/msfs-sdk';
 import {
   ControlPanelAirportSearchMode,
+  ControlPanelMapDataSearchMode,
   ControlPanelStore,
   ControlPanelUtils,
   FmsDataStore,
@@ -33,6 +34,7 @@ import {
 } from '@flybywiresim/oanc';
 import {
   AmdbAirportSearchResult,
+  AmdbProperties,
   Arinc429LocalVarConsumerSubject,
   BtvData,
   EfisSide,
@@ -41,6 +43,7 @@ import {
   FmsOansData,
   MathUtils,
   NXDataStore,
+  NXLogicConfirmNode,
   Runway,
 } from '@flybywiresim/fbw-sdk';
 
@@ -55,9 +58,10 @@ import { TopTabNavigator, TopTabNavigatorPage } from 'instruments/src/MsfsAvioni
 import { Coordinates, distanceTo, placeBearingDistance } from 'msfs-geo';
 import { AdirsSimVars } from 'instruments/src/MsfsAvionicsCommon/SimVarTypes';
 import { NavigationDatabase, NavigationDatabaseBackend, NavigationDatabaseService } from '@fmgc/index';
-import { InteractionMode, InternalKccuKeyEvent } from 'instruments/src/MFD/shared/MFDSimvarPublisher';
 import { NDSimvars } from 'instruments/src/ND/NDSimvarPublisher';
-import { Position } from '@turf/turf';
+import { Feature, Geometry, LineString, Point, Position } from '@turf/turf';
+import { ResetPanelSimvars } from 'instruments/src/MsfsAvionicsCommon/providers/ResetPanelPublisher';
+import { InteractionMode, InternalKccuKeyEvent } from 'instruments/src/MFD/shared/MFDSimvarPublisher';
 
 export interface OansProps extends ComponentProps {
   bus: EventBus;
@@ -66,23 +70,32 @@ export interface OansProps extends ComponentProps {
   togglePanel: () => void;
 }
 
-export enum EntityTypes {
-  RWY,
-  TWY,
-  STAND,
-  OTHER,
-}
-
 const months = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'];
 
 export class OansControlPanel extends DisplayComponent<OansProps> {
-  private readonly subs: (Subscription | MappedSubscribable<any>)[] = [];
+  private readonly subs: Subscription[] = [];
 
-  private readonly sub = this.props.bus.getSubscriber<ClockEvents & FmsOansData & AdirsSimVars & NDSimvars & BtvData>();
+  private readonly sub = this.props.bus.getSubscriber<
+    ClockEvents & FmsOansData & AdirsSimVars & NDSimvars & BtvData & OansControlEvents & ResetPanelSimvars
+  >();
 
   /** If navigraph not available, this class will compute BTV features */
   private readonly navigraphAvailable = Subject.create(false);
 
+  private readonly oansResetPulled = ConsumerSubject.create(this.sub.on('a380x_reset_panel_arpt_nav'), false);
+
+  private oansPerformanceModeSettingSub = () => {};
+  private readonly oansPerformanceMode = Subject.create(false);
+  private showOans = false;
+  private lastUpdateTime: number | null = null;
+  private readonly oansPerformanceModeAndMovedOutOfZoomRange = new NXLogicConfirmNode(60, true);
+
+  private readonly oansAvailable = MappedSubject.create(
+    ([ng, reset]) => ng && !reset,
+    this.navigraphAvailable,
+    this.oansResetPulled,
+  );
+
   private amdbClient = new NavigraphAmdbClient();
 
   private readonly oansMenuRef = FSComponent.createRef<HTMLDivElement>();
@@ -105,13 +118,17 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
 
   private readonly activeTabIndex = Subject.create<number>(2);
 
-  private readonly availableEntityTypes = Object.values(EntityTypes).filter((v) => typeof v === 'string') as string[];
+  private readonly availableEntityTypes = ['RWY', 'TWY', 'STAND', 'OTHER'];
+
+  private mapDataFeatures: Feature<Geometry, AmdbProperties>[] | undefined = undefined;
 
   private readonly thresholdShift = Subject.create<number | null>(null);
 
   private readonly endShift = Subject.create<number | null>(null);
 
-  private readonly selectedEntityType = Subject.create<EntityTypes | null>(EntityTypes.RWY);
+  private readonly selectedEntityType = Subject.create<ControlPanelMapDataSearchMode | null>(
+    ControlPanelMapDataSearchMode.Runway,
+  );
 
   private readonly availableEntityList = ArraySubject.create(['']);
 
@@ -119,6 +136,30 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
 
   private readonly selectedEntityString = Subject.create<string | null>(null);
 
+  private readonly entityIsNotSelected = this.selectedEntityIndex.map((i) => i === null);
+
+  private selectedEntityPosition: Position = [];
+
+  private readonly selectedFeatureId = Subject.create<number | null>(null);
+  private readonly selectedFeatureType = Subject.create<FeatureType | null>(null);
+
+  private readonly symbolsForFeatureIds = ConsumerSubject.create(this.sub.on('oans_symbols_for_feature_ids'), {
+    featureIdsWithCrosses: [],
+    featureIdsWithFlags: [],
+  });
+
+  private readonly flagExistsForEntity = MappedSubject.create(
+    ([symbols, id]) => symbols.featureIdsWithFlags.some((f) => f === id),
+    this.symbolsForFeatureIds,
+    this.selectedFeatureId,
+  );
+
+  private readonly crossExistsForEntity = MappedSubject.create(
+    ([symbols, id]) => symbols.featureIdsWithCrosses.some((f) => f === id),
+    this.symbolsForFeatureIds,
+    this.selectedFeatureId,
+  );
+
   private manualAirportSelection = false;
 
   // TODO: Should be using GPS position interpolated with IRS velocity data
@@ -126,7 +167,7 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
 
   private readonly pposLongWord = Arinc429LocalVarConsumerSubject.create(this.sub.on('longitude'));
 
-  private presentPos = MappedSubject.create(
+  private readonly presentPos = MappedSubject.create(
     ([lat, lon]) => {
       return { lat: lat.value, long: lon.value } as Coordinates;
     },
@@ -134,18 +175,23 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
     this.pposLongWord,
   );
 
-  private presentPosNotAvailable = MappedSubject.create(
+  private readonly presentPosNotAvailable = MappedSubject.create(
     ([lat, long]) => !lat.isNormalOperation() || !long.isNormalOperation(),
     this.pposLatWord,
     this.pposLongWord,
   );
 
+  private readonly setPlanModeConsumer = ConsumerSubject.create(this.sub.on('oans_show_set_plan_mode'), false);
+  private readonly setPlanModeDisplay = this.setPlanModeConsumer.map((it) => (it ? 'inherit' : 'none'));
+
   private readonly fmsDataStore = new FmsDataStore(this.props.bus);
 
   private readonly runwayTora = Subject.create<string | null>(null);
 
   private readonly runwayLda = Subject.create<string | null>(null);
 
+  private readonly standCoordinateString = Subject.create<string>('');
+
   private readonly oansRequestedStoppingDistance = Arinc429LocalVarConsumerSubject.create(
     this.sub.on('oansRequestedStoppingDistance'),
   );
@@ -241,69 +287,159 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
     this.subs.push(this.activeTabIndex.sub((_index) => Coherent.trigger('UNFOCUS_INPUT_FIELD')));
 
     this.subs.push(
-      this.navigraphAvailable.sub((v) => {
+      this.oansAvailable.sub((v) => {
         if (this.mapDataMainRef.getOrDefault() && this.mapDataBtvFallback.getOrDefault()) {
           this.mapDataMainRef.instance.style.display = v ? 'block' : 'none';
           this.mapDataBtvFallback.instance.style.display = v ? 'none' : 'block';
         }
         SimVar.SetSimVarValue('L:A32NX_OANS_AVAILABLE', SimVarValueType.Bool, v);
-        this.props.bus.getPublisher<OansControlEvents>().pub('oansNotAvail', !v, true);
+        this.props.bus.getPublisher<OansControlEvents>().pub('oans_not_avail', !v, true, false);
       }, true),
     );
 
-    this.fmsDataStore.landingRunway.sub(async (it) => {
-      // Set control panel display
-      if (it) {
-        this.availableEntityList.set([it.substring(4)]);
-        this.selectedEntityType.set(EntityTypes.RWY);
-        this.selectedEntityIndex.set(0);
-        this.selectedEntityString.set(it.substring(4));
-
-        // Load runway data
-        const destination = this.fmsDataStore.destination.get();
-        if (destination && this.navigraphAvailable.get() === true) {
-          const data = await this.amdbClient.getAirportData(destination, [FeatureTypeString.RunwayThreshold]);
-          const thresholdFeature = data.runwaythreshold?.features.filter(
-            (td) => td.properties.feattype === FeatureType.RunwayThreshold && td.properties?.idthr === it.substring(4),
-          );
-          if (thresholdFeature && thresholdFeature[0]?.properties.lda && thresholdFeature[0]?.properties.tora) {
-            this.runwayLda.set(
-              (thresholdFeature[0].properties.lda > 0 ? thresholdFeature[0].properties.lda : 0).toFixed(0),
-            );
-            this.runwayTora.set(
-              (thresholdFeature[0]?.properties.tora > 0 ? thresholdFeature[0].properties.tora : 0).toFixed(0),
-            );
-          } else {
-            this.runwayLda.set('N/A');
-            this.runwayTora.set('N/A');
+    this.subs.push(
+      this.oansResetPulled.sub((v) => {
+        if (v) {
+          this.unloadCurrentAirport();
+        }
+      }, true),
+    );
+
+    this.oansPerformanceModeSettingSub = NXDataStore.getAndSubscribe(
+      'CONFIG_A380X_OANS_PERFORMANCE_MODE',
+      (_, v) => this.oansPerformanceMode.set(v === '1'),
+      '0',
+    );
+
+    this.subs.push(
+      this.fmsDataStore.landingRunway.sub(async (it) => {
+        // Set control panel display
+        if (it) {
+          // Load runway data
+          const destination = this.fmsDataStore.destination.get();
+          if (destination && this.navigraphAvailable.get() === false) {
+            this.setBtvRunwayFromFmsRunway();
           }
-        } else if (destination && this.navigraphAvailable.get() === false) {
-          this.setBtvRunwayFromFmsRunway();
         }
-      }
-    });
+      }),
+    );
+
+    this.subs.push(
+      this.sub
+        .on('nd_show_oans')
+        .whenChanged()
+        .handle((showOans) => {
+          if (this.props.side === showOans.side) {
+            this.showOans = showOans.show;
+          }
+        }),
+    );
+
+    this.subs.push(
+      this.sub
+        .on('realTime')
+        .atFrequency(0.5)
+        .handle((time) => {
+          this.oansPerformanceModeAndMovedOutOfZoomRange.write(
+            this.oansPerformanceMode.get() && !this.showOans,
+            this.lastUpdateTime === null ? 0 : time - this.lastUpdateTime,
+          );
+          this.props.bus.getPublisher<OansControlEvents>().pub(
+            'oans_performance_mode_hide',
+            {
+              side: this.props.side,
+              hide: this.oansPerformanceModeAndMovedOutOfZoomRange.read(),
+            },
+            true,
+          );
+          this.autoLoadAirport();
+
+          this.lastUpdateTime = time;
+        }),
+    );
+
+    this.subs.push(
+      this.sub
+        .on('realTime')
+        .atFrequency(5)
+        .handle((_) => {
+          if (this.arpCoordinates && this.navigraphAvailable.get() === false) {
+            globalToAirportCoordinates(this.arpCoordinates, this.presentPos.get(), this.localPpos);
+            this.props.bus.getPublisher<FmsOansData>().pub('oansAirportLocalCoordinates', this.localPpos, true);
+          }
+        }),
+    );
 
-    this.sub
-      .on('realTime')
-      .atFrequency(1)
-      .handle((_) => this.autoLoadAirport());
-
-    this.sub
-      .on('realTime')
-      .atFrequency(5)
-      .handle((_) => {
-        if (this.arpCoordinates && this.navigraphAvailable.get() === false) {
-          globalToAirportCoordinates(this.arpCoordinates, this.presentPos.get(), this.localPpos);
-          this.props.bus.getPublisher<FmsOansData>().pub('oansAirportLocalCoordinates', this.localPpos, true);
+    this.subs.push(this.sub.on('oans_display_airport').handle((arpt) => this.handleSelectAirport(arpt)));
+
+    this.subs.push(
+      this.selectedEntityIndex.sub((val) => {
+        const searchMode = this.selectedEntityType.get();
+        if (searchMode !== null && this.mapDataFeatures && val !== null) {
+          const prop = ControlPanelUtils.getMapDataSearchModeProp(searchMode);
+          const idx = this.mapDataFeatures.findIndex((f) => f.properties[prop] === this.availableEntityList.get(val));
+          this.selectedEntityString.set(
+            idx !== -1 ? this.mapDataFeatures[idx]?.properties[prop]?.toString() ?? '' : '',
+          );
+
+          if (
+            (idx !== -1 && searchMode === ControlPanelMapDataSearchMode.Runway) ||
+            searchMode === ControlPanelMapDataSearchMode.Stand
+          ) {
+            const feature = this.mapDataFeatures[idx] as Feature<Point>;
+            this.selectedEntityPosition = feature.geometry.coordinates;
+            this.selectedFeatureId.set(feature.properties?.id);
+            this.selectedFeatureType.set(feature.properties?.feattype);
+          } else if (
+            idx !== -1 &&
+            (searchMode === ControlPanelMapDataSearchMode.Taxiway || searchMode === ControlPanelMapDataSearchMode.Other)
+          ) {
+            const taxiway = this.mapDataFeatures[idx] as Feature<LineString, AmdbProperties>;
+            this.selectedEntityPosition = taxiway.properties.midpoint?.coordinates ?? [0, 0];
+            this.selectedFeatureId.set(taxiway.properties?.id);
+            this.selectedFeatureType.set(taxiway.properties?.feattype);
+          }
+
+          if (idx !== -1 && this.selectedEntityType.get() === ControlPanelMapDataSearchMode.Runway) {
+            this.runwayLda.set(this.mapDataFeatures[idx].properties.lda?.toFixed(0) ?? '');
+            this.runwayTora.set(this.mapDataFeatures[idx].properties.tora?.toFixed(0) ?? '');
+          }
+        } else {
+          this.selectedEntityString.set('');
+          this.runwayLda.set('');
+          this.runwayTora.set('');
         }
-      });
+      }, true),
+    );
+    this.subs.push(
+      this.selectedEntityType.sub((v) => this.handleSelectMapDataSearchMode(v ?? ControlPanelMapDataSearchMode.Runway)),
+    );
 
-    this.selectedEntityIndex.sub((val) => this.selectedEntityString.set(this.availableEntityList.get(val ?? 0)));
+    this.subs.push(
+      this.sub
+        .on(this.props.side === 'L' ? 'kccuOnL' : 'kccuOnR')
+        .whenChanged()
+        .handle((it) => this.interactionMode.set(it ? InteractionMode.Kccu : InteractionMode.Touchscreen)),
+    );
 
-    this.sub
-      .on(this.props.side === 'L' ? 'kccuOnL' : 'kccuOnR')
-      .whenChanged()
-      .handle((it) => this.interactionMode.set(it ? InteractionMode.Kccu : InteractionMode.Touchscreen));
+    this.subs.push(
+      this.setPlanModeConsumer,
+      this.setPlanModeDisplay,
+      this.oansResetPulled,
+      this.oansAvailable,
+      this.entityIsNotSelected,
+      this.symbolsForFeatureIds,
+      this.flagExistsForEntity,
+      this.crossExistsForEntity,
+      this.pposLatWord,
+      this.pposLongWord,
+      this.presentPos,
+      this.presentPosNotAvailable,
+      this.oansRequestedStoppingDistance,
+      this.reqStoppingDistance,
+      this.fmsLandingRunwayVisibility,
+      this.airportDatabase,
+    );
   }
 
   public updateAirportSearchData() {
@@ -343,7 +479,7 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
     this.store.sortedAirports.set(array.filter((it) => it[prop] !== null));
   }
 
-  private handleSelectAirport = (icao: string, indexInSearchData?: number) => {
+  private handleSelectAirport = async (icao: string, indexInSearchData?: number) => {
     const airport = this.store.airports.getArray().find((it) => it.idarpt === icao);
     const prop = ControlPanelUtils.getSearchModeProp(
       this.store.airportSearchMode.get() ?? ControlPanelAirportSearchMode.Icao,
@@ -363,10 +499,48 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
 
     this.store.airportSearchSelectedAirportIndex.set(airportIndexInSearchData);
     this.store.selectedAirport.set(airport);
+
+    this.handleSelectMapDataSearchMode(ControlPanelMapDataSearchMode.Runway);
+
     this.store.isAirportSelectionPending.set(true);
   };
 
-  private handleSelectSearchMode = (newSearchMode: ControlPanelAirportSearchMode) => {
+  private handleSelectMapDataSearchMode = async (newSearchMode: ControlPanelMapDataSearchMode) => {
+    const selectedAirport = this.store.selectedAirport.get();
+    this.selectedEntityIndex.set(null);
+
+    if (selectedAirport !== null) {
+      let featureType: FeatureTypeString = FeatureTypeString.RunwayThreshold;
+      switch (newSearchMode) {
+        case ControlPanelMapDataSearchMode.Runway:
+          featureType = FeatureTypeString.RunwayThreshold;
+          break;
+        case ControlPanelMapDataSearchMode.Taxiway:
+          featureType = FeatureTypeString.TaxiwayGuidanceLine;
+          break;
+        case ControlPanelMapDataSearchMode.Stand:
+          featureType = FeatureTypeString.ParkingStandLocation;
+          break;
+        case ControlPanelMapDataSearchMode.Other:
+          featureType = FeatureTypeString.DeicingArea;
+          break;
+        default:
+          break;
+      }
+      // Populate MAP DATA
+      const data = await this.amdbClient.getAirportData(selectedAirport.idarpt, [featureType]);
+      this.mapDataFeatures = data[featureType]?.features;
+      if (this.mapDataFeatures) {
+        const prop = ControlPanelUtils.getMapDataSearchModeProp(newSearchMode);
+        const entityData = this.mapDataFeatures
+          .map((f) => f.properties[prop]?.toString().trim().substring(0, 6) ?? '')
+          .filter((it) => it);
+        this.availableEntityList.set([...new Set(entityData)].sort());
+      }
+    }
+  };
+
+  private handleSelectAirportSearchMode = (newSearchMode: ControlPanelAirportSearchMode) => {
     const selectedAirport = this.store.selectedAirport.get();
 
     this.store.airportSearchMode.set(newSearchMode);
@@ -392,22 +566,62 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
     }
 
     this.manualAirportSelection = true;
-    this.props.bus.getPublisher<OansControlEvents>().pub('oansDisplayAirport', selectedArpt.idarpt, true);
+    this.props.bus.getPublisher<OansControlEvents>().pub('oans_display_airport', selectedArpt.idarpt, true);
     this.store.loadedAirport.set(selectedArpt);
     this.store.isAirportSelectionPending.set(false); // TODO should be done when airport is fully loaded
   };
 
-  private autoLoadAirport() {
-    // If we don't have ppos, do not try to auto load
-    if (this.presentPosNotAvailable.get()) {
-      return;
+  private handleCrossButton() {
+    {
+      const selId = this.selectedFeatureId.get();
+      const selFeatType = this.selectedFeatureType.get();
+      if (selId !== null && selFeatType !== null) {
+        this.props.bus
+          .getPublisher<OansControlEvents>()
+          .pub(
+            this.crossExistsForEntity.get() ? 'oans_remove_cross_at_feature' : 'oans_add_cross_at_feature',
+            { id: selId, feattype: selFeatType },
+            true,
+          );
+      }
+    }
+  }
+
+  private handleFlagButton() {
+    {
+      const selId = this.selectedFeatureId.get();
+      const selFeatType = this.selectedFeatureType.get();
+      if (selId !== null && selFeatType !== null) {
+        this.props.bus
+          .getPublisher<OansControlEvents>()
+          .pub(
+            this.flagExistsForEntity.get() ? 'oans_remove_flag_at_feature' : 'oans_add_flag_at_feature',
+            { id: selId, feattype: selFeatType },
+            true,
+          );
+      }
+    }
+  }
+
+  private unloadCurrentAirport() {
+    if (this.store.loadedAirport.get()) {
+      this.props.bus.getPublisher<OansControlEvents>().pub('oans_display_airport', '', true);
+      this.store.loadedAirport.set(null);
+      this.store.isAirportSelectionPending.set(false);
     }
+  }
 
+  private autoLoadAirport() {
+    // If we don't have ppos or airport unloaded due to performance reasons, do not try to auto load
     // If airport has been manually selected, do not auto load.
+    // FIXME reset manualAirportSelection after a while, to enable auto-load for destination even if departure was selected manually
     if (
+      this.presentPosNotAvailable.get() ||
+      this.oansPerformanceModeAndMovedOutOfZoomRange.read() ||
       this.manualAirportSelection === true ||
       this.store.loadedAirport.get() !== this.store.selectedAirport.get() ||
-      this.store.airports.length === 0
+      this.store.airports.length === 0 ||
+      this.oansResetPulled.get()
     ) {
       return;
     }
@@ -425,8 +639,7 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
       if (sortedAirports.length > 0) {
         const ap = sortedAirports[0];
         if (ap.idarpt !== this.store.loadedAirport.get()?.idarpt) {
-          this.handleSelectAirport(ap.idarpt);
-          this.props.bus.getPublisher<OansControlEvents>().pub('oansDisplayAirport', ap.idarpt, true);
+          this.props.bus.getPublisher<OansControlEvents>().pub('oans_display_airport', ap.idarpt, true);
           this.store.loadedAirport.set(ap);
           this.store.isAirportSelectionPending.set(false); // TODO should be done when airport is fully loaded
         }
@@ -438,8 +651,7 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
       const destArpt = this.store.airports.getArray().find((it) => it.idarpt === this.fmsDataStore.destination.get());
       if (destArpt && destArpt.idarpt !== this.store.loadedAirport.get()?.idarpt) {
         if (distanceTo(this.presentPos.get(), { lat: destArpt.coordinates.lat, long: destArpt.coordinates.lon }) < 50) {
-          this.handleSelectAirport(destArpt.idarpt);
-          this.props.bus.getPublisher<OansControlEvents>().pub('oansDisplayAirport', destArpt.idarpt, true);
+          this.props.bus.getPublisher<OansControlEvents>().pub('oans_display_airport', destArpt.idarpt, true);
           this.store.loadedAirport.set(destArpt);
           this.store.isAirportSelectionPending.set(false); // TODO should be done when airport is fully loaded
           return;
@@ -449,11 +661,14 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
   }
 
   private async setBtvRunwayFromFmsRunway() {
-    [this.landingRunwayNavdata, this.arpCoordinates] = await this.btvUtils.setBtvRunwayFromFmsRunway(this.fmsDataStore);
+    const destination = this.fmsDataStore.destination.get();
+    const rwyIdent = this.fmsDataStore.landingRunway.get();
 
-    if (this.landingRunwayNavdata) {
-      this.runwayLda.set(this.landingRunwayNavdata.length.toFixed(0));
-      this.runwayTora.set(this.landingRunwayNavdata.length.toFixed(0));
+    if (destination && rwyIdent) {
+      [this.landingRunwayNavdata, this.arpCoordinates] = await this.btvUtils.setBtvRunwayFromFmsRunway(
+        destination,
+        rwyIdent,
+      );
     }
   }
 
@@ -473,15 +688,33 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
     }
   }
 
+  destroy(): void {
+    for (const s of this.subs) {
+      s.destroy();
+    }
+    this.oansPerformanceModeSettingSub();
+    super.destroy();
+  }
+
   render(): VNode {
     return (
       <>
-        <IconButton
-          ref={this.closePanelButtonRef}
-          onClick={() => this.props.togglePanel()}
-          icon="double-up"
-          containerStyle="z-index: 10; width: 49px; height: 45px; position: absolute; right: 2px; top: 768px;"
-        />
+        <div style={{ display: this.props.isVisible.map((v) => (v ? 'inherit' : 'none')) }}>
+          <IconButton
+            ref={this.closePanelButtonRef}
+            onClick={() => this.props.togglePanel()}
+            icon="double-up"
+            containerStyle="z-index: 10; width: 49px; height: 45px; position: absolute; right: 2px; top: 768px;"
+          />
+        </div>
+        <div style={{ display: this.props.isVisible.map((v) => (v ? 'none' : 'inherit')) }}>
+          <IconButton
+            ref={this.closePanelButtonRef}
+            onClick={() => this.props.togglePanel()}
+            icon="double-down"
+            containerStyle="z-index: 10; width: 49px; height: 45px; position: absolute; right: 2px; top: 768px;"
+          />
+        </div>
         <div class="oans-control-panel-background">
           <div ref={this.oansMenuRef} class="oans-control-panel" style={this.style}>
             <TopTabNavigator
@@ -501,14 +734,13 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
                       idPrefix="oanc-search-letter"
                       freeTextAllowed={false}
                       onModified={(i) => this.selectedEntityIndex.set(i)}
-                      inactive={Subject.create(true)}
                       hEventConsumer={this.hEventConsumer}
                       interactionMode={this.interactionMode}
                     />
                     <div class="oans-cp-map-data-entitytype">
                       <RadioButtonGroup
                         values={this.availableEntityTypes}
-                        valuesDisabled={Subject.create(Array(4).fill(true))}
+                        valuesDisabled={Subject.create(Array(4).fill(false))}
                         selectedIndex={this.selectedEntityType}
                         idPrefix="entityTypesRadio"
                       />
@@ -558,16 +790,16 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
                   <div ref={this.mapDataMainRef} class="oans-cp-map-data-main">
                     <div class="oans-cp-map-data-main-2">
                       <Button
-                        label="ADD CROSS"
-                        onClick={() => console.log('ADD CROSS')}
+                        label={this.crossExistsForEntity.map((e) => (e ? <>DEL CROSS</> : <>ADD CROSS</>))}
+                        onClick={() => this.handleCrossButton()}
                         buttonStyle="flex: 1"
-                        disabled={Subject.create(true)}
+                        disabled={this.entityIsNotSelected}
                       />
                       <Button
-                        label="ADD FLAG"
-                        onClick={() => console.log('ADD FLAG')}
+                        label={this.flagExistsForEntity.map((e) => (e ? <>DEL FLAG</> : <>ADD FLAG</>))}
+                        onClick={() => this.handleFlagButton()}
                         buttonStyle="flex: 1; margin-left: 10px; margin-right: 10px"
-                        disabled={Subject.create(true)}
+                        disabled={this.entityIsNotSelected}
                       />
                       <Button
                         label="LDG SHIFT"
@@ -578,13 +810,17 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
                     </div>
                     <div class="oans-cp-map-data-main-center">
                       <Button
-                        label={`CENTER MAP ON ${this.availableEntityList.get(this.selectedEntityIndex.get() ?? 0)}`}
-                        onClick={() =>
-                          console.log(
-                            `CENTER MAP ON ${this.availableEntityList.get(this.selectedEntityIndex.get() ?? 0)}`,
-                          )
-                        }
-                        disabled={Subject.create(true)}
+                        label={this.selectedEntityString.map((s) => (
+                          <>`CENTER MAP ON ${s}`</>
+                        ))}
+                        onClick={() => {
+                          if (this.selectedEntityPosition) {
+                            this.props.bus
+                              .getPublisher<OansControlEvents>()
+                              .pub('oans_center_map_on', this.selectedEntityPosition, true);
+                          }
+                        }}
+                        disabled={this.entityIsNotSelected}
                       />
                     </div>
                     <OansRunwayInfoBox
@@ -679,13 +915,13 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
                         onModified={(newSelectedIndex) => {
                           switch (newSelectedIndex) {
                             case 0:
-                              this.handleSelectSearchMode(ControlPanelAirportSearchMode.Icao);
+                              this.handleSelectAirportSearchMode(ControlPanelAirportSearchMode.Icao);
                               break;
                             case 1:
-                              this.handleSelectSearchMode(ControlPanelAirportSearchMode.Iata);
+                              this.handleSelectAirportSearchMode(ControlPanelAirportSearchMode.Iata);
                               break;
                             default:
-                              this.handleSelectSearchMode(ControlPanelAirportSearchMode.City);
+                              this.handleSelectAirportSearchMode(ControlPanelAirportSearchMode.City);
                               break;
                           }
                         }}
@@ -716,6 +952,9 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
                           return `${ControlPanelUtils.LAT_FORMATTER(it.coordinates.lat)}/${ControlPanelUtils.LONG_FORMATTER(it.coordinates.lon)}`;
                         })}
                       </span>
+                      <span class="mfd-label bigger" style={{ display: this.setPlanModeDisplay }}>
+                        SET PLAN MODE
+                      </span>
                     </div>
                     <div style="flex-grow: 1;" />
                     <div class="oans-cp-arpt-sel-display-arpt">
@@ -802,3 +1041,71 @@ export class OansControlPanel extends DisplayComponent<OansProps> {
     );
   }
 }
+
+interface EraseSymbolsDialogProps extends ComponentProps {
+  visible: Subscribable<boolean>;
+  confirmAction: () => void;
+  hideDialog: () => void;
+  /** True: Cross, false: flag */
+  isCross: boolean;
+}
+
+/*
+ * ERASE ALL xxx dialog
+ */
+export class EraseSymbolsDialog extends DisplayComponent<EraseSymbolsDialogProps> {
+  // Make sure to collect all subscriptions here, otherwise page navigation doesn't work.
+  private subs = [] as Subscription[];
+
+  private topRef = FSComponent.createRef<HTMLDivElement>();
+
+  onAfterRender(node: VNode): void {
+    super.onAfterRender(node);
+
+    this.subs.push(
+      this.props.visible.sub((val) => {
+        if (this.topRef.getOrDefault()) {
+          this.topRef.instance.style.display = val ? 'block' : 'none';
+        }
+      }, true),
+    );
+  }
+
+  public destroy(): void {
+    // Destroy all subscriptions to remove all references to this instance.
+    for (const x of this.subs) {
+      x.destroy();
+    }
+    super.destroy();
+  }
+
+  render(): VNode {
+    return (
+      <div ref={this.topRef}>
+        <div class="mfd-dialog" style="left: 209px; top: 350px; width: 350px;">
+          <div class="mfd-dialog-title" style="margin-bottom: 20px;">
+            <span class="mfd-label">{`ERASE ALL ${this.props.isCross ? 'CROSSES' : 'FLAGS'}`}</span>
+            <span>
+              <img
+                style="position: relative; top: -5px; left: 10px"
+                width="25px"
+                src={`/Images/fbw-a380x/oans/oans-${this.props.isCross ? 'cross' : 'flag'}.svg`}
+              />
+            </span>
+          </div>
+          <div class="mfd-dialog-buttons">
+            <Button label="CANCEL" onClick={() => this.props.hideDialog()} />
+            <Button
+              label="CONFIRM"
+              onClick={() => {
+                this.props.confirmAction();
+                this.props.hideDialog();
+              }}
+              buttonStyle="padding-right: 6px;"
+            />
+          </div>
+        </div>
+      </div>
+    );
+  }
+}
diff --git a/fbw-a380x/src/systems/instruments/src/ND/instrument.tsx b/fbw-a380x/src/systems/instruments/src/ND/instrument.tsx
index 294d8bcf19f..a9b6a5eb8c7 100644
--- a/fbw-a380x/src/systems/instruments/src/ND/instrument.tsx
+++ b/fbw-a380x/src/systems/instruments/src/ND/instrument.tsx
@@ -10,9 +10,8 @@ import {
   FsInstrument,
   HEventPublisher,
   InstrumentBackplane,
+  MappedSubject,
   Subject,
-  Subscribable,
-  Wait,
 } from '@microsoft/msfs-sdk';
 import {
   A380EfisNdRangeValue,
@@ -27,17 +26,11 @@ import {
   FmsOansSimvarPublisher,
 } from '@flybywiresim/fbw-sdk';
 import { NDComponent } from '@flybywiresim/navigation-display';
-import {
-  a380EfisZoomRangeSettings,
-  A380EfisZoomRangeValue,
-  Oanc,
-  OansControlEvents,
-  ZOOM_TRANSITION_TIME_MS,
-} from '@flybywiresim/oanc';
+import { a380EfisZoomRangeSettings, A380EfisZoomRangeValue, Oanc, OansControlEvents } from '@flybywiresim/oanc';
 
 import { ContextMenu, ContextMenuElement } from 'instruments/src/MsfsAvionicsCommon/UiWidgets/ContextMenu';
-import { MouseCursor } from 'instruments/src/MsfsAvionicsCommon/UiWidgets/MouseCursor';
-import { OansControlPanel } from './OansControlPanel';
+import { MouseCursor, MouseCursorColor } from 'instruments/src/MsfsAvionicsCommon/UiWidgets/MouseCursor';
+import { EraseSymbolsDialog, OansControlPanel } from './OansControlPanel';
 import { FmsSymbolsPublisher } from './FmsSymbolsPublisher';
 import { NDSimvarPublisher, NDSimvars } from './NDSimvarPublisher';
 import { AdirsValueProvider } from '../MsfsAvionicsCommon/AdirsValueProvider';
@@ -50,6 +43,7 @@ import { CdsDisplayUnit, DisplayUnitID, getDisplayIndex } from '../MsfsAvionicsC
 import { EgpwcBusPublisher } from '../MsfsAvionicsCommon/providers/EgpwcBusPublisher';
 import { DmcPublisher } from '../MsfsAvionicsCommon/providers/DmcPublisher';
 import { FMBusPublisher } from '../MsfsAvionicsCommon/providers/FMBusPublisher';
+import { ResetPanelSimvarPublisher, ResetPanelSimvars } from '../MsfsAvionicsCommon/providers/ResetPanelPublisher';
 import { RopRowOansPublisher } from '@flybywiresim/msfs-avionics-common';
 import { SimplaneValueProvider } from 'instruments/src/MsfsAvionicsCommon/providers/SimplaneValueProvider';
 
@@ -99,6 +93,8 @@ class NDInstrument implements FsInstrument {
 
   private readonly hEventPublisher: HEventPublisher;
 
+  private readonly resetPanelPublisher: ResetPanelSimvarPublisher;
+
   private readonly adirsValueProvider: AdirsValueProvider<NDSimvars>;
 
   private readonly simplaneValueProvider: SimplaneValueProvider;
@@ -115,56 +111,15 @@ class NDInstrument implements FsInstrument {
 
   private readonly controlPanelVisible = Subject.create(false);
 
-  private oansContextMenuItems: Subscribable<ContextMenuElement[]> = Subject.create([
-    {
-      name: 'ADD CROSS',
-      disabled: true,
-      onPressed: () =>
-        console.log(
-          `ADD CROSS at (${this.contextMenuPositionTriggered.get().x}, ${this.contextMenuPositionTriggered.get().y})`,
-        ),
-    },
-    {
-      name: 'ADD FLAG',
-      disabled: true,
-      onPressed: () =>
-        console.log(
-          `ADD FLAG at (${this.contextMenuPositionTriggered.get().x}, ${this.contextMenuPositionTriggered.get().y})`,
-        ),
-    },
-    {
-      name: 'MAP DATA',
-      disabled: false,
-      onPressed: () => {
-        if (this.controlPanelRef.getOrDefault()) {
-          this.controlPanelVisible.set(!this.controlPanelVisible.get());
-        }
-      },
-    },
-    {
-      name: 'ERASE ALL CROSSES',
-      disabled: true,
-      onPressed: () => console.log('ERASE ALL CROSSES'),
-    },
-    {
-      name: 'ERASE ALL FLAGS',
-      disabled: true,
-      onPressed: () => console.log('ERASE ALL FLAGS'),
-    },
-    {
-      name: 'CENTER ON ACFT',
-      disabled: false,
-      onPressed: async () => {
-        if (this.oansRef.getOrDefault() !== null) {
-          await this.oansRef.instance.enablePanningTransitions();
-          this.oansRef.instance.panOffsetX.set(0);
-          this.oansRef.instance.panOffsetY.set(0);
-          await Wait.awaitDelay(ZOOM_TRANSITION_TIME_MS);
-          await this.oansRef.instance.disablePanningTransitions();
-        }
-      },
-    },
-  ]);
+  private readonly eraseAllCrossesDialogVisible = Subject.create(false);
+
+  private readonly eraseAllFlagsDialogVisible = Subject.create(false);
+
+  private readonly eraseCrossIndex = Subject.create<number | null>(null);
+
+  private readonly eraseFlagIndex = Subject.create<number | null>(null);
+
+  private oansContextMenuItems = Subject.create(this.getOansContextMenu(false, false));
 
   private contextMenuRef = FSComponent.createRef<ContextMenu>();
 
@@ -209,6 +164,7 @@ class NDInstrument implements FsInstrument {
     this.dmcPublisher = new DmcPublisher(this.bus);
     this.egpwcBusPublisher = new EgpwcBusPublisher(this.bus, side);
     this.hEventPublisher = new HEventPublisher(this.bus);
+    this.resetPanelPublisher = new ResetPanelSimvarPublisher(this.bus);
 
     this.adirsValueProvider = new AdirsValueProvider(this.bus, this.simVarPublisher, side);
     this.simplaneValueProvider = new SimplaneValueProvider(this.bus);
@@ -229,6 +185,7 @@ class NDInstrument implements FsInstrument {
     this.backplane.addPublisher('dmc', this.dmcPublisher);
     this.backplane.addPublisher('egpwc', this.egpwcBusPublisher);
     this.backplane.addPublisher('hEvent', this.hEventPublisher);
+    this.backplane.addPublisher('resetPanel', this.resetPanelPublisher);
 
     this.backplane.addInstrument('Simplane', this.simplaneValueProvider);
     this.backplane.addInstrument('clock', this.clock);
@@ -293,6 +250,32 @@ class NDInstrument implements FsInstrument {
             idPrefix="contextMenu"
             values={this.oansContextMenuItems}
           />
+          <EraseSymbolsDialog
+            visible={MappedSubject.create(
+              ([crosses, flags, oans]) => crosses && !flags && oans,
+              this.eraseAllCrossesDialogVisible,
+              this.eraseAllFlagsDialogVisible,
+              this.oansShown,
+            )}
+            confirmAction={() =>
+              this.bus.getPublisher<OansControlEvents>().pub('oans_erase_all_crosses', true, true, false)
+            }
+            hideDialog={() => this.eraseAllCrossesDialogVisible.set(false)}
+            isCross={true}
+          />
+          <EraseSymbolsDialog
+            visible={MappedSubject.create(
+              ([crosses, flags, oans]) => !crosses && flags && oans,
+              this.eraseAllCrossesDialogVisible,
+              this.eraseAllFlagsDialogVisible,
+              this.oansShown,
+            )}
+            confirmAction={() =>
+              this.bus.getPublisher<OansControlEvents>().pub('oans_erase_all_flags', true, true, false)
+            }
+            hideDialog={() => this.eraseAllFlagsDialogVisible.set(false)}
+            isCross={false}
+          />
           <div
             style={{
               display: this.oansShown.map((v) => (v ? 'block' : 'none')),
@@ -310,6 +293,7 @@ class NDInstrument implements FsInstrument {
             ref={this.mouseCursorRef}
             side={Subject.create(this.efisSide === 'L' ? 'CAPT' : 'FO')}
             visible={this.cursorVisible}
+            color={this.oansShown.map((it) => (it ? MouseCursorColor.Magenta : MouseCursorColor.Yellow))}
           />
           <VerticalDisplayDummy bus={this.bus} side={this.efisSide} />
         </CdsDisplayUnit>
@@ -330,13 +314,10 @@ class NDInstrument implements FsInstrument {
     });
 
     if (this.oansRef?.instance?.labelContainerRef?.instance) {
-      this.oansRef.instance.labelContainerRef.instance.addEventListener('contextmenu', (e) => {
-        // Not firing right now, use double click
-        this.contextMenuPositionTriggered.set({ x: e.clientX, y: e.clientY });
-        this.contextMenuRef.instance.display(e.clientX, e.clientY);
-      });
-
       this.oansRef.instance.labelContainerRef.instance.addEventListener('dblclick', (e) => {
+        this.bus
+          .getPublisher<OansControlEvents>()
+          .pub('oans_query_symbols_at_cursor', { side: this.efisSide, cursorPosition: [e.clientX, e.clientY] });
         this.contextMenuPositionTriggered.set({ x: e.clientX, y: e.clientY });
         this.contextMenuRef.instance.display(e.clientX, e.clientY);
       });
@@ -346,9 +327,9 @@ class NDInstrument implements FsInstrument {
       });
     }
 
-    const sub = this.bus.getSubscriber<FcuSimVars & OansControlEvents>();
+    const sub = this.bus.getSubscriber<FcuSimVars & OansControlEvents & ResetPanelSimvars>();
 
-    this.oansNotAvailable.setConsumer(sub.on('oansNotAvail'));
+    this.oansNotAvailable.setConsumer(sub.on('oans_not_avail'));
 
     sub
       .on('ndMode')
@@ -365,18 +346,85 @@ class NDInstrument implements FsInstrument {
         this.efisCpRange = a380EfisRangeSettings[range];
         this.updateNdOansVisibility();
       });
+
+    sub.on('oans_answer_symbols_at_cursor').handle((symbols) => {
+      if (symbols.side === this.efisSide) {
+        this.eraseCrossIndex.set(symbols.cross);
+        this.eraseFlagIndex.set(symbols.flag);
+        this.oansContextMenuItems.set(this.getOansContextMenu(symbols.cross !== null, symbols.flag !== null));
+      }
+    });
   }
 
   private updateNdOansVisibility() {
     if (this.efisCpRange === -1 && [EfisNdMode.PLAN, EfisNdMode.ARC, EfisNdMode.ROSE_NAV].includes(this.efisNdMode)) {
-      this.bus.getPublisher<OansControlEvents>().pub('ndShowOans', true);
+      this.bus.getPublisher<OansControlEvents>().pub('nd_show_oans', { side: this.efisSide, show: true }, true, false);
       this.oansShown.set(true);
     } else {
-      this.bus.getPublisher<OansControlEvents>().pub('ndShowOans', false);
+      this.bus.getPublisher<OansControlEvents>().pub('nd_show_oans', { side: this.efisSide, show: false }, true, false);
       this.oansShown.set(false);
     }
   }
 
+  getOansContextMenu(hasCross: boolean, hasFlag: boolean): ContextMenuElement[] {
+    const crossIndex = this.eraseCrossIndex.get();
+    const flagIndex = this.eraseFlagIndex.get();
+    return [
+      {
+        name: hasCross ? 'DELETE CROSS' : 'ADD CROSS',
+        disabled: false,
+        onPressed: () =>
+          hasCross && crossIndex !== null
+            ? this.bus.getPublisher<OansControlEvents>().pub('oans_erase_cross_id', crossIndex)
+            : this.bus
+                .getPublisher<OansControlEvents>()
+                .pub('oans_add_cross_at_cursor', [
+                  this.contextMenuPositionTriggered.get().x,
+                  this.contextMenuPositionTriggered.get().y,
+                ]),
+      },
+      {
+        name: hasFlag ? 'DELETE FLAG' : 'ADD FLAG',
+        disabled: false,
+        onPressed: () =>
+          hasFlag && flagIndex !== null
+            ? this.bus.getPublisher<OansControlEvents>().pub('oans_erase_flag_id', flagIndex)
+            : this.bus
+                .getPublisher<OansControlEvents>()
+                .pub('oans_add_flag_at_cursor', [
+                  this.contextMenuPositionTriggered.get().x,
+                  this.contextMenuPositionTriggered.get().y,
+                ]),
+      },
+      {
+        name: 'MAP DATA',
+        disabled: false,
+        onPressed: () => {
+          if (this.controlPanelRef.getOrDefault()) {
+            this.controlPanelVisible.set(!this.controlPanelVisible.get());
+          }
+        },
+      },
+      {
+        name: 'ERASE ALL CROSSES',
+        disabled: false,
+        onPressed: () => this.eraseAllCrossesDialogVisible.set(true),
+      },
+      {
+        name: 'ERASE ALL FLAGS',
+        disabled: false,
+        onPressed: () => this.eraseAllFlagsDialogVisible.set(true),
+      },
+      {
+        name: 'CENTER ON ACFT',
+        disabled: false,
+        onPressed: async () => {
+          this.bus.getPublisher<OansControlEvents>().pub('oans_center_on_acft', true, true, false);
+        },
+      },
+    ];
+  }
+
   /**
    * A callback called when the instrument gets a frame update.
    */
diff --git a/fbw-a380x/src/systems/instruments/src/ND/oans-style.scss b/fbw-a380x/src/systems/instruments/src/ND/oans-style.scss
index 9330f4215cb..7c001e7c789 100644
--- a/fbw-a380x/src/systems/instruments/src/ND/oans-style.scss
+++ b/fbw-a380x/src/systems/instruments/src/ND/oans-style.scss
@@ -199,6 +199,39 @@
   outline: 0px;
 }
 
+.oanc-label-style-cross-symbol {
+  font-size: 0.1px;
+  color: transparent;
+  width: 35px;
+  height: 35px;
+  background-color: transparent;
+  background-image: url('/Images/fbw-a380x/oans/oans-cross.png');
+  background-size: contain;
+  background-repeat: no-repeat;
+}
+
+.oanc-label-style-cross-symbol:hover {
+  outline: 3px solid $display-cyan;
+  pointer-events: auto;
+  outline-offset: 0px !important;
+}
+
+.oanc-label-style-flag-symbol {
+  font-size: 0.1px;
+  color: transparent;
+  width: 40px;
+  height: 40px;
+  background-color: transparent;
+  background-image: url('/Images/fbw-a380x/oans/oans-flag.png');
+  background-size: contain;
+  background-repeat: no-repeat;
+}
+
+.oanc-label-style-flag-symbol:hover {
+  outline: 3px solid $display-cyan;
+  pointer-events: auto;
+  outline-offset: 0px !important;
+}
 
 .oanc-button {
   padding: 10px 6px;
diff --git a/fbw-a380x/src/systems/instruments/src/PFD/FMA.tsx b/fbw-a380x/src/systems/instruments/src/PFD/FMA.tsx
index fd9cc280592..488eb4efd8f 100644
--- a/fbw-a380x/src/systems/instruments/src/PFD/FMA.tsx
+++ b/fbw-a380x/src/systems/instruments/src/PFD/FMA.tsx
@@ -89,6 +89,8 @@ export class FMA extends DisplayComponent<{ bus: EventBus; isAttExcessive: Subsc
 
   private readonly approachCapability = ConsumerSubject.create(this.sub.on('approachCapability'), 0);
 
+  private readonly btvExitMissed = ConsumerSubject.create(this.sub.on('btvExitMissed'), false);
+
   private disconnectApForLdg = MappedSubject.create(
     ([ap1, ap2, ra, altitude, landingElevation, verticalMode, selectedFpa, selectedVs, approachCapability]) => {
       return (
@@ -130,6 +132,7 @@ export class FMA extends DisplayComponent<{ bus: EventBus; isAttExcessive: Subsc
         this.tcasRaInhibited.get(),
         this.tdReached,
         this.disconnectApForLdg.get(),
+        this.btvExitMissed.get(),
       )[0] !== null;
 
     const engineMessage = this.athrModeMessage;
@@ -164,6 +167,8 @@ export class FMA extends DisplayComponent<{ bus: EventBus; isAttExcessive: Subsc
 
     this.disconnectApForLdg.sub(() => this.handleFMABorders());
 
+    this.btvExitMissed.sub(() => this.handleFMABorders());
+
     this.props.isAttExcessive.sub((_a) => {
       this.handleFMABorders();
     });
@@ -235,6 +240,7 @@ export class FMA extends DisplayComponent<{ bus: EventBus; isAttExcessive: Subsc
           bus={this.props.bus}
           isAttExcessive={this.props.isAttExcessive}
           disconnectApForLdg={this.disconnectApForLdg}
+          btvExitMissed={this.btvExitMissed}
           AB3Message={this.AB3Message}
         />
       </g>
@@ -395,6 +401,7 @@ class Row3 extends DisplayComponent<{
   bus: EventBus;
   isAttExcessive: Subscribable<boolean>;
   disconnectApForLdg: Subscribable<boolean>;
+  btvExitMissed: Subscribable<boolean>;
   AB3Message: Subscribable<boolean>;
 }> {
   private cellsToHide = FSComponent.createRef<SVGGElement>();
@@ -422,6 +429,7 @@ class Row3 extends DisplayComponent<{
         <BC3Cell
           isAttExcessive={this.props.isAttExcessive}
           disconnectApForLdg={this.props.disconnectApForLdg}
+          btvExitMissed={this.props.btvExitMissed}
           bus={this.props.bus}
         />
         <E3Cell bus={this.props.bus} />
@@ -1351,6 +1359,7 @@ const getBC3Message = (
   tcasRaInhibited: boolean,
   tdReached: boolean,
   disconnectApForLdg: boolean,
+  exitMissed: boolean,
 ) => {
   const armedVerticalBitmask = armedVerticalMode;
   const TCASArmed = (armedVerticalBitmask >> 6) & 1;
@@ -1392,7 +1401,7 @@ const getBC3Message = (
   } else if (setHoldSpeed) {
     text = 'SET HOLD SPD';
     className = 'FontMedium White';
-  } else if (false) {
+  } else if (exitMissed) {
     text = 'EXIT MISSED';
     className = 'White';
   } else {
@@ -1405,6 +1414,7 @@ const getBC3Message = (
 class BC3Cell extends DisplayComponent<{
   isAttExcessive: Subscribable<boolean>;
   disconnectApForLdg: Subscribable<boolean>;
+  btvExitMissed: Subscribable<boolean>;
   bus: EventBus;
 }> {
   private sub = this.props.bus.getSubscriber<PFDSimvars & Arinc429Values>();
@@ -1434,6 +1444,7 @@ class BC3Cell extends DisplayComponent<{
       this.tcasRaInhibited,
       this.tdReached,
       this.props.disconnectApForLdg.get(),
+      this.props.btvExitMissed.get(),
     );
     this.classNameSub.set(`FontMedium MiddleAlign ${className}`);
     if (text !== null) {
@@ -1455,6 +1466,10 @@ class BC3Cell extends DisplayComponent<{
       this.fillBC3Cell();
     });
 
+    this.props.btvExitMissed.sub(() => {
+      this.fillBC3Cell();
+    });
+
     this.sub
       .on('fmaVerticalArmed')
       .whenChanged()
diff --git a/fbw-a380x/src/systems/instruments/src/PFD/shared/PFDSimvarPublisher.tsx b/fbw-a380x/src/systems/instruments/src/PFD/shared/PFDSimvarPublisher.tsx
index de69cc28db8..e9379de97fa 100644
--- a/fbw-a380x/src/systems/instruments/src/PFD/shared/PFDSimvarPublisher.tsx
+++ b/fbw-a380x/src/systems/instruments/src/PFD/shared/PFDSimvarPublisher.tsx
@@ -167,6 +167,7 @@ export interface PFDSimvars {
   spoilersArmed: boolean;
   fcuLeftVelocityVectorOn: boolean;
   fcuRightVelocityVectorOn: boolean;
+  btvExitMissed: boolean;
 }
 
 export enum PFDVars {
@@ -334,6 +335,7 @@ export enum PFDVars {
   spoilersArmed = 'L:A32NX_SPOILERS_ARMED',
   fcuLeftVelocityVectorOn = 'L:A380X_EFIS_L_VV_BUTTON_IS_ON',
   fcuRightVelocityVectorOn = 'L:A380X_EFIS_R_VV_BUTTON_IS_ON',
+  btvExitMissed = 'L:A32NX_BTV_EXIT_MISSED',
 }
 
 /** A publisher to poll and publish nav/com simvars. */
@@ -500,6 +502,7 @@ export class PFDSimvarPublisher extends UpdatableSimVarPublisher<PFDSimvars> {
     ['spoilersArmed', { name: PFDVars.spoilersArmed, type: SimVarValueType.Bool }],
     ['fcuLeftVelocityVectorOn', { name: PFDVars.fcuLeftVelocityVectorOn, type: SimVarValueType.Bool }],
     ['fcuRightVelocityVectorOn', { name: PFDVars.fcuRightVelocityVectorOn, type: SimVarValueType.Bool }],
+    ['btvExitMissed', { name: PFDVars.btvExitMissed, type: SimVarValueType.Bool }],
   ]);
 
   public constructor(bus: EventBus) {
diff --git a/fbw-a380x/src/systems/systems-host/systems/FlightWarningSystem/FwsCore.ts b/fbw-a380x/src/systems/systems-host/systems/FlightWarningSystem/FwsCore.ts
index 9d4cf36fa3b..77b5923fd22 100644
--- a/fbw-a380x/src/systems/systems-host/systems/FlightWarningSystem/FwsCore.ts
+++ b/fbw-a380x/src/systems/systems-host/systems/FlightWarningSystem/FwsCore.ts
@@ -1176,6 +1176,8 @@ export class FwsCore {
 
   public autoBrakeOffMemoInhibited = false;
 
+  public btvExitMissedPulseNode = new NXLogicPulseNode();
+
   /* NAVIGATION */
 
   public readonly adirsRemainingAlignTime = Subject.create(0);
@@ -2622,6 +2624,15 @@ export class FwsCore {
       this.autoBrakeOffAuralTriggered = true;
     }
 
+    this.btvExitMissedPulseNode.write(
+      SimVar.GetSimVarValue('L:A32NX_BTV_EXIT_MISSED', SimVarValueType.Bool),
+      deltaTime,
+    );
+
+    if (this.btvExitMissedPulseNode.read()) {
+      this.soundManager.enqueueSound('tripleClick');
+    }
+
     // Engine Logic
     this.thrustLeverNotSet.set(this.autothrustLeverWarningFlex.get() || this.autothrustLeverWarningToga.get());
     // FIXME ECU doesn't have the necessary output words so we go purely on TLA
diff --git a/fbw-a380x/src/wasm/systems/a380_systems/src/hydraulic/autobrakes.rs b/fbw-a380x/src/wasm/systems/a380_systems/src/hydraulic/autobrakes.rs
index 3ccc558662a..a17d543f8d3 100644
--- a/fbw-a380x/src/wasm/systems/a380_systems/src/hydraulic/autobrakes.rs
+++ b/fbw-a380x/src/wasm/systems/a380_systems/src/hydraulic/autobrakes.rs
@@ -960,6 +960,7 @@ struct BtvDecelScheduler {
     rot_estimation_id: VariableIdentifier,
     turnaround_idle_reverse_estimation_id: VariableIdentifier,
     turnaround_max_reverse_estimation_id: VariableIdentifier,
+    exit_missed_id: VariableIdentifier,
 
     runway_length: Arinc429Word<Length>,
 
@@ -985,6 +986,9 @@ struct BtvDecelScheduler {
     wet_prediction: Length,
 
     distance_to_rwy_end: Length,
+
+    exit_missed_confirmation: DelayedTrueLogicGate,
+    exit_missed: bool,
 }
 impl BtvDecelScheduler {
     // Target decel when optimizing runway time before braking
@@ -1008,6 +1012,8 @@ impl BtvDecelScheduler {
     const MIN_DECEL_SAFETY_MARGIN_RATIO: f64 = 1.15;
     const DECEL_SAFETY_MARGIN_SHAPING_FACTOR: f64 = 0.4;
 
+    const EXIT_MISSED_CONFIRMATION_TIME_S: u64 = 5;
+
     const REMAINING_BRAKING_DISTANCE_END_OF_RUNWAY_OFFSET_METERS: f64 = 300.;
 
     fn new(context: &mut InitContext) -> Self {
@@ -1022,6 +1028,7 @@ impl BtvDecelScheduler {
                 .get_identifier("BTV_TURNAROUND_IDLE_REVERSE".to_owned()),
             turnaround_max_reverse_estimation_id: context
                 .get_identifier("BTV_TURNAROUND_MAX_REVERSE".to_owned()),
+            exit_missed_id: context.get_identifier("BTV_EXIT_MISSED".to_owned()),
 
             runway_length: Arinc429Word::new(Length::default(), SignStatus::NoComputedData),
             rolling_distance: Length::default(),
@@ -1050,6 +1057,11 @@ impl BtvDecelScheduler {
             wet_prediction: Length::default(),
 
             distance_to_rwy_end: Length::default(),
+
+            exit_missed_confirmation: DelayedTrueLogicGate::new(Duration::from_secs(
+                Self::EXIT_MISSED_CONFIRMATION_TIME_S,
+            )),
+            exit_missed: false,
         }
     }
 
@@ -1099,6 +1111,9 @@ impl BtvDecelScheduler {
 
         self.compute_decel(context);
 
+        self.exit_missed_confirmation
+            .update(context, self.exit_missed);
+
         self.state = self.update_state(context);
     }
 
@@ -1138,6 +1153,17 @@ impl BtvDecelScheduler {
                 let target_deceleration_safety_corrected =
                     target_deceleration_raw * self.safety_margin();
 
+                // If EXIT MISSED already confirmed for 5s, keep until disengaged
+                if !self.exit_missed_confirmation.output() {
+                    // Target deceleration shoots up when nearing release speed, hence only check above twice the release speed
+                    self.exit_missed = target_deceleration_safety_corrected
+                        < Self::MAX_DECEL_DRY_MS2
+                        && delta_speed_to_achieve
+                            > Velocity::new::<meter_per_second>(
+                                Self::TARGET_SPEED_TO_RELEASE_BTV_M_S,
+                            );
+                }
+
                 self.deceleration_request = Acceleration::new::<meter_per_second_squared>(
                     target_deceleration_safety_corrected.clamp(
                         self.desired_deceleration.get::<meter_per_second_squared>(),
@@ -1147,6 +1173,7 @@ impl BtvDecelScheduler {
             }
             BTVState::Armed | BTVState::Disabled => {
                 self.deceleration_request = Acceleration::new::<meter_per_second_squared>(5.);
+                self.exit_missed = false;
             }
         }
     }
@@ -1341,6 +1368,8 @@ impl SimulationElement for BtvDecelScheduler {
             turnaround_time_estimated_in_minutes[0].value(),
             turnaround_time_estimated_in_minutes[0].ssm(),
         );
+
+        writer.write(&self.exit_missed_id, self.exit_missed_confirmation.output());
     }
 
     fn read(&mut self, reader: &mut SimulatorReader) {
diff --git a/fbw-common/src/systems/instruments/src/EFB/AircraftContext.ts b/fbw-common/src/systems/instruments/src/EFB/AircraftContext.ts
index 4e5fa1b2e99..9f061400199 100644
--- a/fbw-common/src/systems/instruments/src/EFB/AircraftContext.ts
+++ b/fbw-common/src/systems/instruments/src/EFB/AircraftContext.ts
@@ -52,6 +52,7 @@ interface SimOptions {
   registrationDecal: boolean;
   wheelChocks: boolean;
   cabinLighting: boolean;
+  oansPerformanceMode: boolean;
 }
 
 interface ThrottleOptions {
@@ -102,6 +103,7 @@ export const AircraftContext = createContext<AircraftEfbContext>({
       registrationDecal: false,
       wheelChocks: false,
       cabinLighting: false,
+      oansPerformanceMode: false,
     },
     throttle: {
       numberOfAircraftThrottles: 0,
diff --git a/fbw-common/src/systems/instruments/src/EFB/Localization/data/en.json b/fbw-common/src/systems/instruments/src/EFB/Localization/data/en.json
index 14b4edef027..60d712da9dc 100644
--- a/fbw-common/src/systems/instruments/src/EFB/Localization/data/en.json
+++ b/fbw-common/src/systems/instruments/src/EFB/Localization/data/en.json
@@ -663,6 +663,7 @@
       "Left": "Left",
       "LoadOnly": "Load Only",
       "None": "None",
+      "OansPerformanceMode": "OANS Performance Mode (Un-Load Airport Map When Not Used)",
       "Off": "Off",
       "PilotSeat": "Pilot Seat for Control",
       "Right": "Right",
diff --git a/fbw-common/src/systems/instruments/src/EFB/Settings/Pages/SimOptionsPage.tsx b/fbw-common/src/systems/instruments/src/EFB/Settings/Pages/SimOptionsPage.tsx
index 60c27bb96d0..9169d8d838b 100644
--- a/fbw-common/src/systems/instruments/src/EFB/Settings/Pages/SimOptionsPage.tsx
+++ b/fbw-common/src/systems/instruments/src/EFB/Settings/Pages/SimOptionsPage.tsx
@@ -47,6 +47,11 @@ export const SimOptionsPage = () => {
   const [cabinManualBrightness, setCabinManualBrightness] = usePersistentNumberProperty('CABIN_MANUAL_BRIGHTNESS', 0);
   const [pilotSeat, setPilotSeat] = usePersistentProperty('CONFIG_PILOT_SEAT', DefaultPilotSeatConfig);
 
+  const [oansPerformanceMode, setOansPerformanceMode] = usePersistentNumberProperty(
+    'CONFIG_A380X_OANS_PERFORMANCE_MODE',
+    0,
+  );
+
   const defaultBaroButtons: ButtonType[] = [
     { name: t('Settings.SimOptions.Auto'), setting: 'AUTO' },
     { name: t('Settings.SimOptions.inHg'), setting: 'IN HG' },
@@ -281,6 +286,12 @@ export const SimOptionsPage = () => {
               )}
             </SettingGroup>
           )}
+
+          {aircraftContext.settingsPages.sim.oansPerformanceMode && (
+            <SettingItem name={t('Settings.SimOptions.OansPerformanceMode')}>
+              <Toggle value={!!oansPerformanceMode} onToggle={(value) => setOansPerformanceMode(value ? 1 : 0)} />
+            </SettingItem>
+          )}
         </SettingsPage>
       )}
       <ThrottleConfig isShown={showThrottleSettings} onClose={() => setShowThrottleSettings(false)} />
diff --git a/fbw-common/src/systems/instruments/src/ND/ND.tsx b/fbw-common/src/systems/instruments/src/ND/ND.tsx
index 04d142918bc..05679ae68d4 100644
--- a/fbw-common/src/systems/instruments/src/ND/ND.tsx
+++ b/fbw-common/src/systems/instruments/src/ND/ND.tsx
@@ -225,9 +225,13 @@ export class NDComponent<T extends number> extends DisplayComponent<NDProps<T>>
     });
 
     sub
-      .on('ndShowOans')
+      .on('nd_show_oans')
       .whenChanged()
-      .handle((show) => this.showOans.set(show));
+      .handle((data) => {
+        if (data.side === this.props.side) {
+          this.showOans.set(data.show);
+        }
+      });
   }
 
   // eslint-disable-next-line arrow-body-style
diff --git a/fbw-common/src/systems/instruments/src/ND/pages/arc/LubberLine.tsx b/fbw-common/src/systems/instruments/src/ND/pages/arc/LubberLine.tsx
index e85297ec9c0..736cd7152c1 100644
--- a/fbw-common/src/systems/instruments/src/ND/pages/arc/LubberLine.tsx
+++ b/fbw-common/src/systems/instruments/src/ND/pages/arc/LubberLine.tsx
@@ -11,6 +11,7 @@ export interface LubberLineProps {
   visible: Subscribable<boolean>;
   ndMode: Subscribable<EfisNdMode>;
   rotation: Subscribable<number>;
+  colorClass?: 'Yellow' | 'Magenta';
 }
 
 export class LubberLine extends DisplayComponent<LubberLineProps> {
@@ -34,7 +35,7 @@ export class LubberLine extends DisplayComponent<LubberLineProps> {
           y1={this.props.ndMode.map((mode) => (mode === EfisNdMode.ARC ? 108 : 116))}
           x2={384}
           y2={this.props.ndMode.map((mode) => (mode === EfisNdMode.ARC ? 148 : 152))}
-          class="Yellow"
+          class={this.props.colorClass ?? 'Yellow'}
           stroke-width={5}
           stroke-linejoin="round"
           stroke-linecap="round"
diff --git a/fbw-common/src/systems/instruments/src/OANC/Oanc.tsx b/fbw-common/src/systems/instruments/src/OANC/Oanc.tsx
index 443ed5e0a99..8c64a9508f0 100644
--- a/fbw-common/src/systems/instruments/src/OANC/Oanc.tsx
+++ b/fbw-common/src/systems/instruments/src/OANC/Oanc.tsx
@@ -35,7 +35,6 @@ import {
   Arinc429LocalVarConsumerSubject,
 } from '@flybywiresim/fbw-sdk';
 import {
-  BBox,
   bbox,
   bboxPolygon,
   booleanPointInPolygon,
@@ -60,8 +59,11 @@ import { OancMovingModeOverlay, OancStaticModeOverlay } from './OancMovingModeOv
 import { OancAircraftIcon } from './OancAircraftIcon';
 import { OancLabelManager } from './OancLabelManager';
 import { OancPositionComputer } from './OancPositionComputer';
+import { OancMarkerManager } from './OancMarkerManager';
+import { ResetPanelSimvars } from './ResetPanelPublisher';
 import { NavigraphAmdbClient } from './api/NavigraphAmdbClient';
 import { globalToAirportCoordinates, pointAngle, pointDistance } from './OancMapUtils';
+import { LubberLine } from '../ND/pages/arc/LubberLine';
 
 export const OANC_RENDER_WIDTH = 768;
 export const OANC_RENDER_HEIGHT = 768;
@@ -117,6 +119,8 @@ export enum LabelStyle {
   BtvStopLineAmber = 'btv-stop-line-amber',
   BtvStopLineRed = 'btv-stop-line-red',
   BtvStopLineGreen = 'btv-stop-line-green',
+  CrossSymbol = 'cross-symbol',
+  FlagSymbol = 'flag-symbol',
 }
 
 export interface Label {
@@ -124,7 +128,7 @@ export interface Label {
   style: LabelStyle;
   position: Position;
   rotation: number | undefined;
-  associatedFeature: Feature<Geometry, AmdbProperties>;
+  associatedFeature?: Feature<Geometry, AmdbProperties>;
 }
 
 export interface ContextMenuItemData {
@@ -183,9 +187,7 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
 
   public data: AmdbFeatureCollection | undefined;
 
-  private dataBbox: BBox | undefined;
-
-  private arpCoordinates: Subject<Coordinates | undefined> = Subject.create(undefined);
+  private arpCoordinates = Subject.create<Coordinates | undefined>(undefined);
 
   private canvasCenterCoordinates: Coordinates | undefined;
 
@@ -207,6 +209,11 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
     this.dataAirportIata,
   );
 
+  private readonly resetPulled = ConsumerSubject.create(
+    this.props.bus.getSubscriber<ResetPanelSimvars>().on('a380x_reset_panel_arpt_nav'),
+    false,
+  );
+
   private layerFeatures: FeatureCollection<Geometry, AmdbProperties>[] = [
     featureCollection([]), // Layer 0: TAXIWAY BG + TAXIWAY SHOULDER
     featureCollection([]), // Layer 1: APRON + STAND BG + BUILDINGS (terminal only)
@@ -215,14 +222,14 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
     featureCollection([]), // Layer 4: TAXIWAY GUIDANCE LINES (scaled width), HOLD SHORT LINES
     featureCollection([]), // Layer 5: TAXIWAY GUIDANCE LINES (unscaled width)
     featureCollection([]), // Layer 6: STAND GUIDANCE LINES (scaled width)
-    featureCollection([]), // Layer 7: DYNAMIC CONTENT (BTV PATH, STOP LINES)
+    featureCollection([]), // Layer 7: DYNAMIC BTV CONTENT (BTV PATH, STOP LINES)
   ];
 
-  public amdbClient = new NavigraphAmdbClient();
+  public readonly amdbClient = new NavigraphAmdbClient();
 
-  private labelManager = new OancLabelManager<T>(this);
+  private readonly labelManager = new OancLabelManager<T>(this);
 
-  private positionComputer = new OancPositionComputer<T>(this);
+  private readonly positionComputer = new OancPositionComputer<T>(this);
 
   public dataLoading = false;
 
@@ -289,15 +296,17 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
 
   private readonly airportWithinRange = Subject.create(false);
 
+  private readonly airportTooFarAwayAndInArcNavMode = Subject.create(false);
+
   private readonly airportBearing = Subject.create(0);
 
-  public readonly projectedPpos = MappedSubject.create(
-    ([ppos, arpCoordinates], previous: Position) => {
+  public readonly projectedPpos = MappedSubject.create<[Coordinates, Coordinates | undefined], Position>(
+    ([ppos, arpCoordinates], previous?: Position | undefined) => {
       if (arpCoordinates) {
         return globalToAirportCoordinates(arpCoordinates, ppos, [0, 0]);
       }
 
-      return previous;
+      return previous ?? [0, 0];
     },
     this.ppos,
     this.arpCoordinates,
@@ -317,7 +326,10 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
 
   public readonly arpReferencedMapParams = new MapParameters();
 
-  private readonly oansVisible = ConsumerSubject.create<boolean>(null, false);
+  private readonly oansVisible = ConsumerSubject.create<{ side: EfisSide; show: boolean }>(null, {
+    side: this.props.side,
+    show: false,
+  });
 
   private readonly efisNDModeSub = ConsumerSubject.create<EfisNdMode>(null, EfisNdMode.PLAN);
 
@@ -341,6 +353,8 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
     this.getZoomLevelInverseScale.bind(this),
   );
 
+  private readonly markerManager = new OancMarkerManager<T>(this, this.labelManager, this.props.bus);
+
   private readonly airportNotInActiveFpln = MappedSubject.create(
     ([ndMode, arpt, origin, dest, altn]) => ndMode !== EfisNdMode.ARC && ![origin, dest, altn].includes(arpt),
     this.overlayNDModeSub,
@@ -405,6 +419,8 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
     this.pleaseWaitFlagVisible,
   );
 
+  private readonly oansPerformanceModeHide = Subject.create(false);
+
   public getZoomLevelInverseScale() {
     const multiplier = this.overlayNDModeSub.get() === EfisNdMode.ROSE_NAV ? 0.5 : 1;
 
@@ -418,8 +434,8 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
     this.labelContainerRef.instance.addEventListener('mousemove', this.handleCursorPanMove.bind(this));
     this.labelContainerRef.instance.addEventListener('mouseup', this.handleCursorPanStop.bind(this));
 
-    this.oansVisible.setConsumer(this.sub.on('ndShowOans'));
-    this.oansNotAvailable.setConsumer(this.sub.on('oansNotAvail'));
+    this.oansVisible.setConsumer(this.sub.on('nd_show_oans'));
+    this.oansNotAvailable.setConsumer(this.sub.on('oans_not_avail'));
     this.efisNDModeSub.setConsumer(this.sub.on('ndMode'));
 
     this.efisNDModeSub.sub((mode) => {
@@ -431,13 +447,63 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
 
     this.efisOansRangeSub.sub((range) => this.zoomLevelIndex.set(range), true);
 
+    this.airportTooFarAwayAndInArcNavMode.sub((v) =>
+      this.props.bus.getPublisher<OansControlEvents>().pub('oans_show_set_plan_mode', v, true),
+    );
+
     this.sub
-      .on('oansDisplayAirport')
+      .on('oans_display_airport')
       .whenChanged()
       .handle((airport) => {
-        this.loadAirportMap(airport);
+        if (this.oansPerformanceModeHide.get()) {
+          this.dataAirportIcao.set(airport);
+        } else {
+          this.loadAirportMap(airport);
+        }
       });
 
+    this.sub
+      .on('oans_performance_mode_hide')
+      .whenChanged()
+      .handle((perfHide) => {
+        if (this.props.side === perfHide.side) {
+          this.oansPerformanceModeHide.set(perfHide.hide);
+        }
+      });
+
+    this.oansPerformanceModeHide.sub((hide) => {
+      if (hide) {
+        this.unloadAirportMap();
+      } else if (this.dataAirportIcao.get()) {
+        this.loadAirportMap(this.dataAirportIcao.get());
+      }
+    });
+
+    this.sub.on('oans_center_on_acft').handle(() => this.centerOnAcft());
+    this.sub.on('oans_center_map_on').handle((coords) => this.centerMapOn(coords));
+    this.sub.on('oans_add_cross_at_feature').handle((f) => this.markerManager.addCrossAtFeature(f.id, f.feattype));
+    this.sub.on('oans_add_flag_at_feature').handle((f) => this.markerManager.addFlagAtFeature(f.id, f.feattype));
+    this.sub
+      .on('oans_remove_cross_at_feature')
+      .handle((f) => this.markerManager.removeCrossAtFeature(f.id, f.feattype));
+    this.sub.on('oans_remove_flag_at_feature').handle((f) => this.markerManager.removeFlagAtFeature(f.id, f.feattype));
+    this.sub
+      .on('oans_add_cross_at_cursor')
+      .handle(([x, y]) => this.markerManager.addCross(this.unprojectPoint([x, y])));
+    this.sub.on('oans_add_flag_at_cursor').handle(([x, y]) => this.markerManager.addFlag(this.unprojectPoint([x, y])));
+    this.sub.on('oans_erase_all_crosses').handle(() => this.markerManager.eraseAllCrosses());
+    this.sub.on('oans_erase_all_flags').handle(() => this.markerManager.eraseAllFlags());
+    this.sub.on('oans_erase_cross_id').handle((id) => this.markerManager.removeCross(id));
+    this.sub.on('oans_erase_flag_id').handle((id) => this.markerManager.removeFlag(id));
+    this.sub.on('oans_query_symbols_at_cursor').handle((data) => {
+      const foundSymbols = this.markerManager.findSymbolAtCursor(this.unprojectPoint(data.cursorPosition));
+      this.props.bus.getPublisher<OansControlEvents>().pub('oans_answer_symbols_at_cursor', {
+        side: data.side,
+        cross: foundSymbols.cross,
+        flag: foundSymbols.flag,
+      });
+    });
+
     this.fmsDataStore.origin.sub(() => this.updateLabelClasses());
     this.fmsDataStore.departureRunway.sub(() => this.updateLabelClasses());
     this.fmsDataStore.destination.sub(() => this.updateLabelClasses());
@@ -447,7 +513,7 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
       this.updateLabelClasses();
     });
 
-    this.labelManager.visibleLabels.sub((index, type, item) => {
+    this.labelManager.visibleLabels.sub((_index, type, item) => {
       switch (type) {
         case SubscribableArrayEventType.Added: {
           if (Array.isArray(item)) {
@@ -469,8 +535,10 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
           if (Array.isArray(item)) {
             for (const label of item as Label[]) {
               const element = this.labelManager.visibleLabelElements.get(label);
-              this.labelContainerRef.instance.removeChild(element);
-              this.labelManager.visibleLabelElements.delete(label);
+              if (element) {
+                this.labelContainerRef.instance.removeChild(element);
+                this.labelManager.visibleLabelElements.delete(label);
+              }
             }
           } else {
             const element = this.labelManager.visibleLabelElements.get(item as Label);
@@ -492,11 +560,16 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
       this.panContainerRef[0].instance.style.transform = `translate(${x}px, ${y}px)`;
       this.panContainerRef[1].instance.style.transform = `translate(${x}px, ${y}px)`;
 
+      const depRwy = this.fmsDataStore.departureRunway.get();
+      const ldgRwy = this.fmsDataStore.landingRunway.get();
+      const btvRwy = this.btvUtils.btvRunway.get();
+      const btvExit = this.btvUtils.btvExit.get();
+
       this.labelManager.reflowLabels(
-        this.fmsDataStore.departureRunway.get(),
-        this.fmsDataStore.landingRunway.get(),
-        this.btvUtils.btvRunway.get(),
-        this.btvUtils.btvExit.get(),
+        depRwy !== null ? depRwy : undefined,
+        ldgRwy !== null ? ldgRwy : undefined,
+        btvRwy !== null ? btvRwy : undefined,
+        btvExit !== null ? btvExit : undefined,
       );
     });
 
@@ -542,21 +615,52 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
     setTimeout(() => (this.labelManager.showLabels = true), ZOOM_TRANSITION_TIME_MS + 200);
   }
 
+  public unloadAirportMap() {
+    this.btvUtils.clearSelection();
+    this.markerManager.eraseAllCrosses();
+    this.markerManager.eraseAllFlags();
+    this.clearMap();
+    this.clearData();
+
+    this.arpCoordinates.set(undefined);
+    this.data = undefined;
+    this.aircraftWithinAirport.set(false);
+  }
+
+  /**
+   *
+   * @param icao four letter ICAO code of airport to load
+   * @returns
+   */
   public async loadAirportMap(icao: string) {
     this.dataLoading = true;
-
     this.airportLoading.set(true);
 
-    this.clearData();
-    this.clearMap();
-    this.btvUtils.clearSelection();
+    this.unloadAirportMap();
+
+    if (!icao) {
+      this.dataLoading = false;
+      this.airportLoading.set(false);
+
+      this.dataAirportName.set('');
+      this.dataAirportIcao.set('');
+      this.dataAirportIata.set('');
+
+      return;
+    }
 
     const includeFeatureTypes: FeatureType[] = Object.values(STYLE_DATA).reduce(
       (acc, it) => [
         ...acc,
-        ...it.reduce((acc, it) => [...acc, ...(it?.dontFetchFromAmdb ? [] : it.forFeatureTypes)], []),
+        ...it.reduce(
+          (acc, it) => [
+            ...acc,
+            ...(it?.dontFetchFromAmdb || it.forFeatureTypes === undefined ? [] : it.forFeatureTypes),
+          ],
+          [] as FeatureType[],
+        ),
       ],
-      [],
+      [] as FeatureType[],
     );
     const includeLayers = includeFeatureTypes.map((it) => AmdbFeatureTypeStrings[it]);
 
@@ -602,7 +706,7 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
     );
     const airportMap: AmdbFeatureCollection = featureCollection(features);
 
-    const wgs84ReferencePoint = wgs84ArpDat.aerodromereferencepoint.features[0];
+    const wgs84ReferencePoint = wgs84ArpDat.aerodromereferencepoint?.features[0];
 
     if (!wgs84ReferencePoint) {
       console.error('[OANC](loadAirportMap) Invalid airport data - aerodrome reference point not found');
@@ -623,9 +727,11 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
 
     this.data = airportMap;
 
-    this.dataAirportName.set(wgs84ReferencePoint.properties.name);
-    this.dataAirportIcao.set(icao);
-    this.dataAirportIata.set(wgs84ReferencePoint.properties.iata);
+    if (wgs84ReferencePoint) {
+      this.dataAirportName.set(wgs84ReferencePoint?.properties?.name ?? '');
+      this.dataAirportIcao.set(icao);
+      this.dataAirportIata.set(wgs84ReferencePoint?.properties?.iata ?? '');
+    }
 
     // Figure out the boundaries of the map data
     const dataBbox = bbox(airportMap);
@@ -653,23 +759,27 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
   }
 
   private calculateCanvasCenterCoordinates() {
-    const pxDistanceToCanvasCentre = pointDistance(
-      this.canvasWidth.get() / 2,
-      this.canvasHeight.get() / 2,
-      this.canvasCentreX.get(),
-      this.canvasCentreY.get(),
-    );
-    const nmDistanceToCanvasCentre = UnitType.NMILE.convertFrom(pxDistanceToCanvasCentre / 1_000, UnitType.KILOMETER);
-    const angleToCanvasCentre = clampAngle(
-      pointAngle(
+    const arpCoordinates = this.arpCoordinates.get();
+
+    if (arpCoordinates) {
+      const pxDistanceToCanvasCentre = pointDistance(
         this.canvasWidth.get() / 2,
         this.canvasHeight.get() / 2,
         this.canvasCentreX.get(),
         this.canvasCentreY.get(),
-      ) + 90,
-    );
+      );
+      const nmDistanceToCanvasCentre = UnitType.NMILE.convertFrom(pxDistanceToCanvasCentre / 1_000, UnitType.KILOMETER);
+      const angleToCanvasCentre = clampAngle(
+        pointAngle(
+          this.canvasWidth.get() / 2,
+          this.canvasHeight.get() / 2,
+          this.canvasCentreX.get(),
+          this.canvasCentreY.get(),
+        ) + 90,
+      );
 
-    return placeBearingDistance(this.arpCoordinates.get(), reciprocal(angleToCanvasCentre), nmDistanceToCanvasCentre);
+      return placeBearingDistance(arpCoordinates, reciprocal(angleToCanvasCentre), nmDistanceToCanvasCentre);
+    }
   }
 
   private createLabelElement(label: Label): HTMLDivElement {
@@ -681,22 +791,26 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
 
     if (label.style === LabelStyle.RunwayEnd) {
       element.addEventListener('click', () => {
-        const thresholdFeature = this.data.features.filter(
+        const thresholdFeature = this.data?.features.filter(
           (it) => it.properties.feattype === FeatureType.RunwayThreshold && it.properties?.idthr === label.text,
         );
-        this.btvUtils.selectRunwayFromOans(
-          `${this.dataAirportIcao.get()}${label.text}`,
-          label.associatedFeature,
-          thresholdFeature[0],
-        );
+        if (thresholdFeature && label.associatedFeature) {
+          this.btvUtils.selectRunwayFromOans(
+            `${this.dataAirportIcao.get()}${label.text}`,
+            label.associatedFeature,
+            thresholdFeature[0],
+          );
+        }
       });
     }
     if (
       label.style === LabelStyle.ExitLine &&
-      label.associatedFeature.properties.feattype === FeatureType.RunwayExitLine
+      label.associatedFeature?.properties.feattype === FeatureType.RunwayExitLine
     ) {
       element.addEventListener('click', () => {
-        this.btvUtils.selectExitFromOans(label.text, label.associatedFeature);
+        if (label.associatedFeature) {
+          this.btvUtils.selectExitFromOans(label.text, label.associatedFeature);
+        }
       });
     }
 
@@ -708,7 +822,7 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
       const layer = this.layerFeatures[i];
 
       const layerFeatureTypes = STYLE_DATA[i].reduce(
-        (acc, rule) => [...acc, ...rule.forFeatureTypes],
+        (acc, rule) => [...acc, ...(rule.forFeatureTypes !== undefined ? rule.forFeatureTypes : [])],
         [] as FeatureType[],
       );
       const layerPolygonStructureTypes = STYLE_DATA[i].reduce(
@@ -719,6 +833,7 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
         if (it.properties.feattype === FeatureType.VerticalPolygonalStructure) {
           return (
             layerFeatureTypes.includes(FeatureType.VerticalPolygonalStructure) &&
+            it.properties.plysttyp &&
             layerPolygonStructureTypes.includes(it.properties.plysttyp)
           );
         }
@@ -743,12 +858,13 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
       // Only include "VerticalPolygonObject" features whose "plysttyp" property has what we want
       if (
         feature.properties.feattype === FeatureType.VerticalPolygonalStructure &&
+        feature.properties.plysttyp &&
         !LABEL_POLYGON_STRUCTURE_TYPES.includes(feature.properties.plysttyp)
       ) {
         continue;
       }
 
-      let labelPosition: Position;
+      let labelPosition: Position = [0, 0];
       switch (feature.geometry.type) {
         case 'Point': {
           const point = feature.geometry as Point;
@@ -805,9 +921,11 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
 
         const isFmsOrigin = this.dataAirportIcao.get() === this.fmsDataStore.origin.get();
         const isFmsDestination = this.dataAirportIcao.get() === this.fmsDataStore.origin.get();
+        const depRwy = this.fmsDataStore.departureRunway.get()?.substring(4);
+        const ldgRwy = this.fmsDataStore.landingRunway.get()?.substring(4);
         const isSelectedRunway =
-          (isFmsOrigin && designators.includes(this.fmsDataStore.departureRunway.get()?.substring(4))) ||
-          (isFmsDestination && designators.includes(this.fmsDataStore.landingRunway.get()?.substring(4)));
+          (isFmsOrigin && depRwy && designators.includes(depRwy)) ||
+          (isFmsDestination && ldgRwy && designators.includes(ldgRwy));
 
         const label1: Label = {
           text: designators[0],
@@ -933,7 +1051,7 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
 
           if (
             (feature.properties.feattype === FeatureType.ParkingStandLocation &&
-              existing.some((it) => feature.properties.termref === it.associatedFeature.properties.termref)) ||
+              existing.some((it) => feature.properties.termref === it.associatedFeature?.properties.termref)) ||
             shortestDistance < 50
           ) {
             continue;
@@ -965,42 +1083,47 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
     const deltaTime = (now - this.lastTime) / 1_000;
     this.lastTime = now;
 
-    if (!this.data || this.dataLoading) return;
+    if (this.data && this.resetPulled.get()) {
+      this.unloadAirportMap();
+    }
+
+    if (!this.data || this.dataLoading || this.resetPulled.get()) return;
 
     this.aircraftOnGround.set(
       ![6, 7, 8, 9].includes(SimVar.GetSimVarValue('L:A32NX_FWC_FLIGHT_PHASE', SimVarValueType.Number)),
     );
 
-    // This will always be false without ppos, otherwise it will be updated below
-    let airportTooFarAwayAndInArcMode = false;
-
-    if (!this.pposNotAvailable.get()) {
+    const arpCoordinates = this.arpCoordinates.get();
+    if (!this.pposNotAvailable.get() && arpCoordinates) {
       this.aircraftWithinAirport.set(booleanPointInPolygon(this.projectedPpos.get(), bboxPolygon(bbox(this.data))));
 
-      const distToArpt = this.arpCoordinates.get() ? distanceTo(this.ppos.get(), this.arpCoordinates.get()) : 9999;
+      const distToArpt = this.arpCoordinates.get() ? distanceTo(this.ppos.get(), arpCoordinates) : 9999;
 
       // If in ARC mode and airport more than 30nm away, apply a hack to not create a huge canvas (only shift airport a little bit out of view with a static offset)
-      airportTooFarAwayAndInArcMode = this.usingPposAsReference.get() && distToArpt > 30;
+      this.airportTooFarAwayAndInArcNavMode.set(
+        !this.pposNotAvailable.get() && this.usingPposAsReference.get() && distToArpt > 30,
+      );
 
       if (this.arpCoordinates.get()) {
         this.airportWithinRange.set(distToArpt < this.props.zoomValues[this.zoomLevelIndex.get()] + 3); // Add 3nm for airport dimension, FIXME better estimation
-        this.airportBearing.set(bearingTo(this.ppos.get(), this.arpCoordinates.get()));
+        this.airportBearing.set(bearingTo(this.ppos.get(), arpCoordinates));
       } else {
         this.airportWithinRange.set(true);
         this.airportBearing.set(0);
       }
     } else {
+      this.airportTooFarAwayAndInArcNavMode.set(false);
       this.aircraftWithinAirport.set(false);
       this.airportWithinRange.set(true);
     }
 
-    if (this.usingPposAsReference.get() || !this.arpCoordinates.get()) {
+    if (this.usingPposAsReference.get() || !arpCoordinates) {
       this.referencePos = this.ppos.get();
     } else {
-      this.referencePos = this.arpCoordinates.get();
+      this.referencePos = arpCoordinates;
     }
 
-    if (!this.pposNotAvailable.get()) {
+    if (!this.pposNotAvailable.get() && arpCoordinates) {
       const position = this.positionComputer.computePosition();
 
       if (position) {
@@ -1013,7 +1136,7 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
       this.props.bus.getPublisher<FmsOansData>().pub('oansAirportLocalCoordinates', this.projectedPpos.get(), true);
       this.btvUtils.updateRwyAheadAdvisory(
         this.ppos.get(),
-        this.arpCoordinates.get(),
+        arpCoordinates,
         this.trueHeadingWord.get().value,
         this.layerFeatures[2],
       );
@@ -1022,7 +1145,7 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
     }
 
     // If OANS is not visible on this side (i.e. range selector is not on ZOOM), don't continue here to save runtime
-    if (!this.oansVisible.get()) {
+    if (this.oansVisible.get().side === this.props.side && !this.oansVisible.get().show) {
       return;
     }
 
@@ -1051,11 +1174,15 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
 
     const mapCurrentHeading = this.interpolatedMapHeading.get();
 
-    this.canvasCentreReferencedMapParams.compute(this.canvasCenterCoordinates, 0, 0.539957, 1_000, mapCurrentHeading);
-    this.arpReferencedMapParams.compute(this.arpCoordinates.get(), 0, 0.539957, 1_000, mapCurrentHeading);
+    if (this.canvasCenterCoordinates) {
+      this.canvasCentreReferencedMapParams.compute(this.canvasCenterCoordinates, 0, 0.539957, 1_000, mapCurrentHeading);
+    }
+    if (arpCoordinates) {
+      this.arpReferencedMapParams.compute(arpCoordinates, 0, 0.539957, 1_000, mapCurrentHeading);
+    }
 
     let [offsetX, offsetY]: [number, number] = [0, 0];
-    if (airportTooFarAwayAndInArcMode) {
+    if (this.airportTooFarAwayAndInArcNavMode.get()) {
       const shiftBy = 5 * Math.max(this.canvasWidth.get(), this.canvasHeight.get());
       [offsetX, offsetY] = [shiftBy, shiftBy];
     } else {
@@ -1084,10 +1211,10 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
       canvasScaleContainer.style.transform = `scale(${scale})`;
 
       const context = canvas.getContext('2d');
-
-      context.resetTransform();
-
-      context.translate(this.canvasCentreX.get(), this.canvasCentreY.get());
+      if (context) {
+        context.resetTransform();
+        context.translate(this.canvasCentreX.get(), this.canvasCentreY.get());
+      }
     }
 
     // Transform airplane
@@ -1110,20 +1237,24 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
 
       this.airportLoading.set(false);
 
+      const depRwy = this.fmsDataStore.departureRunway.get();
+      const ldgRwy = this.fmsDataStore.landingRunway.get();
+      const btvRwy = this.btvUtils.btvRunway.get();
+      const btvExit = this.btvUtils.btvExit.get();
+
       this.labelManager.reflowLabels(
-        this.fmsDataStore.departureRunway.get(),
-        this.fmsDataStore.landingRunway.get(),
-        this.btvUtils.btvRunway.get(),
-        this.btvUtils.btvExit.get(),
+        depRwy !== null ? depRwy : undefined,
+        ldgRwy !== null ? ldgRwy : undefined,
+        btvRwy !== null ? btvRwy : undefined,
+        btvExit !== null ? btvExit : undefined,
       );
-
       return;
     }
 
     const layerFeatures = this.layerFeatures[this.lastLayerDrawnIndex];
     const layerCanvas = this.layerCanvasRefs[this.lastLayerDrawnIndex].instance.getContext('2d');
 
-    if (this.lastFeatureDrawnIndex < layerFeatures.features.length) {
+    if (this.lastFeatureDrawnIndex < layerFeatures.features.length && layerCanvas) {
       renderFeaturesToCanvas(
         this.lastLayerDrawnIndex,
         layerCanvas,
@@ -1140,12 +1271,14 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
   }
 
   private updateLabelClasses() {
+    const btvRwy = this.btvUtils.btvRunway.get();
+    const btvExit = this.btvUtils.btvExit.get();
     this.labelManager.updateLabelClasses(
       this.fmsDataStore,
       this.dataAirportIcao.get() === this.fmsDataStore.origin.get(),
       this.dataAirportIcao.get() === this.fmsDataStore.destination.get(),
-      this.btvUtils.btvRunway.get(),
-      this.btvUtils.btvExit.get(),
+      btvRwy !== null ? btvRwy : undefined,
+      btvExit !== null ? btvExit : undefined,
     );
   }
 
@@ -1155,6 +1288,8 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
     }
 
     this.labelManager.clearLabels();
+    this.markerManager.eraseAllFlags();
+    this.markerManager.eraseAllCrosses();
   }
 
   private clearMap(): void {
@@ -1166,9 +1301,17 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
       const cw = this.canvasWidth.get();
       const ch = this.canvasHeight.get();
 
-      ctx.clearRect(0, 0, cw, ch);
+      if (ctx) {
+        ctx.clearRect(0, 0, cw, ch);
+      }
     }
 
+    this.canvasWidth.set(0);
+    this.canvasHeight.set(0);
+
+    this.canvasCentreX.set(0);
+    this.canvasCentreY.set(0);
+
     this.panOffsetX.set(0);
     this.panOffsetY.set(0);
   }
@@ -1336,6 +1479,70 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
     return [labelScreenX, labelScreenY];
   }
 
+  public unprojectPoint(screenCoordinates: [number, number]): Position {
+    let [labelScreenX, labelScreenY] = screenCoordinates;
+
+    // Undo animation offsets
+    labelScreenX -= this.modeAnimationOffsetX.get() + OANC_RENDER_WIDTH / 2 + this.panOffsetX.get();
+    labelScreenY -= this.modeAnimationOffsetY.get() + OANC_RENDER_HEIGHT / 2 + this.panOffsetY.get();
+
+    const zoomLevelScale = this.getZoomLevelInverseScale();
+    const [offsetX, offsetY] = this.arpReferencedMapParams.coordinatesToXYy(this.referencePos);
+
+    // Undo scaling offsets
+    const scaledOffsetX = offsetX * zoomLevelScale;
+    const scaledOffsetY = -1 * (offsetY * zoomLevelScale);
+    labelScreenX += scaledOffsetX;
+    labelScreenY -= scaledOffsetY;
+
+    // Reverse rotation
+    const mapCurrentHeading = this.interpolatedMapHeading.get();
+    const rotate = -mapCurrentHeading; // Original rotation
+    const reverseRotate = -rotate; // Undo rotation
+
+    const hypotenuse = Math.sqrt(labelScreenX ** 2 + labelScreenY ** 2);
+    const angle = clampAngle(Math.atan2(-labelScreenY, labelScreenX) * MathUtils.RADIANS_TO_DEGREES);
+
+    const originalX = hypotenuse * Math.cos((angle - reverseRotate) * MathUtils.DEGREES_TO_RADIANS);
+    const originalY = hypotenuse * Math.sin((angle - reverseRotate) * MathUtils.DEGREES_TO_RADIANS);
+
+    // Scale back the original position
+    const labelX = originalX / zoomLevelScale;
+    const labelY = originalY / zoomLevelScale;
+
+    return [labelX, labelY];
+  }
+
+  public offsetToPoint(coordinates: Position): [number, number] {
+    const projected = this.projectPoint(coordinates);
+    const xOffset = -(projected[0] - this.panOffsetX.get() - OANC_RENDER_WIDTH / 2 - this.modeAnimationOffsetX.get());
+    const yOffset = -(projected[1] - this.panOffsetY.get() - OANC_RENDER_HEIGHT / 2 - this.modeAnimationOffsetY.get());
+
+    return [xOffset, yOffset];
+  }
+
+  async centerOnAcft() {
+    await this.enablePanningTransitions();
+    this.panOffsetX.set(0);
+    this.panOffsetY.set(0);
+    await Wait.awaitDelay(ZOOM_TRANSITION_TIME_MS);
+    await this.disablePanningTransitions();
+  }
+
+  /**
+   * Centers map on point supplied in parameters
+   * @param x X position in local coordinate system
+   * @param y Y position in local coordinate system
+   */
+  async centerMapOn(pos: Position) {
+    const xy = this.offsetToPoint(pos);
+    await this.enablePanningTransitions();
+    this.panOffsetX.set(xy[0]);
+    this.panOffsetY.set(xy[1]);
+    await Wait.awaitDelay(ZOOM_TRANSITION_TIME_MS);
+    await this.disablePanningTransitions();
+  }
+
   render(): VNode | null {
     return (
       <>
@@ -1448,6 +1655,26 @@ export class Oanc<T extends number> extends DisplayComponent<OancProps<T>> {
                 y={this.aircraftY}
                 rotation={this.aircraftRotation}
               />
+
+              <svg
+                class="nd-svg nd-top-layer"
+                viewBox="0 0 768 768"
+                style={this.efisNDModeSub.map(
+                  (mode) => `transform: translateY(${mode === EfisNdMode.ARC ? -236 : 0}px);`,
+                )}
+              >
+                <LubberLine
+                  bus={this.props.bus}
+                  visible={MappedSubject.create(
+                    ([ac, mode]) => ac && mode !== EfisNdMode.PLAN,
+                    this.showAircraft,
+                    this.efisNDModeSub,
+                  )}
+                  rotation={Subject.create(0)}
+                  ndMode={this.efisNDModeSub}
+                  colorClass="Magenta"
+                />
+              </svg>
             </div>
           </div>
 
@@ -1551,12 +1778,13 @@ function renderFeaturesToCanvas(
     const matchingRule = styleRules.find((it) => {
       if (feature.properties.feattype === FeatureType.VerticalPolygonalStructure) {
         return (
-          it.forFeatureTypes.includes(feature.properties.feattype) &&
-          it.forPolygonStructureTypes.includes(feature.properties.plysttyp)
+          it.forFeatureTypes?.includes(feature.properties.feattype) &&
+          feature.properties.plysttyp &&
+          it.forPolygonStructureTypes?.includes(feature.properties.plysttyp)
         );
       }
 
-      return it.forFeatureTypes.includes(feature.properties.feattype);
+      return it.forFeatureTypes?.includes(feature.properties.feattype);
     });
 
     if (!matchingRule) {
diff --git a/fbw-common/src/systems/instruments/src/OANC/OancControlPanelUtils.ts b/fbw-common/src/systems/instruments/src/OANC/OancControlPanelUtils.ts
index b60886419ea..bcb3098bfc6 100644
--- a/fbw-common/src/systems/instruments/src/OANC/OancControlPanelUtils.ts
+++ b/fbw-common/src/systems/instruments/src/OANC/OancControlPanelUtils.ts
@@ -2,7 +2,7 @@
 // SPDX-License-Identifier: GPL-3.0
 
 import { ArraySubject, ConsumerSubject, DmsFormatter2, EventBus, Subject, UnitType } from '@microsoft/msfs-sdk';
-import { AmdbAirportSearchResult, FmsOansData } from '@flybywiresim/fbw-sdk';
+import { AmdbAirportSearchResult, AmdbProperties, FmsOansData } from '@flybywiresim/fbw-sdk';
 
 export enum ControlPanelAirportSearchMode {
   Icao,
@@ -10,6 +10,13 @@ export enum ControlPanelAirportSearchMode {
   City,
 }
 
+export enum ControlPanelMapDataSearchMode {
+  Runway,
+  Taxiway,
+  Stand,
+  Other,
+}
+
 export class ControlPanelUtils {
   static readonly LAT_FORMATTER = DmsFormatter2.create('{dd}°{mm}.{s}{+[N]-[S]}', UnitType.DEGREE, 0.1);
 
@@ -33,6 +40,26 @@ export class ControlPanelUtils {
     }
     return prop;
   }
+
+  static getMapDataSearchModeProp(mode: ControlPanelMapDataSearchMode): keyof AmdbProperties {
+    let prop: keyof AmdbProperties;
+    switch (mode) {
+      default:
+      case ControlPanelMapDataSearchMode.Runway:
+        prop = 'idthr';
+        break;
+      case ControlPanelMapDataSearchMode.Taxiway:
+        prop = 'idlin';
+        break;
+      case ControlPanelMapDataSearchMode.Stand:
+        prop = 'idstd';
+        break;
+      case ControlPanelMapDataSearchMode.Other:
+        prop = 'ident';
+        break;
+    }
+    return prop;
+  }
 }
 
 export class ControlPanelStore {
@@ -48,6 +75,10 @@ export class ControlPanelStore {
 
   public readonly airportSearchSelectedAirportIndex = Subject.create<number | null>(null);
 
+  public readonly mapDataSearchMode = Subject.create<number | null>(ControlPanelMapDataSearchMode.Runway);
+
+  public readonly mapDataSearchData = ArraySubject.create<string>();
+
   public readonly selectedAirport = Subject.create<AmdbAirportSearchResult | null>(null);
 
   public readonly loadedAirport = Subject.create<AmdbAirportSearchResult | null>(null);
diff --git a/fbw-common/src/systems/instruments/src/OANC/OancLabelFilter.ts b/fbw-common/src/systems/instruments/src/OANC/OancLabelFilter.ts
index 3378a16aa7f..0418bb4cfca 100644
--- a/fbw-common/src/systems/instruments/src/OANC/OancLabelFilter.ts
+++ b/fbw-common/src/systems/instruments/src/OANC/OancLabelFilter.ts
@@ -11,7 +11,7 @@ export interface BaseOancLabelFilter {
 
 export interface RunwayBtvSelectionLabelFilter extends BaseOancLabelFilter {
   type: 'runwayBtvSelection';
-  runwayIdent: string;
+  runwayIdent: string | null;
   showAdjacent: boolean;
 }
 
@@ -60,6 +60,8 @@ export function filterLabel(
       LabelStyle.BtvStopLineAmber,
       LabelStyle.BtvStopLineRed,
       LabelStyle.BtvStopLineGreen,
+      LabelStyle.CrossSymbol,
+      LabelStyle.FlagSymbol,
     ].includes(label.style)
   ) {
     return true;
@@ -90,8 +92,8 @@ export function labelStyle(
   fmsDataStore: FmsDataStore,
   isFmsOrigin: boolean,
   isFmsDestination: boolean,
-  btvSelectedRunway: string,
-  btvSelectedExit: string,
+  btvSelectedRunway?: string,
+  btvSelectedExit?: string,
 ): LabelStyle {
   if (label.style === LabelStyle.RunwayEnd || label.style === LabelStyle.BtvSelectedRunwayEnd) {
     return btvSelectedRunway?.substring(4) === label.text ? LabelStyle.BtvSelectedRunwayEnd : LabelStyle.RunwayEnd;
diff --git a/fbw-common/src/systems/instruments/src/OANC/OancLabelManager.ts b/fbw-common/src/systems/instruments/src/OANC/OancLabelManager.ts
index f24fccdc05e..a34443c6b2a 100644
--- a/fbw-common/src/systems/instruments/src/OANC/OancLabelManager.ts
+++ b/fbw-common/src/systems/instruments/src/OANC/OancLabelManager.ts
@@ -100,13 +100,14 @@ export class OancLabelManager<T extends number> {
 
           element.style.left = `${labelScreenX}px`;
           element.style.top = `${labelScreenY}px`;
+          const labelRotation = label.rotation ?? 0;
 
           if (label.style === LabelStyle.RunwayEnd || label.style === LabelStyle.BtvSelectedRunwayEnd) {
-            element.style.transform = `translate(-50%, -50%) rotate(${label.rotation - mapCurrentHeading}deg) translate(0px, 50px)`;
+            element.style.transform = `translate(-50%, -50%) rotate(${labelRotation - mapCurrentHeading}deg) translate(0px, 50px)`;
           } else if (label.style === LabelStyle.BtvSelectedRunwayArrow) {
-            element.style.transform = `translate(-50%, -50%) rotate(${label.rotation - mapCurrentHeading}deg) translate(0px, -100px) rotate(-180deg)`;
+            element.style.transform = `translate(-50%, -50%) rotate(${labelRotation - mapCurrentHeading}deg) translate(0px, -100px) rotate(-180deg)`;
           } else if (label.style === LabelStyle.FmsSelectedRunwayEnd) {
-            element.style.transform = `translate(-50%, -50%) rotate(${label.rotation - mapCurrentHeading}deg) translate(0px, 82.5px)`;
+            element.style.transform = `translate(-50%, -50%) rotate(${labelRotation - mapCurrentHeading}deg) translate(0px, 82.5px)`;
           } else {
             element.style.transform = 'translate(-50%, -50%)';
           }
@@ -205,8 +206,8 @@ export class OancLabelManager<T extends number> {
     fmsDataStore: FmsDataStore,
     isFmsOrigin: boolean,
     isFmsDestination: boolean,
-    btvSelectedRunway: string,
-    btvSelectedExit: string,
+    btvSelectedRunway?: string,
+    btvSelectedExit?: string,
   ) {
     this.visibleLabelElements.forEach((val, key) => {
       const newLabelStyle = labelStyle(
diff --git a/fbw-common/src/systems/instruments/src/OANC/OancMarkerManager.ts b/fbw-common/src/systems/instruments/src/OANC/OancMarkerManager.ts
new file mode 100644
index 00000000000..4056f9490df
--- /dev/null
+++ b/fbw-common/src/systems/instruments/src/OANC/OancMarkerManager.ts
@@ -0,0 +1,278 @@
+// Copyright (c) 2025 FlyByWire Simulations
+// SPDX-License-Identifier: GPL-3.0
+
+import { ArraySubject, EventBus } from '@microsoft/msfs-sdk';
+import { along, Feature, Geometry, length, LineString, Point, Position } from '@turf/turf';
+import { Label, LabelStyle, Oanc, OansControlEvents } from './';
+import { OancLabelManager } from './OancLabelManager';
+import { AmdbProperties, FeatureType } from '@flybywiresim/fbw-sdk';
+
+const MAX_SYMBOL_DIST_NEIGHBORHOOD_SEARCH = 20;
+const TAXIWAY_SYMBOL_SPACING = 250;
+
+export class OancMarkerManager<T extends number> {
+  constructor(
+    public oanc: Oanc<T>,
+    private readonly labelManager: OancLabelManager<T>,
+    private readonly bus: EventBus,
+  ) {
+    this.crosses.sub(() => this.updateSymbolsForFeatureIds(), true);
+    this.flags.sub(() => this.updateSymbolsForFeatureIds(), true);
+  }
+
+  private crosses = ArraySubject.create<Label>();
+
+  private flags = ArraySubject.create<Label>();
+
+  private nextCrossId = 0;
+  private nextFlagId = 0;
+
+  addCross(coords: Position, feature?: Feature<Geometry, AmdbProperties>) {
+    const crossSymbolLabel: Label = {
+      text: (this.nextCrossId++).toString(),
+      style: LabelStyle.CrossSymbol,
+      position: coords,
+      rotation: 0,
+      associatedFeature: feature,
+    };
+    this.labelManager.visibleLabels.insert(crossSymbolLabel);
+    this.labelManager.labels.push(crossSymbolLabel);
+    this.crosses.insert(crossSymbolLabel);
+  }
+
+  addFlag(coords: Position, feature?: Feature<Geometry, AmdbProperties>) {
+    const flagSymbolLabel: Label = {
+      text: (this.nextFlagId++).toString(),
+      style: LabelStyle.FlagSymbol,
+      position: coords,
+      rotation: 0,
+      associatedFeature: feature,
+    };
+    this.labelManager.visibleLabels.insert(flagSymbolLabel);
+    this.labelManager.labels.push(flagSymbolLabel);
+    this.flags.insert(flagSymbolLabel);
+  }
+
+  removeCross(id: number) {
+    if (!this.crosses.getArray().some((l) => l.text === id.toString())) {
+      return;
+    }
+
+    const label = this.crosses.getArray().filter((l) => l.text === id.toString())[0];
+    this.labelManager.visibleLabels.removeAt(
+      this.labelManager.visibleLabels
+        .getArray()
+        .findIndex((it) => it.text === label.text && it.style === LabelStyle.CrossSymbol),
+    );
+    this.labelManager.labels = this.labelManager.labels.filter(
+      (it) => !(it.text === label.text && it.style === LabelStyle.CrossSymbol),
+    );
+    this.crosses.removeAt(this.crosses.getArray().findIndex((l) => l.text === id.toString()));
+  }
+
+  removeFlag(id: number) {
+    if (!this.flags.getArray().some((l) => l.text === id.toString())) {
+      return;
+    }
+
+    const label = this.flags.getArray().filter((l) => l.text === id.toString())[0];
+    this.labelManager.visibleLabels.removeAt(
+      this.labelManager.visibleLabels
+        .getArray()
+        .findIndex((it) => it.text === label.text && it.style === LabelStyle.FlagSymbol),
+    );
+    this.labelManager.labels = this.labelManager.labels.filter(
+      (it) => !(it.text === label.text && it.style === LabelStyle.FlagSymbol),
+    );
+    this.flags.removeAt(this.flags.getArray().findIndex((l) => l.text === id.toString()));
+  }
+
+  eraseAllCrosses() {
+    while (this.labelManager.visibleLabels.getArray().findIndex((it) => it.style === LabelStyle.CrossSymbol) !== -1) {
+      this.labelManager.visibleLabels.removeAt(
+        this.labelManager.visibleLabels.getArray().findIndex((it) => it.style === LabelStyle.CrossSymbol),
+      );
+    }
+    this.labelManager.labels = this.labelManager.labels.filter((it) => !(it.style === LabelStyle.CrossSymbol));
+    this.crosses.clear();
+  }
+
+  eraseAllFlags() {
+    while (this.labelManager.visibleLabels.getArray().findIndex((it) => it.style === LabelStyle.FlagSymbol) !== -1) {
+      this.labelManager.visibleLabels.removeAt(
+        this.labelManager.visibleLabels.getArray().findIndex((it) => it.style === LabelStyle.FlagSymbol),
+      );
+    }
+    this.labelManager.labels = this.labelManager.labels.filter((it) => !(it.style === LabelStyle.FlagSymbol));
+    this.flags.clear();
+  }
+
+  updateSymbolsForFeatureIds() {
+    const data = {
+      featureIdsWithCrosses: [
+        ...new Set(
+          this.crosses
+            .getArray()
+            .map((l) => l.associatedFeature?.properties.id)
+            .filter((it) => it !== undefined),
+        ),
+      ],
+      featureIdsWithFlags: [
+        ...new Set(
+          this.flags
+            .getArray()
+            .map((l) => l.associatedFeature?.properties.id)
+            .filter((it) => it !== undefined),
+        ),
+      ],
+    };
+    this.bus.getPublisher<OansControlEvents>().pub('oans_symbols_for_feature_ids', data, true);
+  }
+
+  addSymbolAtFeature(
+    id: number,
+    feattype: FeatureType,
+    addFunction: (coords: Position, feature?: Feature<Geometry, AmdbProperties>) => void,
+  ) {
+    // Find feature by id in loaded airport data
+    const feature = this.oanc.data?.features.filter(
+      (it) => it.properties?.id === id && it.properties.feattype === feattype,
+    );
+    if (feature) {
+      if (feattype === FeatureType.TaxiwayGuidanceLine) {
+        // Look up all taxiways by name
+        const taxiwayLines = this.oanc.data?.features.filter(
+          (f) =>
+            f.properties.idlin === feature[0].properties.idlin &&
+            (f.properties.feattype === FeatureType.TaxiwayGuidanceLine ||
+              f.properties.feattype === FeatureType.RunwayExitLine),
+        );
+        if (taxiwayLines) {
+          for (const tw of taxiwayLines) {
+            if (tw.geometry.type === 'LineString') {
+              const twLength = length(tw, { units: 'degrees' });
+              const lineString = tw.geometry as LineString;
+              if (twLength > TAXIWAY_SYMBOL_SPACING) {
+                // One point every 250m
+                for (let alongDistance = 0; alongDistance < twLength; alongDistance += TAXIWAY_SYMBOL_SPACING) {
+                  addFunction(
+                    along(lineString, Math.min(alongDistance, twLength), { units: 'degrees' }).geometry.coordinates,
+                    tw,
+                  );
+                }
+              } else {
+                addFunction(lineString.coordinates[0], tw);
+                addFunction(lineString.coordinates[lineString.coordinates.length - 1], tw);
+              }
+            }
+          }
+        }
+      } else if (feattype === FeatureType.RunwayThreshold || feattype === FeatureType.ParkingStandLocation) {
+        const geo = this.oanc.data?.features.filter(
+          (f) =>
+            f.properties.id === id &&
+            (f.properties.feattype === FeatureType.RunwayThreshold ||
+              f.properties.feattype === FeatureType.ParkingStandLocation),
+        );
+        if (geo && geo[0].geometry.type === 'Point') {
+          const point = geo[0].geometry as Point;
+          addFunction(point.coordinates, geo[0]);
+        }
+      }
+    }
+  }
+
+  addCrossAtFeature(id: number, feattype: FeatureType) {
+    this.addSymbolAtFeature(id, feattype, this.addCross.bind(this));
+  }
+
+  addFlagAtFeature(id: number, feattype: FeatureType) {
+    this.addSymbolAtFeature(id, feattype, this.addFlag.bind(this));
+  }
+
+  removeSymbolAtFeature(
+    id: number,
+    feattype: FeatureType,
+    symbols: readonly Label[],
+    removeFunction: (index: number) => void,
+  ) {
+    const isTaxiway = symbols.some(
+      (v) =>
+        v.associatedFeature?.properties.id === id &&
+        v.associatedFeature.properties.feattype === FeatureType.TaxiwayGuidanceLine,
+    );
+
+    if (isTaxiway) {
+      // Find by name
+      let taxiwayName = '';
+      for (const label of symbols) {
+        if (label.associatedFeature?.properties.id === id && label.associatedFeature.properties.feattype === feattype) {
+          taxiwayName = label.associatedFeature.properties.idlin ?? '';
+          return;
+        }
+      }
+
+      const idsToDelete = symbols
+        .map((label) => (label.associatedFeature?.properties.idlin === taxiwayName ? parseInt(label.text) : null))
+        .filter((i) => i !== null);
+      idsToDelete.forEach((i) => removeFunction(i));
+    } else {
+      // Find by ID
+      const idsToDelete = symbols
+        .map((label) =>
+          label.associatedFeature?.properties.id === id && label.associatedFeature.properties.feattype === feattype
+            ? parseInt(label.text)
+            : null,
+        )
+        .filter((i) => i !== null);
+      idsToDelete.forEach((i) => removeFunction(i));
+    }
+  }
+
+  removeCrossAtFeature(id: number, feattype: FeatureType) {
+    this.removeSymbolAtFeature(id, feattype, this.crosses.getArray(), this.removeCross.bind(this));
+  }
+
+  removeFlagAtFeature(id: number, feattype: FeatureType) {
+    this.removeSymbolAtFeature(id, feattype, this.flags.getArray(), this.removeFlag.bind(this));
+  }
+
+  findSymbolAtCursor(position: Position): { cross: number | null; flag: number | null } {
+    const flag = this.flags
+      .getArray()
+      .find(
+        (label) =>
+          Math.hypot(position[0] - label.position[0], position[1] - label.position[1]) <
+          MAX_SYMBOL_DIST_NEIGHBORHOOD_SEARCH,
+      );
+    const cross = this.crosses
+      .getArray()
+      .find(
+        (label) =>
+          Math.hypot(position[0] - label.position[0], position[1] - label.position[1]) <
+          MAX_SYMBOL_DIST_NEIGHBORHOOD_SEARCH,
+      );
+
+    return {
+      cross: cross !== undefined ? parseInt(cross.text) : null,
+      flag: flag !== undefined ? parseInt(flag.text) : null,
+    };
+  }
+
+  findSymbolAtFeature(id: number, feattype: FeatureType): { hasCross: boolean; hasFlag: boolean } {
+    return {
+      hasCross: this.crosses
+        .getArray()
+        .some(
+          (label) =>
+            label.associatedFeature?.properties.id === id && label.associatedFeature.properties.feattype === feattype,
+        ),
+      hasFlag: this.flags
+        .getArray()
+        .some(
+          (label) =>
+            label.associatedFeature?.properties.id === id && label.associatedFeature.properties.feattype === feattype,
+        ),
+    };
+  }
+}
diff --git a/fbw-common/src/systems/instruments/src/OANC/OancMovingModeOverlay.tsx b/fbw-common/src/systems/instruments/src/OANC/OancMovingModeOverlay.tsx
index fd9b39d408f..75539b4500f 100644
--- a/fbw-common/src/systems/instruments/src/OANC/OancMovingModeOverlay.tsx
+++ b/fbw-common/src/systems/instruments/src/OANC/OancMovingModeOverlay.tsx
@@ -1,8 +1,16 @@
 // Copyright (c) 2023-2024 FlyByWire Simulations
 // SPDX-License-Identifier: GPL-3.0
 
-import { DisplayComponent, EventBus, FSComponent, MappedSubject, Subscribable, VNode } from '@microsoft/msfs-sdk';
-import { Arinc429SignStatusMatrix, Arinc429Word, EfisNdMode } from '@flybywiresim/fbw-sdk';
+import {
+  DisplayComponent,
+  EventBus,
+  FSComponent,
+  MappedSubject,
+  Subscribable,
+  Subscription,
+  VNode,
+} from '@microsoft/msfs-sdk';
+import { Arinc429RegisterSubject, Arinc429SignStatusMatrix, EfisNdMode } from '@flybywiresim/fbw-sdk';
 
 import { OANC_RENDER_HEIGHT, OANC_RENDER_WIDTH } from './';
 import { ArcModeUnderlay } from './OancArcModeCompass';
@@ -28,6 +36,8 @@ export interface OancMapOverlayProps {
 }
 
 export class OancMovingModeOverlay extends DisplayComponent<OancMapOverlayProps> {
+  private subs: Subscription[] = [];
+
   private readonly arcModeVisible = MappedSubject.create(
     ([ndMode, isPanning]) => ndMode === EfisNdMode.ARC && isPanning,
     this.props.ndMode,
@@ -40,6 +50,26 @@ export class OancMovingModeOverlay extends DisplayComponent<OancMapOverlayProps>
     this.props.isMapPanned,
   );
 
+  private readonly rotationArinc429Word = Arinc429RegisterSubject.createEmpty();
+
+  onAfterRender(node: VNode): void {
+    super.onAfterRender(node);
+
+    this.subs.push(
+      this.props.rotation.sub((r) => {
+        this.rotationArinc429Word.setValueSsm(r, Arinc429SignStatusMatrix.NormalOperation);
+      }),
+    );
+
+    this.subs.push(this.arcModeVisible, this.roseModeVisible);
+  }
+
+  destroy(): void {
+    for (const s of this.subs) {
+      s.destroy();
+    }
+  }
+
   render(): VNode | null {
     return (
       <svg
@@ -50,14 +80,7 @@ export class OancMovingModeOverlay extends DisplayComponent<OancMapOverlayProps>
         <RoseModeUnderlay
           bus={this.props.bus}
           visible={this.roseModeVisible}
-          rotation={this.props.rotation.map((r) => {
-            const word = Arinc429Word.empty();
-
-            word.ssm = Arinc429SignStatusMatrix.NormalOperation;
-            word.value = r;
-
-            return word;
-          })}
+          rotation={this.rotationArinc429Word}
           oansRange={this.props.oansRange}
           doClip={false}
         />
@@ -65,14 +88,7 @@ export class OancMovingModeOverlay extends DisplayComponent<OancMapOverlayProps>
         <ArcModeUnderlay
           bus={this.props.bus}
           visible={this.arcModeVisible}
-          rotation={this.props.rotation.map((r) => {
-            const word = Arinc429Word.empty();
-
-            word.ssm = Arinc429SignStatusMatrix.NormalOperation;
-            word.value = r;
-
-            return word;
-          })}
+          rotation={this.rotationArinc429Word}
           oansRange={this.props.oansRange}
           doClip={false}
           yOffset={620 - 384}
@@ -86,6 +102,8 @@ export class OancMovingModeOverlay extends DisplayComponent<OancMapOverlayProps>
 }
 
 export class OancStaticModeOverlay extends DisplayComponent<OancMapOverlayProps> {
+  private subs: Subscription[] = [];
+
   private readonly arcModeVisible = MappedSubject.create(
     ([ndMode, isPanning]) => ndMode === EfisNdMode.ARC && !isPanning,
     this.props.ndMode,
@@ -98,6 +116,24 @@ export class OancStaticModeOverlay extends DisplayComponent<OancMapOverlayProps>
     this.props.isMapPanned,
   );
 
+  private readonly rotationArinc429Word = Arinc429RegisterSubject.createEmpty();
+
+  onAfterRender(node: VNode): void {
+    super.onAfterRender(node);
+
+    this.subs.push(
+      this.props.rotation.sub((r) => {
+        this.rotationArinc429Word.setValueSsm(r, Arinc429SignStatusMatrix.NormalOperation);
+      }),
+    );
+  }
+
+  destroy(): void {
+    for (const s of this.subs) {
+      s.destroy();
+    }
+  }
+
   render(): VNode | null {
     return (
       <svg
@@ -108,14 +144,7 @@ export class OancStaticModeOverlay extends DisplayComponent<OancMapOverlayProps>
         <RoseModeUnderlay
           bus={this.props.bus}
           visible={this.roseModeVisible}
-          rotation={this.props.rotation.map((r) => {
-            const word = Arinc429Word.empty();
-
-            word.ssm = Arinc429SignStatusMatrix.NormalOperation;
-            word.value = r;
-
-            return word;
-          })}
+          rotation={this.rotationArinc429Word}
           oansRange={this.props.oansRange}
           doClip
         />
@@ -123,14 +152,7 @@ export class OancStaticModeOverlay extends DisplayComponent<OancMapOverlayProps>
         <ArcModeUnderlay
           bus={this.props.bus}
           visible={this.arcModeVisible}
-          rotation={this.props.rotation.map((r) => {
-            const word = Arinc429Word.empty();
-
-            word.ssm = Arinc429SignStatusMatrix.NormalOperation;
-            word.value = r;
-
-            return word;
-          })}
+          rotation={this.rotationArinc429Word}
           oansRange={this.props.oansRange}
           doClip
           yOffset={0}
diff --git a/fbw-common/src/systems/instruments/src/OANC/OancPositionComputer.ts b/fbw-common/src/systems/instruments/src/OANC/OancPositionComputer.ts
index 1dd8629865e..561e9a0d1c0 100644
--- a/fbw-common/src/systems/instruments/src/OANC/OancPositionComputer.ts
+++ b/fbw-common/src/systems/instruments/src/OANC/OancPositionComputer.ts
@@ -18,6 +18,9 @@ export class OancPositionComputer<T extends number> {
   constructor(private readonly oanc: Oanc<T>) {}
 
   public computePosition(): string | undefined {
+    if (!this.oanc.data) {
+      return;
+    }
     const features = this.oanc.data.features;
 
     for (const feature of features) {
@@ -39,7 +42,7 @@ export class OancPositionComputer<T extends number> {
             return feature.properties.idlin;
           case FeatureType.RunwayElement:
           case FeatureType.Stopway:
-            return feature.properties.idrwy.replace('.', '-');
+            return feature.properties.idrwy?.replace('.', '-');
           case FeatureType.BlastPad:
           case FeatureType.RunwayDisplacedArea:
             return feature.properties.idthr;
diff --git a/fbw-common/src/systems/instruments/src/OANC/OansBrakeToVacateSelection.ts b/fbw-common/src/systems/instruments/src/OANC/OansBrakeToVacateSelection.ts
index c5ffdacca57..2e77b50191c 100644
--- a/fbw-common/src/systems/instruments/src/OANC/OansBrakeToVacateSelection.ts
+++ b/fbw-common/src/systems/instruments/src/OANC/OansBrakeToVacateSelection.ts
@@ -17,7 +17,7 @@ import {
   Position,
 } from '@turf/turf';
 import { Arinc429Register, Arinc429SignStatusMatrix, MathUtils } from '@flybywiresim/fbw-sdk';
-import { FmsDataStore, Label, LabelStyle } from '.';
+import { Label, LabelStyle } from '.';
 import { BtvData } from '../../../shared/src/publishers/OansBtv/BtvPublisher';
 import { OancLabelManager } from './OancLabelManager';
 import {
@@ -80,10 +80,10 @@ export class OansBrakeToVacateSelection<T extends number> {
   readonly btvRunwayBearingTrue = Subject.create<number | null>(null);
 
   /** Threshold, used for runway end distance calculation */
-  private btvThresholdPosition: Position;
+  private btvThresholdPosition: Position | undefined;
 
   /** Opposite threshold, used for runway end distance calculation */
-  private btvOppositeThresholdPosition: Position;
+  private btvOppositeThresholdPosition: Position | undefined;
 
   /** Selected exit */
   readonly btvExit = Subject.create<string | null>(null);
@@ -91,7 +91,7 @@ export class OansBrakeToVacateSelection<T extends number> {
   /** Distance to exit, in meters. Null if not set. */
   readonly btvExitDistance = Subject.create<number | null>(null);
 
-  private btvExitPosition: Position;
+  private btvExitPosition: Position | undefined;
 
   /** "runway ahead" advisory was triggered */
   private rwyAheadTriggered: boolean = false;
@@ -112,7 +112,7 @@ export class OansBrakeToVacateSelection<T extends number> {
 
   private readonly rwyAheadArinc = Arinc429Register.empty();
 
-  private btvPathGeometry: Position[];
+  private btvPathGeometry: Position[] = [];
 
   /** Stopping distance for dry rwy conditions, in meters. Null if not set. Counted from touchdown distance (min. 400m).  */
   private readonly dryStoppingDistance = ConsumerSubject.create(this.sub.on('dryStoppingDistance').whenChanged(), 0);
@@ -195,7 +195,7 @@ export class OansBrakeToVacateSelection<T extends number> {
     // Derive LDA from geometry (if we take the LDA database value, there might be drawing errors)
     const lda = dist1 > dist2 ? dist1 : dist2;
 
-    const heading = thresholdFeature.properties?.brngtrue ?? 0;
+    const heading = thresholdFeature.properties?.brngmag ?? 0;
 
     this.btvRunwayLda.set(lda);
     this.btvRunwayBearingTrue.set(heading);
@@ -217,7 +217,7 @@ export class OansBrakeToVacateSelection<T extends number> {
   }
 
   selectExitFromOans(exit: string, feature: Feature<Geometry, AmdbProperties>) {
-    if (this.btvRunway.get() == null) {
+    if (this.btvRunway.get() == null || !this.btvThresholdPosition || !this.btvOppositeThresholdPosition) {
       return;
     }
 
@@ -242,17 +242,13 @@ export class OansBrakeToVacateSelection<T extends number> {
         ? pointDistance(thrLoc[0], thrLoc[1], exitLoc1[0], exitLoc1[1])
         : pointDistance(thrLoc[0], thrLoc[1], exitLoc2[0], exitLoc2[1]);
 
+    const geoCoords = feature.geometry.coordinates as Position[]; // trust me, bro
     const exitAngle =
       exitDistFromCenterLine1 < exitDistFromCenterLine2
         ? pointAngle(thrLoc[0], thrLoc[1], exitLoc1[0], exitLoc1[1]) -
-          pointAngle(exitLoc1[0], exitLoc1[1], feature.geometry.coordinates[1][0], feature.geometry.coordinates[1][1])
+          pointAngle(exitLoc1[0], exitLoc1[1], geoCoords[1][0], geoCoords[1][1])
         : pointAngle(thrLoc[0], thrLoc[1], exitLoc2[0], exitLoc2[1]) -
-          pointAngle(
-            exitLoc2[0],
-            exitLoc2[1],
-            feature.geometry.coordinates[exitLastIndex - 1][0],
-            feature.geometry.coordinates[exitLastIndex - 1][1],
-          );
+          pointAngle(exitLoc2[0], exitLoc2[1], geoCoords[exitLastIndex - 1][0], geoCoords[exitLastIndex - 1][1]);
     // Don't run backwards, don't start outside of runway, don't start before minimum touchdown distance
     if (
       Math.abs(exitAngle) > 120 ||
@@ -270,7 +266,9 @@ export class OansBrakeToVacateSelection<T extends number> {
       MIN_TOUCHDOWN_ZONE_DISTANCE;
 
     this.bus.getPublisher<FmsOansData>().pub('oansSelectedExit', exit);
-    this.bus.getPublisher<FmsOansData>().pub('ndBtvMessage', `BTV ${this.btvRunway.get().substring(4)}/${exit}`, true);
+    this.bus
+      .getPublisher<FmsOansData>()
+      .pub('ndBtvMessage', `BTV ${this.btvRunway.get()?.substring(4) ?? ''}/${exit}`, true);
 
     this.btvPathGeometry = Array.from(feature.geometry.coordinates as Position[]);
     if (exitDistFromCenterLine1 < exitDistFromCenterLine2) {
@@ -313,37 +311,33 @@ export class OansBrakeToVacateSelection<T extends number> {
     this.runwayBearingArinc.writeToSimVar('L:A32NX_OANS_RWY_BEARING');
   }
 
-  public async setBtvRunwayFromFmsRunway(fmsDataStore: FmsDataStore): Promise<[Runway, Coordinates]> {
-    const destination = fmsDataStore.destination.get();
-    const rwyIdent = fmsDataStore.landingRunway.get();
-    if (destination && rwyIdent) {
-      const db = NavigationDatabaseService.activeDatabase.backendDatabase;
-
-      const arps = await db.getAirports([destination]);
-      const arpCoordinates = arps[0].location;
-
-      const runways = await db.getRunways(destination);
-      const landingRunwayNavdata = runways.filter((rw) => rw.ident === rwyIdent)[0];
-      const oppositeThreshold = placeBearingDistance(
-        landingRunwayNavdata.thresholdLocation,
-        landingRunwayNavdata.bearing,
-        landingRunwayNavdata.length / MathUtils.METRES_TO_NAUTICAL_MILES,
-      );
-      const localThr: Position = [0, 0];
-      const localOppThr: Position = [0, 0];
-      globalToAirportCoordinates(arpCoordinates, landingRunwayNavdata.thresholdLocation, localThr);
-      globalToAirportCoordinates(arpCoordinates, oppositeThreshold, localOppThr);
-
-      this.selectRunwayFromNavdata(
-        rwyIdent,
-        landingRunwayNavdata.length,
-        landingRunwayNavdata.bearing,
-        localThr,
-        localOppThr,
-      );
+  public async setBtvRunwayFromFmsRunway(destination: string, rwyIdent: string): Promise<[Runway, Coordinates]> {
+    const db = NavigationDatabaseService.activeDatabase.backendDatabase;
 
-      return [landingRunwayNavdata, arpCoordinates];
-    }
+    const arps = await db.getAirports([destination]);
+    const arpCoordinates = arps[0].location;
+
+    const runways = await db.getRunways(destination);
+    const landingRunwayNavdata = runways.filter((rw) => rw.ident === rwyIdent)[0];
+    const oppositeThreshold = placeBearingDistance(
+      landingRunwayNavdata.thresholdLocation,
+      landingRunwayNavdata.bearing,
+      landingRunwayNavdata.length / MathUtils.METRES_TO_NAUTICAL_MILES,
+    );
+    const localThr: Position = [0, 0];
+    const localOppThr: Position = [0, 0];
+    globalToAirportCoordinates(arpCoordinates, landingRunwayNavdata.thresholdLocation, localThr);
+    globalToAirportCoordinates(arpCoordinates, oppositeThreshold, localOppThr);
+
+    this.selectRunwayFromNavdata(
+      rwyIdent,
+      landingRunwayNavdata.length,
+      landingRunwayNavdata.bearing,
+      localThr,
+      localOppThr,
+    );
+
+    return [landingRunwayNavdata, arpCoordinates];
   }
 
   selectExitFromManualEntry(reqStoppingDistance: number, btvExitPosition: Position) {
@@ -356,7 +350,7 @@ export class OansBrakeToVacateSelection<T extends number> {
     pub.pub('oansSelectedExit', 'N/A');
     pub.pub('oansExitPosition', this.btvExitPosition, true);
 
-    pub.pub('ndBtvMessage', `BTV ${this.btvRunway.get().substring(4)}/MANUAL`, true);
+    pub.pub('ndBtvMessage', `BTV ${this.btvRunway.get()?.substring(4) ?? ''}/MANUAL`, true);
 
     this.btvExitDistance.set(correctedStoppingDistance);
     this.btvExit.set('N/A');
@@ -392,13 +386,13 @@ export class OansBrakeToVacateSelection<T extends number> {
   }
 
   drawBtvPath() {
-    if (!this.btvPathGeometry.length || !this.canvasRef?.getOrDefault()) {
+    const ctx = this.canvasRef?.instance.getContext('2d');
+    if (!this.btvPathGeometry.length || !this.canvasRef?.getOrDefault() || !ctx) {
       return;
     }
 
-    const ctx = this.canvasRef.instance.getContext('2d');
     ctx.resetTransform();
-    ctx.translate(this.canvasCentreX.get(), this.canvasCentreY.get());
+    ctx.translate(this.canvasCentreX?.get() ?? 0, this.canvasCentreY?.get() ?? 0);
 
     ctx.lineWidth = 5;
     ctx.strokeStyle = '#00ffff';
@@ -415,13 +409,25 @@ export class OansBrakeToVacateSelection<T extends number> {
   }
 
   drawStopLines() {
-    if (!this.btvThresholdPosition.length || !this.canvasRef?.getOrDefault()) {
+    const ctx = this.canvasRef?.instance.getContext('2d');
+    const aircraftPpos = this.aircraftPpos?.get();
+    const acOnGround = this.aircraftOnGround?.get();
+    const rwyBearingTrue = this.btvRunwayBearingTrue.get();
+    if (
+      !this.btvThresholdPosition?.length ||
+      !this.btvOppositeThresholdPosition ||
+      !this.canvasRef?.getOrDefault() ||
+      !ctx ||
+      !aircraftPpos ||
+      !this.getZoomLevelInverseScale ||
+      acOnGround === undefined ||
+      rwyBearingTrue === null
+    ) {
       return;
     }
 
-    const ctx = this.canvasRef.instance.getContext('2d');
     ctx.resetTransform();
-    ctx.translate(this.canvasCentreX.get(), this.canvasCentreY.get());
+    ctx.translate(this.canvasCentreX?.get() ?? 0, this.canvasCentreY?.get() ?? 0);
 
     const radioAlt =
       this.radioAltitude1.get().isFailureWarning() || this.radioAltitude1.get().isNoComputedData()
@@ -432,53 +438,53 @@ export class OansBrakeToVacateSelection<T extends number> {
     const dryWetLinesAreUpdating = radioAlt.valueOr(1000) <= 600;
 
     // Aircraft distance after threshold
+
     const aircraftDistFromThreshold = pointDistance(
       this.btvThresholdPosition[0],
       this.btvThresholdPosition[1],
-      this.aircraftPpos.get()[0],
-      this.aircraftPpos.get()[1],
+      aircraftPpos[0],
+      aircraftPpos[1],
     );
     const aircraftDistFromRunwayEnd = pointDistance(
       this.btvOppositeThresholdPosition[0],
       this.btvOppositeThresholdPosition[1],
-      this.aircraftPpos.get()[0],
-      this.aircraftPpos.get()[1],
+      aircraftPpos[0],
+      aircraftPpos[1],
     );
-    const isPastThreshold = aircraftDistFromRunwayEnd < this.btvRunwayLda.get();
+    const rwyLda = this.btvRunwayLda.get() ?? 0;
+    const isPastThreshold = aircraftDistFromRunwayEnd < rwyLda;
     // As soon as aircraft passes the touchdown zone distance, draw DRY and WET stop bars from there
     const touchdownDistance =
       dryWetLinesAreUpdating && isPastThreshold && aircraftDistFromThreshold > MIN_TOUCHDOWN_ZONE_DISTANCE
         ? aircraftDistFromThreshold
         : MIN_TOUCHDOWN_ZONE_DISTANCE;
-    const dryRunoverCondition = touchdownDistance + this.dryStoppingDistance.get() > this.btvRunwayLda.get();
-    const wetRunoverCondition = touchdownDistance + this.wetStoppingDistance.get() > this.btvRunwayLda.get();
+    const dryRunoverCondition = touchdownDistance + this.dryStoppingDistance.get() > rwyLda;
+    const wetRunoverCondition = touchdownDistance + this.wetStoppingDistance.get() > rwyLda;
 
     const latDistance = 27.5 / this.getZoomLevelInverseScale();
     const strokeWidth = 3.5 / this.getZoomLevelInverseScale();
 
     // DRY stop line
-    if (this.dryStoppingDistance.get() > 0 && !this.aircraftOnGround.get()) {
+    if (this.dryStoppingDistance.get() > 0 && !acOnGround) {
       const distanceToDraw = Math.min(
         this.dryStoppingDistance.get(),
-        this.btvRunwayLda.get() - touchdownDistance + CLAMP_DRY_STOPBAR_DISTANCE,
+        rwyLda - touchdownDistance + CLAMP_DRY_STOPBAR_DISTANCE,
       );
       const dryStopLinePoint = fractionalPointAlongLine(
         this.btvThresholdPosition[0],
         this.btvThresholdPosition[1],
         this.btvOppositeThresholdPosition[0],
         this.btvOppositeThresholdPosition[1],
-        (touchdownDistance + distanceToDraw) / this.btvRunwayLda.get(),
+        (touchdownDistance + distanceToDraw) / rwyLda,
       );
 
       const dryP1 = [
-        latDistance * Math.cos((180 - this.btvRunwayBearingTrue.get()) * MathUtils.DEGREES_TO_RADIANS) +
-          dryStopLinePoint[0],
-        latDistance * Math.sin((180 - this.btvRunwayBearingTrue.get()) * MathUtils.DEGREES_TO_RADIANS) +
-          dryStopLinePoint[1],
+        latDistance * Math.cos((180 - rwyBearingTrue) * MathUtils.DEGREES_TO_RADIANS) + dryStopLinePoint[0],
+        latDistance * Math.sin((180 - rwyBearingTrue) * MathUtils.DEGREES_TO_RADIANS) + dryStopLinePoint[1],
       ];
       const dryP2 = [
-        latDistance * Math.cos(-this.btvRunwayBearingTrue.get() * MathUtils.DEGREES_TO_RADIANS) + dryStopLinePoint[0],
-        latDistance * Math.sin(-this.btvRunwayBearingTrue.get() * MathUtils.DEGREES_TO_RADIANS) + dryStopLinePoint[1],
+        latDistance * Math.cos(-rwyBearingTrue * MathUtils.DEGREES_TO_RADIANS) + dryStopLinePoint[0],
+        latDistance * Math.sin(-rwyBearingTrue * MathUtils.DEGREES_TO_RADIANS) + dryStopLinePoint[1],
       ];
 
       ctx.beginPath();
@@ -501,35 +507,33 @@ export class OansBrakeToVacateSelection<T extends number> {
         style: dryRunoverCondition ? LabelStyle.BtvStopLineRed : LabelStyle.BtvStopLineMagenta,
         position: dryP2,
         rotation: 0,
-        associatedFeature: null,
+        associatedFeature: undefined,
       };
-      this.labelManager.visibleLabels.insert(dryLabel);
-      this.labelManager.labels.push(dryLabel);
+      this.labelManager?.visibleLabels.insert(dryLabel);
+      this.labelManager?.labels.push(dryLabel);
     }
 
     // WET stop line
-    if (this.wetStoppingDistance.get() > 0 && !this.aircraftOnGround.get()) {
+    if (this.wetStoppingDistance.get() > 0 && !acOnGround) {
       const distanceToDraw = Math.min(
         this.wetStoppingDistance.get(),
-        this.btvRunwayLda.get() - touchdownDistance + CLAMP_WET_STOPBAR_DISTANCE,
+        rwyLda - touchdownDistance + CLAMP_WET_STOPBAR_DISTANCE,
       );
       const wetStopLinePoint = fractionalPointAlongLine(
         this.btvThresholdPosition[0],
         this.btvThresholdPosition[1],
         this.btvOppositeThresholdPosition[0],
         this.btvOppositeThresholdPosition[1],
-        (touchdownDistance + distanceToDraw) / this.btvRunwayLda.get(),
+        (touchdownDistance + distanceToDraw) / rwyLda,
       );
 
       const wetP1 = [
-        latDistance * Math.cos((180 - this.btvRunwayBearingTrue.get()) * MathUtils.DEGREES_TO_RADIANS) +
-          wetStopLinePoint[0],
-        latDistance * Math.sin((180 - this.btvRunwayBearingTrue.get()) * MathUtils.DEGREES_TO_RADIANS) +
-          wetStopLinePoint[1],
+        latDistance * Math.cos((180 - rwyBearingTrue) * MathUtils.DEGREES_TO_RADIANS) + wetStopLinePoint[0],
+        latDistance * Math.sin((180 - rwyBearingTrue) * MathUtils.DEGREES_TO_RADIANS) + wetStopLinePoint[1],
       ];
       const wetP2 = [
-        latDistance * Math.cos(-this.btvRunwayBearingTrue.get() * MathUtils.DEGREES_TO_RADIANS) + wetStopLinePoint[0],
-        latDistance * Math.sin(-this.btvRunwayBearingTrue.get() * MathUtils.DEGREES_TO_RADIANS) + wetStopLinePoint[1],
+        latDistance * Math.cos(-rwyBearingTrue * MathUtils.DEGREES_TO_RADIANS) + wetStopLinePoint[0],
+        latDistance * Math.sin(-rwyBearingTrue * MathUtils.DEGREES_TO_RADIANS) + wetStopLinePoint[1],
       ];
 
       ctx.beginPath();
@@ -562,17 +566,17 @@ export class OansBrakeToVacateSelection<T extends number> {
         style: labelStyle,
         position: wetP2,
         rotation: 0,
-        associatedFeature: null,
+        associatedFeature: undefined,
       };
-      this.labelManager.visibleLabels.insert(wetLabel);
-      this.labelManager.labels.push(wetLabel);
+      this.labelManager?.visibleLabels.insert(wetLabel);
+      this.labelManager?.labels.push(wetLabel);
     }
 
     // On ground & above 25kts: STOP line
     const distToRwyEnd = this.remaininingDistToRwyEnd.get();
     if (
       this.liveStoppingDistance.get() > 0 &&
-      this.aircraftOnGround.get() &&
+      acOnGround &&
       this.groundSpeed.get().value > 25 &&
       distToRwyEnd.ssm === Arinc429SignStatusMatrix.NormalOperation
     ) {
@@ -587,18 +591,16 @@ export class OansBrakeToVacateSelection<T extends number> {
         this.btvThresholdPosition[1],
         this.btvOppositeThresholdPosition[0],
         this.btvOppositeThresholdPosition[1],
-        (aircraftDistFromThreshold + distanceToDraw) / this.btvRunwayLda.get(),
+        (aircraftDistFromThreshold + distanceToDraw) / rwyLda,
       );
 
       const stopP1 = [
-        latDistance * Math.cos((180 - this.btvRunwayBearingTrue.get()) * MathUtils.DEGREES_TO_RADIANS) +
-          stopLinePoint[0],
-        latDistance * Math.sin((180 - this.btvRunwayBearingTrue.get()) * MathUtils.DEGREES_TO_RADIANS) +
-          stopLinePoint[1],
+        latDistance * Math.cos((180 - rwyBearingTrue) * MathUtils.DEGREES_TO_RADIANS) + stopLinePoint[0],
+        latDistance * Math.sin((180 - rwyBearingTrue) * MathUtils.DEGREES_TO_RADIANS) + stopLinePoint[1],
       ];
       const stopP2 = [
-        latDistance * Math.cos(-this.btvRunwayBearingTrue.get() * MathUtils.DEGREES_TO_RADIANS) + stopLinePoint[0],
-        latDistance * Math.sin(-this.btvRunwayBearingTrue.get() * MathUtils.DEGREES_TO_RADIANS) + stopLinePoint[1],
+        latDistance * Math.cos(-rwyBearingTrue * MathUtils.DEGREES_TO_RADIANS) + stopLinePoint[0],
+        latDistance * Math.sin(-rwyBearingTrue * MathUtils.DEGREES_TO_RADIANS) + stopLinePoint[1],
       ];
 
       ctx.beginPath();
@@ -621,10 +623,10 @@ export class OansBrakeToVacateSelection<T extends number> {
         style: liveRunOverCondition ? LabelStyle.BtvStopLineRed : LabelStyle.BtvStopLineGreen,
         position: stopP1,
         rotation: 0,
-        associatedFeature: null,
+        associatedFeature: undefined,
       };
-      this.labelManager.visibleLabels.insert(stoplineLabel);
-      this.labelManager.labels.push(stoplineLabel);
+      this.labelManager?.visibleLabels.insert(stoplineLabel);
+      this.labelManager?.labels.push(stoplineLabel);
     }
   }
 
@@ -643,9 +645,9 @@ export class OansBrakeToVacateSelection<T extends number> {
 
     this.canvasRef.instance
       .getContext('2d')
-      .clearRect(0, 0, this.canvasRef.instance.width, this.canvasRef.instance.height);
-    while (this.labelManager.visibleLabels.getArray().findIndex((it) => isStopLineStyle(it.style)) !== -1) {
-      this.labelManager.visibleLabels.removeAt(
+      ?.clearRect(0, 0, this.canvasRef.instance.width, this.canvasRef.instance.height);
+    while (this.labelManager?.visibleLabels.getArray().findIndex((it) => isStopLineStyle(it.style)) !== -1) {
+      this.labelManager?.visibleLabels.removeAt(
         this.labelManager.visibleLabels.getArray().findIndex((it) => isStopLineStyle(it.style)),
       );
     }
@@ -675,11 +677,14 @@ export class OansBrakeToVacateSelection<T extends number> {
       return;
     }
 
+    const aircraftPpos = this.aircraftPpos?.get();
+
     if (
       this.onGround.get() === false ||
       this.groundSpeed.get().ssm !== Arinc429SignStatusMatrix.NormalOperation ||
       this.groundSpeed.get().value > 40 ||
-      this.groundSpeed.get().value < 1
+      this.groundSpeed.get().value < 1 ||
+      !aircraftPpos
     ) {
       // Transmit no advisory
       this.rwyAheadArinc.ssm = Arinc429SignStatusMatrix.NormalOperation;
@@ -746,10 +751,10 @@ export class OansBrakeToVacateSelection<T extends number> {
     // From here on comparing local to local coords
     const predictionVolume = polygon([this.rwyAheadPredictionVolumePoints]);
 
-    const insideRunways = [];
+    const insideRunways: string[] = [];
     runwayFeatures.features.forEach((feat) => {
       if (feat.properties.idrwy) {
-        const inside = booleanContains(feat.geometry as Polygon, point(this.aircraftPpos.get()));
+        const inside = booleanContains(feat.geometry as Polygon, point(aircraftPpos));
         if (inside) {
           insideRunways.push(feat.properties.idrwy.replace('.', ' - '));
         }
diff --git a/fbw-common/src/systems/instruments/src/OANC/OansControlEventPublisher.ts b/fbw-common/src/systems/instruments/src/OANC/OansControlEventPublisher.ts
index bd5ac43ddd4..138e730d559 100644
--- a/fbw-common/src/systems/instruments/src/OANC/OansControlEventPublisher.ts
+++ b/fbw-common/src/systems/instruments/src/OANC/OansControlEventPublisher.ts
@@ -1,11 +1,34 @@
 // Copyright (c) 2023-2024 FlyByWire Simulations
 // SPDX-License-Identifier: GPL-3.0
 
+import { EfisSide, FeatureType } from '@flybywiresim/fbw-sdk';
+import { Position } from '@turf/turf';
+
 export interface OansControlEvents {
-  ndShowOans: boolean;
-  ndSetContextMenu: { x: number; y: number };
-  oansDisplayAirport: string;
-  oansZoomIn: number;
-  oansZoomOut: number;
-  oansNotAvail: boolean;
+  nd_show_oans: { side: EfisSide; show: boolean };
+  oans_performance_mode_hide: { side: EfisSide; hide: boolean };
+  oans_display_airport: string;
+  oans_not_avail: boolean;
+  oans_center_map_on: Position;
+  oans_center_on_acft: boolean;
+  oans_add_cross_at_feature: { id: number; feattype: FeatureType };
+  oans_add_flag_at_feature: { id: number; feattype: FeatureType };
+  oans_remove_cross_at_feature: { id: number; feattype: FeatureType };
+  oans_remove_flag_at_feature: { id: number; feattype: FeatureType };
+  /** OANC -> ND, whether symbol (flag or cross) already exists for feature id */
+  oans_symbols_for_feature_ids: { featureIdsWithCrosses: number[]; featureIdsWithFlags: number[] };
+  /** Mouse X, Y */
+  oans_add_cross_at_cursor: [number, number];
+  /** Mouse X, Y */
+  oans_add_flag_at_cursor: [number, number];
+  oans_erase_all_crosses: boolean;
+  oans_erase_all_flags: boolean;
+  /** Fires when context menu is called on the ND, to check whether there are symbols to delete */
+  oans_query_symbols_at_cursor: { side: EfisSide; cursorPosition: [number, number] };
+  /** Answer from OANC to ND: Whether symbols exist at the queried mouse cursor position, returns indices of symbols */
+  oans_answer_symbols_at_cursor: { side: EfisSide; cross: number | null; flag: number | null };
+  oans_erase_cross_id: number;
+  oans_erase_flag_id: number;
+  /** OANC -> ND: Show SET PLAN MODE in control panel, if in ARC/NAV mode and arpt too far away */
+  oans_show_set_plan_mode: boolean;
 }
diff --git a/fbw-common/src/systems/instruments/src/OANC/ResetPanelPublisher.tsx b/fbw-common/src/systems/instruments/src/OANC/ResetPanelPublisher.tsx
new file mode 100644
index 00000000000..0e347d460d6
--- /dev/null
+++ b/fbw-common/src/systems/instruments/src/OANC/ResetPanelPublisher.tsx
@@ -0,0 +1,11 @@
+// Copyright (c) 2025 FlyByWire Simulations
+//
+// SPDX-License-Identifier: GPL-3.0
+
+/**
+ * Events for reset panel on overhead panel. If pulled out, the LVar is set to true, if pushed in it's set to false.
+ * Functionally, these behave similarly to circuit breakers, however they only interrupt software. If pulled out, execution of SW is halted.
+ */
+export type ResetPanelSimvars = {
+  a380x_reset_panel_arpt_nav: boolean;
+};
diff --git a/fbw-common/src/systems/instruments/src/OANC/tsconfig.json b/fbw-common/src/systems/instruments/src/OANC/tsconfig.json
index c5f8a505543..b19ddd26ea6 100644
--- a/fbw-common/src/systems/instruments/src/OANC/tsconfig.json
+++ b/fbw-common/src/systems/instruments/src/OANC/tsconfig.json
@@ -4,7 +4,7 @@
     "incremental": false /* Enables incremental builds */,
     "target": "es2017" /* Specifies the ES2017 target, compatible with Coherent GT */,
     "module": "es2015" /* Ensures that modules are at least es2015 */,
-    "strict": false /* Enables strict type checking, highly recommended but optional */,
+    "strict": true /* Enables strict type checking, highly recommended but optional */,
     "esModuleInterop": true /* Emits additional JS to work with CommonJS modules */,
     "skipLibCheck": true /* Skip type checking on library .d.ts files */,
     "forceConsistentCasingInFileNames": true /* Ensures correct import casing */,
diff --git a/fbw-common/src/systems/shared/src/amdb.ts b/fbw-common/src/systems/shared/src/amdb.ts
index 2110feebea9..81fbe354c09 100644
--- a/fbw-common/src/systems/shared/src/amdb.ts
+++ b/fbw-common/src/systems/shared/src/amdb.ts
@@ -1,7 +1,7 @@
 // Copyright (c) 2021-2024 FlyByWire Simulations
 // SPDX-License-Identifier: GPL-3.0
 
-import { FeatureCollection, Geometry } from '@turf/turf';
+import { FeatureCollection, Geometry, Point } from '@turf/turf';
 import { LatLonInterface } from '@microsoft/msfs-sdk';
 
 export enum AmdbProjection {
@@ -183,6 +183,8 @@ export interface AmdbProperties {
   brngmag?: number;
 
   brngtrue?: number;
+
+  midpoint?: Point;
 }
 
 export type AmdbFeatureCollection = FeatureCollection<Geometry, AmdbProperties>;
diff --git a/fbw-common/src/systems/shared/src/publishers/OansBtv/FmsOansPublisher.ts b/fbw-common/src/systems/shared/src/publishers/OansBtv/FmsOansPublisher.ts
index 316cb85bc10..1927cf2233f 100644
--- a/fbw-common/src/systems/shared/src/publishers/OansBtv/FmsOansPublisher.ts
+++ b/fbw-common/src/systems/shared/src/publishers/OansBtv/FmsOansPublisher.ts
@@ -20,13 +20,13 @@ export interface FmsOansData {
   /** (FMS -> OANS) Identifier of landing runway selected through FMS. */
   fmsLandingRunway: string;
   /** Identifier of landing runway selected for BTV through OANS. */
-  oansSelectedLandingRunway: string;
+  oansSelectedLandingRunway: string | null;
   /** Arinc429: Length of landing runway selected for BTV through OANS, in meters. */
   oansSelectedLandingRunwayLength: number;
   /** Arinc429: Bearing of landing runway selected for BTV through OANS, in degrees. */
   oansSelectedLandingRunwayBearing: number;
   /** Identifier of exit selected for BTV through OANS. */
-  oansSelectedExit: string;
+  oansSelectedExit: string | null;
   /** (OANS -> ND) QFU to be displayed in flashing RWY AHEAD warning in ND */
   ndRwyAheadQfu: string;
   /** (OANS -> BTV) Arinc429: Requested stopping distance (through OANS), in meters. */