diff --git a/src/client/components/App.js b/src/client/components/App.js
index cf785afd49b166a8efb41cc0d5b1a396af96f8a2..a4de9f0f5fb08173eac788f591d8b9faf746405d 100644
--- a/src/client/components/App.js
+++ b/src/client/components/App.js
@@ -1,12 +1,22 @@
 import React from 'react'
-import { ThemeProvider, StyledEngineProvider, createTheme } from '@mui/material/styles'
+import { ThemeProvider, createTheme } from '@mui/material/styles'
 import AdapterMoment from '@mui/lab/AdapterDateFns'
 import LocalizationProvider from '@mui/lab/LocalizationProvider'
 // import 'moment/locale/fi'
 import SemanticPortal from '../containers/SemanticPortal'
 import portalConfig from '../../configs/portalConfig.json'
 
-const { colorPalette } = portalConfig.layoutConfig
+const { colorPalette, reducedHeightBreakpoint, hundredPercentHeightBreakPoint, topBar } = portalConfig.layoutConfig
+
+const muiDefaultBreakpoints = {
+  xs: 0,
+  sm: 600,
+  md: 900,
+  lg: 1200,
+  xl: 1536
+}
+
+const defaultTheme = createTheme()
 
 const theme = createTheme({
   palette: {
@@ -17,7 +27,26 @@ const theme = createTheme({
       main: colorPalette.secondary.main
     }
   },
+  breakpoints: {
+    values: {
+      ...muiDefaultBreakpoints,
+      reducedHeight: muiDefaultBreakpoints[reducedHeightBreakpoint],
+      hundredPercentHeight: muiDefaultBreakpoints[hundredPercentHeightBreakPoint]
+    }
+  },
   components: {
+    MuiToolbar: {
+      styleOverrides: {
+        regular: {
+          [defaultTheme.breakpoints.down(reducedHeightBreakpoint)]: {
+            minHeight: topBar.reducedHeight
+          },
+          [defaultTheme.breakpoints.up(reducedHeightBreakpoint)]: {
+            minHeight: topBar.defaultHeight
+          }
+        }
+      }
+    },
     MuiTooltip: {
       tooltip: {
         fontSize: '1 rem'
@@ -64,11 +93,9 @@ const theme = createTheme({
 
 const App = () => (
   <LocalizationProvider dateAdapter={AdapterMoment}>
-    <StyledEngineProvider injectFirst>
-      <ThemeProvider theme={theme}>
-        <SemanticPortal />
-      </ThemeProvider>
-    </StyledEngineProvider>
+    <ThemeProvider theme={theme}>
+      <SemanticPortal />
+    </ThemeProvider>
   </LocalizationProvider>
 )
 
diff --git a/src/client/components/main_layout/TextPage.js b/src/client/components/main_layout/TextPage.js
index 5f7f70cddebd67007a1a7fa803863219d29dd531..c7b992495de7359c6becfd2e86c30b388f9e1211 100644
--- a/src/client/components/main_layout/TextPage.js
+++ b/src/client/components/main_layout/TextPage.js
@@ -1,50 +1,77 @@
 import React from 'react'
 import PropTypes from 'prop-types'
-import makeStyles from '@mui/styles/makeStyles';
 import Paper from '@mui/material/Paper'
-
-const useStyles = makeStyles(theme => ({
-  root: {
-    width: '100%',
-    height: '100%',
-    display: 'flex',
-    justifyContent: 'center'
-  },
-  layout: {
-    width: 'auto',
-    padding: theme.spacing(3),
-    marginLeft: theme.spacing(3),
-    marginRight: theme.spacing(3),
-    [theme.breakpoints.down('md')]: {
-      padding: theme.spacing(1.5),
-      marginLeft: 0,
-      marginRight: 0
-    },
-    [theme.breakpoints.up(1100 + theme.spacing(6))]: {
-      width: 1100,
-      marginLeft: 'auto',
-      marginRight: 'auto'
-    },
-    overflow: 'auto'
-  }
-}))
+import Box from '@mui/material/Box'
+import { getSpacing } from '../../helpers/helpers'
 
 /**
  * A component for creating a responsive page with static content.
  */
 const TextPage = props => {
-  const classes = useStyles()
-
+  const { layoutConfig } = props
   return (
-    <div className={classes.root}>
-      <Paper className={classes.layout}>
-        {props.children}
-      </Paper>
-    </div>
+    <Box
+      sx={theme => ({
+        margin: theme.spacing(0.5),
+        width: `calc(100% - ${getSpacing(theme, 1)}px)`,
+        [theme.breakpoints.up(layoutConfig.hundredPercentHeightBreakPoint)]: {
+          height: `calc(100% - ${layoutConfig.topBar.reducedHeight + getSpacing(theme, 1)}px)`
+        },
+        [theme.breakpoints.up(layoutConfig.reducedHeightBreakpoint)]: {
+          height: `calc(100% - ${layoutConfig.topBar.defaultHeight + getSpacing(theme, 1)}px)`
+        }
+      })}
+    >
+      <Box
+        sx={{
+          width: '100%',
+          height: '100%',
+          display: 'flex',
+          justifyContent: 'center'
+        }}
+      >
+        <Paper
+          sx={theme => ({
+            width: 'auto',
+            padding: theme.spacing(3),
+            marginLeft: theme.spacing(3),
+            marginRight: theme.spacing(3),
+            [theme.breakpoints.down('md')]: {
+              padding: theme.spacing(1.5),
+              marginLeft: 0,
+              marginRight: 0
+            },
+            [theme.breakpoints.up(1100 + getSpacing(theme, 6))]: {
+              width: 1100,
+              marginLeft: 'auto',
+              marginRight: 'auto'
+            },
+            overflow: 'auto',
+            '& h1': {
+              ...theme.typography.h2,
+              marginTop: 0,
+              marginBottom: theme.spacing(1)
+            },
+            '& h2': {
+              ...theme.typography.h4
+            },
+            '& h3': {
+              ...theme.typography.h6
+            },
+            '& p, li': {
+              ...theme.typography.body1
+            }
+          })}
+        >
+          {props.children}
+        </Paper>
+      </Box>
+    </Box>
   )
 }
 
 TextPage.propTypes = {
+  layoutConfig: PropTypes.object.isRequired,
   /**
    * The content of the page.
    */
diff --git a/src/client/components/main_layout/TopBar.js b/src/client/components/main_layout/TopBar.js
index 312f6d578a339eeaabfdd16231761acd8ebe7c11..862f9add1965ccc1a59a652217bf166c33e7accb 100644
--- a/src/client/components/main_layout/TopBar.js
+++ b/src/client/components/main_layout/TopBar.js
@@ -7,9 +7,10 @@ import IconButton from '@mui/material/IconButton'
 import Typography from '@mui/material/Typography'
 import MenuItem from '@mui/material/MenuItem'
 import Menu from '@mui/material/Menu'
-import makeStyles from '@mui/styles/makeStyles'
 import MoreIcon from '@mui/icons-material/MoreVert'
 import Button from '@mui/material/Button'
+import Box from '@mui/material/Box'
+import { useTheme } from '@mui/material/styles'
 import { Link, NavLink } from 'react-router-dom'
 import TopBarSearchField from './TopBarSearchField'
 import TopBarInfoButton from './TopBarInfoButton'
@@ -18,113 +19,22 @@ import Divider from '@mui/material/Divider'
 import { has } from 'lodash'
 import secoLogo from '../../img/logos/seco-logo-48x50.png'
 
-const useStyles = makeStyles(theme => ({
-  grow: {
-    flexGrow: 1
-  },
-  topBarToolbar: props => ({
-    minHeight: props.layoutConfig.topBar.reducedHeight,
-    [theme.breakpoints.up(props.layoutConfig.reducedHeightBreakpoint)]: {
-      minHeight: props.layoutConfig.topBar.defaultHeight
-    },
-    paddingLeft: theme.spacing(1.5),
-    paddingRight: theme.spacing(1.5)
-  }),
-  sectionDesktop: props => ({
-    display: 'none',
-    [theme.breakpoints.up(props.layoutConfig.topBar.mobileMenuBreakpoint)]: {
-      display: 'flex'
-    }
-  }),
-  link: {
-    textDecoration: 'none'
-  },
-  sectionMobile: props => ({
-    display: 'flex',
-    [theme.breakpoints.up(props.layoutConfig.topBar.mobileMenuBreakpoint)]: {
-      display: 'none'
-    }
-  }),
-  appBarButton: {
-    whiteSpace: 'nowrap',
-    color: 'white !important',
-    border: `1px solid ${theme.palette.primary.main}`
-  },
-  appBarButtonActive: {
-    border: '1px solid white'
-  },
-  appBarDivider: {
-    marginLeft: theme.spacing(1),
-    marginRight: theme.spacing(1),
-    borderLeft: '2px solid white'
-  },
-  secoLogo: props => ({
-    marginLeft: theme.spacing(1),
-    [theme.breakpoints.down(props.layoutConfig.topBar.mobileMenuBreakpoint)]: {
-      display: 'none'
-    }
-  }),
-  secoLogoImage: props => ({
-    height: 32,
-    [theme.breakpoints.up(props.layoutConfig.reducedHeightBreakpoint)]: {
-      height: 50
-    }
-  }),
-  mainLogo: props => ({
-    height: props.layoutConfig.topBar.logoImageReducedHeight || 23,
-    [theme.breakpoints.up(props.layoutConfig.reducedHeightBreakpoint)]: {
-      height: props.layoutConfig.topBar.logoImageHeight || 40
-    },
-    marginRight: theme.spacing(1)
-  }),
-  mainLogoButtonRoot: {
-    paddingLeft: 0,
-    [theme.breakpoints.down('sm')]: {
-      minWidth: 48
-    }
-  },
-  mainLogoButtonLabel: {
-    justifyContent: 'left'
-  },
-  mainLogoTypography: props => ({
-    // set color and background explicitly to keep Google Lighthouse happy
-    color: '#fff',
-    background: theme.palette.primary.main,
-    whiteSpace: 'nowrap',
-    textTransform: props.layoutConfig.topBar.logoTextTransform,
-    [theme.breakpoints.down('md')]: {
-      fontSize: '1.5rem'
-    },
-    ...(props.layoutConfig.topBar.hideLogoTextOnMobile && {
-      [theme.breakpoints.down('sm')]: {
-        display: 'none'
-      }
-    })
-  }),
-  logoSecondary: props => ({
-    height: 26,
-    [theme.breakpoints.up('sm')]: {
-      height: 32
-    },
-    [theme.breakpoints.up(props.layoutConfig.reducedHeightBreakpoint)]: {
-      height: 52
-    }
-  }),
-  mobileMenuButton: {
-    padding: 12
-  }
-}))
-
 /**
  * Responsive app bar with a search field, perspective links, info links and a language
  * selector. Based on Material-UI's App Bar component.
  */
 const TopBar = props => {
+  const theme = useTheme()
+  // custom style function for utilizing React Router's isActive prop
+  const createAppBarButtonStyle = isActive => ({
+    whiteSpace: 'nowrap',
+    color: 'white !important',
+    border: isActive ? '1px solid white' : `1px solid ${theme.palette.primary.main}`
+  })
   const [mobileMoreAnchorEl, setMobileMoreAnchorEl] = React.useState(null)
   const isMobileMenuOpen = Boolean(mobileMoreAnchorEl)
   const { perspectives, currentLocale, availableLocales, rootUrl, layoutConfig } = props
   const { topBar } = layoutConfig
-  const classes = useStyles(props)
   const handleMobileMenuOpen = event => setMobileMoreAnchorEl(event.currentTarget)
   const handleMobileMenuClose = () => setMobileMoreAnchorEl(null)
   const federatedSearchMode = props.location.pathname.indexOf('federated-search') !== -1
@@ -133,9 +43,11 @@ const TopBar = props => {
     showSearchField = layoutConfig.topBar.showSearchField
   }
 
-  // https://material-ui.com/components/buttons/#third-party-routing-library
-  const AdapterLink = React.forwardRef((props, ref) => <Link innerRef={ref} {...props} />)
-  const AdapterNavLink = React.forwardRef((props, ref) => <NavLink innerRef={ref} {...props} />)
+  // https://mui.com/guides/routing/#button
+  const AdapterLink = React.forwardRef((props, ref) =>
+    <Link ref={ref} {...props} role={undefined} />)
+  const AdapterNavLink = React.forwardRef((props, ref) =>
+    <NavLink ref={ref} {...props} role={undefined} />)
 
   const getInternalLink = perspective => {
     const searchMode = has(perspective, 'searchMode') ? perspective.searchMode : 'faceted-search'
@@ -152,19 +64,22 @@ const TopBar = props => {
   const renderMobileMenuItem = perspective => {
     if (has(perspective, 'externalUrl')) {
       return (
-        <a
-          className={classes.link}
+        <Box
+          component='a'
           key={perspective.id}
           href={perspective.externalUrl}
           target='_blank'
           rel='noopener noreferrer'
+          sx={{
+            textDecoration: 'none'
+          }}
         >
           <MenuItem>
             {perspective.label
               ? perspective.label.toUpperCase()
               : intl.get(`perspectives.${perspective.id}.label`).toUpperCase()}
           </MenuItem>
-        </a>
+        </Box>
       )
     } else {
       return (
@@ -183,31 +98,33 @@ const TopBar = props => {
   const renderDesktopTopMenuItem = perspective => {
     if (has(perspective, 'externalUrl')) {
       return (
-        <a
-          className={classes.link}
+        <Box
+          component='a'
           key={perspective.id}
           href={perspective.externalUrl}
           target='_blank'
           rel='noopener noreferrer'
+          sx={{
+            textDecoration: 'none'
+          }}
         >
           <Button
-            className={classes.appBarButton}
+            sx={createAppBarButtonStyle(false)}
           >
             {perspective.label
               ? perspective.label
               : intl.get(`perspectives.${perspective.id}.label`).toUpperCase()}
           </Button>
-        </a>
+        </Box>
       )
     } else {
       return (
         <Button
           key={perspective.id}
-          className={classes.appBarButton}
           component={AdapterNavLink}
           to={getInternalLink(perspective)}
           isActive={(match, location) => location.pathname.startsWith(`${props.rootUrl}/${perspective.id}`)}
-          activeClassName={classes.appBarButtonActive}
+          style={isActive => createAppBarButtonStyle(isActive)}
         >
           {intl.get(`perspectives.${perspective.id}.label`).toUpperCase()}
         </Button>
@@ -219,17 +136,19 @@ const TopBar = props => {
     let jsx
     if (item.externalLink) {
       jsx = (
-        <a
-          className={classes.link}
+        <Box
           key={item.id}
           href={intl.get(`topBar.info.${item.translatedUrl}`)}
           target='_blank'
           rel='noopener noreferrer'
+          sx={{
+            textDecoration: 'none'
+          }}
         >
           <MenuItem onClick={handleMobileMenuClose}>
             {intl.get(`topBar.info.${item.translatedText}`).toUpperCase()}
           </MenuItem>
-        </a>
+        </Box>
       )
     } else {
       jsx = (
@@ -284,28 +203,56 @@ const TopBar = props => {
   }
 
   return (
-    <div className={classes.root}>
-      {/* Add an empty Typography element to ensure that that the MuiTypography class is loaded for
-         any lower level components that use MuiTypography class only in translation files */}
-      <Typography />
+    <>
       <AppBar position='static'>
-        <Toolbar className={classes.topBarToolbar}>
+        <Toolbar
+          disableGutters
+          sx={theme => ({
+            paddingLeft: theme.spacing(1.5),
+            paddingRight: theme.spacing(1.5)
+          })}
+        >
           <Button
+            sx={theme => ({
+              paddingLeft: 0,
+              [theme.breakpoints.down('sm')]: {
+                minWidth: 48
+              }
+            })}
             component={AdapterLink} to='/'
-            classes={{
-              root: classes.mainLogoButtonRoot,
-              label: classes.mainLogoButtonLabel
-            }}
             onClick={() => federatedSearchMode ? props.clientFSClearResults() : null}
           >
             {topBar.logoImage &&
-              <img
-                className={classes.mainLogo}
+              <Box
+                component='img'
                 src={topBar.logoImage}
                 alt={`${intl.get('appTitle.short')} logo`}
+                sx={theme => ({
+                  height: props.layoutConfig.topBar.logoImageReducedHeight || 23,
+                  [theme.breakpoints.up(props.layoutConfig.reducedHeightBreakpoint)]: {
+                    height: props.layoutConfig.topBar.logoImageHeight || 40
+                  },
+                  marginRight: theme.spacing(1)
+                })}
               />}
             {!topBar.hideLogoText &&
-              <Typography className={classes.mainLogoTypography} variant='h5'>
+              <Typography
+                sx={theme => ({
+                  color: '#fff',
+                  background: theme.palette.primary.main,
+                  whiteSpace: 'nowrap',
+                  textTransform: props.layoutConfig.topBar.logoTextTransform,
+                  [theme.breakpoints.down('md')]: {
+                    fontSize: '1.5rem'
+                  },
+                  ...(props.layoutConfig.topBar.hideLogoTextOnMobile && {
+                    [theme.breakpoints.down('sm')]: {
+                      display: 'none'
+                    }
+                  })
+                })}
+                variant='h5'
+              >
                 {props.xsScreen ? intl.get('appTitle.mobile') : intl.get('appTitle.short')}
               </Typography>}
           </Button>
@@ -316,7 +263,20 @@ const TopBar = props => {
               rel='noopener noreferrer'
             >
               <Button>
-                <img className={classes.logoSecondary} src={topBar.logoImageSecondary} alt='logoSecondary' />
+                <Box
+                  component='img'
+                  src={topBar.logoImageSecondary}
+                  alt='logoSecondary'
+                  sx={theme => ({
+                    height: 26,
+                    [theme.breakpoints.up('sm')]: {
+                      height: 32
+                    },
+                    [theme.breakpoints.up(props.layoutConfig.reducedHeightBreakpoint)]: {
+                      height: 52
+                    }
+                  })}
+                />
               </Button>
             </a>}
           {showSearchField &&
@@ -326,10 +286,23 @@ const TopBar = props => {
               xsScreen={props.xsScreen}
               rootUrl={rootUrl}
             />}
-          <div className={classes.grow} />
-          <div className={classes.sectionDesktop}>
+          <Box sx={{ flexGrow: 1 }} />
+          <Box
+            sx={theme => ({
+              display: 'none',
+              [theme.breakpoints.up(props.layoutConfig.topBar.mobileMenuBreakpoint)]: {
+                display: 'flex'
+              }
+            })}
+          >
             {perspectives.map((perspective, index) => perspective.hideTopPerspectiveButton ? null : renderDesktopTopMenuItem(perspective, index))}
-            <div className={classes.appBarDivider} />
+            <Box
+              sx={theme => ({
+                marginLeft: theme.spacing(1),
+                marginRight: theme.spacing(1),
+                borderLeft: '2px solid white'
+              })}
+            />
             {renderDesktopTopMenuItem({
               id: 'feedback',
               externalUrl: props.layoutConfig.topBar.feedbackLink,
@@ -343,11 +316,10 @@ const TopBar = props => {
             })}
             {!topBar.externalInstructions &&
               <Button
-                className={classes.appBarButton}
                 component={AdapterNavLink}
                 to={`${props.rootUrl}/instructions`}
                 isActive={(match, location) => location.pathname.startsWith(`${props.rootUrl}/instructions`)}
-                activeClassName={classes.appBarButtonActive}
+                style={isActive => createAppBarButtonStyle(isActive)}
               >
                 {intl.get('topBar.instructions')}
               </Button>}
@@ -358,22 +330,41 @@ const TopBar = props => {
                 loadLocales={props.loadLocales}
                 location={props.location}
               />}
-          </div>
-          <a
-            className={classes.secoLogo}
+          </Box>
+          <Box
+            component='a'
             href='https://seco.cs.aalto.fi'
             target='_blank'
             rel='noopener noreferrer'
+            sx={theme => ({
+              marginLeft: theme.spacing(1),
+              [theme.breakpoints.down(props.layoutConfig.topBar.mobileMenuBreakpoint)]: {
+                display: 'none'
+              }
+            })}
           >
             <Button aria-label='link to Semantic Computing research group homepage'>
-              <img
-                className={classes.secoLogoImage}
+              <Box
+                component='img'
                 src={secoLogo}
                 alt='Semantic Computing research group logo'
+                sx={theme => ({
+                  height: 32,
+                  [theme.breakpoints.up(props.layoutConfig.reducedHeightBreakpoint)]: {
+                    height: 50
+                  }
+                })}
               />
             </Button>
-          </a>
-          <div className={classes.sectionMobile}>
+          </Box>
+          <Box
+            sx={theme => ({
+              display: 'flex',
+              [theme.breakpoints.up(props.layoutConfig.topBar.mobileMenuBreakpoint)]: {
+                display: 'none'
+              }
+            })}
+          >
             {props.layoutConfig.topBar.showLanguageButton &&
               <TopBarLanguageButton
                 currentLocale={currentLocale}
@@ -384,17 +375,17 @@ const TopBar = props => {
             <IconButton
               aria-label='display more actions'
               color='inherit'
-              className={classes.mobileMenuButton}
+              edge='end'
               onClick={handleMobileMenuOpen}
               size='large'
             >
               <MoreIcon />
             </IconButton>
-          </div>
+          </Box>
         </Toolbar>
       </AppBar>
       {renderMobileMenu(perspectives)}
-    </div>
+    </>
   )
 }
 
diff --git a/src/client/components/main_layout/TopBarSearchField.js b/src/client/components/main_layout/TopBarSearchField.js
index 0c89fb4708e67a8354a7c68dccf749c4ec7f0699..0b6bd6a7ab5c60eadd412594cda9fd9f420fd3a6 100644
--- a/src/client/components/main_layout/TopBarSearchField.js
+++ b/src/client/components/main_layout/TopBarSearchField.js
@@ -1,56 +1,12 @@
 import React from 'react'
 import PropTypes from 'prop-types'
 import intl from 'react-intl-universal'
-import { alpha } from '@mui/material/styles';
-import withStyles from '@mui/styles/withStyles';
+import { alpha } from '@mui/material/styles'
+import Box from '@mui/material/Box'
 import SearchIcon from '@mui/icons-material/Search'
 import InputBase from '@mui/material/InputBase'
-// import CircularProgress from '@mui/material/CircularProgress';
 import history from '../../History'
 
-const styles = theme => ({
-  search: {
-    position: 'relative',
-    borderRadius: theme.shape.borderRadius,
-    backgroundColor: alpha(theme.palette.common.white, 0.15),
-    '&:hover': {
-      backgroundColor: alpha(theme.palette.common.white, 0.25)
-    },
-    // marginRight: theme.spacing(3),
-    // marginLeft: theme.spacing(2.5),
-    width: '100%',
-    maxWidth: 300,
-    [theme.breakpoints.up('sm')]: {
-      marginLeft: theme.spacing(3),
-      width: 'auto'
-    }
-  },
-  searchIcon: {
-    width: theme.spacing(9),
-    height: '100%',
-    position: 'absolute',
-    pointerEvents: 'none',
-    display: 'flex',
-    alignItems: 'center',
-    justifyContent: 'center'
-  },
-  inputRoot: {
-    color: 'inherit',
-    width: '100%'
-  },
-  inputInput: {
-    paddingTop: theme.spacing(1),
-    paddingRight: theme.spacing(1),
-    paddingBottom: theme.spacing(1),
-    paddingLeft: theme.spacing(10),
-    transition: theme.transitions.create('width'),
-    width: '100%',
-    [theme.breakpoints.up('md')]: {
-      width: 200
-    }
-  }
-})
-
 /**
  * A search field that can be embedded into the TopBar.
  */
@@ -93,30 +49,66 @@ class TopBarSearchField extends React.Component {
   }
 
   render () {
-    const { classes, xsScreen } = this.props
-    const placeholder = xsScreen ? intl.get('topBar.searchBarPlaceHolderShort') : intl.get('topBar.searchBarPlaceHolder')
+    const { xsScreen } = this.props
+    const placeholder = xsScreen
+      ? intl.get('topBar.searchBarPlaceHolderShort')
+      : intl.get('topBar.searchBarPlaceHolder')
     return (
-      <div className={classes.search}>
-        <div className={classes.searchIcon}>
+      <Box
+        sx={theme => ({
+          position: 'relative',
+          borderRadius: theme.shape.borderRadius,
+          backgroundColor: alpha(theme.palette.common.white, 0.15),
+          '&:hover': {
+            backgroundColor: alpha(theme.palette.common.white, 0.25)
+          },
+          marginRight: theme.spacing(2),
+          marginLeft: 0,
+          width: '100%',
+          [theme.breakpoints.up('sm')]: {
+            marginLeft: theme.spacing(3),
+            width: 'auto'
+          }
+        })}
+      >
+        <Box
+          sx={theme => ({
+            padding: theme.spacing(0, 2),
+            height: '100%',
+            position: 'absolute',
+            pointerEvents: 'none',
+            display: 'flex',
+            alignItems: 'center',
+            justifyContent: 'center'
+          })}
+        >
           <SearchIcon />
-        </div>
+        </Box>
         <InputBase
           placeholder={placeholder}
-          classes={{
-            root: classes.inputRoot,
-            input: classes.inputInput
-          }}
           inputProps={{ 'aria-label': 'search' }}
           onChange={this.handleChange}
           onKeyDown={this.handleOnKeyDown}
+          sx={theme => ({
+            color: 'inherit',
+            '& .MuiInputBase-input': {
+              padding: theme.spacing(1, 1, 1, 0),
+              // vertical padding + font size from searchIcon
+              paddingLeft: `calc(1em + ${theme.spacing(4)})`,
+              transition: theme.transitions.create('width'),
+              width: '100%',
+              [theme.breakpoints.up('md')]: {
+                width: '20ch'
+              }
+            }
+          })}
         />
-      </div>
+      </Box>
     )
   }
 }
 
 TopBarSearchField.propTypes = {
-  classes: PropTypes.object.isRequired,
   fetchFullTextResults: PropTypes.func,
   xsScreen: PropTypes.bool.isRequired,
   rootUrl: PropTypes.string.isRequired
@@ -124,4 +116,4 @@ TopBarSearchField.propTypes = {
 
 export const TopBarSearchFieldComponent = TopBarSearchField
 
-export default withStyles(styles)(TopBarSearchField)
+export default TopBarSearchField
diff --git a/src/client/components/perspectives/sampo/Footer.js b/src/client/components/perspectives/sampo/Footer.js
index 6a3018660c0ec4ad740133ac690a8f97ee2a4c48..c400c34f1ba11f8f92c3d42aec65856fc272624f 100644
--- a/src/client/components/perspectives/sampo/Footer.js
+++ b/src/client/components/perspectives/sampo/Footer.js
@@ -2,33 +2,13 @@ import React from 'react'
 import Paper from '@mui/material/Paper'
 import PropTypes from 'prop-types'
 import Grid from '@mui/material/Grid'
-import makeStyles from '@mui/styles/makeStyles';
+import makeStyles from '@mui/styles/makeStyles'
+import { getSpacing } from '../../../helpers/helpers'
 import aaltoLogo from '../../../img/logos/Aalto_SCI_EN_13_BLACK_2_cropped.png'
 import hyLogo from '../../../img/logos/university-of-helsinki-logo-transparent-black.png'
 import heldigLogo from '../../../img/logos/heldig-logo-transparent-black.png'
 
 const useStyles = makeStyles(theme => ({
-  root: {
-    display: 'block',
-    boxShadow: '0 -20px 20px -20px #333',
-    borderRadius: 0
-  },
-  layout: props => ({
-    [theme.breakpoints.up(props.layoutConfig.hundredPercentHeightBreakPoint)]: {
-      height: props.layoutConfig.footer.reducedHeight
-      // height: 115, for two row footer
-    },
-    [theme.breakpoints.up(props.layoutConfig.reducedHeightBreakpoint)]: {
-      height: props.layoutConfig.footer.defaultHeight
-    },
-    marginLeft: theme.spacing(2),
-    marginRight: theme.spacing(2),
-    [theme.breakpoints.up(1500 + theme.spacing(6))]: {
-      width: 1500,
-      marginLeft: 'auto',
-      marginRight: 'auto'
-    }
-  }),
   gridContainer: {
     height: '100%',
     marginTop: 0,
@@ -85,26 +65,46 @@ const useStyles = makeStyles(theme => ({
 const Footer = props => {
   const classes = useStyles(props)
   return (
-    <Paper className={classes.root}>
-      <div className={classes.layout}>
-        <Grid className={classes.gridContainer} container spacing={3}>
-          <Grid item xs className={classes.gridItem}>
-            <a className={classes.link} href='https://www.aalto.fi/en/school-of-science' target='_blank' rel='noopener noreferrer'>
-              <img className={classes.aaltoLogo} src={aaltoLogo} alt='Aalto University logo' />
-            </a>
-          </Grid>
-          <Grid item xs className={classes.gridItem}>
-            <a className={classes.link} href='https://www.helsinki.fi/en' target='_blank' rel='noopener noreferrer'>
-              <img className={classes.hyLogo} src={hyLogo} alt='University of Helsinki logo' />
-            </a>
-          </Grid>
-          <Grid item xs className={classes.gridItem}>
-            <a className={classes.link} href='https://www.helsinki.fi/en/helsinki-centre-for-digital-humanities' target='_blank' rel='noopener noreferrer'>
-              <img className={classes.heldigLogo} src={heldigLogo} alt='Helsinki Centre for Digital Humanities logo' />
-            </a>
-          </Grid>
+    <Paper
+      sx={theme => ({
+        boxShadow: '0 -20px 20px -20px #333',
+        borderRadius: 0,
+        height: {
+          hundredPercentHeight: props.layoutConfig.footer.reducedHeight,
+          reducedHeight: props.layoutConfig.footer.defaultHeight
+        }
+      })}
+    >
+      <Grid
+        className={classes.gridContainer}
+        container spacing={3}
+        sx={theme => ({
+          height: '100%',
+          marginTop: 0,
+          marginBottom: 0,
+          [theme.breakpoints.up(1500 + getSpacing(theme, 6))]: {
+            width: 1500,
+            marginLeft: 'auto',
+            marginRight: 'auto'
+          }
+        })}
+      >
+        <Grid item xs className={classes.gridItem}>
+          <a className={classes.link} href='https://www.aalto.fi/en/school-of-science' target='_blank' rel='noopener noreferrer'>
+            <img className={classes.aaltoLogo} src={aaltoLogo} alt='Aalto University logo' />
+          </a>
+        </Grid>
+        <Grid item xs className={classes.gridItem}>
+          <a className={classes.link} href='https://www.helsinki.fi/en' target='_blank' rel='noopener noreferrer'>
+            <img className={classes.hyLogo} src={hyLogo} alt='University of Helsinki logo' />
+          </a>
+        </Grid>
+        <Grid item xs className={classes.gridItem}>
+          <a className={classes.link} href='https://www.helsinki.fi/en/helsinki-centre-for-digital-humanities' target='_blank' rel='noopener noreferrer'>
+            <img className={classes.heldigLogo} src={heldigLogo} alt='Helsinki Centre for Digital Humanities logo' />
+          </a>
         </Grid>
-      </div>
+      </Grid>
     </Paper>
   )
 }
diff --git a/src/client/components/perspectives/sampo/Main.js b/src/client/components/perspectives/sampo/Main.js
index 62df9eea49e5716cf4320c5b04bf26c04e0913a3..56db65f0af0c1f00990609dd13ea8b22a175a7af 100644
--- a/src/client/components/perspectives/sampo/Main.js
+++ b/src/client/components/perspectives/sampo/Main.js
@@ -49,19 +49,18 @@ const Main = props => {
       sx={theme => {
         const { layoutConfig } = props
         const defaultHeightReduction = layoutConfig.topBar.defaultHeight +
-          layoutConfig.footer.defaultHeight + getSpacing(theme, 1)
+          layoutConfig.footer.defaultHeight + getSpacing(theme, 2)
         const reducedHeightReduction = layoutConfig.topBar.reducedHeight +
-          layoutConfig.footer.reducedHeight + getSpacing(theme, 1)
+          layoutConfig.footer.reducedHeight + getSpacing(theme, 2)
         return {
-          [theme.breakpoints.up(props.layoutConfig.hundredPercentHeightBreakPoint)]: {
-            overflow: 'auto',
-            height: `calc(100% - ${reducedHeightReduction}px)`
+          paddingBottom: theme.spacing(2),
+          height: {
+            hundredPercentHeight: `calc(100% - ${reducedHeightReduction}px)`,
+            reducedHeight: `calc(100% - ${defaultHeightReduction}px)`
           },
-          [theme.breakpoints.up(props.layoutConfig.reducedHeightBreakpoint)]: {
-            overflow: 'auto',
-            height: `calc(100% - ${defaultHeightReduction}px)`
-          },
-          marginBottom: theme.spacing(1)
+          overflow: {
+            hundredPercentHeight: 'auto'
+          }
         }
       }}
     >
diff --git a/src/client/containers/SemanticPortal.js b/src/client/containers/SemanticPortal.js
index 7b24a5d1c1de884e76d8da0b98494703dfe773f1..069ab294a4c79d300130cdbd843d16ebd5569651 100644
--- a/src/client/containers/SemanticPortal.js
+++ b/src/client/containers/SemanticPortal.js
@@ -5,7 +5,6 @@ import { has } from 'lodash'
 import { connect } from 'react-redux'
 import { makeStyles } from '@material-ui/core/styles'
 import { withRouter, Route, Redirect, Switch } from 'react-router-dom'
-import classNames from 'classnames'
 import { compose } from '@shakacode/recompose'
 import { useTheme } from '@mui/material/styles'
 import useMediaQuery from '@mui/material/useMediaQuery'
@@ -114,16 +113,6 @@ const useStyles = makeStyles(theme => ({
       height: `calc(100% - ${layoutConfig.topBar.defaultHeight + layoutConfig.footer.defaultHeight + theme.spacing(1)}px)`
     }
   },
-  textPageContainer: {
-    margin: theme.spacing(0.5),
-    width: `calc(100% - ${theme.spacing(1)}px)`,
-    [theme.breakpoints.up(layoutConfig.hundredPercentHeightBreakPoint)]: {
-      height: `calc(100% - ${layoutConfig.topBar.reducedHeight + theme.spacing(1.5)}px)`
-    },
-    [theme.breakpoints.up(layoutConfig.reducedHeightBreakpoint)]: {
-      height: `calc(100% - ${layoutConfig.topBar.defaultHeight + theme.spacing(1.5)}px)`
-    }
-  },
   perspectiveContainer: {
     margin: theme.spacing(0.5),
     width: `calc(100% - ${theme.spacing(1)}px)`,
@@ -244,7 +233,7 @@ const SemanticPortal = props => {
   const { error } = props
   const theme = useTheme()
   const classes = useStyles(props)
-  const xsScreen = useMediaQuery(theme.breakpoints.down('xs'))
+  const xsScreen = useMediaQuery(theme.breakpoints.down('sm'))
   const smScreen = useMediaQuery(theme.breakpoints.between('sm', 'md'))
   const mdScreen = useMediaQuery(theme.breakpoints.between('md', 'lg'))
   const lgScreen = useMediaQuery(theme.breakpoints.between('lg', 'xl'))
@@ -626,31 +615,29 @@ const SemanticPortal = props => {
           <Route
             path={`${rootUrlWithLang}/about`}
             render={() =>
-              <div className={classNames(classes.mainContainer, classes.textPageContainer)}>
-                <TextPage>
-                  {intl.getHTML('aboutThePortalPartOne')}
-                  {knowledgeGraphMetadataConfig.showTable &&
-                    <KnowledgeGraphMetadataTable
-                      portalConfig={portalConfig}
-                      layoutConfig={layoutConfig}
-                      perspectiveID={knowledgeGraphMetadataConfig.perspective}
-                      resultClass='knowledgeGraphMetadata'
-                      fetchKnowledgeGraphMetadata={props.fetchKnowledgeGraphMetadata}
-                      knowledgeGraphMetadata={props[knowledgeGraphMetadataConfig.perspective]
-                        ? props[knowledgeGraphMetadataConfig.perspective].knowledgeGraphMetadata
-                        : null}
-                    />}
-                  {intl.getHTML('aboutThePortalPartTwo')}
-                </TextPage>
-              </div>}
+              <TextPage layoutConfig={layoutConfig}>
+                {intl.getHTML('aboutThePortalPartOne')}
+                {knowledgeGraphMetadataConfig.showTable &&
+                  <KnowledgeGraphMetadataTable
+                    portalConfig={portalConfig}
+                    layoutConfig={layoutConfig}
+                    perspectiveID={knowledgeGraphMetadataConfig.perspective}
+                    resultClass='knowledgeGraphMetadata'
+                    fetchKnowledgeGraphMetadata={props.fetchKnowledgeGraphMetadata}
+                    knowledgeGraphMetadata={props[knowledgeGraphMetadataConfig.perspective]
+                      ? props[knowledgeGraphMetadataConfig.perspective].knowledgeGraphMetadata
+                      : null}
+                  />}
+                {intl.getHTML('aboutThePortalPartTwo')}
+              </TextPage>}
           />}
         {!layoutConfig.topBar.externalInstructions &&
           <Route
             path={`${rootUrlWithLang}/instructions`}
             render={() =>
-              <div className={classNames(classes.mainContainer, classes.textPageContainer)}>
-                <TextPage>{intl.getHTML('instructions')}</TextPage>
-              </div>}
+              <TextPage layoutConfig={layoutConfig}>
+                {intl.getHTML('instructions')}
+              </TextPage>}
           />}
       </>
     </div>
diff --git a/src/client/img/logos/logo.png b/src/client/img/logos/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..1738c87bdb9b30662d587927cc0e822d5bac06a7
Binary files /dev/null and b/src/client/img/logos/logo.png differ
diff --git a/src/configs/portalConfig.json b/src/configs/portalConfig.json
index fe3e88ce656d75ed5744d46c2c9e3807f7e9443f..bbc7c36fdc536d05eca6a8da357d2900105d80ca 100644
--- a/src/configs/portalConfig.json
+++ b/src/configs/portalConfig.json
@@ -62,11 +62,14 @@
         "paginationToolbarHeight": 37,
         "tableFontSize": "0.8rem",
         "topBar": {
+            "logoImage": "logos/logo.png",
+            "logoTextTransform": "none",
+            "hideLogoTextOnMobile": true,
             "showLanguageButton": true,
             "feedbackLink": "https://link.webropolsurveys.com/...",
             "externalInstructions": false,
             "externalAboutPage": false,
-            "reducedHeight": 44,
+            "reducedHeight": 48,
             "defaultHeight": 64,
             "mobileMenuBreakpoint": 1360,
             "infoDropdown": [