diff --git a/.gitignore b/.gitignore
index fadb807b38bbbade09582f298c5ace3d94b0c031..323de17c5dfb94e304ace7a3ff8d52f5551d7d63 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,5 @@ cachedKgDataset.json
 tmp
 storybook-static
 documentation.json
+
+.k8s/secret-*.yml
diff --git a/.k8s/certificate-siibra-explorer.yml b/.k8s/certificate-siibra-explorer.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7b74dafa228951b14da53aed7ab5f13b1416e00f
--- /dev/null
+++ b/.k8s/certificate-siibra-explorer.yml
@@ -0,0 +1,21 @@
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+  name: siibra-explorer-certificate
+spec:
+  secretName: siibra-explorer-prod-secret
+  renewBefore: 120h 
+  commonName: siibra-explorer.apps.tc.humanbrainproject.eu
+  isCA: false
+  privateKey:
+    algorithm: RSA
+    encoding: PKCS1
+    size: 2048
+  usages:
+  - server auth
+  dnsNames:
+  # (CHANGE ME! same as `commonName`)
+  - siibra-explorer.apps.tc.humanbrainproject.eu
+  issuerRef:
+    name: letsencrypt-production-issuer-1
+    kind: ClusterIssuer 
\ No newline at end of file
diff --git a/.k8s/configmap-siibra-explorer.yml b/.k8s/configmap-siibra-explorer.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9dd25153d1449e599ba4eedab890228be7ee096e
--- /dev/null
+++ b/.k8s/configmap-siibra-explorer.yml
@@ -0,0 +1,13 @@
+apiVersion: v1
+data:
+  HOST_PATHNAME: "/viewer"
+  HOSTNAME: "https://siibra-explorer.apps.tc.humanbrainproject.eu"
+  SIIBRA_CACHEDIR: /siibra-api-volume
+  HBP_DISCOVERY_URL: "https://iam.ebrains.eu/auth/realms/hbp"
+  REDIS_ADDR: "cache-redis-service"
+  V2_7_PLUGIN_URLS: "https://siibra-toolbox-jugex.apps.hbp.eu/viewer_plugin/manifest.json;https://ngpy.apps.hbp.eu/viewer_plugin/manifest.json"
+  LOGGER_DIR: "/sxplr-log"
+
+kind: ConfigMap
+metadata:
+  name: siibra-sxplr-common
diff --git a/.k8s/deployment-explorer.yml b/.k8s/deployment-explorer.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a70407dbd0f9ce344f39f0b1d4b786c5ec3d6e08
--- /dev/null
+++ b/.k8s/deployment-explorer.yml
@@ -0,0 +1,51 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app: siibra-explorer
+    flavor: prod
+  name: siibra-explorer-prod-deployment
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: siibra-explorer
+      flavor: prod
+  strategy:
+    rollingUpdate:
+      maxSurge: 25%
+      maxUnavailable: 25%
+    type: RollingUpdate
+  template:
+    metadata:
+      labels:
+        app: siibra-explorer
+        flavor: prod
+    spec:
+      containers:
+      - envFrom:
+        - configMapRef:
+            name: siibra-sxplr-common
+        - secretRef:
+            name: siibra-sxplr-secret
+        image: docker-registry.ebrains.eu/siibra/siibra-explorer:master
+        name: siibra-explorer-prod-container
+        ports:
+        - containerPort: 8080
+          protocol: TCP
+        resources:
+          limits:
+            cpu: "400m"
+            memory: 500Mi
+          requests:
+            cpu: "200m"
+            memory: 100Mi
+        volumeMounts:
+        - mountPath: /sxplr-log
+          name: log-volume
+      restartPolicy: Always
+      volumes:
+      - name: log-volume
+        persistentVolumeClaim:
+          claimName: log-volume-claim
+
diff --git a/.k8s/deployment-redis.yml b/.k8s/deployment-redis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..263e06258257b16c71e489d62e2b37fc9c5c0449
--- /dev/null
+++ b/.k8s/deployment-redis.yml
@@ -0,0 +1,33 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app: sxplr-redis
+    role: cache
+  name: redis-cache-deployment
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: sxplr-redis
+  template:
+    metadata:
+      labels:
+        app: sxplr-redis
+        role: cache
+    spec:
+      containers:
+      - image: docker-registry.ebrains.eu/monitoring/redis:alpine3.17
+        imagePullPolicy: IfNotPresent
+        name: sxplr-redis
+        ports:
+        - containerPort: 6379
+          protocol: TCP
+        resources:
+          limits:
+            cpu: 200m
+            memory: 1Gi
+          requests:
+            cpu: 100m
+            memory: 128Mi
+      restartPolicy: Always
diff --git a/.k8s/example-secret-siibra-explorer.yml b/.k8s/example-secret-siibra-explorer.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e4118f80194842f5a40ffc849eec748fd4ce2180
--- /dev/null
+++ b/.k8s/example-secret-siibra-explorer.yml
@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: Secret
+metadata:
+  name: siibra-sxplr-secret
+type: Opaque
+data:
+  # n.b. echo -n "foobar" | base64
+  # or else the new line will also be encoded, and you will
+  # wonder why your application does not work
+  OVERWRITE_API_ENDPOINT: Zm9vYmFy
+  HBP_CLIENTID_V2: Zm9vYmFy
+  HBP_CLIENTSECRET_V2: Zm9vYmFy
+  SXPLR_EBRAINS_IAM_SA_CLIENT_ID: Zm9vYmFy
+  SXPLR_EBRAINS_IAM_SA_CLIENT_SECRET: Zm9vYmFy
+
diff --git a/.k8s/ingress-sxplr.yml b/.k8s/ingress-sxplr.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a35f32f05b59844de24f5baddd8b6ac3e209db94
--- /dev/null
+++ b/.k8s/ingress-sxplr.yml
@@ -0,0 +1,22 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: siibra-explorer-prod-ingress
+  annotations:
+    # nginx.ingress.kubernetes.io/rewrite-target: /
+spec:
+  tls:
+  - hosts: 
+    - siibra-explorer.apps.tc.humanbrainproject.eu
+    secretName: siibra-explorer-prod-secret
+  rules:
+  - host: siibra-explorer.apps.tc.humanbrainproject.eu
+    http:
+      paths:
+      - path: /viewer
+        pathType: Prefix
+        backend:
+          service:
+            name: siibra-explorer-prod-service
+            port:
+              number: 8080
diff --git a/.k8s/pvc-log-volume.yml b/.k8s/pvc-log-volume.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ea0aabd8090b27ab6a5eb06d7dbf142f335d8b5a
--- /dev/null
+++ b/.k8s/pvc-log-volume.yml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: log-volume-claim
+  labels:
+    type: longhorn-pvc
+spec:
+  # https://wiki.ebrains.eu/bin/view/Collabs/migration-faq/EBRAINS%20Kubernetes%20README/?srid=01ZnoA2n#HDownloadandconfigureyourkubeconfigfile
+  storageClassName: longhorn-1
+  resources:
+    requests:
+      storage: 4Gi
+  accessModes:
+    - ReadWriteMany
diff --git a/.k8s/service-explorer.yml b/.k8s/service-explorer.yml
new file mode 100644
index 0000000000000000000000000000000000000000..474668de535aa5349d115ee132d0e291d936842c
--- /dev/null
+++ b/.k8s/service-explorer.yml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: siibra-explorer-prod-service
+spec:
+  ports:
+  - port: 8080
+    protocol: TCP
+    targetPort: 8080
+  selector:
+    app: siibra-explorer
+    flavor: prod
+  type: ClusterIP
diff --git a/.k8s/service-redis.yml b/.k8s/service-redis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..729063427240446a52f94d170819751c29016c97
--- /dev/null
+++ b/.k8s/service-redis.yml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: cache-redis-service
+spec:
+  ports:
+  - port: 6379
+    protocol: TCP
+    targetPort: 6379
+  selector:
+    app: sxplr-redis
+  type: ClusterIP
diff --git a/backend/app/config.py b/backend/app/config.py
index ec7bd8c3853c94cff2f11eae7c23ed3648ec7b22..bc824fd52776656cb2cbaf480f918d091a342e51 100644
--- a/backend/app/config.py
+++ b/backend/app/config.py
@@ -3,7 +3,6 @@ import os
 SESSION_SECRET = os.getenv("SESSION_SECRET", "hey joline, remind me to set a more secure session secret")
 
 HOST_PATHNAME = os.getenv("HOST_PATHNAME", "")
