[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/components/LoadingContext.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, {
  useContext,
  useCallback,
  useMemo,
  useRef,
  ComponentType,
  FunctionComponent,
  useEffect,
} from 'react'
import { canUseDOM } from 'exenv'

import GenericPreview from './Preview/GenericPreview'

interface LoadingContext {
  setLoading: (treePath: string, isLoading: boolean) => void
  isParentLoading?: boolean
}

const LoadingContext = React.createContext<LoadingContext>({
  setLoading: () => {},
  isParentLoading: false,
})

LoadingContext.displayName = 'LoadingContext'

const LoadingContextProvider = LoadingContext.Provider

interface LoadingState {
  components: { [key: string]: boolean }
}

const displayContent = (
  contentRef: React.RefObject<HTMLElement>,
  loaderRef: React.RefObject<HTMLElement>
) => {
  if (contentRef.current) {
    contentRef.current.style.position = ''
    contentRef.current.style.width = ''
    contentRef.current.style.opacity = ''
  }
  if (loaderRef.current) {
    loaderRef.current.style.display = 'none'
  }
}

const displayLoader = (
  contentRef: React.RefObject<HTMLElement>,
  loaderRef: React.RefObject<HTMLElement>
) => {
  if (contentRef.current) {
    contentRef.current.style.position = 'absolute'
    contentRef.current.style.width = '100%'
    contentRef.current.style.opacity = '0'
  }
  if (loaderRef.current) {
    loaderRef.current.style.display = ''
  }
}

/** TODO: LoadingWrapper is in the end a makeshift Suspense.
 * Should probably be replaced in the future. */
const LoadingWrapper: FunctionComponent = ({ children }) => {
  /* Uses Ref instead of state to prevent rerenders */
  const state = useRef<LoadingState>({ components: {} })

  /* A parent component can include a LoadingContext to tell its
   * children that it is loading data. */
  const { isParentLoading } = useContext(LoadingContext)

  const contentContainer = useRef<HTMLDivElement>(null)
  const loaderContainer = useRef<HTMLDivElement>(null)

  const loadingTimeout = useRef<number | null>(null)
  const loadingComplete = useRef(false)

  const updateLoading = useCallback(() => {
    const areComponentsLoading = Object.values(state.current.components).some(
      Boolean
    )

    const isLoading = isParentLoading || areComponentsLoading

    if (!isLoading) {
      displayContent(contentContainer, loaderContainer)
      loadingComplete.current = true
    } else {
      if (!loadingComplete.current && loadingTimeout.current !== null) {
        window.clearTimeout(loadingTimeout.current)
        loadingTimeout.current = null
      }

      if (isParentLoading && loadingComplete.current) {
        loadingComplete.current = false
        displayLoader(contentContainer, loaderContainer)
      }
    }
  }, [isParentLoading])

  const setLoading = useCallback(
    (treePath, loading) => {
      if (loadingComplete.current) {
        return
      }

      state.current.components[treePath] = loading

      updateLoading()
    },
    [updateLoading]
  )

  useEffect(() => {
    updateLoading()
  }, [isParentLoading, updateLoading])

  const value = useMemo(
    () => ({
      setLoading,
    }),
    [setLoading]
  )

  const isSSR = !canUseDOM

  const returnValue = useMemo(
    () => (
      /** Renders both the content and the loader, and hides them via changing the
       * style via their refs. This is done for two reasons:
       * 1: to make the content execute its code while it is loading, because the
       * content can in turn require more components to be loaded, thus keeping
       * the loading state for longer.
       * 2: To prevent re-rendering when the loading state changes, which seemed
       * to cause some bugs. */
      <LoadingContextProvider value={value}>
        <div
          // Content container
          ref={contentContainer}
          suppressHydrationWarning
          style={{
            opacity: isSSR ? 1 : 0,
            position: isSSR ? 'unset' : 'absolute',
            width: isSSR ? 'unset' : '100%',
          }}
        >
          {children}
        </div>
        <div
          // Loader container
          ref={loaderContainer}
          suppressHydrationWarning
          style={{ display: isSSR ? 'none' : 'unset' }}
        >
          {/** TODO: Use a better preview in the future */}
          <GenericPreview />
        </div>
      </LoadingContextProvider>
    ),
    [children, isSSR, value]
  )

  return returnValue
}

const useLoadingContext = () => {
  return useContext(LoadingContext)
}

const withLoading = <T extends {}>(Component: ComponentType<T>) => {
  const EnhancedComponent: FunctionComponent<T> = props => {
    const isSSR = !canUseDOM
    const { setLoading } = useLoadingContext()

    if (isSSR) {
      return <Component {...props} setLoading={() => {}} />
    }

    return <Component {...props} setLoading={setLoading} />
  }

  EnhancedComponent.displayName = `WithLoading(${Component.displayName ||
    Component.name ||
    'Component'})`

  return EnhancedComponent
}

export {
  LoadingWrapper,
  useLoadingContext,
  withLoading,
  LoadingContextProvider,
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/hooks/extension.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { ReactElement } from 'react'

import { useRuntime } from '../components/RenderContext'
import { useTreePath } from '../utils/treePath'

function mountTreePath(base: string, children: string[]) {
  return [base, ...children].filter(id => !!id).join('/')
}

interface Options {
  children?: string[] | string
}

const useExtension = ({ children }: Options = {}): any | null => {
  const { extensions } = useRuntime()

  const { treePath: baseTreePath } = useTreePath()

  const treePath = children
    ? mountTreePath(
        baseTreePath,
        Array.isArray(children) ? children : [children]
      )
    : baseTreePath

  const extension = treePath && extensions[treePath]

  return extension || null
}

interface ExtensionContext {
  extension?: any | null
}

interface Props {
  children({ extension }: ExtensionContext): ReactElement<any> | null
}

const ExtensionConsumer = ({ children }: Props) => {
  const extension = useExtension()

  return children({ extension })
}

export { useExtension, ExtensionConsumer }

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/utils/client/generateHash.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  ArgumentNode,
  BREAK,
  DocumentNode,
  StringValueNode,
  visit,
} from 'graphql'

interface HashedDocumentNode extends DocumentNode {
  documentId: string
}

const isHashedDocumentNode = (arg: any): arg is HashedDocumentNode => {
  return arg && arg.documentId
}

export const generateHash = (query: HashedDocumentNode | DocumentNode) => {
  if (isHashedDocumentNode(query)) {
    return query.documentId
  }

  const asset = { hash: '' }
  visit(query, {
    Argument(node: ArgumentNode) {
      if (node.name.value === 'hash') {
        asset.hash = (node.value as StringValueNode).value
        return BREAK
      }
    },
  })
  return asset.hash
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/utils/client/index.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  InMemoryCache,
  IntrospectionFragmentMatcher,
  IntrospectionResultData,
  NormalizedCacheObject,
} from 'apollo-cache-inmemory'
import { ApolloClient } from 'apollo-client'
import { ApolloLink } from 'apollo-link'
import { onError } from 'apollo-link-error'
import { createHttpLink } from 'apollo-link-http'
import { createPersistedQueryLink } from 'apollo-link-persisted-queries'
import { createUploadLink } from 'apollo-upload-client'
import { canUseDOM } from 'exenv'

import PageCacheControl from '../cacheControl'
import graphQLErrorsStore from '../graphQLErrorsStore'
import { generateHash } from './generateHash'
import { toBase64Link } from './links/base64Link'
import { cachingLink } from './links/cachingLink'
import { ensureSessionLink } from './links/ensureSessionLink'
import { createIOFetchLink } from './links/ioFetchLink'
import { omitTypenameLink } from './links/omitVariableTypenameLink'
import { createUriSwitchLink } from './links/uriSwitchLink'
import { versionSplitterLink } from './links/versionSplitterLink'

interface ApolloClientsRegistry {
  [key: string]: ApolloClient<NormalizedCacheObject>
}

const buildCacheId = (
  vendor: string | undefined,
  app: string | undefined,
  major: string | undefined,
  type: string,
  cacheId: string
) =>
  app && major
    ? `${vendor}.${app}@${major}.x:${type}:${cacheId}`
    : `${type}:${cacheId}`

const dataIdFromObject = (value: any) => {
  const { cacheId, __typename } = value || ({} as any)
  if (value && __typename && cacheId) {
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    const [vendor, app, major, ...type] = __typename.split('_')
    const typename = type.join('_') || __typename
    return buildCacheId(vendor, app, major, typename, cacheId)
  }
  return null
}

export const buildCacheLocator = (
  app: string,
  type: string,
  cacheId: string
) => {
  const [vendor, appAndMajor] = app.replace(/-/g, '').split('.')
  const [appName, major] = appAndMajor && appAndMajor.split('@')
  return buildCacheId(vendor, appName, major, type, cacheId)
}

const clientsByWorkspace: ApolloClientsRegistry = {}

export const getState = (runtime: any) => {
  const { account, workspace } = runtime
  const apolloClient = clientsByWorkspace[`${account}/${workspace}`]
  return apolloClient ? apolloClient.cache.extract() : {}
}

export const getClient = (
  runtime: any,
  baseURI: string,
  runtimeContextLink: ApolloLink,
  sessionPromise: Promise<any>,
  fetcher: any['fetch'],
  cacheControl?: PageCacheControl
) => {
  const {
    account,
    workspace,
    introspectionResult,
  }: {
    account: string
    workspace: string
    introspectionResult: IntrospectionResultData
  } = runtime

  if (!clientsByWorkspace[`${account}/${workspace}`]) {
    const cache = new InMemoryCache({
      addTypename: true,
      dataIdFromObject,
      fragmentMatcher: new IntrospectionFragmentMatcher({
        introspectionQueryResultData: introspectionResult,
      }),
    })

    const httpLink = ApolloLink.from([
      toBase64Link,
      createHttpLink({
        credentials: 'include',
        useGETForQueries: false,
        fetch: fetcher,
      }),
    ])

    const uploadLink = createUploadLink({
      credentials: 'include',
    })

    const fetcherLink = createIOFetchLink(httpLink, uploadLink)

    const persistedQueryLink = createPersistedQueryLink({
      disable: () => false,
      generateHash,
      useGETForHashedQueries: true,
    })

    const uriSwitchLink = createUriSwitchLink(baseURI, runtime)

    const cacheLink = cacheControl ? [cachingLink(cacheControl)] : []

    const errorLink = onError(({ graphQLErrors }) => {
      if (graphQLErrors) {
        graphQLErrorsStore.addOperationIds(graphQLErrors)
      }
    })

    const link = ApolloLink.from([
      errorLink,
      omitTypenameLink,
      versionSplitterLink,
      runtimeContextLink,
      persistedQueryLink,
      uriSwitchLink,
      ensureSessionLink(sessionPromise),
      ...cacheLink,
      fetcherLink, //this is a final link
    ])

    clientsByWorkspace[`${account}/${workspace}`] = new ApolloClient({
      cache: canUseDOM ? cache.restore(window.__STATE__) : cache,
      link,
      resolvers: {},
      ssrMode: !canUseDOM,
    })
  }

  return clientsByWorkspace[`${account}/${workspace}`]
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/utils/client/links/base64Link.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { ApolloLink, NextLink, Operation } from 'apollo-link'
import { Base64 } from 'js-base64'

export const toBase64Link = new ApolloLink(
  (operation: Operation, forward?: NextLink) => {
    const { extensions, variables } = operation
    if (variables && Object.keys(variables).length > 0) {
      operation.variables = {}
      operation.extensions = {
        ...extensions,
        variables: Base64.encode(JSON.stringify(variables)),
      }
    }
    return forward ? forward(operation) : null
  }
)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/utils/client/links/uriSwitchLink.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { ApolloLink, NextLink, Operation } from 'apollo-link'
import { path } from 'ramda'
import { canUseDOM } from 'exenv'
import {
  ASTNode,
  DirectiveNode,
  OperationDefinitionNode,
  StringValueNode,
  visit,
} from 'graphql'

import { generateHash } from '../generateHash'
import { appendLocationSearch } from '../../location'

interface Assets {
  operationType: string
  queryScope?: string
}

const assetsFromQuery = (query: ASTNode) => {
  const assets: Assets = { operationType: 'mutation' }
  visit(query, {
    Directive(node: DirectiveNode) {
      if (node.name.value === 'context') {
        const scopeArg =
          node.arguments &&
          node.arguments.find(argNode => argNode.name.value === 'scope')
        if (scopeArg) {
          assets.queryScope = (scopeArg.value as StringValueNode).value
        }
      }
    },
    OperationDefinition(node: OperationDefinitionNode) {
      assets.operationType = node.operation
    },
  })
  return assets
}

export interface OperationContext {
  fetchOptions: any
  runtime: Pick<
    any,
    | 'appsEtag'
    | 'cacheHints'
    | 'components'
    | 'culture'
    | 'extensions'
    | 'messages'
    | 'pages'
  >
}

const equals = (a: string, b: string) =>
  a && b && a.toLowerCase() === b.toLowerCase()

const extractHints = (query: ASTNode, meta: any) => {
  const { operationType, queryScope } = assetsFromQuery(query)

  let hints
  if (equals(operationType, 'query')) {
    hints = meta ? meta : { scope: queryScope }
  } else {
    hints = { ...meta, scope: 'private' }
  }

  const {
    maxAge = 'long',
    scope = 'public',
    version = 1,
    provider,
    sender,
  } = hints
  return {
    maxAge: maxAge.toLowerCase(),
    operationType,
    scope: scope.toLowerCase(),
    version,
    provider,
    sender,
  }
}

export const createUriSwitchLink = (
  baseURI: string,
  initialRuntime: any
) =>
  new ApolloLink((operation: Operation, forward?: NextLink) => {
    operation.setContext((oldContext: OperationContext) => {
      const {
        fetchOptions = {},
        // Fetches from context for not fetching a stale version of runtime
        runtime: {
          appsEtag,
          cacheHints,
          culture: { locale },
        },
      } = oldContext
      const { extensions } = operation
      const {
        binding,
        workspace,
        route: { domain },
      } = initialRuntime
      const hash = generateHash(operation.query)
      const {
        maxAge,
        scope,
        version,
        operationType,
        provider,
        sender,
      } = extractHints(operation.query, cacheHints[hash])
      const requiresAuthorization = path(
        ['settings', `vtex.${domain}`, 'requiresAuthorization'],
        initialRuntime
      )
      const customScope = requiresAuthorization ? 'private' : scope
      const oldMethod = fetchOptions.method || 'POST'
      const protocol = canUseDOM ? 'https:' : 'http:'
      const method =
        equals(scope, 'private') && equals(operationType, 'query')
          ? 'POST'
          : oldMethod
      extensions.persistedQuery = {
        ...extensions.persistedQuery,
        sender,
        provider,
      }

      let query = `?workspace=${workspace}&maxAge=${maxAge}&appsEtag=${appsEtag}&domain=${domain}&locale=${locale}`
      if (binding && binding.id) {
        query = appendLocationSearch(query, { __bindingId: binding.id })
      }

      return {
        ...oldContext,
        scope: customScope,
        fetchOptions: { ...fetchOptions, method },
        uri: `${protocol}//${baseURI}/_v/${customScope}/graphql/v${version}${query}`,
      }
    })
    return forward ? forward(operation) : null
  })

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/utils/client/links/omitVariableTypenameLink.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { ApolloLink, NextLink, Operation } from 'apollo-link'
import { canUseDOM } from 'exenv'

const deepCopyFiles = (src: any, dst: any) =>
  src &&
  typeof src === 'object' &&
  Object.keys(src).forEach(key => {
    if (
      src[key] instanceof File ||
      src[key] instanceof Blob ||
      src[key] instanceof FileList
    ) {
      dst[key] = src[key]
    } else {
      deepCopyFiles(src[key], dst[key])
    }
  })

const omitTypename = (key: string, value: any) =>
  key === '__typename' ? undefined : value

export const omitTypenameLink = new ApolloLink(
  (operation: Operation, forward?: NextLink) => {
    const { variables } = operation
    if (variables && canUseDOM) {
      operation.variables = JSON.parse(
        JSON.stringify(operation.variables),
        omitTypename
      )
      deepCopyFiles(variables, operation.variables)
    }
    return forward ? forward(operation) : null
  }
)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/utils/client/links/cachingLink.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { ApolloLink, NextLink, Operation } from 'apollo-link'
import PageCacheControl from '../../cacheControl'

export const cachingLink = (cacheControl: PageCacheControl) => {
  return new ApolloLink((operation: Operation, forward?: NextLink) => {
    if (forward) {
      return forward(operation).map(data => {
        const { response } = operation.getContext()
        cacheControl.evaluate(response)
        return data
      })
    }
    return null
  })
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/utils/client/links/ioFetchLink.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { ApolloLink, NextLink, Operation } from 'apollo-link'
import { canUseDOM } from 'exenv'

const isUploadable = (v: any) =>
  v instanceof File || v instanceof Blob || v instanceof FileList

const usesUpload = (value: any): boolean => {
  if (isUploadable(value)) {
    return true
  }

  // If it isn't an object we can't recurse anymore
  if (Object(value) !== value) {
    return false
  }

  return Object.values(value).some(v => usesUpload(v))
}

const useHttpLink = (operation: Operation) => {
  const { variables } = operation

  // No file upload is allowed during SSR
  if (!canUseDOM) {
    return true
  }

  const doUseHttpLink = !usesUpload(variables)
  return doUseHttpLink
}

const passthrough = (operation: Operation, forward?: NextLink) =>
  forward ? forward(operation) : null

export const createIOFetchLink = (
  httpLink: ApolloLink,
  uploadLink: ApolloLink
) => new ApolloLink(passthrough).split(useHttpLink, httpLink, uploadLink)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/utils/client/links/versionSplitterLink.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import {
  ApolloLink,
  createOperation,
  FetchResult,
  GraphQLRequest,
  NextLink,
  Observable,
  Operation,
} from 'apollo-link'
import {
  transformOperation,
  validateOperation,
} from 'apollo-link/lib/linkUtils'
import {
  BREAK,
  DirectiveNode,
  DocumentNode,
  OperationDefinitionNode,
  parse,
  print,
  SelectionNode,
  VariableDefinitionNode,
  VariableNode,
  visit,
} from 'graphql'

interface Variables {
  [name: string]: VariableDefinitionNode
}

interface Node {
  selection: SelectionNode
  usedVariables: Variables
}

const pickAvailableVariables = (query: DocumentNode) => {
  const availableVariables: Variables = {}
  visit(query, {
    VariableDefinition(node: VariableDefinitionNode) {
      availableVariables[node.variable.name.value] = node
    },
  })
  return availableVariables
}

const isRuntimeMetaDirective = (node: DirectiveNode) =>
  node.name.value === 'runtimeMeta'

const pickUsedVariables = (
  selection: SelectionNode,
  availableVariables: Variables
) => {
  const usedVariables: Variables = {}
  visit(selection, {
    Variable(varNode: VariableNode) {
      usedVariables[varNode.name.value] = availableVariables[varNode.name.value]
    },
  })
  return usedVariables
}

const pickFields = (query: DocumentNode, availableVariables: Variables) => {
  const nodes: Node[] = []
  visit(query, {
    Field(selection: SelectionNode) {
      if (
        selection.directives &&
        selection.directives.find(isRuntimeMetaDirective)
      ) {
        nodes.push({
          selection,
          usedVariables: pickUsedVariables(selection, availableVariables),
        })
      }
    },
  })
  return nodes
}

const operationWhiteList = ['query', 'mutation', 'subscription']

const queryFromNodeCreator = (query: DocumentNode) => (node: Node) =>
  visit(parse(print(query)), {
    OperationDefinition(opNode: OperationDefinitionNode) {
      if (operationWhiteList.includes(opNode.operation)) {
        return {
          ...opNode,
          selectionSet: {
            ...opNode.selectionSet,
            selections: [node.selection],
          },
          variableDefinitions: Object.values(node.usedVariables),
        }
      }

      return null
    },
  }) as DocumentNode

const isTypeQuery = (docNode: DocumentNode) => {
  const asset = { isQuery: false }
  visit(docNode, {
    OperationDefinition(node: OperationDefinitionNode) {
      if (node.operation === 'query') {
        asset.isQuery = true
        return BREAK
      }
    },
  })
  return asset.isQuery
}

const assertSingleOperation = (query: DocumentNode) => {
  const ops = query.definitions.filter(definition =>
    operationWhiteList.includes(
      (definition as OperationDefinitionNode).operation
    )
  )

  if (ops.length > 1) {
    throw new Error(
      'Only one operation definition is allowed per query. Please split your queries in two different files'
    )
  }
}

const queriesByRuntimeMetaDirective = (query: DocumentNode) => {
  const availableVariables: Variables = pickAvailableVariables(query)
  const nodes: Node[] = pickFields(query, availableVariables)

  assertSingleOperation(query)

  return nodes.map(queryFromNodeCreator(query))
}

const mergeRecursively = (accumulator: any, value: any) => {
  if (value) {
    Object.keys(value).forEach(key => {
      if (accumulator[key] && typeof value[key] === 'object') {
        accumulator[key] = mergeRecursively(accumulator[key], value[key])
      } else {
        accumulator[key] = value[key]
      }
    })
  }

  return accumulator
}

const createOperationForQuery = (operation: Operation) => (
  query: DocumentNode
) => {
  const graphQLRequest: GraphQLRequest = {
    ...operation,
    query,
    extensions: { ...operation.extensions },
  }
  const op = validateOperation(transformOperation(graphQLRequest))
  return createOperation(operation.getContext(), op)
}

const operationByRuntimeMetaDirective = (operation: Operation) => {
  const queries = queriesByRuntimeMetaDirective(operation.query)
  return queries.map(createOperationForQuery(operation))
}

const observableFromOperations = (operations: Operation[], forward: NextLink) =>
  new Observable(observer => {
    const reduced = {}
    let togo = 0

    operations.forEach((op: Operation) =>
      forward(op).subscribe({
        complete: () => {
          if (togo === operations.length) {
            togo++
            observer.next(reduced)
            observer.complete()
          }
        },
        error: err => {
          togo++
          observer.error(err)
        },
        next: data => {
          togo++
          mergeRecursively(reduced, data)
        },
      })
    )
  }) as Observable<
    FetchResult<
      { [key: string]: any },
      Record<string, any>,
      Record<string, any>
    >
  >

export const versionSplitterLink = new ApolloLink(
  (operation: Operation, forward?: NextLink): any => {
    if (forward) {
      const query = operation.query
      const operations = operationByRuntimeMetaDirective(operation)

      if (operations.length && isTypeQuery(query)) {
        return observableFromOperations(operations, forward)
      } else {
        return forward(operation)
      }
    }
    return null
  }
)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/utils/client/links/runtimeContextLink.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { ApolloLink, NextLink, Operation } from 'apollo-link'

export const createRuntimeContextLink = () =>
  new ApolloLink((operation: Operation, forward?: NextLink) => {
    operation.setContext((currentContext: Record<string, any>) => {
      return {
        ...currentContext,
        runtime: {},
      }
    })
    return forward ? forward(operation) : null
  })

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/utils/client/links/ensureSessionLink.ts from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { ApolloLink, NextLink, Observable, Operation } from 'apollo-link'
import { Subscription } from 'apollo-client/util/Observable'

const sessionRequiredForScope = new Set(['segment', 'private'])

export const ensureSessionLink = (sessionPromise: Promise<any>) => {
  return new ApolloLink(
    (operation: Operation, forward?: NextLink) =>
      new Observable(observer => {
        let handle: Subscription | undefined

        const { scope } = operation.getContext()
        const promise = sessionRequiredForScope.has(scope)
          ? sessionPromise
          : Promise.resolve()

        promise
          .then(() => {
            handle =
              forward &&
              forward(operation).subscribe({
                complete: observer.complete.bind(observer),
                error: observer.error.bind(observer),
                next: observer.next.bind(observer),
              })
          })
          .catch(observer.error.bind(observer))

        return () => {
          if (handle) {
            handle.unsubscribe()
          }
        }
      })
  )
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/components/Preview/index.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { ReactElement, RefObject } from 'react'

import Box from './Box'
import Circle from './Circle'
import Grid from './Grid'
import Spinner from './Spinner'
import Text from './Text'

interface Props {
  extension: any
}
interface State {
  containerWidth?: number | null
}

export const TEST_ID = 'loading-preview'

export default class Preview extends React.PureComponent<Props, State> {
  private container: RefObject<HTMLDivElement>

  public constructor(props: Props) {
    super(props)

    this.container = React.createRef()
    this.state = {
      containerWidth: null,
    }
  }

  private renderPreviewGraphic = (
    width: number | string,
    height: number | string,
    type: string,
    options: any = {}
  ): ReactElement<any> | null => {
    if (!type || type === 'none') {
      return null
    }

    switch (type) {
      case 'box':
      /** TODO: deprecate block in favor of box */
      // eslint-disable-next-line no-fallthrough
      case 'block':
        return <Box width={width} height={height} />
      case 'text':
        return (
          <Text
            width={width}
            height={height}
            fontSize={options.fontSize}
            lineHeight={options.lineHeight}
          />
        )
      case 'grid':
        return <Grid width={width} height={height} />
      case 'circle':
        return <Circle width={width} height={height} />
      case 'spinner':
        return <Spinner width={width} height={height} />
      case 'transparent':
        return <div style={{ width, height }} />
      default:
        return null
    }
  }

  public componentDidMount() {
    /** Fixes a bug on react-content-loader related to limiting
     * the width of the component
     */
    const containerElement = this.container.current
    if (!containerElement) {
      return
    }

    this.setState({
      containerWidth: containerElement.offsetWidth,
    })
  }

  private getDimension = (dimension: any) => {
    if (typeof dimension === 'number') {
      return dimension
    }

    if (!dimension) {
      return null
    }

    const { extension } = this.props

    // TODO: support mobile
    const dimensionObject = dimension.desktop
    if (!dimensionObject) {
      return null
    }

    const { defaultValue } = dimensionObject

    const valueFromProp =
      dimensionObject.fromProp && extension.props[dimensionObject.fromProp]

    if (typeof valueFromProp === 'number') {
      return valueFromProp
    }

    return defaultValue
  }

  private getDimensions = () => {
    const { extension } = this.props

    if (!extension.preview) {
      return { width: null, height: null }
    }

    const { width, height } = extension.preview

    return {
      height: this.getDimension(height),
      width: this.getDimension(width),
    }
  }

  public render() {
    const { extension } = this.props

    if (!extension.preview) {
      return null
    }

    const { type, options = {}, fullWidth } = extension.preview

    const { width: initialWidth, height: initialHeight } = this.getDimensions()

    const { containerWidth } = this.state

    const maxWidth =
      containerWidth || (window && window.innerWidth) || initialWidth || 0

    const padding = options.padding == null ? 20 : options.padding
    const width = Math.max(
      (typeof initialWidth === 'number'
        ? Math.min(maxWidth, initialWidth)
        : maxWidth) -
        padding * 2,
      0
    )
    const height =
      initialHeight && initialHeight > padding * 2
        ? initialHeight - padding * 2
        : 0

    if (height === 0) {
      return null
    }

    return (
      /** TODO: remove this div in favor of the Container component,
       * currently on store-components
       * @author: lbebber
       */
      <div
        ref={this.container}
        className={fullWidth ? '' : 'mw9 center w-100'}
        data-testid={TEST_ID}
        style={{ padding }}
      >
        {this.renderPreviewGraphic(width || '100%', height, type, options)}
      </div>
    )
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/components/Preview/Circle.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { ContentLoader, Rect } from './ContentLoader'

interface Props {
  width: number | string
  height: number | string
}

const Circle = ({ width, height }: Props) => (
  <ContentLoader width={width} height={height}>
    <Rect width={width} height={height} borderRadius="100%" />
  </ContentLoader>
)

export default Circle

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/components/Preview/Grid.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { ContentLoader, Rect } from './ContentLoader'
import Box from './Box'
import { useSSR } from '../../index'

interface Props {
  width: number | string
  height: number | string
}

const Grid = ({ width, height }: Props) => {
  const isSSR = useSSR()

  if (isSSR || typeof width === 'string' || typeof height === 'string') {
    return <Box width={width} height={height} />
  }

  // TODO: make these values configurable
  const itemWidth = 250
  const itemHeight = 400
  const minSpacingX = 10
  const minSpacingY = 30
  const itemsNumX = Math.floor(width / (itemWidth + minSpacingX))
  const itemsNumY = Math.floor(height / (itemHeight + minSpacingY))
  // distributes the remaining available space between each item of the grid
  const spacingX =
    (width - itemsNumX * itemWidth) / (itemsNumX > 1 ? itemsNumX - 1 : 2)
  const spacingY =
    (height - itemsNumY * itemHeight) / (itemsNumY > 1 ? itemsNumY - 1 : 2)

  return (
    <ContentLoader width={width} height={height}>
      {Array.from({ length: itemsNumX }).map((_, x) =>
        Array.from({ length: itemsNumY }).map((__, y) => (
          <Rect
            key={`${x}-${y}`}
            x={x * (itemWidth + spacingX)}
            y={y * (itemHeight + spacingY)}
            width={itemWidth}
            height={itemHeight}
          />
        ))
      )}
    </ContentLoader>
  )
}

export default Grid

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/components/Preview/ContentLoader.css from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```css
@keyframes slide {
  0% {
    transform: translate3d(-50%, 0, 0);
  }
  100% {
    transform: translate3d(0, 0, 0);
  }
}

.slide {
  animation: slide 1.5s infinite linear;
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/components/Preview/Box.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { ContentLoader, Rect } from './ContentLoader'

interface Props {
  width: number | string
  height: number | string
}

const Box = ({ width, height }: Props) => (
  <ContentLoader width={width} height={height}>
    <Rect x={0} y={0} width={width} height={height} />
  </ContentLoader>
)

export default Box

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/components/Preview/ContentLoader.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { FunctionComponent } from 'react'
import styles from './ContentLoader.css'

// TODO: make these colors dynamic, probably based on
// muted colors from the color theme
const PRIMARY_COLOR = '#e8e8e8'
const SECONDARY_COLOR = '#e0e0e0'

interface RectProps {
  x?: number
  y?: number
  width: number | string
  height: number | string
  preserveAspectRatio?: string
  borderRadius?: number | string
}

const Rect: FunctionComponent<RectProps> = ({
  x = 0,
  y = 0,
  width,
  height,
  borderRadius = 5,
}) => (
  <div
    style={{
      width,
      height,
      overflow: 'hidden',
      position: 'absolute',
      top: y,
      left: x,
      borderRadius,
    }}
  >
    <div
      className={styles.slide}
      style={{
        width: '300vw',
        height: '100%',
        position: 'relative',
        left: -x,
        backgroundColor: SECONDARY_COLOR,
        backgroundImage: `linear-gradient(90deg, ${SECONDARY_COLOR}, ${SECONDARY_COLOR} 50%, ${PRIMARY_COLOR} 60%, ${SECONDARY_COLOR} 65%, ${SECONDARY_COLOR})`,
        backgroundSize: '50% 100%',
        backgroundRepeat: 'repeat-x',
      }}
    />
  </div>
)

interface ContentLoaderProps {
  width: number | string
  height: number | string
}

const ContentLoader: FunctionComponent<ContentLoaderProps> = ({
  width,
  height,
  children,
}) => (
  <div style={{ width, height, position: 'relative' }} suppressHydrationWarning>
    {children}
  </div>
)

export { ContentLoader, Rect }

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/components/Preview/GenericPreview.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import Box from './Box'

const GenericPreview = () => {
  const padding = 20
  const height = (window && window.innerHeight) || 1400

  return (
    <div className="center w-100 mw9" style={{ padding }}>
      <Box height={height} width="100%" />
    </div>
  )
}

export default GenericPreview

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/components/Preview/Text.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { ContentLoader, Rect } from './ContentLoader'
import Box from './Box'

interface Props {
  width: number | string
  height: number | string
  lineHeight?: number
  fontSize?: number
}

const Text = ({ width, height, fontSize = 16, lineHeight = 1.5 }: Props) => {
  // Height needs to be a value in pixels in order to be able to split it properly into lines.
  // Falls back to `Box` if it's e.g. `100%`
  if (typeof height === 'string') {
    return <Box width={width} height={height} />
  }

  // TODO: make the line height configurable
  const lineSize = fontSize * lineHeight
  const lines = Math.round(height / lineSize)

  return (
    <ContentLoader width={width} height={height}>
      {Array.from({ length: lines }).map((_, i) => {
        const lineWidth = width
        return (
          <Rect
            key={i}
            x={0}
            y={Math.round(i * lineSize)}
            width={lineWidth}
            height={fontSize}
          />
        )
      })}
    </ContentLoader>
  )
}

export default Text

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of store-on-localhost/src/vtex.render-runtime/components/Preview/Spinner.tsx from the store-on-localhost VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'

interface Props {
  width: number | string
  height: number | string
}

const Spinner = ({ width, height }: Props) => (
  <div className="flex items-center justify-center" style={{ width, height }}>
    <svg
      width="26px"
      height="26px"
      viewBox="0 0 100 100"
      preserveAspectRatio="xMidYMid"
      xmlns="http://www.w3.org/2000/svg"
      xmlnsXlink="http://www.w3.org/1999/xlink"
    >
      <use xlinkHref="#sti-loading" />
    </svg>
  </div>
)

export default Spinner

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/checkout-ui-custom/checkout5-custom.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
/* /files/checkout5-custom.css */

/* Displays the option to enter a foreign document */
.document-box { display: block; }

/* Displays the option to enter an international phone */
.phone-box { display: block; }

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/checkout-ui-custom/checkout6-custom.js from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```javascript
// WARNING: THE USAGE OF CUSTOM SCRIPTS IS NOT SUPPORTED. VTEX IS NOT LIABLE FOR ANY DAMAGES THIS MAY CAUSE. THIS MAY BREAK YOUR STORE AND STOP SALES. IN CASE OF ERRORS, PLEASE DELETE THE CONTENT OF THIS SCRIPT.
!(function (window, jQuery) {
  jQuery(function ($) {
    var disablePersonalInfoEditButton = {
      init: function init() {
        util.waitElement($("#edit-profile-data"), function () {
          $(
            ".accordion-toggle.collapsed .link-box-edit.btn.btn-small"
          ).remove();
          $("#is-not-me").remove();
        });
      },
    };

    var poNumberFeature = {
      showInputOnPOSection: false,
      init: function init() {
        poNumberInput.init();
        fakeSubmitButton.init();
        util.onPageStopLoading(function () {
          if (poNumberFeature.showInputOnPOSection) {
            $(
              ".box-payment-group2.box-payment-option.custom201PaymentGroupPaymentGroup"
            ).append(poNumberInput.input);
          } else {
            $(".payment-submit-wrap").append(poNumberInput.input);
          }

          originalSubmitButton.hide();
          $(".payment-submit-wrap").append(fakeSubmitButton.btn);
        });
        util.waitElement($("#payment-data-submit"), function () {});
      },
    };

    var fakeSubmitButton = {
      btn: null,
      init: function init() {
        fakeSubmitButton.btn = fakeSubmitButton.buildButton();
        fakeSubmitButton.btn.on("click", function () {
          theCheckout.handleSubmit();
        });
      },
      buildButton: function buildButton() {
        return $(
          '<button class="jsSubmitFakeButton btn btn-success btn-large btn-block">\n        <i class="icon-lock"></i>\n        <i class="icon-spinner icon-spin" style="display: none;"></i>\n        <span>Complete Order</span>\n      </button>'
        );
      },
      hideLoadingAndResetButton: function hideLoadingAndResetButton() {
        fakeSubmitButton.btn.find("i.icon-spinner").hide();
        fakeSubmitButton.btn.find("i.icon-lock").show();
        fakeSubmitButton.enableButton();
      },
      setButtonAsLoading: function setButtonAsLoading() {
        fakeSubmitButton.btn.find("i.icon-lock").hide();
        fakeSubmitButton.btn.find("i.icon-spinner").show();
        fakeSubmitButton.disableButton();
      },
      disableButton: function disableButton() {
        fakeSubmitButton.btn.attr("disabled", "");
      },
      enableButton: function enableButton() {
        fakeSubmitButton.btn.removeAttr("disabled");
      },
    };

    var originalSubmitButton = {
      hide: function hide() {
        $("[id=payment-data-submit]").css("visibility", "hidden");
        $("[id=payment-data-submit]").css("max-height", "0");
        $("[id=payment-data-submit]").css("height", "0");
        $("[id=payment-data-submit]").addClass("jsSubmitButton");
      },
    };

    var poNumberInput = {
      input: null,
      init: function init() {
        poNumberInput.input = poNumberInput.buildInput();
      },
      buildInput: function buildInput() {
        return $(
          '\n        <div style="\n          padding-right: 15px;\n          margin-bottom: 10px;\n        " id="poWrap">\n        <label> Purchase Order Number: (optional) </label>\n          <input \n            type="text"\n            id="poNumberInput" style="\n            font-size: 20px;\n            height: 36px;\n            line-height: 34px;\n            width: 100%;" \n            name="poNumber">\n          <span class="help error feedback" style="display: none">This field is required.</span>\n        </div>'
        );
      },
      showError: function showError() {
        $("#poNumberInput").addClass("error");
        $("#poWrap").find(".feedback").show();
      },
      hideError: function hideError() {
        $("#poNumberInput").removeClass("error");
        $("#poWrap").find(".feedback").hide();
      },
      handleEmpty: function handleEmpty() {
        poNumberInput.showError();
        $("#poNumberInput").on("keypress", poNumberInput.hideError);
      },
    };

    var util = {
      waitElement: function waitElement(selector, fn) {
        var element = setInterval(function () {
          if ($(selector).length) {
            clearInterval(element);
            fn();
          }
        }, 200);
      },
      onOrignalButtonStopLoading: function onOrignalButtonStopLoading(fn) {
        var internal = setInterval(function () {
          if (!!!$(".jsSubmitButton").prop("disabled")) {
            clearInterval(internal);
            fn();
          }
        }, 200);
      },
      onPageStopLoading: function onPageStopLoading(fn) {
        var internal = setInterval(function () {
          if (!$("body.loading").length) {
            clearInterval(internal);
            fn();
          }
        }, 200);
      },
      onEmailIsSet: function onEmailIsSet(fn) {
        var internal = setInterval(function () {
          if (!!$(".client-profile-email span.email").text()) {
            clearInterval(internal);
            fn();
          }
        }, 200);
      },
    };

    var theCheckout = {
      submit: function submit() {
        $("#payment-data-submit").click();
      },
      handleSubmit: function handleSubmit() {
        var poNumber = {
          value: $("#poNumberInput")[0].value,
        };
        fakeSubmitButton.setButtonAsLoading();
        util.onOrignalButtonStopLoading(function () {
          fakeSubmitButton.enableButton();
          fakeSubmitButton.hideLoadingAndResetButton();
        });
        vtexjs.checkout.getOrderForm().then(function (data) {
          console.log("here: " + poNumber.value);

          if (!!poNumber.value) {
            $.ajax({
              type: "PUT",
              url: "/api/checkout/pub/orderForm/".concat(
                data.orderFormId,
                "/customData/profile/poNumber"
              ),
              data: poNumber,
              dataType: "json",
            }).then(theCheckout.submit);
          } else {
            theCheckout.submit();
          }
        });
      },
    };

    $(window).on("checkoutRequestBegin.vtex", function (event, orderForm) {
      fakeSubmitButton.setButtonAsLoading();
      setTimeout(function () {
        fakeSubmitButton.hideLoadingAndResetButton();
      }, 1000);
    });

    poNumberFeature.init();
    disablePersonalInfoEditButton.init();
  });
})(window, window.jQuery);

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/checkout-ui-custom/checkout-confirmation-custom.js from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```javascript
// WARNING: THE USAGE OF CUSTOM SCRIPTS IS NOT SUPPORTED. VTEX IS NOT LIABLE FOR ANY DAMAGES THIS MAY CAUSE.
// THIS MAY BREAK YOUR STORE AND STOP SALES. IN CASE OF ERRORS, PLEASE DELETE THE CONTENT OF THIS SCRIPT.

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/checkout-ui-custom/checkout5-custom.js from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```javascript
// WARNING: THE USAGE OF CUSTOM SCRIPTS IS NOT SUPPORTED. VTEX IS NOT LIABLE FOR ANY DAMAGES THIS MAY CAUSE. THIS MAY BREAK YOUR STORE AND STOP SALES. IN CASE OF ERRORS, PLEASE DELETE THE CONTENT OF THIS SCRIPT.

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/checkout-ui-custom/checkout6-custom.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
/* Content copied from "checkout5-custom.css" at 2019-03-01T05:12:59.334Z */

/* /files/checkout5-custom.css */

/* Displays the option to enter a foreign document */
.document-box { display: block; }

/* Displays the option to enter an international phone */
.phone-box { display: block; }

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/docs/README.md from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```markdown
# Installing the B2B Store Theme

B2B Store Theme is a front-end template to help your store get started with VTEX’s core features for businesses selling to other businesses.

## Prerequisites

### Set up your development environment

Before starting with the B2B Store Theme setup itself, you must:

1. [Set up a workspace to develop in VTEX IO](https://developers.vtex.com/vtex-developer-docs/docs/vtex-io-documentation-2-basicsetuptodevelopinvtexio) on your machine.
2. Follow [these instructions](https://developers.vtex.com/vtex-developer-docs/docs/vtex-io-documentation-2-prerequesites) to make sure you meet all the prerequisites to develop using Store Framework.
3. Make sure your store’s catalog is integrated with VTEX Intelligent Search, as described in [this article](https://help.vtex.com/en/tracks/vtex-intelligent-search--19wrbB7nEQcmwzDPl1l4Cb/6wKQgKmu2FT6084BJT7z5V).

### Install required B2B apps

Now you must install the required apps listed below. They are mandatory for the B2B Store Theme to work properly.

- [Wishlist](https://developers.vtex.com/vtex-developer-docs/docs/installing-the-b2b-store-theme#wishlist)
- [Reviews and Ratings](https://developers.vtex.com/vtex-developer-docs/docs/installing-the-b2b-store-theme#reviews-and-ratings)
- [Quick Order](https://developers.vtex.com/vtex-developer-docs/docs/installing-the-b2b-store-theme#quick-order)
- [Location Availability](https://developers.vtex.com/vtex-developer-docs/docs/installing-the-b2b-store-theme#location-availability)
- [Shopper Location](https://developers.vtex.com/vtex-developer-docs/docs/installing-the-b2b-store-theme#shopper-location)
- [Wordpress Integration](https://developers.vtex.com/vtex-developer-docs/docs/installing-the-b2b-store-theme#wordpress-integration)

#### Wishlist

[Wishlist](https://github.com/vtex-apps/wish-list) is an app that allows your store’s customers to bookmark their favorite products by clicking on a heart icon.

To install this app on your store, run the following command on the CLI:

```
vtex install vtex.wish-list@1.x
```

#### Reviews and Ratings

The [Reviews and ratings](https://github.com/vtex-apps/reviews-and-ratings) app enables your clients to submit reviews and ratings — using a star rating system — to your store’s products.

Install it using the command:

```
vtex install vtex.reviews-and-ratings@2.x
```

After that, go to your store's Admin to proceed with the installation.

Once you are logged in, follow these steps:

1. Go to the **Account Settings** module.
2. Click on `Apps`.
3. Then, click on `My apps`.
4. Then, find the **Reviews and Ratings** app card and click on `Settings`.
5. It is recommended that you check the **Display stars in product-rating-summary if there are no reviews** option and uncheck the **Display total reviews number on product-rating-summary block** option, as illustrated below.
6. Click on the `Save` button.

![Reviews and Ratings Settings](/assets/image1.png "Reviews and Ratings Settings")

#### Quick Order

[Quick Order](https://github.com/vtex-apps/quickorder) is an app that enables customers to make bulk orders.

To install it, use the following command:

```
 vtex install vtex.quickorder@3.x
```

#### Location Availability

The [Location Availability](https://github.com/vtex-apps/location-availability) app shows product availability and shipping information in the storefront based on the customer’s location, providing a personalized shopping experience.

Install this app on your store using the `vtex.location-availability@0.x ` command.

#### Shopper Location

[Shopper Location](https://github.com/vtex-apps/shopper-location) is a geolocation app. Once it is installed, the app tracks the customer’s location, after permission is granted.

To install it, use the following command:

```
vtex install vtex.shopper-location@0.x
```

#### Wordpress integration

The [Wordpress integration](https://github.com/vtex-apps/wordpress-integration) app enables the account admin to create content on your store’s front through Wordpress’ API.

To install this app, run the following command on the CLI:

```
vtex install vtex.wordpress-integration@2.x
```

### Install B2B Easy Setup (optional)

If you are setting up a new store, you can follow the instructions in [this guide](https://developers.vtex.com/vtex-rest-api/docs/installing-b2b-easy-set-up) to quickly set up a test store with sample data using the B2B Easy Setup app.

> 🚨 We strongly advise that you do not run Easy Setup on a production environment. It will make irreversible changes and may delete some previous configurations on your store.

## Installation

After following the steps above, you are ready to install the B2B Store Theme. You must:

1. Run the `vtex install vtex.b2bstore@3.x `command on the CLI.
2. Run the `vtex browse` command to see the B2B Store Theme on your browser.

Finally, your storefront should look like this:

![B2B Store Theme](/assets/image3.png "B2B Store Theme")

## Customization

After installing the B2B Store Theme, you can customize it according to your store’s business needs. Check our guide on [Customizing the B2B Store Theme](https://developers.vtex.com/vtex-developer-docs/docs/customizing-the-b2b-store-theme) for more information.

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/schemas/SellerRegistrationSchema.json from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "title": "Revenda",
  "type": "object",
  "properties": {
    "email": {
      "type": "string",
      "format": "email",
      "title": "Email"
    },
    "stateRegistration": {
      "type": "string",
      "maxLength": 750,
      "title": "State Registration"
    },
    "homePhone": {
      "type": "string",
      "title": "Mobile"
    },
    "corporateDocument": {
      "type": "string",
      "maxLength": 14,
      "title": "EIN #: "
    },
    "phone": {
      "type": "string",
      "title": "Phone"
    },
    "lastName": {
      "type": "string",
      "maxLength": 750,
      "title": "Last Name"
    },
    "tradeName": {
      "type": "string",
      "maxLength": 750,
      "title": "Trade Name"
    },
    "corporateName": {
      "type": "string",
      "maxLength": 750,
      "title": "Company Name"
    },
    "firstName": {
      "type": "string",
      "maxLength": 750,
      "title": "First Name"
    },
    "streetType": {
      "type": "string",
      "title": "Stree Type",
      "enum": ["Street", "Avenue", "Boulevard", "Road", "Junction"]
    },
    "city": {
      "type": "string",
      "maxLength": 750,
      "title": "City"
    },
    "reference": {
      "type": "string",
      "maxLength": 750,
      "title": "Reference"
    },
    "street": {
      "type": "string",
      "title": "Street"
    },
    "state": {
      "type": "string",
      "title": "State",
      "enum": [
        "Alabama",
        "Alaska",
        "American Samoa",
        "Arizona",
        "Arkansas",
        "California",
        "Colorado",
        "Connecticut",
        "Delaware",
        "District Of Columbia",
        "Federated States Of Micronesia",
        "Florida",
        "Georgia",
        "Guam",
        "Hawaii",
        "Idaho",
        "Illinois",
        "Indiana",
        "Iowa",
        "Kansas",
        "Kentucky",
        "Louisiana",
        "Maine",
        "Marshall Islands",
        "Maryland",
        "Massachusetts",
        "Michigan",
        "Minnesota",
        "Mississippi",
        "Missouri",
        "Montana",
        "Nebraska",
        "Nevada",
        "New Hampshire",
        "New Jersey",
        "New Mexico",
        "New York",
        "North Carolina",
        "North Dakota",
        "Northern Mariana Islands",
        "Ohio",
        "Oklahoma",
        "Oregon",
        "Palau",
        "Pennsylvania",
        "Puerto Rico",
        "Rhode Island",
        "South Carolina",
        "South Dakota",
        "Tennessee",
        "Texas",
        "Utah",
        "Vermont",
        "Virgin Islands",
        "Virginia",
        "Washington",
        "West Virginia",
        "Wisconsin",
        "Wyoming"
      ]
    },
    "complement": {
      "type": "string",
      "maxLength": 750,
      "title": "Complement"
    },
    "neighborhood": {
      "type": "string",
      "maxLength": 750,
      "title": "Neighborhood"
    },
    "number": {
      "type": "string",
      "maxLength": 750,
      "title": "Number"
    },
    "postalCode": {
      "type": "string",
      "maxLength": 9,
      "title": "Zip Code"
    },
    "upload": {
      "type": "string",
      "maxLength": 99999,
      "title": "Operating Agreement"
    }
  },
  "required": [
    "email",
    "stateRegistration",
    "corporateDocument",
    "tradeName",
    "corporateName",
    "firstName",
    "lastName",
    "city",
    "street",
    "state",
    "postalCode"
  ],
  "v-security": {
    "allowGetAll": true,
    "publicWrite": [
      "email",
      "firstName",
      "lastName",
      "homePhone",
      "corporateName",
      "corporateDocument",
      "stateRegistration",
      "tradeName",
      "city",
      "street",
      "state",
      "neighborhood",
      "number",
      "postalCode"
    ],
    "publicRead": [
      "email",
      "stateRegistration",
      "homePhone",
      "corporateDocument",
      "phone",
      "lastName",
      "tradeName",
      "corporateName",
      "firstName",
      "city",
      "street",
      "state",
      "streetType",
      "neighborhood",
      "number",
      "postalCode",
      "upload",
      "complement",
      "reference"
    ],
    "publicJsonSchema": true
  },
  "v-triggers": [
    {
      "name": "insert-customer-table",
      "active": true,
      "condition": "",
      "action": {
        "type": "save",
        "dataEntity": "CL",
        "json": {
          "id": "{!id}",
          "approved": "false",
          "firstName": "{!firstName}",
          "lastName": "{!lastName}",
          "email": "{!email}",
          "homePhone": "{!homePhone}",
          "isCorporate": "true",
          "corporateName": "{!corporateName}",
          "tradeName": "{!tradeName}",
          "stateRegistration": "{!stateRegistration}",
          "corporateDocument": "{!corporateDocument}",
          "isOrgAdmin": "true"
        }
      }
    },
    {
      "name": "insert-address-table",
      "active": true,
      "condition": "",
      "action": {
        "type": "save",
        "dataEntity": "AD",
        "json": {
          "userId": "{!id}",
          "city": "{!city}",
          "reference": "{!reference}",
          "street": "{!street}",
          "state": "{!state}",
          "streetType": "{!streetType}",
          "neighborhood": "{!neighborhood}",
          "addressName": "Principal",
          "number": "{!number}",
          "country": "USA",
          "postalCode": "{!postalCode}",
          "complement": "{!complement}",
          "upload": "{!upload}"
        }
      }
    }
  ]
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/store/interfaces.json from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store.search.product-comparison": {
    "around": ["comparison-context-wrapper"]
  },
  "store.custom.product-comparison": {
    "around": ["comparison-context-wrapper"]
  },
  "search-result-layout.desktop.product-comparison": {
    "allowed": ["product-comparison-drawer"]
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/store/routes.json from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "store.custom#product-comparison-list": {
    "path": "/product-comparison"
  },
  "store.custom#registration": {
    "path": "/registration"
  },
  "store.custom#quickOrderByOne": {
    "path": "/quickorder/one-by-one"
  },
  "store.custom#quickOrderByCategory": {
    "path": "/quickorder/by-category"
  },
  "store.custom#not-allow": {
    "path": "not-allowed"
  },
  "store.custom.product-comparison#deals": {
    "path": "/deals"
  },
  "store.custom.product-comparison#releases": {
    "path": "/releases"
  },
  "store.custom.product-comparison#top-sales": {
    "path": "/top-sales"
  },
  "store.custom#customer-services": {
    "path": "/services"
  },
  "store.custom#gift-cards": {
    "path": "/gift-cards"
  },
  "store.custom.product-comparison#popular": {
    "path": "/popular"
  },
  "store.custom.product-comparison#trending": {
    "path": "/trending"
  },
  "store.custom#company": {
    "path": "/company"
  },
  "store.custom#careers": {
    "path": "/careers"
  },
  "store.custom#sell": {
    "path": "/sell"
  },
  "store.custom#investors": {
    "path": "/investors"
  },
  "store.custom#advertise": {
    "path": "/advertise"
  },
  "store.custom#locations": {
    "path": "/locations"
  },
  "store.custom#accessibility": {
    "path": "/accessibility"
  },
  "store.custom#contact": {
    "path": "/contact"
  },
  "store.custom#help-center": {
    "path": "/help-center"
  },
  "store.custom#pickup": {
    "path": "/pickup"
  },
  "store.custom#recalls": {
    "path": "/recalls"
  },
  "store.custom#returns": {
    "path": "/returns"
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/store/plugins.json from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "my-account-pages > my-account-page": "my-account-page.wishlist-page",
  "my-account-menu > my-account-link": "my-account-link.wishlist-link"
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/styles/css/vtex.store-link.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.link--popularLink,
.link--trendingLink {
  text-decoration: none;
}

.label--popularLink,
.label--trendingLink {
  color: #0067c7;
  font-size: 14px;
  line-height: 24px;
  font-weight: bold;
}

.label--popularLink::after,
.label--trendingLink::after {
  content: url("assets/icons/chevronBlue.svg");
  margin-left: 8px;
  top: 1px;
  position: relative;
}

.link--networkLink {
  width: 32px;
  height: 32px;
  background: rgba(255, 255, 255, 0.16);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.link--shopByLink {
  width: 100%;
  text-decoration: none;
}

.link--shopByLink:hover :global(.vtex-rich-text-0-x-paragraph--shopByCategory) {
  color: #0067c7;
}

.link--shopByLink:hover .childrenContainer {
  border: 1px solid #0067c7;
}

.childrenContainer--shopByLink {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-flow: column nowrap;
  max-width: 216px;
  height: 196px;
  background: #f3f9ff;
  border-radius: 4px;
  transition: all 0.3s ease;
  border: 1px solid transparent;
}

.childrenContainer--linkCategorySlider {
  display: flex;
  flex-flow: column nowrap;
  align-items: center;
}

.link--linkCategorySlider {
  text-decoration: none;
}

.link--blogLink {
  display: block;
  max-width: 100px;
  width: 100%;
  height: 32px;
  font-size: 14px;
  line-height: 32px;
  text-align: center;
  color: #0067c7;
  background: #f3f9ff;
  text-decoration: none;
}

.childrenContainer--linkMail,
.childrenContainer--linkCall {
  display: flex;
  align-items: center;
  margin: 0;
  height: 48px;
  padding: 0px 20px;
  border-radius: 4px;
  max-width: 280px;
  width: 100%;
}

.childrenContainer--linkCall {
  background: var(--b2b-header-blue-medium);
}

.childrenContainer--linkMail {
  border: 1px solid var(--b2b-header-blue-medium);
}

.link--linkCall,
.link--linkMail {
  text-transform: uppercase;
  color: #fff;
  font-size: 14px;
  line-height: 24px;
  font-weight: 700;
  font-family: Roboto;
  text-decoration: none;
}

.link--linkCall :global(.vtex-store-components-3-x-imageElement),
.link--linkMail :global(.vtex-store-components-3-x-imageElement) {
  margin-right: 12px;
}

.link--linkCall {
  margin-bottom: 12px;
  display: block;
}

.link--quickLink {
  text-decoration: none;
  position: relative;
}

.link--quickLink::after {
  content: url("assets/icons/nav-arrow-right.svg");
  display: block;
  position: absolute;
  color: #717786;
  right: 0;
  top: 50%;
  transform: translate(-50%, -50%);
}

.link--quickOrderButton {
  text-decoration: none;
  padding: 24px;
  background: #f2f5f9;
  border: 1px solid #dee7ef;
  display: block;
  margin-bottom: 8px;
  border-radius: 4px;
  position: relative;
}

.link--quickOrderButton::after {
  content: url("assets/icons/nav-arrow-right-blue.svg");
  display: block;
  position: absolute;
  color: #717786;
  right: 12px;
  top: 50%;
  transform: translate(-50%, -50%);
}
.link--order-quote {
	margin: 0 16px 16px;
  width: 92%;
  padding: 13px 0;
  font-size: 18px;
}

.link--menu-order-quote {
	text-decoration: none;
	font-size: 16px;
	line-height: 44px;
	font-family: Roboto;
	color: rgb(113, 119, 134);
  font-size: 20px;
  line-height: 28px;
  color: #000;
  font-weight: 500;
  margin: 0;
  margin-bottom: 4px;
  display: flex;
  align-items: center;
  margin-top: 15px;
}

.link--orderQuote,
.link--resellerLink {
  display: flex;
  align-items: center;
  text-decoration: none;
  color: #fff;
  height: 100%;
  font-weight: 500;
  font-size: 14px;
  line-height: 20px;
}

@media (max-width: 64rem) {
  .childrenContainer--accountLink :global(.vtex-store-icons-0-x-profileIcon) {
    color: #fff;
    width: 20px;
    height: 20px;
  }

  .link--footerLink {
    color: #fff;
    font-size: 16px;
    line-height: 48px;
    font-weight: 500;
    font-family: Roboto;
    text-decoration: none;
  }

  .link--networkLink {
    width: 32px;
    height: 32px;
    background: rgba(255, 255, 255, 0.16);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/styles/css/vtex.product-comparison.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.drawerContainer {
  z-index: 6;
}

.productSelectorContainer {
  opacity: 0;
  transition: all 0.3s ease;
}

.productSelectorContainer :global(.vtex-checkbox__line-container) {
  justify-content: center;
}

.productSelectorContainer :global(.vtex-checkbox__label) {
  width: auto;
}

.productSelectorContainer :global(.vtex-checkbox__inner-container) {
  width: 20px;
  height: 20px;
  border-width: 1px;
}

.productSelectorContainer :global(.vtex-checkbox__container),
.productSelectorContainer :global(.vtex-checkbox__input) {
  width: 20px;
  height: 20px;
}

.imageElement--paymentImage {
  margin: 0px auto;
}
.showDifferencesContainer :global(.vtex-checkbox__inner-container),
.productSelectorContainer :global(.vtex-checkbox__inner-container) {
  border-color: #a3afbc;
}

.productSelectorContainer :global(.vtex-checkbox__box-wrapper) {
  width: 20px;
  height: 20px;
}

.productSelectorContainer :global(.vtex__icon-check) {
  width: 16px;
  height: 16px;
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/styles/css/vtex.search.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.tileList .tileListList {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-gap: 12px;
  padding: 0px 24px;
  margin: 0;
}

.tileListTitle {
  display: none;
  opacity: 0;
}

.biggy-autocomplete {
  padding-top: 0;
}

.tileList,
.itemList--suggestion {
  padding-top: 24px;
}

.itemListTitle {
  font-size: 20px;
  line-height: 24px;
  font-weight: 500;
  color: #000;
  text-transform: initial;
}

@media (max-width: 64rem) {
  .biggy-autocomplete {
    padding: 0;
  }

  .tileList .tileListList {
    grid-template-columns: 1fr;
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/styles/css/vtex.product-price.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.sellingPrice--desktop {
  font-size: 24px;
  font-weight: normal;
  line-height: 32px;
  color: #000000;
}

.sellingPrice .sellingPriceValue--desktop {
  display: none;
}

.sellingPriceWithTax--desktop {
  font-size: 28px;
  font-weight: bold;
}

.listPrice--desktop {
  font-size: 16px;
  line-height: 20px;
  text-decoration-line: line-through;
  color: #717786;
}

.savings--desktop {
  font-size: 14px;
  line-height: 20px;
  color: #717786;
}

.savingsValue--desktop {
  color: #468a2e;
  font-weight: 500;
}

.savings--savingSummary {
  display: block;
  background: #e5f1e1;
  color: #468a2e;
  text-transform: uppercase;
  font-size: 12px;
  line-height: 18px;
  font-weight: 500;
  padding: 0px 8px;
  border-radius: 10px;
}

.savings--savingPercentage {
  display: block;
  background: var(--fresh-orange);
  color: #fff;
  text-transform: uppercase;
  font-size: 12px;
  line-height: 18px;
  font-weight: 700;
  padding: 0px 8px;
  border-radius: 10px;
}

.savings--savingPercent {
  margin-left: 4px;
  color: #468a2e;
  font-weight: 500;
}

@media (max-width: 64rem) {
  .savings--savingPercent {
    color: #000;
  }

  .currencyContainer--sticky {
    font-size: 20px;
    line-height: 28px;
    color: #000;
    font-weight: bold;
    font-family: Roboto;
  }
}

/* Seller Name */

.sellerNameContainer--default {
  font-size: 0.875rem;
  color: var(--black-medium);
  margin-bottom: 0.5rem;
}

.sellerName--default {
  color: var(--black-dark);
  font-weight: 500;
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/styles/css/vtex.product-customizer.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.textInputValue {
  margin-top: 8px !important;
}

.textInputValue :global(.vtex-input-prefix__group) {
  border: none;
}

.textInputValue :global(.vtex-styleguide-9-x-input) {
  background: #ffffff;
  border: 1px solid #a3afbc;
  box-sizing: border-box;
  border-radius: 4px;
  padding: 0 20px;
}

.textInputValue :global(.vtex-input__label) {
  display: none;
}

.textInputValue::after {
  display: inline-block;
  color: #717786;
  content: "Max. of 20 characters";
  font-size: 12px;
  margin-top: 8px;
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/styles/css/vtex.store.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
:global(.vtex-store__template),
:global(.vtex-modal-layout-0-x-container),
:global(.vtex-minicart-2-x-drawer),
:global(.vtex-telemarketing-2-x-portalContainer),
:global(.vtex-login-2-x-portalContainer) {
  --black-dark: #000000;
  --fresh-blue: #0067c7;
  --fresh-blue-dark: #0067c7;
  --fresh-blue-lightest: #f3f9ff;
  --fresh-orange: #ff5f00;
  --fresh-darkest: #003364;
  --green-dark: #468a2e;
  --black-medium: #717786;
  --b2b-header-blue-medium: #597298;
  --blue-medium: #597298;
  --b2b-blue-darkest: #1b3255;
  --lines-dark: #bdc9d6;
  --lines-darker: #a3afbc;
  --lines-light: #dee7ef;
  --serious-blue-dark: #214d8e;
  --serious-black: #142032;
  --serious-orange: #ff7d30;
  --base: #fff;
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/styles/css/vtex.quickorder.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
@media (max-width: 64rem) {
  .categoryButtonAdd {
    padding: 0;
  }

  .categoryButtonAdd :global(.vtex-button) {
    width: 100%;
    height: 48px;
    background: #ff7d30;
    border-radius: 4px;
    display: block;
    line-height: 48px;
    border: none;
    margin: 16px 0px 24px;
  }

  .categoryContainer .textContainer :not(:global(.vtex-fake)) {
    margin: 0;
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/styles/css/vtex.orderquote.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.containerCreate,
.containerList,
.containerView {
  max-width: 1440px;
  width: 100%;
  padding: 0px;
  margin: 0px auto;
}

.buttonSave :global(.vtex-button),
.createButton :global(.vtex-button),
.buttonUse :global(.vtex-button) {
  background: var(--serious-blue-dark);
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/styles/css/vtex.minicart.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.drawer {
  z-index: 999;
}

.minicartIconContainer {
  color: #fff;
}

.closeIconContainer::before {
  content: "My cart";
  font-size: 24px;
  line-height: 32px;
  font-family: Roboto;
  color: #000;
  font-weight: 500;
}

.closeIconButton {
  margin-left: auto;
  padding: 12px 0px;
}

.closeIconContainer {
  background: #f3f9ff;
  align-items: center;
  padding: 0px 24px;
}

.minicartTitle {
  display: none;
  opacity: 0;
}

.openIconContainer {
  padding: 0;
}

.openIconContainer :global(.vtex-button) {
  border: none;
  border-radius: 0;
  outline: none;
}

.minicartQuantityBadge {
  background-color: #ff5f00;
  font-weight: 700;
}

.minicartCheckoutButton {
  padding: 12px 16px 16px;
  margin: 0;
}

.minicartCheckoutButton :global(.vtex-button) {
  height: 52px;
  background: #ff5f00;
  border-radius: 4px;
  border: none;
  font-weight: 700;
  font-family: Roboto;
  font-size: 18px;
  line-height: 28px;
  outline: none;
}

@media (max-width: 64rem) {
  .openIconContainer {
    padding: 0;
  }

  .drawer {
    width: 100% !important;
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/styles/css/vtex.sku-list.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.skuContentWrapper {
  cursor: pointer;
  border-radius: 0;
  border-width: 0.0625rem;
  margin: 0 -0.5rem -0.0625rem;
  padding: 0.5rem 1rem;
}

.skuContentWrapper:focus {
  outline: none;
}

.skuContentWrapper:first-child {
  margin-top: -0.5rem;
  border-top-left-radius: 0.25rem;
  border-top-right-radius: 0.25rem;
}

.skuContentWrapper:last-child {
  margin-bottom: -0.5rem;
  border-bottom-left-radius: 0.25rem;
  border-bottom-right-radius: 0.25rem;
}

.itemHighlight,
.priceContainer,
.inventoryContainer,
.highlightContent {
  padding: 0;
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/styles/css/vtex.rich-text.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
/* BEGIN - Header */
.container--HeaderStripeText {
  margin-right: 24px;
}

.container--HeaderStripeText .link {
  color: #fff;
  font-weight: 500;
  font-size: 14px;
  line-height: 20px;
  text-decoration: none;
}

.headingLevel2--menuTitle {
  font-size: 20px;
  line-height: 24px;
  font-weight: 500;
  font-family: Roboto;
  color: #000;
  margin: 0;
  margin-bottom: 24px;
}

.container--menuTitle {
  margin-top: 38px;
  padding-top: 38px;
  border-top: 1px solid #dee7ef;
}

.headingLevel2--quickTitle {
  font-size: 20px;
  line-height: 28px;
  color: #000;
  font-weight: 500;
  margin: 0;
  margin-bottom: 4px;
  display: flex;
  align-items: center;
}

.headingLevel2--quickTitle::before {
  content: url("assets/icons/quickOrderIcon.svg");
  display: block;
  margin-right: 10px;
  width: 22px;
  height: 22px;
}

.paragraph--quickText {
  font-size: 14px;
  line-height: 20px;
  margin: 0;
  color: #717786;
}

/* END - Header */
/* BEGIN - Generic */

.headingLevel3--sectionTitle,
.headingLevel3--shopByCategoryTitle {
  font-size: 24px;
  font-weight: 500;
  line-height: 32px;
  color: #000000;
  margin: 0;
  margin-bottom: 16px;
}

.wrapper--alsoView,
.wrapper--sectionTitle {
  width: 100%;
}

.headingLevel3--alsoView,
.headingLevel3--sectionTitle {
  padding-bottom: 16px;
  border-bottom: 1px solid #e9eff5;
}

.headingLevel3--alsoView {
  font-size: 24px;
  font-weight: 500;
  line-height: 32px;
  color: #000000;
  margin: 0;
  margin-bottom: 16px;
  margin-top: 32px;
}

/* END - Generic */
/* BEGIN - ShopByCategory */

.wrapper--shopByCategory {
  width: 100%;
  height: 100%;
}

.paragraph--shopByCategory {
  margin: 0;
  height: 100%;
}

.link--shopByCategory {
  display: flex;
  flex-flow: column;
  align-items: center;
  text-decoration: none;
  height: 100%;
  justify-content: center;
}

.image--shopByCategory {
  display: block;
  margin-bottom: 24px;
}

.strong--shopByCategory {
  font-size: 18px;
  line-height: 24px;
  color: #000;
  font-weight: 400;
}

/* END - ShopByCategory */
/* BEGIN - QuickViewTrigger */

.container--quickviewTrigger .image {
  display: block;
  width: 20px;
}

/* END - QuickViewTrigger */
/* BEGIN - BannerThird */

.headingLevel4--bannerTitle {
  margin: 0;
  margin-bottom: 12px;
  font-size: 20px;
  line-height: 28px;
  font-weight: 500;
  color: #000;
}

.paragraph--bannerDesc {
  max-width: 388px;
  width: 100%;
  margin: 0px auto 16px;
  color: #717786;
  font-size: 16px;
  font-weight: 400;
  line-height: 24px;
}

.container--bannerTitle,
.container--bannerDesc,
.container--bannerLink {
  display: flex;
  align-items: center;
  justify-content: center;
}

.paragraph--bannerLink {
  margin: 0;
}

.link--bannerLink {
  width: 244px;
  height: 48px;
  background-color: #0067c7;
  border-radius: 4px;
  color: #fff;
  font-size: 14px;
  line-height: 48px;
  font-weight: 700;
  font-family: Roboto;
  display: block;
  text-decoration: none;
}

/* END - BannerThird */
/* BEGIN - Benefits Bar */

.wrapper--benefitsItem .paragraph {
  display: flex;
  flex-flow: column nowrap;
  align-items: center;
  margin: 0;
  color: #717786;
  font-size: 14px;
  line-height: 20px;
  font-family: Roboto;
}

.wrapper--benefitsItem .image {
  object-fit: contain;
  display: block;
  margin-bottom: 24px;
  width: 34px;
  height: 26px;
}

.wrapper--benefitsItem .strong {
  font-size: 18px;
  line-height: 24px;
  font-family: Roboto;
  color: #000;
  font-weight: 500;
  display: block;
  margin: 0;
  margin-bottom: 8px;
}
/* END - Benefits Bar */
/* BEGIN - Footer */

.paragraph--footerStripe {
  font-size: 12px;
  line-height: 18px;
  color: rgba(225, 239, 255, 0.5);
  margin: 0;
  padding: 32px 0px;
}

.paragraph--footerTitle {
  margin: 0;
  color: #e1efff;
  margin-bottom: 16px;
  font-size: 18px;
  line-height: 24px;
  font-family: Roboto;
  font-weight: 500;
}

.paragraph--mailTo,
.paragraph--callTo {
  text-transform: uppercase;
  color: #fff;
  font-size: 14px;
  line-height: 24px;
  font-weight: 700;
  font-family: Roboto;
  text-decoration: none;
  margin: 0;
}

.paragraph--footerText {
  margin: 0;
  color: #e1efff;
  font-size: 12px;
  line-height: 16px;
  font-weight: 500;
  text-align: left;
}

.paragraph--footerRights {
  font-size: 14px;
  line-height: 24px;
  color: #fff;
}

.paragraph--followTitle {
  margin: 0;
  margin-bottom: 16px;
  font-size: 14px;
  line-height: 20px;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.5);
}

/* END - Footer */
/* BEGIN - Trending Shelf */

.heading--trendingTitle {
  font-size: 24px;
  line-height: 32px;
  color: #000;
  font-family: Roboto;
  margin: 0;
}

/* END - Trending Shelf */
/* BEGIN - Popular Shelf */

.headingLevel3--popularTitle {
  font-size: 24px;
  line-height: 32px;
  color: #000;
  font-weight: 500;
  font-family: Roboto;
  margin: 0;
  margin-bottom: 16px;
}

/* END - Popular Shelf */
/* BEGIN - QuickOrder */

.headingLevel3--titleQuickorder {
  margin-left: 0.5rem;
}

/* END - QuickOrder */
/* BEGIN - Search Page */

.paragraph--SEOText {
  font-size: 14px;
  line-height: 18px;
  font-family: Roboto;
  color: #717786;
  margin: 0;
  margin-bottom: 24px;
}

.paragraph--textCategorySlider {
  font-size: 14px;
  line-height: 20px;
  color: #717786;
  margin: 0;
}

.paragraph--blogSEO {
  max-height: 400px;
  overflow: auto scroll;
  padding: 0;
  margin: 0;
  font-size: 14px;
  line-height: 20px;
  color: #717786;
}

.heading--blogTitle {
  font-size: 16px;
  line-height: 20px;
  font-weight: 500;
  font-family: Roboto;
  margin: 0;
  margin-bottom: 8px;
  color: #000;
}

.paragraph--blogDescription {
  font-size: 14px;
  line-height: 18px;
  font-family: Roboto;
  color: #717786;
  margin: 0;
  margin-bottom: 24px;
}

/* END - Search Page */

@media (max-width: 64rem) {
  .paragraph--blogSEO {
    width: 100%;
    max-width: 100%;
    margin: 0;
    padding: 0;
    max-height: initial;
    margin-bottom: 40px;
  }

  .headingLevel3--blogSecondarySEO {
    font-size: 18px;
    line-height: 28px;
    color: #000;
    margin: 0;
    margin-bottom: 40px;
  }

  .wrapper--shopByCategoryTitle {
    margin: 0px auto;
  }

  .headingLevel3--sectionTitle {
    border: none;
    padding: 0;
    margin: 0;
  }

  .link--sectionLink {
    text-decoration: none;
    font-size: 14px;
    line-height: 24px;
    color: var(--fresh-blue);
    font-family: Roboto;
    display: flex;
    align-items: center;
  }

  .link--sectionLink::after {
    content: url("assets/icons/chevronRight.svg");
    display: block;
    margin-left: 8px;
    height: 21px;
  }

  .headingLevel4--bannerTitle {
    max-width: 250px;
    width: 100%;
    margin: 0px auto 12px;
    font-size: 20px;
    line-height: 28px;
    font-weight: 500;
  }

  .paragraph--bannerDesc {
    font-size: 14px;
    line-height: 20px;
  }

  .link--bannerLink {
    height: 40px;
    line-height: 40px;
  }

  .headingLevel3--titleWithBorder {
    font-size: 24px;
    line-height: 32px;
    font-weight: 500;
    font-family: Roboto;
    color: #000;
    margin: 0;
    margin-bottom: 16px;
    padding-bottom: 16px;
    border-bottom: 1px solid #e9eff5;
    text-align: center;
  }

  .wrapper--titleWithBorder {
    width: 100%;
  }

  .paragraph--benefitsItem {
    text-align: center;
    font-size: 12px;
    line-height: 16px;
  }

  .strong--benefitsItem {
    font-size: 16px;
    line-height: 24px;
  }

  .container--paymentLabel {
    justify-content: center;
  }

  .paragraph--paymentLabel {
    margin: 0;
    font-size: 12px;
    line-height: 16px;
    margin-bottom: 12px;
    color: rgba(255, 255, 255, 0.5);
  }

  .paragraph--footerStripe {
    text-align: center;
    padding: 0px;
    margin-bottom: 24px;
  }

  .container--copyright {
    justify-content: center;
  }

  .paragraph--copyright {
    margin: 0;
    margin-bottom: 8px;
    font-size: 12px;
    line-height: 16px;
    font-weight: 500;
    color: #fff;
  }

  .link--HeaderStripeText {
    white-space: nowrap;
  }

  .paragraph--HeaderStripeText,
  .container--HeaderStripeText {
    margin: 0;
  }

  .paragraph--SEOText {
    font-size: 12px;
    line-height: 16px;
  }

  .headingLevel2--quickOrderButtonTitle {
    font-size: 16px;
    line-height: 24px;
    color: #000;
    margin: 0;
    margin-bottom: 4px;
  }

  .paragraph--quickOrderButtonText {
    font-size: 14px;
    line-height: 18px;
    color: #717786;
    margin: 0;
    max-width: 240px;
  }

  .wrapper--quickOrderTitlePageMobile {
    width: 100%;
  }

  .headingLevel1--quickOrderTitlePageMobile {
    font-size: 24px;
    line-height: 32px;
    margin: 0;
    color: #000;
    padding-bottom: 16px;
    margin-bottom: 24px;
    border-bottom: 1px solid #e9eff5;
  }
}

.paragraph--disclosure-trigger-heading {
  color: #000000;
  font-weight: 500;
  font-size: 20px;
  line-height: 24px;
  margin: 0;
  padding: 0;
}

.paragraph--skuList {
  margin: 0;
  line-height: 1.5;
}

.paragraph--modal-trigger-shipping-availability {
  cursor: pointer;
}

.paragraph--modal-trigger-shipping-availability:hover {
  text-decoration: underline;
}

/* Reset Spacing */

.container--reset-spacing,
.container--reset-spacing :not(:global(.vtex-fake)) {
  margin: 0;
  padding: 0;
}

.container--black-medium {
  color: var(--black-medium);
}

.container--fw5 {
  font-weight: 500;
}

.container--newsletter-title,
.wrapper--newsletter-title {
  width: 100%;
}

.container--newsletter-title .heading {
  color: #fff;
  font-size: 2rem;
  font-weight: 500;
  line-height: 1.25;
  margin-right: auto;
}

@media (max-width: 64rem) {
  .container--newsletter-title .heading {
    font-size: 1.25rem;
    line-height: 1.4;
    margin-bottom: 0.75rem;
    text-align: center;
  }
}

.paragraph--form-section-title {
  margin: 0;
  margin-bottom: 0.5rem;
}

.paragraph--product-price-message,
.paragraph--product-summary-price-message {
  text-align: center;
  color: var(--black-medium);
  font-weight: 500;
  margin: 0;
  padding: 0;
}

.paragraph--product-summary-price-message {
  font-size: 0.75rem;
  line-height: 1.5;
}

.container--product-price-message,
.container--product-summary-price-message {
  border: 1px solid var(--lines-dark);
  border-radius: 0.25rem;
  padding: 1rem;
}

.container--product-summary-price-message {
  margin-bottom: 0.5rem;
  padding: 0.5rem;
}

.wrapper--product-price-message,
.wrapper--product-summary-price-message {
  width: 100%;
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/styles/css/vtex.store-icons.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.caretIcon--fresh-blue {
  color: var(--fresh-blue);
}

.caretIcon--lines-darker {
  color: var(--lines-darker);
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/styles/css/vtex.login.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.container :global(.vtex-button) {
  border: 1px solid #fff;
  border-radius: 4px;
  width: 176px;
  height: 48px;
}

.container :global(.vtex-button__label) {
  padding: 0 0 0 0;
}

.label {
  color: #fff;
  text-transform: initial;
  font-size: 16px;
  line-height: 24px;
}

.profile {
  color: #fff;
}

.sendButton :global(.vtex-button) {
  background: #214d8e;
  border: none;
}

@media (max-width: 64rem) {
  .profile {
    display: block;
  }

  .container :global(.vtex-button) {
    width: 74px;
    height: 32px;
    border-color: #fff;
  }

  .label {
    display: block;
    color: #fff;
    font-size: 0;
    padding: 0;
  }

  .label::after {
    content: "Sing in";
    font-family: Roboto;
    font-size: 14px;
    line-height: 32px;
    font-weight: 500;
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/styles/css/vtex.product-summary.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.container--summaryComplete {
  position: relative;
  max-width: 240px;
  border: 1px solid transparent;
  border-radius: 8px;
  padding: 20px;
  transition: all 0.3s ease;
}

.containerNormal--minimumSummary {
  padding: 0 0.5rem;
}

.container--summaryComplete:hover {
  border-color: #dee7ef;
}

.container--summaryComplete:hover
  :global(.vtex-product-comparison-0-x-productSelectorContainer),
.container--summaryComplete:hover .buyButtonContainer,
.container--summaryComplete:hover
  :global(.vtex-flex-layout-0-x-flexRow--product-summary-buy-button),
.container--summaryComplete:hover
  :global(.vtex-wish-list-1-x-wishlistIconContainer),
.container--summaryComplete:hover
  :global(.vtex-modal-layout-0-x-triggerContainer) {
  opacity: 1;
}

.container--summaryComplete
  :global(.vtex-store-components-3-x-installmentsPrice) {
  display: none;
}

.container--summaryComplete .buyButton :global(.vtex-button),
.container--summaryComplete
  :global(.vtex-flex-layout-0-x-flexRow--product-summary-buy-button)
  :global(.vtex-button) {
  border: none;
  background-color: #ff5f00;
  height: 48px;
  border-radius: 4px;
}

.priceContainer {
  align-items: flex-start;
}

.nameWrapper,
.price_sellingPriceContainer,
.price_listPriceContainer {
  text-align: left;
  padding-bottom: 0;
  margin-bottom: 4px;
}

.price_sellingPriceLabel,
.element--minimumSummary .price_listPriceContainer,
.element--minimumSummary .price_installmentContainer {
  display: none;
  overflow: 0;
  visibility: hidden;
}

.container--summaryComplete .price_listPrice,
.container--summaryComplete .price_sellingPrice {
  padding: 0;
}

.container--summaryComplete .productBrandContainer {
  font-size: 14px;
  color: #0067c7;
  font-weight: 500;
  line-height: 20px;
  text-align: left;
}

.container--summaryComplete .nameContainer {
  padding: 0;
}

.container--summaryComplete .productNameContainer {
  text-align: left;
  font-size: 16px;
  line-height: 22px;
  color: #000;
  width: 100%;
  margin-bottom: 16px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.container--summaryComplete .buyButtonContainer,
.container--summaryComplete
  :global(.vtex-flex-layout-0-x-flexRow--product-summary-buy-button) {
  margin-top: auto;
  margin-bottom: 16px;
  padding: 0;
}

.container--summaryComplete .image {
  margin-bottom: 16px;
  width: 196px;
  height: 196px;
  object-fit: contain;
}

.element--summaryComplete {
  padding: 0;
}

.element--summaryComplete .priceContainer {
  align-items: flex-start;
  padding: 0;
}

.element--summaryComplete .buyButtonContainer,
.element--summaryComplete
  :global(.vtex-flex-layout-0-x-flexRow--product-summary-buy-button) {
  opacity: 0;
  transition: all 0.3s ease;
}

.element--summaryComplete .productPriceClass {
  flex-flow: column-reverse;
}

.element--summaryComplete .listPriceLabel,
.element--summaryComplete .sellingPriceLabel {
  display: none;
}

.element--summaryComplete .listPriceValue .currencyContainer {
  font-size: 12px;
  line-height: 16px;
  font-weight: 400;
  font-family: Roboto;
  color: #717786;
}

.currencyCode {
  margin-right: 4px;
}

/* BEGIN - Trending Shelg */

.column--summaryCol {
  flex-flow: column nowrap;
  align-items: flex-start;
}

.element--trendingSummary
  :global(.vtex-reviews-and-ratings-1-x-inlineContainer) {
  margin: 0;
}

.element--trendingSummary :global(.vtex-flex-layout-0-x-flexRowContent) {
  align-items: center;
}

.element--trendingSummary .imageStackContainer {
  margin-right: 24px;
}

.container--trendingSummary {
  max-width: 100% !important;
  width: 100%;
  background: #fff;
  border-radius: 8px;
  padding: 16px 24px;
  border: 1px solid transparent;
  transition: all 0.3s ease;
}

.container--trendingSummary:hover {
  border: 1px solid var(--fresh-blue);
  box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.1);
}

.element--trendingSummary {
  justify-content: center;
  padding: 0;
}

.element--trendingSummary .price_installmentContainer,
.element--trendingSummary .listPriceContainer {
  display: none;
}

.element--trendingSummary .image {
  width: 96px !important;
  height: 96px;
  object-fit: cover;
}

.element--trendingSummary .nameContainer {
  padding: 0;
  margin-bottom: 8px;
}

.element--trendingSummary .productBrand {
  font-weight: 700;
  text-align: left;
  color: #000;
  font-size: 16px;
  line-height: 22px;
}

.element--trendingSummary .price_sellingPrice,
.element--trendingSummary .price_sellingPriceContainer,
.element--trendingSummary .priceContainer {
  padding: 0;
}

/* END - Trending Shelg */
/* BEGIN - Popular Shelf */

.container--minimumSummary .image {
  width: 192px;
  height: 192px;
  object-fit: contain;
}

/* END - Popular Shelf */

.column--drawer-summary-col2 {
  align-items: flex-start;
}

.element--comparison-page-summary .buyButton :global(.vtex-button),
.element--comparison-page-summary
  :global(.vtex-flex-layout-0-x-flexRow--product-summary-buy-button)
  :global(.vtex-button) {
  border: none;
  height: 48px;
  background: #ff5f00;
}

.element--comparison-page-summary .sellingPrice,
.element--comparison-page-summary .buyButtonContainer,
.element--comparison-page-summary
  :global(.vtex-flex-layout-0-x-flexRow--product-summary-buy-button) {
  padding: 0;
}

/* BEGIN - Search Bar Summary */

.element--summarySearch .imageContainer {
  margin-bottom: 8px;
  width: auto;
  margin-right: auto;
  margin-left: initial;
}

.element--summarySearch .productBrandContainer {
  text-align: left;
}

.element--summarySearch .productBrandContainer .productBrandName {
  font-size: 14px;
  color: #0067c7;
  font-weight: 500;
  line-height: 20px;
  margin-bottom: 4px;
}

.element--summarySearch .nameContainer {
  padding: 0;
  justify-content: flex-start;
}

.element--summarySearch .nameContainer .productBrand {
  font-size: 12px;
  line-height: 18px;
  color: #000;
}

/* END - Search Bar Summary */

@media (max-width: 64rem) {
  .container--summaryComplete {
    padding: 8px;
  }

  .container--summaryComplete {
    min-width: 144px !important;
    max-width: 100% !important;
  }

  .element--minimumSummary
    :global(.vtex-reviews-and-ratings-1-x-inlineContainer) {
    margin: 0;
  }

  .element--minimumSummary .priceContainer {
    align-items: flex-start;
  }

  .element--summaryComplete .price_sellingPrice {
    font-size: 20px;
    color: #000;
    line-height: 24px;
    font-weight: 500;
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of b2b-theme/styles/css/vtex.location-availability.css from the b2b-theme VTEX app.

[Assistant]
Here's the implementation:

```css
.shippingHeader--desktop {
  display: none;
  font-size: 16px;
  font-weight: 500;
  color: black;
}

.shippingListItem--desktop {
  display: none;
}

.shippingListItem--desktop:first-child {
  display: block;
}

.shippingListEmptyMessage,
.shippingDeliveryName--desktop,
.shippingListItem--desktop {
  font-size: 14px;
  color: black;
}

```