-PORT = os.getenv("PORT")
 
 HOSTNAME = os.getenv("HOSTNAME", "http://localhost:3000")
 
@@ -14,13 +13,10 @@ LOCAL_CDN = os.getenv("LOCAL_CDN")
 HBP_CLIENTID_V2 = os.getenv("HBP_CLIENTID_V2", "no hbp id")
 HBP_CLIENTSECRET_V2 = os.getenv("HBP_CLIENTSECRET_V2", "no hbp client secret")
 
-HBP_DISCOVERY_URL = "https://iam.ebrains.eu/auth/realms/hbp"
-
 BUILD_TEXT = os.getenv("BUILD_TEXT", "")
 
 # REDIS env var
 
-REDIS_PROTO = os.getenv("REDIS_PROTO")
 REDIS_ADDR = os.getenv("REDIS_ADDR") or os.getenv("REDIS_RATE_LIMITING_DB_EPHEMERAL_PORT_6379_TCP_ADDR") or "localhost"
 REDIS_PORT = os.getenv("REDIS_PORT") or os.getenv("REDIS_RATE_LIMITING_DB_EPHEMERAL_PORT_6379_TCP_PORT") or "6379"
 REDIS_USERNAME = os.getenv("REDIS_USERNAME")
diff --git a/backend/requirements.txt b/backend/requirements.txt
index c321ab8212610d7d4f96853cc375492df8393ef8..3afe4cbd03ae7ed0d2b2714d058662f18d900518 100644
--- a/backend/requirements.txt
+++ b/backend/requirements.txt
@@ -5,8 +5,4 @@ uvicorn[standard] # required as a asgi
 itsdangerous # required for starlette session middleware
 httpx # required for async uvicorn
 redis
-
-# cherrypicks https://github.com/HumanBrainProject/ebrains-drive/pull/20 and https://github.com/HumanBrainProject/ebrains-drive/pull/22
-# once both merged and published, use ebrains-drive instead
-git+https://github.com/xgui3783/ebrains-drive.git@tmp_fixDeleteUseIO
-
+ebrains-drive>=0.6.0
diff --git a/docs/releases/v2.14.1.md b/docs/releases/v2.14.1.md
new file mode 100644
index 0000000000000000000000000000000000000000..7f3d1ba8fc0b77b35f2bda9ec2c676c83183e31b
--- /dev/null
+++ b/docs/releases/v2.14.1.md
@@ -0,0 +1,12 @@
+# v2.4.1
+
+## Bugfixes
+
+- fixed PLI best view point
+- fixed font size of section header under feature
+- temporarily fixed nehuba navigation panel
+
+## Under the hood stuff
+
+- updated backend requirements, removed unused environment variable definitions
+- added k8s deployment config
diff --git a/package.json b/package.json
index 22253b1c38ba48c197710f0f78d2e34dee792e8e..12cb12804b487c93bb108c201f5c1cbd37968315 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "siibra-explorer",
-  "version": "2.14.0",
+  "version": "2.14.1",
   "description": "siibra-explorer - explore brain atlases. Based on humanbrainproject/nehuba & google/neuroglancer. Built with angular",
   "scripts": {
     "lint": "eslint src --ext .ts",
diff --git a/src/atlasComponents/sapi/translateV3.ts b/src/atlasComponents/sapi/translateV3.ts
index e1c7efa0b9a2969e217fbc56f411c01171205e82..b0e0ad5a458608a930f1eb76f739dd2aba7844c2 100644
--- a/src/atlasComponents/sapi/translateV3.ts
+++ b/src/atlasComponents/sapi/translateV3.ts
@@ -32,7 +32,23 @@ const TMP_META_REGISTRY: Record<string, MetaV1Schema> = {
     data: {
       type: "image/3d"
     },
-    transform: [[7.325973427896315e-8,2.866510051546811e-8,-1,-16600000],[-0.9899035692214966,0.14174138009548187,-6.845708355740499e-8,70884888],[-0.14174138009548187,-0.9899035692214966,-3.875962661936683e-8,64064704],[0,0,0,1]]
+    transform: [[7.325973427896315e-8,2.866510051546811e-8,-1,-16600000],[-0.9899035692214966,0.14174138009548187,-6.845708355740499e-8,70884888],[-0.14174138009548187,-0.9899035692214966,-3.875962661936683e-8,64064704],[0,0,0,1]],
+    bestViewPoints: [{
+      type: "enclosed",
+      points: [{
+        type: "point",
+        value: [-16.625, -81.397, 42.385]
+      },{
+        type: "point",
+        value: [-16.625, -65.063, -67.262]
+      },{
+        type: "point",
+        value: [-16.625, 85.858, -44.395]
+      },{
+        type: "point",
+        value: [-16.625, 71.157, 63.871]
+      }]
+    }],
   },
   "https://1um.brainatlas.eu/cyto_reconstructions/ebrains_release/BB_1um/VOI_1/precomputed": {
     version: 1,
diff --git a/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html b/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html
index 8036ecca8901496183703b76e28d7c62c3918b8a..25a7643b6e7315249dd34ec480b831d78dec4bdc 100644
--- a/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html
+++ b/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html
@@ -188,7 +188,7 @@
 
           <div class="section-divider"></div>
 
-          <h2 class="sxplr-ml-2 mat-h4">Related Regions</h2>
+          <span class="sxplr-ml-2 mat-h4 text-muted">Features of Related Regions</span>
 
           <div class="h-carousel">
             <div class="h-carousel-item-container">
diff --git a/src/viewerModule/nehuba/statusCard/statusCard.component.spec.ts b/src/viewerModule/nehuba/statusCard/statusCard.component.spec.ts
index 7c8c9842cdf45a91b3b18880a0991bce68f6e6d6..df15daa10962bb9b2a739d65da5535bd6c8ab8fd 100644
--- a/src/viewerModule/nehuba/statusCard/statusCard.component.spec.ts
+++ b/src/viewerModule/nehuba/statusCard/statusCard.component.spec.ts
@@ -7,7 +7,6 @@ import { NEVER, of } from "rxjs"
 import { ShareModule } from "src/share"
 import { StateModule } from "src/state"
 import { MockStore, provideMockStore } from "@ngrx/store/testing"
-import { By } from "@angular/platform-browser"
 import { NoopAnimationsModule } from "@angular/platform-browser/animations"
 import { FormsModule, ReactiveFormsModule } from "@angular/forms"
 import { UtilModule } from "src/util"
@@ -15,7 +14,6 @@ import { NEHUBA_CONFIG_SERVICE_TOKEN } from "../config.service"
 import { QuickTourModule } from "src/ui/quickTour/module";
 import { atlasSelection } from "src/state"
 import { SxplrTemplate } from "src/atlasComponents/sapi/sxplrTypes"
-import { MatSlideToggle } from "src/sharedModules/angularMaterial.exports"
 import { NEHUBA_INSTANCE_INJTKN } from "../util"
 
 const mockNehubaConfig = {
@@ -125,19 +123,11 @@ describe('> statusCard.component.ts', () => {
             setNavigationState: setNavigationStateSpy,
           } as any
 
-          fixture.componentInstance.statusPanelRealSpace = true
           fixture.componentInstance.textNavigateTo('1, 0, 0')
           expect(setNavigationStateSpy).toHaveBeenCalledWith({
             position: [1e6, 0, 0],
             positionReal: true
           })
-
-          fixture.componentInstance.statusPanelRealSpace = false
-          fixture.componentInstance.textNavigateTo('1, 0, 0')
-          expect(setNavigationStateSpy).toHaveBeenCalledWith({
-            position: [1, 0, 0],
-            positionReal: false
-          })
         })
       })
     })
diff --git a/src/viewerModule/nehuba/statusCard/statusCard.component.ts b/src/viewerModule/nehuba/statusCard/statusCard.component.ts
index b8e6e0817457f07fc8a16e092a032017c4a8f915..1b1f6f6f0c1b9b875b638e5f9b8a5b37cc3796f8 100644
--- a/src/viewerModule/nehuba/statusCard/statusCard.component.ts
+++ b/src/viewerModule/nehuba/statusCard/statusCard.component.ts
@@ -8,11 +8,11 @@ import {
 import { select, Store } from "@ngrx/store";
 import { LoggingService } from "src/logging";
 import { NehubaViewerUnit } from "../nehubaViewer/nehubaViewer.component";
-import { Observable, combineLatest } from "rxjs";
-import { map, filter, startWith, throttleTime, takeUntil, switchMap, shareReplay, debounceTime } from "rxjs/operators";
+import { Observable, concat, of } from "rxjs";
+import { map, filter, takeUntil, switchMap, shareReplay, debounceTime } from "rxjs/operators";
 import { Clipboard, MatBottomSheet, MatDialog, MatSnackBar } from "src/sharedModules/angularMaterial.exports"
 import { ARIA_LABELS, QUICKTOUR_DESC } from 'common/constants'
-import { FormControl, FormGroup, UntypedFormControl } from "@angular/forms";
+import { FormControl, FormGroup } from "@angular/forms";
 
 import { NEHUBA_INSTANCE_INJTKN } from '../util'
 import { IQuickTourData } from "src/ui/quickTour/constrants";
@@ -59,20 +59,12 @@ export class StatusCardComponent {
   public readonly navVal$ = this.nehubaViewer$.pipe(
     filter(v => !!v),
     switchMap(nehubaViewer => 
-      combineLatest([
-        this.statusPanelRealSpace$,
+      concat(
+        of(`nehubaViewer initialising`),
         nehubaViewer.viewerPosInReal$.pipe(
-          filter(v => !!v)
-        ),
-        nehubaViewer.viewerPosInVoxel$.pipe(
-          filter(v => !!v)
-        ),
-      ]).pipe(
-        map(([realFlag, real, voxel]) => realFlag
-          ? real.map(v => `${ (v / 1e6).toFixed(3) }mm`).join(', ')
-          : voxel.map(v => v.toFixed(3)).join(', ') ),
-        startWith(`nehubaViewer initialising`),
-        throttleTime(16),
+          filter(v => !!v),
+          map(real => real.map(v => `${ (v / 1e6).toFixed(3) }mm`).join(', '))
+        )
       )
     ),
     shareReplay(1),
@@ -80,20 +72,13 @@ export class StatusCardComponent {
   public readonly mouseVal$ = this.nehubaViewer$.pipe(
     filter(v => !!v),
     switchMap(nehubaViewer => 
-      combineLatest([
-        this.statusPanelRealSpace$,
+      concat(
+        of(``),
         nehubaViewer.mousePosInReal$.pipe(
           filter(v => !!v),
-        ),
-        nehubaViewer.mousePosInVoxel$.pipe(
-          filter(v => !!v)
-        ),
-      ]).pipe(
-        map(([realFlag, real, voxel]) => realFlag
-          ? real.map(v => `${ (v/1e6).toFixed(3) }mm`).join(', ')
-          : voxel.map(v => v.toFixed(3)).join(', ')),
-        startWith(``),
-      )
+          map(real => real.map(v => `${ (v/1e6).toFixed(3) }mm`).join(', '))
+        )
+      ),
     )
   )
 
@@ -139,11 +124,6 @@ export class StatusCardComponent {
     ).subscribe(
       viewer => this.nehubaViewer = viewer
     )
-    this.statusPanelFormCtrl.valueChanges.pipe(
-      takeUntil(this.#destroy$)
-    ).subscribe(val => {
-      this.statusPanelRealSpace = val
-    })
     this.store$.pipe(
       select(atlasSelection.selectors.navigation)
     ).pipe(
@@ -199,18 +179,12 @@ export class StatusCardComponent {
       .map(Number)
   }
 
-  public statusPanelFormCtrl = new UntypedFormControl(true, [])
-  public statusPanelRealSpace = true
-  public statusPanelRealSpace$ = this.statusPanelFormCtrl.valueChanges.pipe(
-    startWith(true)
-  )
-
   public textNavigateTo(string: string): void {
     if (string.split(/[\s|,]+/).length >= 3 && string.split(/[\s|,]+/).slice(0, 3).every(entry => !isNaN(Number(entry.replace(/mm/, ''))))) {
-      const pos = (string.split(/[\s|,]+/).slice(0, 3).map((entry) => Number(entry.replace(/mm/, '')) * (this.statusPanelRealSpace ? 1000000 : 1)))
+      const pos = (string.split(/[\s|,]+/).slice(0, 3).map((entry) => Number(entry.replace(/mm/, '')) * 1000000))
       this.nehubaViewer.setNavigationState({
         position : (pos as [number, number, number]),
-        positionReal : this.statusPanelRealSpace,
+        positionReal : true,
       })
     } else {
       this.log.log('input did not parse to coordinates ', string)
diff --git a/src/viewerModule/nehuba/statusCard/statusCard.template.html b/src/viewerModule/nehuba/statusCard/statusCard.template.html
index 50c06ab83a0960ab5e2acc2a46e20063c902a823..3dab5a5b1a8fbd4762d35e10887a55dbcf779582 100644
--- a/src/viewerModule/nehuba/statusCard/statusCard.template.html
+++ b/src/viewerModule/nehuba/statusCard/statusCard.template.html
@@ -50,7 +50,7 @@
 
         <mat-form-field class="flex-grow-1">
           <mat-label>
-            {{ (statusPanelRealSpace$ | async) ? 'Physical Coord' : 'Voxel Coord' }}
+            Physical Coord
           </mat-label>
           <input type="text"
             matInput