diff --git a/.drone/drone.yml b/.drone/drone.yml deleted file mode 100644 index e1f3d6f..0000000 --- a/.drone/drone.yml +++ /dev/null @@ -1,170 +0,0 @@ -kind: pipeline -type: docker -name: linux-amd64 - -platform: - arch: amd64 - os: linux - -steps: -- name: test - image: docker.io/drycc/go-dev - pull: always - privileged: true - commands: - - make test docker-build-test upload-coverage - environment: - VERSION: ${DRONE_TAG:-latest}-linux-amd64 - DEV_REGISTRY: ${DEV_REGISTRY:-docker.io} - DRYCC_REGISTRY: ${DRYCC_REGISTRY:-docker.io} - CODECOV_TOKEN: - from_secret: codecov_token - when: - event: - - push - - tag - - pull_request - volumes: - - name: image_registries - path: /etc/containers/registries.conf - -- name: publish - image: docker.io/drycc/go-dev - pull: always - privileged: true - commands: - - echo $DOCKER_PASSWORD | docker login $DRYCC_REGISTRY --username $DOCKER_USERNAME --password-stdin - - make docker-build docker-immutable-push - environment: - VERSION: ${DRONE_TAG:-latest}-linux-amd64 - DEV_REGISTRY: - from_secret: dev_registry - DRYCC_REGISTRY: - from_secret: drycc_registry - DOCKER_USERNAME: - from_secret: docker_username - DOCKER_PASSWORD: - from_secret: docker_password - when: - event: - - push - - tag - volumes: - - name: image_registries - path: /etc/containers/registries.conf - -trigger: - event: - - push - - tag - - pull_request - -volumes: -- name: image_registries - host: - path: /etc/containers/registries.conf - ---- -kind: pipeline -type: docker -name: linux-arm64 - -platform: - arch: arm64 - os: linux - -steps: -- name: publish - image: docker.io/drycc/go-dev - pull: always - privileged: true - commands: - - echo $DOCKER_PASSWORD | docker login $DRYCC_REGISTRY --username $DOCKER_USERNAME --password-stdin - - make docker-build docker-immutable-push - environment: - VERSION: ${DRONE_TAG:-latest}-linux-arm64 - DEV_REGISTRY: - from_secret: dev_registry - DRYCC_REGISTRY: - from_secret: drycc_registry - DOCKER_USERNAME: - from_secret: docker_username - DOCKER_PASSWORD: - from_secret: docker_password - volumes: - - name: image_registries - path: /etc/containers/registries.conf - -trigger: - event: - - push - - tag - -volumes: -- name: image_registries - host: - path: /etc/containers/registries.conf - ---- -kind: pipeline -type: docker -name: manifest - -steps: -- name: generate manifest - image: docker.io/library/alpine - pull: always - commands: - - sed -i "s/docker.io/$${DRYCC_REGISTRY}/g" .drone/manifest.tmpl - environment: - DRYCC_REGISTRY: - from_secret: drycc_registry - -- name: publish - image: plugins/manifest - settings: - spec: .drone/manifest.tmpl - username: - from_secret: docker_username - password: - from_secret: docker_password - environment: - DEV_REGISTRY: - from_secret: dev_registry - DRYCC_REGISTRY: - from_secret: drycc_registry - -trigger: - event: - - push - - tag - -depends_on: -- linux-amd64 -- linux-arm64 - ---- -kind: pipeline -type: docker -name: chart - -steps: -- name: generate chart - image: docker.io/drycc/python-dev - commands: - - IMAGE_TAG=$([ ! -z $DRONE_TAG ] && echo \"${DRONE_TAG:1}\" || echo \"canary\") - - sed -i "s/image_tag:\ \"canary\"/image_tag:\ $IMAGE_TAG/g" charts/passport/values.yaml - - helm package charts/passport --version ${DRONE_TAG:-v1.0.0} - - curl -u $CHARTMUSEUM_USERNAME:$CHARTMUSEUM_PASSWORD -F chart=@passport-${DRONE_TAG:-v1.0.0}.tgz "$CHARTMUSEUM_API/api/$([ -z $DRONE_TAG ] && echo testing || echo stable)/charts" - environment: - CHARTMUSEUM_USERNAME: - from_secret: chartmuseum_username - CHARTMUSEUM_PASSWORD: - from_secret: chartmuseum_password - CHARTMUSEUM_API: - from_secret: chartmuseum_api - -trigger: - event: - - push - - tag diff --git a/.drone/manifest.tmpl b/.drone/manifest.tmpl deleted file mode 100644 index 7ae9b31..0000000 --- a/.drone/manifest.tmpl +++ /dev/null @@ -1,18 +0,0 @@ -image: docker.io/drycc/passport:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}canary{{/if}} -{{#if build.tags}} -tags: -{{#each build.tags}} - - {{this}} -{{/each}} -{{/if}} -manifests: - - - image: docker.io/drycc/passport:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-amd64 - platform: - architecture: amd64 - os: linux - - - image: docker.io/drycc/passport:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-arm64 - platform: - architecture: arm64 - os: linux diff --git a/.gitignore b/.gitignore index c2d15d2..035dd09 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,9 @@ develop-eggs .installed.cfg lib lib64 +.env +.vscode +.venv # coverage reports .coverage @@ -24,6 +27,7 @@ htmlcov/ venv/ .idea +.sisyphus env/ rootfs/web/yarn-error.log rootfs/node_modules/ diff --git a/.woodpecker/build-linux.yml b/.woodpecker/build-linux.yml new file mode 100644 index 0000000..ef4ecfd --- /dev/null +++ b/.woodpecker/build-linux.yml @@ -0,0 +1,35 @@ +matrix: + platform: + - linux/amd64 + - linux/arm64 + +labels: + type: exec + platform: ${platform} + +steps: +- name: publish-linux + image: bash + commands: + - export VERSION=$([ -z $CI_COMMIT_TAG ] && echo latest || echo $CI_COMMIT_TAG)-$(sed 's#/#-#g' <<< $CI_SYSTEM_PLATFORM) + - echo $CONTAINER_PASSWORD | podman login $DRYCC_REGISTRY --username $CONTAINER_USERNAME --password-stdin > /dev/null 2>&1 + - make podman-build podman-immutable-push + environment: + CODENAME: + from_secret: codename + DEV_REGISTRY: + from_secret: dev_registry + DRYCC_REGISTRY: + from_secret: drycc_registry + CONTAINER_USERNAME: + from_secret: container_username + CONTAINER_PASSWORD: + from_secret: container_password + when: + event: + - push + - tag + - cron + +depends_on: +- test-linux \ No newline at end of file diff --git a/.woodpecker/chart.yaml b/.woodpecker/chart.yaml new file mode 100644 index 0000000..cfcd3ec --- /dev/null +++ b/.woodpecker/chart.yaml @@ -0,0 +1,33 @@ +labels: + type: exec + platform: linux/amd64 + +steps: +- name: generate-chart + image: bash + commands: + - export VERSION=$(sed 's#v##' <<< $CI_COMMIT_TAG) + - export IMAGE_TAG=$([ ! -z $CI_COMMIT_TAG ] && echo \"$VERSION\" || echo \"canary\") + - export APP_VERSION=$([ -z $CI_COMMIT_TAG ] && echo $CI_COMMIT_SHA || echo $VERSION) + - export CHART_VERSION=$([ -z $CI_COMMIT_TAG ] && echo 1.0.0 || echo $VERSION) + - sed -i "s/imageTag:\ \"canary\"/imageTag:\ $IMAGE_TAG/g" charts/$${CI_REPO_NAME}/values.yaml + - helm package -u charts/$${CI_REPO_NAME} --version $CHART_VERSION --app-version $APP_VERSION + - echo $CONTAINER_PASSWORD | helm registry login $DRYCC_REGISTRY -u $CONTAINER_USERNAME --password-stdin + - helm push $${CI_REPO_NAME}-$CHART_VERSION.tgz oci://$DRYCC_REGISTRY/$([ -z $CI_COMMIT_TAG ] && echo charts-testing || echo charts) + environment: + DEV_REGISTRY: + from_secret: dev_registry + DRYCC_REGISTRY: + from_secret: drycc_registry + CONTAINER_USERNAME: + from_secret: container_username + CONTAINER_PASSWORD: + from_secret: container_password + when: + event: + - push + - tag + - cron + +depends_on: +- manifest diff --git a/.woodpecker/manifest.tmpl b/.woodpecker/manifest.tmpl new file mode 100644 index 0000000..8739535 --- /dev/null +++ b/.woodpecker/manifest.tmpl @@ -0,0 +1,18 @@ +image: registry.drycc.cc/drycc/{{project}}:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}canary{{/if}} +{{#if build.tags}} +tags: +{{#each build.tags}} + - {{this}} +{{/each}} +{{/if}} +manifests: + - + image: registry.drycc.cc/drycc/{{project}}:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-amd64 + platform: + architecture: amd64 + os: linux + - + image: registry.drycc.cc/drycc/{{project}}:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-arm64 + platform: + architecture: arm64 + os: linux diff --git a/.woodpecker/manifest.yml b/.woodpecker/manifest.yml new file mode 100644 index 0000000..19fc70c --- /dev/null +++ b/.woodpecker/manifest.yml @@ -0,0 +1,43 @@ +labels: + type: exec + platform: linux/amd64 + +steps: +- name: generate-manifest + image: bash + commands: + - sed -i "s/{{project}}/$${CI_REPO_NAME}/g" .woodpecker/manifest.tmpl + - sed -i "s/registry.drycc.cc/$${DRYCC_REGISTRY}/g" .woodpecker/manifest.tmpl + environment: + DRYCC_REGISTRY: + from_secret: drycc_registry + when: + event: + - tag + - push + - cron + +- name: publish-manifest + image: bash + commands: + - podman run --rm + -e PLUGIN_SPEC=.woodpecker/manifest.tmpl + -e PLUGIN_USERNAME=$CONTAINER_USERNAME + -e PLUGIN_PASSWORD=$CONTAINER_PASSWORD + -e DRONE_TAG=$CI_COMMIT_TAG + -v $(pwd):$(pwd) + -w $(pwd) + docker.io/plugins/manifest + environment: + CONTAINER_USERNAME: + from_secret: container_username + CONTAINER_PASSWORD: + from_secret: container_password + when: + event: + - tag + - push + - cron + +depends_on: +- build-linux diff --git a/.woodpecker/test-linux.yml b/.woodpecker/test-linux.yml new file mode 100644 index 0000000..f22a5f0 --- /dev/null +++ b/.woodpecker/test-linux.yml @@ -0,0 +1,26 @@ +matrix: + platform: + - linux/amd64 + - linux/arm64 + +labels: + type: exec + platform: ${platform} + +steps: +- name: test-linux + image: bash + commands: + - make test podman-build-test upload-coverage + environment: + CODENAME: + from_secret: codename + DEV_REGISTRY: + from_secret: dev_registry + CODECOV_TOKEN: + from_secret: codecov_token + when: + event: + - push + - tag + - cron diff --git a/Makefile b/Makefile index e6db5d5..b070b54 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ PLATFORM ?= linux/amd64,linux/arm64 include versioning.mk -SHELLCHECK_PREFIX := docker run -v ${CURDIR}:/workdir -w /workdir ${DEV_REGISTRY}/drycc/go-dev shellcheck +SHELLCHECK_PREFIX := podman run -v ${CURDIR}:/workdir -w /workdir ${DEV_REGISTRY}/drycc/go-dev shellcheck SHELL_SCRIPTS = $(wildcard rootfs/bin/*) $(shell find "rootfs" -name '*.sh') $(wildcard _scripts/*.sh) # Test processes used in quick unit testing @@ -19,44 +19,41 @@ check-kubectl: exit 2; \ fi -check-docker: - @if [ -z $$(which docker) ]; then \ - echo "Missing \`docker\` client which is required for development"; \ +check-podman: + @if [ -z $$(which podman) ]; then \ + echo "Missing \`podman\` client which is required for development"; \ exit 2; \ fi -build: docker-build +build: podman-build -docker-build: check-docker - docker build ${DOCKER_BUILD_FLAGS} -t ${IMAGE} rootfs - docker tag ${IMAGE} ${MUTABLE_IMAGE} +podman-build: check-podman + podman build --build-arg CODENAME=${CODENAME} -t ${IMAGE} rootfs + podman tag ${IMAGE} ${MUTABLE_IMAGE} -docker-buildx: check-docker - docker buildx build --platform ${PLATFORM} -t ${IMAGE} rootfs --push +podman-build-test: check-podman + podman build --build-arg CODENAME=${CODENAME} -t ${IMAGE}.test -f rootfs/Dockerfile.test rootfs -docker-build-test: check-docker - docker build ${DOCKER_BUILD_FLAGS} -t ${IMAGE}.test -f rootfs/Dockerfile.test rootfs - -deploy: check-kubectl docker-build docker-push +deploy: check-kubectl podman-build podman-push kubectl --namespace=drycc patch deployment drycc-$(COMPONENT) --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"$(IMAGE)"}]' -clean: check-docker - docker rmi $(IMAGE) +clean: check-podman + podman rmi $(IMAGE) commit-hook: cp _scripts/util/commit-msg .git/hooks/commit-msg -full-clean: check-docker - docker images -q $(IMAGE_PREFIX)/$(COMPONENT) | xargs docker rmi -f +full-clean: check-podman + podman images -q $(IMAGE_PREFIX)/$(COMPONENT) | xargs podman rmi -f test: test-style test-unit test-functional -test-style: docker-build-test - docker run -v ${CURDIR}:/test -w /test/rootfs ${IMAGE}.test /test/rootfs/bin/test-style +test-style: podman-build-test + podman run -v ${CURDIR}:/test -w /test/rootfs ${IMAGE}.test /test/rootfs/bin/test-style ${SHELLCHECK_PREFIX} $(SHELL_SCRIPTS) -test-unit: docker-build-test - docker run -v ${CURDIR}:/test -w /test/rootfs ${IMAGE}.test /test/rootfs/bin/test-unit +test-unit: podman-build-test + podman run -v ${CURDIR}:/test -w /test/rootfs ${IMAGE}.test /test/rootfs/bin/test-unit test-functional: @echo "Implement functional tests in _tests directory" @@ -66,6 +63,6 @@ test-integration: upload-coverage: $(eval CI_ENV := $(shell curl -s https://codecov.io/env | bash)) - docker run ${CI_ENV} -v ${CURDIR}:/test -w /test/rootfs ${IMAGE}.test codecov --required + podman run ${CI_ENV} -v ${CURDIR}:/test -w /test/rootfs -e CODECOV_TOKEN=${CODECOV_TOKEN} ${IMAGE}.test /test/rootfs/bin/upload-coverage -.PHONY: check-kubectl check-docker build docker-build docker-build-test deploy clean commit-hook full-clean test test-style test-unit test-functional test-integration upload-coverage +.PHONY: check-kubectl check-podman build podman-build podman-build-test deploy clean commit-hook full-clean test test-style test-unit test-functional test-integration upload-coverage diff --git a/README.md b/README.md index 76f222a..725655e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Drycc Passport -[![Build Status](https://drone.drycc.cc/api/badges/drycc/passport/status.svg)](https://drone.drycc.cc/drycc/passport) +[![Build Status](https://woodpecker.drycc.cc/api/badges/drycc/passport/status.svg)](https://woodpecker.drycc.cc/drycc/passport) [![codecov.io](https://codecov.io/github/drycc/passport/coverage.svg?branch=main)](https://codecov.io/github/drycc/passport?branch=main) Drycc (pronounced DAY-iss) Workflow is an open source Platform as a Service (PaaS) that adds a developer-friendly layer to any [Kubernetes](http://kubernetes.io) cluster, making it easy to deploy and manage applications on your own servers. @@ -12,5 +12,4 @@ If you'd like to participate in development, please read the "Development" secti # About -The Passport is the Oauth2.0 API server for [Drycc Workflow](https://drycc.cc). - +The Passport is the Oauth2.0 API server for [Drycc Workflow](https://www.drycc.cc). diff --git a/charts/passport/Chart.yaml b/charts/passport/Chart.yaml index 81e3433..ca02b02 100644 --- a/charts/passport/Chart.yaml +++ b/charts/passport/Chart.yaml @@ -1,7 +1,13 @@ name: passport home: https://github.com/drycc/passport -version: v1.0.0 +apiVersion: v2 +appVersion: 1.0.0 +dependencies: + - name: common + repository: oci://registry.drycc.cc/charts + version: ~1.1.2 description: Drycc Workflow passport (API). maintainers: - name: Drycc Team email: engineering@drycc.com +version: v1.0.0 diff --git a/charts/passport/files/reserved-name-patterns.txt b/charts/passport/files/reserved-name-patterns.txt new file mode 100644 index 0000000..1b6ca23 --- /dev/null +++ b/charts/passport/files/reserved-name-patterns.txt @@ -0,0 +1,13 @@ +^backup$ +^catalog$ +^cert-manager$ +^default$ +^drycc(?:-[\w-]+)?$ +^istio(?:-[\w-]+)?$ +^kube(?:-[\w-]+)?$ +^longhorn-system$ +^metallb$ +^mount-s3$ +^topolvm$ +^rook-ceph$ +^personal$ \ No newline at end of file diff --git a/charts/passport/templates/_helpers.tpl b/charts/passport/templates/_helpers.tpl index 81902d1..e29a72f 100644 --- a/charts/passport/templates/_helpers.tpl +++ b/charts/passport/templates/_helpers.tpl @@ -14,61 +14,51 @@ rbac.authorization.k8s.io/v1 {{/* Generate passport deployment envs */}} {{- define "passport.envs" }} env: -- name: "TZ" +- name: TZ value: {{ .Values.time_zone | default "UTC" | quote }} -- name: "DRYCC_CONTROLLER_DOMAIN" -{{- if .Values.global.cert_manager_enabled }} - value: https://drycc.{{ .Values.global.platform_domain }} -{{- else }} - value: http://drycc.{{ .Values.global.platform_domain }} -{{- end }} -- name: SOCIAL_AUTH_DRYCC_CONTROLLER_KEY - valueFrom: - secretKeyRef: - name: passport-creds - key: social-auth-drycc-controller-key -- name: SOCIAL_AUTH_DRYCC_CONTROLLER_SECRET - valueFrom: - secretKeyRef: - name: passport-creds - key: social-auth-drycc-controller-secret -- name: WORKFLOW_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace +- name: "DJANGO_SETTINGS_MODULE" + value: "api.settings.production" +- name: VERSION + value: {{ .Chart.AppVersion }} - name: ADMIN_USERNAME - value: {{ .Values.admin_username | default "admin" | quote }} + value: {{ .Values.adminUsername | default "admin" | quote }} - name: ADMIN_PASSWORD - value: {{ .Values.admin_password | default "admin" | quote }} + value: {{ .Values.adminPassword | default "admin" | quote }} - name: ADMIN_EMAIL - value: {{ .Values.admin_email | default "admin@email.com" | quote }} -{{- if eq .Values.global.grafana_location "on-cluster" }} -- name: "DRYCC_MONITOR_GRAFANA_DOMAIN" -{{- if .Values.global.cert_manager_enabled }} - value: https://drycc-monitor-grafana.{{ .Values.global.platform_domain }} -{{- else }} - value: http://drycc-monitor-grafana.{{ .Values.global.platform_domain }} -{{- end }} -- name: GRAFANA_ON_CLUSTER - value: "true" -- name: SOCIAL_AUTH_DRYCC_GRAFANA_KEY + value: {{ .Values.adminEmail | default "admin@email.com" | quote }} +- name: PLATFORM_DOMAIN + value: {{ .Values.global.platformDomain }} +- name: CERT_MANAGER_ENABLED + value: "{{ .Values.global.certManagerEnabled }}" +{{- if (.Values.valkeyUrl) }} +- name: DRYCC_VALKEY_URL valueFrom: secretKeyRef: name: passport-creds - key: social-auth-drycc-grafana-key -- name: SOCIAL_AUTH_DRYCC_GRAFANA_SECRET + key: valkey-url +{{- else if .Values.valkey.enabled }} +- name: VALKEY_PASSWORD valueFrom: secretKeyRef: - name: passport-creds - key: social-auth-drycc-grafana-secret + name: valkey-creds + key: password +- name: DRYCC_VALKEY_URL + value: "redis://:$(VALKEY_PASSWORD)@drycc-valkey:16379/1" {{- end }} -{{- if (.Values.database_url) }} +{{- if (.Values.databaseUrl) }} - name: DRYCC_DATABASE_URL valueFrom: secretKeyRef: name: passport-creds key: database-url -{{- else if eq .Values.global.database_location "on-cluster" }} +{{- if (.Values.databaseReplicaUrl) }} +- name: DRYCC_DATABASE_REPLICA_URL + valueFrom: + secretKeyRef: + name: passport-creds + key: database-replica-url +{{- end }} +{{- else if .Values.database.enabled }} - name: DRYCC_DATABASE_USER valueFrom: secretKeyRef: @@ -79,13 +69,10 @@ env: secretKeyRef: name: database-creds key: password -- name: DRYCC_DATABASE_NAME - valueFrom: - secretKeyRef: - name: database-creds - key: passport-database-name - name: DRYCC_DATABASE_URL - value: "postgres://$(DRYCC_DATABASE_USER):$(DRYCC_DATABASE_PASSWORD)@$(DRYCC_DATABASE_SERVICE_HOST):$(DRYCC_DATABASE_SERVICE_PORT)/$(DRYCC_DATABASE_NAME)" + value: "postgres://$(DRYCC_DATABASE_USER):$(DRYCC_DATABASE_PASSWORD)@drycc-database:5432/passport" +- name: DRYCC_DATABASE_REPLICA_URL + value: "postgres://$(DRYCC_DATABASE_USER):$(DRYCC_DATABASE_PASSWORD)@drycc-database-replica:5432/passport" {{- end }} {{- range $key, $value := .Values.environment }} - name: {{ $key }} @@ -94,34 +81,24 @@ env: {{- end }} -{{/* Generate passport deployment limits */}} -{{- define "passport.limits" -}} -{{- if or (.Values.limits_cpu) (.Values.limits_memory) }} -resources: - limits: -{{- if (.Values.limits_cpu) }} - cpu: {{.Values.limits_cpu}} -{{- end }} -{{- if (.Values.limits_memory) }} - memory: {{.Values.limits_memory}} -{{- end }} -{{- end }} -{{- end }} - - {{/* Generate passport deployment volumeMounts */}} {{- define "passport.volumeMounts" }} volumeMounts: - name: passport-creds mountPath: /var/run/secrets/drycc/passport readOnly: true + - name: passport-config + mountPath: /etc/drycc/passport + readOnly: true {{- end }} - {{/* Generate passport deployment volumes */}} {{- define "passport.volumes" }} volumes: - name: passport-creds secret: secretName: passport-creds + - name: passport-config + configMap: + name: passport-config {{- end }} diff --git a/charts/passport/templates/api/passport-api-deployment.yaml b/charts/passport/templates/api/passport-api-deployment.yaml new file mode 100644 index 0000000..a06f714 --- /dev/null +++ b/charts/passport/templates/api/passport-api-deployment.yaml @@ -0,0 +1,73 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: drycc-passport-api + labels: + heritage: drycc + annotations: + component.drycc.cc/version: {{ .Values.imageTag }} +spec: + replicas: {{ .Values.api.replicas }} + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + type: RollingUpdate + selector: + matchLabels: + app: drycc-passport + component: drycc-passport-api + template: + metadata: + labels: {{- include "common.labels.standard" . | nindent 8 }} + app: drycc-passport + component: drycc-passport-api + spec: + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.api.podAffinityPreset.type "component" "" "extraMatchLabels" .Values.api.podAffinityPreset.extraMatchLabels "topologyKey" "" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.api.podAntiAffinityPreset.type "component" "" "extraMatchLabels" .Values.api.podAntiAffinityPreset.extraMatchLabels "topologyKey" "" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.api.nodeAffinityPreset.type "key" .Values.api.nodeAffinityPreset.key "values" .Values.api.nodeAffinityPreset.values ) | nindent 10 }} + serviceAccount: drycc-passport + initContainers: + - name: drycc-passport-api-init + image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/python-dev:latest + imagePullPolicy: {{.Values.imagePullPolicy}} + args: + - netcat + - -v + - -u + - $(DRYCC_DATABASE_URL),$(DRYCC_DATABASE_REPLICA_URL),$(DRYCC_VALKEY_URL) + {{- include "passport.envs" . | indent 8 }} + containers: + - name: drycc-passport-api + image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/passport:{{.Values.imageTag}} + imagePullPolicy: {{.Values.imagePullPolicy}} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 10 }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 10 }} + {{- end }} + {{- if not .Values.diagnosticMode.enabled }} + livenessProbe: + httpGet: + path: /healthz + port: 8000 + initialDelaySeconds: 30 + timeoutSeconds: 10 + readinessProbe: + httpGet: + path: /readiness + port: 8000 + initialDelaySeconds: 30 + timeoutSeconds: 10 + periodSeconds: 5 + {{- end }} + ports: + - containerPort: 8000 + name: http + {{- with index .Values "api" "resources" }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- include "passport.envs" . | indent 8 }} + {{- include "passport.volumeMounts" . | indent 8 }} + {{- include "passport.volumes" . | indent 6 }} diff --git a/charts/passport/templates/celery/passport-celery-deployment.yaml b/charts/passport/templates/celery/passport-celery-deployment.yaml new file mode 100644 index 0000000..5c118b0 --- /dev/null +++ b/charts/passport/templates/celery/passport-celery-deployment.yaml @@ -0,0 +1,65 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: drycc-passport-celery + labels: + heritage: drycc + annotations: + component.drycc.cc/version: {{ .Values.imageTag }} +spec: + replicas: {{ .Values.celery.replicas }} + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + type: RollingUpdate + selector: + matchLabels: + app: drycc-passport + component: drycc-passport-celery + template: + metadata: + labels: {{- include "common.labels.standard" . | nindent 8 }} + app: drycc-passport + component: drycc-passport-celery + spec: + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.celery.podAffinityPreset.type "component" "" "extraMatchLabels" .Values.celery.podAffinityPreset.extraMatchLabels "topologyKey" "" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.celery.podAntiAffinityPreset.type "component" "" "extraMatchLabels" .Values.celery.podAntiAffinityPreset.extraMatchLabels "topologyKey" "" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.celery.nodeAffinityPreset.type "key" .Values.celery.nodeAffinityPreset.key "values" .Values.celery.nodeAffinityPreset.values ) | nindent 10 }} + serviceAccount: drycc-passport + initContainers: + - name: drycc-passport-init + image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/python-dev:latest + imagePullPolicy: {{.Values.imagePullPolicy}} + args: + - netcat + - -v + - -u + - $(DRYCC_DATABASE_URL),$(DRYCC_DATABASE_REPLICA_URL),$(DRYCC_VALKEY_URL) + {{- include "passport.envs" . | indent 8 }} + containers: + - name: drycc-passport-celery + image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/passport:{{.Values.imageTag}} + imagePullPolicy: {{.Values.imagePullPolicy}} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 10 }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 10 }} + {{- else }} + args: + - celery + - -A + - api + - worker + - -Q + - passport.notifications + - -l + - info + {{- end }} + {{- with index .Values "celery" "resources" }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- include "passport.envs" . | indent 8 }} + {{- include "passport.volumeMounts" . | indent 8 }} + {{- include "passport.volumes" . | indent 6 }} diff --git a/charts/passport/templates/passport-certificate.yaml b/charts/passport/templates/passport-certificate.yaml deleted file mode 100644 index a5b000c..0000000 --- a/charts/passport/templates/passport-certificate.yaml +++ /dev/null @@ -1,17 +0,0 @@ -{{- if eq .Values.global.passport_location "on-cluster" }} -{{- if .Values.global.cert_manager_enabled }} -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: drycc-passport -spec: - secretName: drycc-passport-certificate-auto - issuerRef: - name: drycc-cluster-issuer - kind: ClusterIssuer - dnsNames: - - drycc-passport.{{ .Values.global.platform_domain }} - privateKey: - rotationPolicy: Always -{{- end }} -{{- end }} diff --git a/charts/passport/templates/passport-configmap.yaml b/charts/passport/templates/passport-configmap.yaml new file mode 100644 index 0000000..8280dcf --- /dev/null +++ b/charts/passport/templates/passport-configmap.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: passport-config + labels: + heritage: drycc +data: + init-applications.json: |- +{{ toPrettyJson .Values.initApplications | indent 4 }} + reserved-name-patterns.txt: |- + {{- if .Values.reservedNames }} + {{- (tpl .Values.reservedNames $) | nindent 4 }} + {{- else}} + {{- .Files.Get "files/reserved-name-patterns.txt" | nindent 4 }} + {{- end }} \ No newline at end of file diff --git a/charts/passport/templates/passport-deployment.yaml b/charts/passport/templates/passport-deployment.yaml deleted file mode 100644 index 6346128..0000000 --- a/charts/passport/templates/passport-deployment.yaml +++ /dev/null @@ -1,60 +0,0 @@ -{{- if eq .Values.global.passport_location "on-cluster" }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: drycc-passport - labels: - heritage: drycc - annotations: - component.drycc.cc/version: {{ .Values.image_tag }} -spec: - replicas: {{ .Values.replicas }} - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - type: RollingUpdate - selector: - matchLabels: - app: drycc-passport - template: - metadata: - labels: - app: drycc-passport - spec: - serviceAccount: drycc-passport - initContainers: - - name: drycc-passport-init - image: docker.io/drycc/python-dev:latest - imagePullPolicy: {{.Values.image_pull_policy}} - command: - - netcat - - -v - - -u - - $(DRYCC_DATABASE_URL) - {{- include "passport.envs" . | indent 8 }} - containers: - - name: drycc-passport - image: {{.Values.image_registry}}/{{.Values.image_org}}/passport:{{.Values.image_tag}} - imagePullPolicy: {{.Values.image_pull_policy}} - livenessProbe: - httpGet: - path: /healthz - port: 8000 - initialDelaySeconds: 30 - timeoutSeconds: 10 - readinessProbe: - httpGet: - path: /readiness - port: 8000 - initialDelaySeconds: 30 - timeoutSeconds: 10 - periodSeconds: 5 - ports: - - containerPort: 8000 - name: http - {{- include "passport.limits" . | indent 8 }} - {{- include "passport.envs" . | indent 8 }} - {{- include "passport.volumeMounts" . | indent 8 }} - {{- include "passport.volumes" . | indent 6 }} -{{- end }} diff --git a/charts/passport/templates/passport-ingress.yaml b/charts/passport/templates/passport-ingress.yaml deleted file mode 100644 index 7de1973..0000000 --- a/charts/passport/templates/passport-ingress.yaml +++ /dev/null @@ -1,38 +0,0 @@ -{{- if eq .Values.global.passport_location "on-cluster" }} -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: "passport-api-server" - labels: - app: "passport" - chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" - annotations: - kubernetes.io/tls-acme: "true" - {{- if not (eq .Values.global.ingress_class "") }} - kubernetes.io/ingress.class: "{{ .Values.global.ingress_class }}" - {{ end }} -spec: - rules: - - host: drycc-passport.{{ .Values.global.platform_domain }} - http: - paths: - - pathType: Prefix - {{- if eq .Values.global.ingress_class "gce" "alb" }} - path: /* - {{- else }}{{/* Has annotations but ingress class is not "gce" nor "alb" */}} - path: / - {{- end }} - backend: - service: - name: drycc-passport - port: - number: 80 - {{ if .Values.global.cert_manager_enabled }} - tls: - - secretName: drycc-passport-certificate-auto - hosts: - - drycc-passport.{{ .Values.global.platform_domain }} - {{- end }} -{{- end }} diff --git a/charts/passport/templates/passport-job-upgrade.yaml b/charts/passport/templates/passport-job-upgrade.yaml new file mode 100644 index 0000000..b15a2e0 --- /dev/null +++ b/charts/passport/templates/passport-job-upgrade.yaml @@ -0,0 +1,47 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: drycc-passport-job-upgrade + annotations: + component.drycc.cc/version: {{ .Values.imageTag }} +spec: + template: + spec: + initContainers: + - name: drycc-passport-init + image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/python-dev:latest + imagePullPolicy: {{.Values.imagePullPolicy}} + args: + - netcat + - -v + - -u + - $(DRYCC_DATABASE_URL),$(DRYCC_DATABASE_REPLICA_URL) + {{- include "passport.envs" . | indent 8 }} + containers: + - name: drycc-passport-job-upgrade + image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/passport:{{.Values.imageTag}} + imagePullPolicy: {{.Values.imagePullPolicy}} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 8 }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 8 }} + {{- else }} + args: + - /usr/bin/env + - bash + - -ec + - | + python -u /workspace/manage.py migrate --noinput + if [ "${ADMIN_USERNAME}" ] && [ "${ADMIN_PASSWORD}" ] && [ "${ADMIN_EMAIL}" ]; then + echo "Create administrator" + python /workspace/manage.py createadminuser --username "${ADMIN_USERNAME}" --password "${ADMIN_PASSWORD}" --noinput --email "${ADMIN_EMAIL}" + fi + python /workspace/manage.py create_oauth2_application --path /etc/drycc/passport/init-applications.json + {{- end }} + {{- with index .Values "resources" }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- include "passport.envs" . | indent 8 }} + {{- include "passport.volumeMounts" . | indent 8 }} + {{- include "passport.volumes" . | indent 6 }} + restartPolicy: Never diff --git a/charts/passport/templates/passport-secret-creds.yaml b/charts/passport/templates/passport-secret-creds.yaml index 6a21cd6..a3b0618 100644 --- a/charts/passport/templates/passport-secret-creds.yaml +++ b/charts/passport/templates/passport-secret-creds.yaml @@ -1,22 +1,24 @@ -{{- if eq .Values.global.passport_location "on-cluster" }} apiVersion: v1 kind: Secret metadata: name: passport-creds labels: heritage: drycc - annotations: - "helm.sh/hook": pre-install data: - {{- if (.Values.database_url) }} - database-url: {{ .Values.database_url | b64enc }} + {{- if (.Values.valkeyUrl) }} + valkey-url: {{ .Values.valkeyUrl | b64enc }} {{- end }} - django-secret-key: {{ randAscii 64 | b64enc }} - social-auth-drycc-controller-key: {{ randAlphaNum 40 | b64enc }} - social-auth-drycc-controller-secret: {{ randAlphaNum 64 | b64enc }} - {{- if eq .Values.global.grafana_location "on-cluster" }} - social-auth-drycc-grafana-key: {{ randAlphaNum 40 | b64enc }} - social-auth-drycc-grafana-secret: {{ randAlphaNum 64 | b64enc }} + {{- if (.Values.databaseUrl) }} + database-url: {{ .Values.databaseUrl | b64enc }} + {{- end }} + {{- if (.Values.databaseReplicaUrl) }} + database-replica-url: {{ .Values.databaseReplicaUrl | b64enc }} + {{- end }} + django-secret-key: {{ (include "common.secrets.lookup" (dict "secret" "passport-creds" "key" "django-secret-key" "defaultValue" (randAlphaNum 64) "context" $)) }} + oidc-rsa-private-key: {{genPrivateKey "rsa" | b64enc}} + {{- range $item := .Values.initApplications }} + {{- $name := ($item.name | replace " " "-" | lower) }} + drycc-passport-{{$name}}-key: {{ (include "common.secrets.lookup" (dict "secret" "passport-creds" "key" (printf "drycc-passport-%s-key" $name) "defaultValue" ($item.key | default (randAlphaNum 40)) "context" $)) }} + drycc-passport-{{$name}}-secret: {{ (include "common.secrets.lookup" (dict "secret" "passport-creds" "key" (printf "drycc-passport-%s-secret" $name) "defaultValue" ($item.secret | default (randAlphaNum 64)) "context" $)) }} + drycc-passport-{{$name}}-scopes: {{ ($item.allowed_scopes | default "") | b64enc | quote }} {{- end }} - oidc-rsa-private-key: "{{genPrivateKey "rsa" | b64enc}}" -{{- end }} diff --git a/charts/passport/templates/passport-service-account.yaml b/charts/passport/templates/passport-service-account.yaml index 6fbc446..c5714ad 100644 --- a/charts/passport/templates/passport-service-account.yaml +++ b/charts/passport/templates/passport-service-account.yaml @@ -1,8 +1,6 @@ -{{- if eq .Values.global.passport_location "on-cluster" }} apiVersion: v1 kind: ServiceAccount metadata: name: drycc-passport labels: heritage: drycc -{{- end }} diff --git a/charts/passport/templates/passport-service.yaml b/charts/passport/templates/passport-service.yaml index a320960..17119f7 100644 --- a/charts/passport/templates/passport-service.yaml +++ b/charts/passport/templates/passport-service.yaml @@ -1,10 +1,15 @@ -{{- if eq .Values.global.passport_location "on-cluster" }} apiVersion: v1 kind: Service metadata: name: drycc-passport + annotations: + {{- with .Values.service.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} labels: + app: drycc-passport heritage: drycc + component: drycc-passport-api spec: ports: - name: http @@ -12,4 +17,4 @@ spec: targetPort: 8000 selector: app: drycc-passport -{{- end }} \ No newline at end of file + component: drycc-passport-api diff --git a/charts/passport/values.yaml b/charts/passport/values.yaml index 8f81201..0da7257 100644 --- a/charts/passport/values.yaml +++ b/charts/passport/values.yaml @@ -1,13 +1,74 @@ -image_org: "drycc" -image_pull_policy: "Always" -image_tag: "canary" -image_registry: "docker.io" -# Set passport deployment replicas -replicas: 1 -# limits_cpu: "100m" -# limits_memory: "50Mi" -## Configuring this will no longer use the built-in database component -database_url: "" +imageOrg: "drycc" +imagePullPolicy: "Always" +imageTag: "canary" +imageRegistry: "registry.drycc.cc" + +## Enable diagnostic mode +## +diagnosticMode: + ## @param diagnosticMode.enabled Enable diagnostic mode (all probes will be disabled and the command will be overridden) + ## + enabled: false + ## @param diagnosticMode.command Command to override all containers + ## + command: + - sleep + ## @param diagnosticMode.args Args to override all containers + ## + args: + - infinity + +api: + replicas: 1 + resources: {} + # limits: + # cpu: 200m + # memory: 50Mi + # requests: + # cpu: 100m + # memory: 30Mi + nodeAffinityPreset: + key: "drycc.cc/node" + type: "soft" + values: + - "true" + podAffinityPreset: + type: "" + extraMatchLabels: + security: "drycc-security" + podAntiAffinityPreset: + type: "soft" + extraMatchLabels: + app: "drycc-passport-api" + +celery: + replicas: 1 + resources: {} + # limits: + # cpu: 200m + # memory: 50Mi + # requests: + # cpu: 100m + # memory: 30Mi + nodeAffinityPreset: + key: "drycc.cc/node" + type: "soft" + values: + - "true" + podAffinityPreset: + type: "" + extraMatchLabels: + security: "drycc-security" + podAntiAffinityPreset: + type: "soft" + extraMatchLabels: + app: "drycc-passport" + component: "drycc-passport-celery" +## valkeyUrl is will no longer use the built-in valkey component +valkeyUrl: "" +## databaseUrl and databaseReplicaUrl are will no longer use the built-in database component +databaseUrl: "" +databaseReplicaUrl: "" # Any custom controller environment variables # can be specified as key-value pairs under environment # this is usually a non required setting. @@ -42,40 +103,65 @@ environment: # EMAIL_USE_TLS: "" # EMAIL_USE_SSL: "" # Used to create Django admin users -admin_username: "admin" -admin_password: "admin" -admin_email: "admin@email.com" +adminUsername: "admin" +adminPassword: "admin" +adminEmail: "admin@email.com" +# Reserved names +reservedNames: "" +# The following configurations to initialize oauth2 application +# Names are all lowercase letters +# The key and secret are generated automatically if they are empty +# If prefix is not empty, it represents internal application. +# +initApplications: +- name: "controller" + key: "" + secret: "" + prefix: "drycc" + grant_type: "internal" + client_type: "confidential" + allowed_scopes: "openid profile email manager:workspace manager:usage passport:message" + redirect_uri: "/v2/complete/drycc/" +- name: "grafana" + key: "" + secret: "" + prefix: "drycc-grafana" + grant_type: "internal" + client_type: "confidential" + allowed_scopes: "openid profile email controller:alerts controller:metrics controller:logs" + redirect_uri: "/oauth2/callback" +- name: "builder" + key: "" + secret: "" + prefix: "" + grant_type: "client-credentials" + client_type: "confidential" + allowed_scopes: "controller:hook" + redirect_uri: "" +- name: "manager" + key: "" + secret: "" + prefix: "" + grant_type: "client-credentials" + client_type: "confidential" + allowed_scopes: "controller:blocklist" + redirect_uri: "" -global: - # Set the location of Workflow's grafana instance - # - # Valid values are: - # - on-cluster: Run Grafana within the Kubernetes cluster - # - off-cluster: Grafana is running outside of the cluster - grafana_location: "on-cluster" +# Service +service: + # Provide any additional service annotations + annotations: {} - # Admin email, used for each component to send email to administrator - email: "drycc@drycc.cc" - # Set the location of Workflow's PostgreSQL database - # - # Valid values are: - # - on-cluster: Run PostgreSQL within the Kubernetes cluster (credentials are generated - # automatically; backups are sent to object storage - # configured above) - # - off-cluster: Run PostgreSQL outside the Kubernetes cluster (configure in database section) - database_location: "on-cluster" +valkey: + enabled: true - # Please check `kubernetes.io/ingress.class` - ingress_class: "" - # A domain name consists of one or more parts. - # Periods (.) are used to separate these parts. - # Each part must be 1 to 63 characters in length and can contain lowercase letters, digits, and hyphens (-). - # It must start and end with a lowercase letter or digit. - cluster_domain: "cluster.local" +database: + enabled: true + +global: # The public resolvable hostname to build your cluster with. # # This will be the hostname that is used to build endpoints such as "drycc.$HOSTNAME" - platform_domain: "" + platformDomain: "" # Whether cert_passport is enabled to automatically generate passport certificates - cert_manager_enabled: true - passport_location: "on-cluster" + certManagerEnabled: true diff --git a/rootfs/Dockerfile b/rootfs/Dockerfile index 80d2623..c08620f 100644 --- a/rootfs/Dockerfile +++ b/rootfs/Dockerfile @@ -1,43 +1,63 @@ -FROM node:16-alpine3.14 as build-app +ARG CODENAME +FROM registry.drycc.cc/drycc/base:${CODENAME} as build-app -ADD web /app -WORKDIR /app +ADD web /web +WORKDIR /web -RUN npm install \ +ENV NODE_VERSION="24" + +RUN install-stack node $NODE_VERSION && . init-stack \ + && npm install --global yarn \ + && yarn install \ && yarn build -FROM docker.io/library/python:3.9-alpine - -COPY requirements.txt /app/requirements.txt - -RUN apk add --update --virtual .build-deps \ - postgresql-dev \ - gcc \ - libffi-dev \ - musl-dev \ - openldap-dev \ - openssl-dev \ - cargo \ - rust \ - && python3 -m venv /app/.venv \ - && source /app/.venv/bin/activate \ - && pip3 install --disable-pip-version-check --no-cache-dir -r /app/requirements.txt \ - && find /app/.venv /usr/local -type f -executable ! -path '*/cryptography*' -exec scanelf --needed --nobanner --format '%n#p' '{}' ';' \ - | tr ',' '\n' \ - | sort -u \ - | awk 'system("[[ -e /app/.venv/lib/" $1 " || -e /usr/local/lib/" $1 " ]]") == 0 { next } { print "so:" $1 }' \ - | xargs -rt apk add --no-cache --virtual .python-rundeps \ - && apk add --update --virtual .passport-rundeps \ - ca-certificates \ - su-exec \ - bash \ - shadow \ - && apk del .build-deps - -COPY . /app -COPY --from=build-app /app/dist /app/web/dist - -ENV PATH /app/.venv/bin:/app/bin:$PATH -WORKDIR /app -CMD ["/app/bin/boot"] +FROM registry.drycc.cc/drycc/base:${CODENAME} + +ARG DRYCC_UID=1001 \ + DRYCC_GID=1001 \ + DRYCC_HOME_DIR=/workspace \ + PYTHON_VERSION="3.14" + +RUN groupadd drycc --gid ${DRYCC_GID} \ + && useradd drycc -u ${DRYCC_UID} -g ${DRYCC_GID} -s /bin/bash -m -d ${DRYCC_HOME_DIR} + +COPY requirements.txt ${DRYCC_HOME_DIR}/requirements.txt + +RUN buildDeps='gcc rustc cargo libffi-dev musl-dev libldap2-dev libsasl2-dev'; \ + install-packages $buildDeps \ + && install-stack python $PYTHON_VERSION && . init-stack \ + && python3 -m venv ${DRYCC_HOME_DIR}/.venv \ + && source ${DRYCC_HOME_DIR}/.venv/bin/activate \ + && pip3 install --disable-pip-version-check --no-cache-dir -r ${DRYCC_HOME_DIR}/requirements.txt \ + && chown -R ${DRYCC_UID}:${DRYCC_GID} ${DRYCC_HOME_DIR} \ + # set env + && echo "source ${DRYCC_HOME_DIR}/.venv/bin/activate" >> /opt/drycc/python/profile.d/python.sh \ + # cleanup + && scanelp ${DRYCC_HOME_DIR}/.venv/lib > runtime.txt \ + && apt-get purge -y --auto-remove $buildDeps \ + && install-packages $(< runtime.txt) \ + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf \ + /usr/share/doc \ + /usr/share/man \ + /usr/share/info \ + /usr/share/locale \ + /var/lib/apt/lists/* \ + /var/log/* \ + /var/cache/debconf/* \ + /etc/systemd \ + /lib/lsb \ + /lib/udev \ + /usr/lib/`echo $(uname -m)`-linux-gnu/gconv/IBM* \ + /usr/lib/`echo $(uname -m)`-linux-gnu/gconv/EBC* \ + && mkdir -p /usr/share/man/man{1..8} + +USER ${DRYCC_UID} + +COPY --chown=${DRYCC_UID}:${DRYCC_GID} . ${DRYCC_HOME_DIR} +COPY --chown=${DRYCC_UID}:${DRYCC_GID} --from=build-app /web/dist ${DRYCC_HOME_DIR}/web/dist + +WORKDIR ${DRYCC_HOME_DIR} +CMD ["bin/boot"] EXPOSE 8000 diff --git a/rootfs/Dockerfile.test b/rootfs/Dockerfile.test index 0a3b174..ea284df 100644 --- a/rootfs/Dockerfile.test +++ b/rootfs/Dockerfile.test @@ -1,48 +1,80 @@ -FROM docker.io/library/python:3.9-alpine - -COPY requirements.txt /app/requirements.txt -COPY dev_requirements.txt /app/dev_requirements.txt - -ENV PGDATA /var/lib/postgresql/12 - -ENV PATH="/app/.venv/bin:${PATH}" - -RUN echo https://dl-cdn.alpinelinux.org/alpine/edge/testing >>/etc/apk/repositories \ - && apk add --update --virtual .build-deps \ - postgresql-dev \ - gcc \ - libffi-dev \ - musl-dev \ - openldap-dev \ - openssl-dev \ - cargo \ - rust \ - && python3 -m venv /app/.venv \ - && source /app/.venv/bin/activate \ - && pip3 install --disable-pip-version-check --no-cache-dir -r /app/requirements.txt \ - && pip3 install --disable-pip-version-check --no-cache-dir -r /app/dev_requirements.txt \ - && find /app/.venv /usr/local -type f -executable ! -path '*/cryptography*' -exec scanelf --needed --nobanner --format '%n#p' '{}' ';' \ - | tr ',' '\n' \ - | sort -u \ - | awk 'system("[[ -e /app/.venv/lib/" $1 " || -e /usr/local/lib/" $1 " ]]") == 0 { next } { print "so:" $1 }' \ - | xargs -rt apk add --no-cache --virtual .python-rundeps \ - && apk add --update --virtual .passport-rundeps \ - git \ - mercurial \ - ca-certificates \ - su-exec \ - bash \ - shadow \ - postgresql \ - openssl \ +ARG CODENAME +FROM registry.drycc.cc/drycc/base:${CODENAME} as build-app + +ADD web /web +WORKDIR /web + +ENV NODE_VERSION="24" + +RUN install-stack node $NODE_VERSION && . init-stack \ + && npm install --global yarn \ + && yarn install \ + && yarn build + + +ARG CODENAME +FROM registry.drycc.cc/drycc/base:${CODENAME} + +ARG DRYCC_UID=1001 \ + DRYCC_GID=1001 \ + DRYCC_HOME_DIR=/workspace \ + PYTHON_VERSION="3.14" \ + VALKEY_VERSION="9.0.1" \ + POSTGRES_VERSION="18.1" \ + GOSU_VERSION="1.19" + + +RUN groupadd drycc --gid ${DRYCC_GID} \ + && useradd drycc -u ${DRYCC_UID} -g ${DRYCC_GID} -s /bin/bash -m -d ${DRYCC_HOME_DIR} + +ENV PGDATA="/var/lib/postgresql/data" + +COPY requirements.txt ${DRYCC_HOME_DIR}/requirements.txt +COPY dev_requirements.txt ${DRYCC_HOME_DIR}/dev_requirements.txt + +RUN buildDeps='gcc rustc cargo libffi-dev musl-dev libldap2-dev libsasl2-dev'; \ + install-packages ldap-utils mercurial ca-certificates openssl git $buildDeps \ + && curl -SsL https://cli.codecov.io/latest/$([ $(dpkg --print-architecture) == "arm64" ] && echo linux-arm64 || echo linux)/codecov -o /usr/local/bin/codecov \ + && chmod +x /usr/local/bin/codecov \ + && install-stack python $PYTHON_VERSION \ + && install-stack valkey $VALKEY_VERSION \ + && install-stack postgresql $POSTGRES_VERSION \ + && install-stack gosu $GOSU_VERSION && . init-stack \ + && python3 -m venv ${DRYCC_HOME_DIR}/.venv \ + && source ${DRYCC_HOME_DIR}/.venv/bin/activate \ + && pip3 install --disable-pip-version-check --no-cache-dir -r ${DRYCC_HOME_DIR}/requirements.txt \ + && pip3 install --disable-pip-version-check --no-cache-dir -r ${DRYCC_HOME_DIR}/dev_requirements.txt \ + # set env + && echo "source ${DRYCC_HOME_DIR}/.venv/bin/activate" >> /opt/drycc/python/profile.d/python.sh \ + # cleanup + && scanelp ${DRYCC_HOME_DIR}/.venv/lib > runtime.txt \ + && apt-get purge -y --auto-remove $buildDeps \ + && install-packages $(< runtime.txt) \ + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf \ + /usr/share/doc \ + /usr/share/man \ + /usr/share/info \ + /usr/share/locale \ + /var/lib/apt/lists/* \ + /var/log/* \ + /var/cache/debconf/* \ + /etc/systemd \ + /lib/lsb \ + /lib/udev \ + /usr/lib/`echo $(uname -m)`-linux-gnu/gconv/IBM* \ + /usr/lib/`echo $(uname -m)`-linux-gnu/gconv/EBC* \ + && mkdir -p /usr/share/man/man{1..8} \ && mkdir -p /run/postgresql $PGDATA \ + && groupadd postgres && useradd -g postgres postgres \ && chown -R postgres:postgres /run/postgresql $PGDATA \ - && apk del .build-deps \ - && su-exec postgres initdb -D $PGDATA + && gosu postgres initdb -D $PGDATA -COPY . /app +COPY . ${DRYCC_HOME_DIR} +COPY --chown=${DRYCC_UID}:${DRYCC_GID} . ${DRYCC_HOME_DIR} +COPY --chown=${DRYCC_UID}:${DRYCC_GID} --from=build-app /web/dist ${DRYCC_HOME_DIR}/web/dist -ENV PATH /app/.venv/bin:/app/bin:$PATH -WORKDIR /app -CMD ["/app/bin/boot"] +WORKDIR ${DRYCC_HOME_DIR} +CMD ["bin/boot"] EXPOSE 8000 diff --git a/rootfs/api/__init__.py b/rootfs/api/__init__.py index 1a72d32..15d33ec 100644 --- a/rootfs/api/__init__.py +++ b/rootfs/api/__init__.py @@ -1 +1,7 @@ +""" +The **api** Django app presents a RESTful web API for interacting with the **drycc** system. +""" +from .settings.celery import app as celery_app + __version__ = '1.1.0' +__all__ = ('celery_app',) diff --git a/rootfs/api/admin.py b/rootfs/api/admin.py new file mode 100644 index 0000000..e6328f0 --- /dev/null +++ b/rootfs/api/admin.py @@ -0,0 +1,45 @@ +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin as BaseUserAdmin +from oauth2_provider.admin import ApplicationAdmin as BaseApplicationAdmin + +from .models import User, Message, MessagePreference, Application + + +try: + admin.site.unregister(Application) +except admin.sites.NotRegistered: + pass + + +@admin.register(Application) +class ApplicationAdmin(BaseApplicationAdmin): + list_display = ( + "id", "name", "user", "client_type", + "authorization_grant_type", "allowed_scopes", + ) + + +class UserAdmin(BaseUserAdmin): + add_fieldsets = ( + (None, { + 'classes': ('wide',), + 'fields': ('username', 'password1', 'password2', 'email'), + }), + ) + + +class MessageAdmin(admin.ModelAdmin): + list_display = ('id', 'user', 'category', 'title', 'severity', 'is_read', 'created_at') + list_filter = ('category', 'severity', 'is_read', 'created_at') + search_fields = ('title', 'content', 'user__username') + readonly_fields = ('created_at', 'updated_at') + + +class MessagePreferenceAdmin(admin.ModelAdmin): + list_display = ('user', 'email_alerts', 'push_alerts') + search_fields = ('user__username',) + + +admin.site.register(User, UserAdmin) +admin.site.register(Message, MessageAdmin) +admin.site.register(MessagePreference, MessagePreferenceAdmin) diff --git a/rootfs/api/apps.py b/rootfs/api/apps.py new file mode 100644 index 0000000..85e1f47 --- /dev/null +++ b/rootfs/api/apps.py @@ -0,0 +1,10 @@ +from django import apps + + +class AppConfig(apps.AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'api' + + def ready(self): + super(AppConfig, self).ready() + __import__("api.signals") diff --git a/rootfs/api/apps_extra/__init__.py b/rootfs/api/apps_extra/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rootfs/api/apps_extra/social_core/__init__.py b/rootfs/api/apps_extra/social_core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rootfs/api/apps_extra/social_core/backends.py b/rootfs/api/apps_extra/social_core/backends.py new file mode 100644 index 0000000..34f8ab6 --- /dev/null +++ b/rootfs/api/apps_extra/social_core/backends.py @@ -0,0 +1,82 @@ +import json +from os.path import join, dirname +from pathlib import Path +from social_core.backends.oauth import BaseOAuth2 +from social_core.backends.github import GithubOAuth2 as BaseGithubOAuth2 +from social_core.backends.google import GoogleOAuth2 as BaseGoogleOAuth2 +from social_core.backends.weixin import WeixinOAuth2 as BaseWeixinOAuth2 + + +def icon_path(name): + return Path(join(dirname(__file__), "icons", f"{name}.svg")) + + +class GithubOAuth2(BaseGithubOAuth2): + icon = icon_path("github").read_text(encoding="utf-8") + + +class GoogleOAuth2(BaseGoogleOAuth2): + name = "google" + icon = icon_path("google").read_text(encoding="utf-8") + + +class WeixinOAuth2(BaseWeixinOAuth2): + icon = icon_path("weixin").read_text(encoding="utf-8") + + +class FeiShuOAuth2(BaseOAuth2): + """FeiShu OAuth2 authentication backend""" + name = 'feishu' + icon = icon_path("feishu").read_text(encoding="utf-8") + + AUTHORIZATION_URL = 'https://accounts.feishu.cn/open-apis/authen/v1/authorize' + ACCESS_TOKEN_URL = 'https://open.feishu.cn/open-apis/authen/v2/oauth/token' + USER_INFO_URL = 'https://open.feishu.cn/open-apis/authen/v1/user_info' + + DEFAULT_SCOPE = [''] + REDIRECT_STATE = False + ACCESS_TOKEN_METHOD = 'POST' + EXTRA_DATA = [ + ('refresh_token', 'refresh_token'), + ('expires_in', 'expires'), + ('union_id', 'union_id'), + ('access_token', 'access_token'), + ] + + def request_access_token(self, *args, **kwargs): + """Override to send JSON request provided by FeiShu""" + if 'data' in kwargs: + kwargs['data']['app_id'] = self.setting('KEY') + kwargs['data']['app_secret'] = self.setting('SECRET') + kwargs['data'] = json.dumps(kwargs['data']) + if 'headers' not in kwargs: + kwargs['headers'] = {} + kwargs['headers']['Content-Type'] = 'application/json; charset=utf-8' + return super().request_access_token(*args, **kwargs) + + def get_user_details(self, response): + """Return user details from FeiShu account""" + return { + 'username': response.get('name', ''), + 'email': response.get('email', ''), + } + + def user_data(self, access_token, *args, **kwargs): + """Loads user data from service""" + headers = { + 'Authorization': f'Bearer {access_token}', + 'Content-Type': 'application/json; charset=utf-8' + } + response = self.get_json( + self.USER_INFO_URL, + headers=headers + ) + # FeiShu returns data wrapped in 'data' field + if 'data' in response: + response.update(response['data']) + + response['union_id'] = response.get('union_id', '') + return response + + +__all__ = [GithubOAuth2, GoogleOAuth2, WeixinOAuth2, FeiShuOAuth2] diff --git a/rootfs/api/apps_extra/social_core/icons/feishu.svg b/rootfs/api/apps_extra/social_core/icons/feishu.svg new file mode 100644 index 0000000..7afdb94 --- /dev/null +++ b/rootfs/api/apps_extra/social_core/icons/feishu.svg @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/rootfs/api/apps_extra/social_core/icons/github.svg b/rootfs/api/apps_extra/social_core/icons/github.svg new file mode 100644 index 0000000..c5858b0 --- /dev/null +++ b/rootfs/api/apps_extra/social_core/icons/github.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/rootfs/api/apps_extra/social_core/icons/google.svg b/rootfs/api/apps_extra/social_core/icons/google.svg new file mode 100644 index 0000000..c2fd469 --- /dev/null +++ b/rootfs/api/apps_extra/social_core/icons/google.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/rootfs/api/apps_extra/social_core/icons/weixin.svg b/rootfs/api/apps_extra/social_core/icons/weixin.svg new file mode 100644 index 0000000..fe20def --- /dev/null +++ b/rootfs/api/apps_extra/social_core/icons/weixin.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rootfs/api/apps_extra/social_core/pipelines.py b/rootfs/api/apps_extra/social_core/pipelines.py new file mode 100644 index 0000000..d8f24b2 --- /dev/null +++ b/rootfs/api/apps_extra/social_core/pipelines.py @@ -0,0 +1,59 @@ +""" +Custom social auth pipeline for OAuth2 binding and creation guidance. +""" + +import logging + +from django.shortcuts import redirect +from social_django.models import UserSocialAuth + +from api.utils import get_oauth_callback + +logger = logging.getLogger(__name__) + + +def handle_authenticated_binding(backend, uid, details, response, *args, **kwargs): + request = backend.strategy.request + if not request or not request.user.is_authenticated: + return None + + current_user = request.user + try: + existing_social = UserSocialAuth.objects.filter( + provider=backend.name, uid=uid + ).select_related('user').first() + if existing_social and existing_social.user_id != current_user.id: + return redirect(get_oauth_callback(request, 'conflict', backend.name)) + if existing_social and existing_social.user_id == current_user.id: + return redirect(get_oauth_callback(request, 'already_linked', backend.name)) + + UserSocialAuth.objects.create( + user=current_user, + provider=backend.name, + uid=uid, + extra_data=response or {} + ) + return redirect(get_oauth_callback(request, 'linked', backend.name)) + except Exception as exc: + logger.exception(exc) + return redirect(get_oauth_callback(request, 'error', backend.name)) + + +def require_username_password(backend, uid, details, response, user=None, *args, **kwargs): + request = backend.strategy.request + if request and request.user.is_authenticated: + return None + if user: + return None + + email = details.get('email') + if not email: + return redirect(get_oauth_callback(request, 'missing_email', backend.name)) + + backend.strategy.session_set('oauth_pending', { + 'provider': backend.name, + 'uid': uid, + 'email': email, + 'extra_data': response or {}, + }) + return redirect(get_oauth_callback(request, 'pending', backend.name)) diff --git a/rootfs/api/asgi.py b/rootfs/api/asgi.py new file mode 100644 index 0000000..e89b917 --- /dev/null +++ b/rootfs/api/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for passport project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'api.settings.production') + +application = get_asgi_application() diff --git a/rootfs/api/context_processors.py b/rootfs/api/context_processors.py new file mode 100644 index 0000000..5c97b0f --- /dev/null +++ b/rootfs/api/context_processors.py @@ -0,0 +1,7 @@ +from django.conf import settings + + +def legal(request): + return { + 'LEGAL_ENABLED': settings.LEGAL_ENABLED, + } diff --git a/rootfs/api/exceptions.py b/rootfs/api/exceptions.py index d409c39..dfd7d2e 100644 --- a/rootfs/api/exceptions.py +++ b/rootfs/api/exceptions.py @@ -43,7 +43,6 @@ def custom_exception_handler(exc, context): # No response means DRF couldn't handle it # Output a generic 500 in a JSON format - print(response) if response is None: logging.exception('Uncaught Exception', exc_info=exc) set_rollback() diff --git a/rootfs/api/forms.py b/rootfs/api/forms.py new file mode 100644 index 0000000..f805838 --- /dev/null +++ b/rootfs/api/forms.py @@ -0,0 +1,52 @@ +import requests +from django import forms +from django.conf import settings +from django.utils.translation import gettext_lazy as _ +from django.core.exceptions import ValidationError +from django.contrib.auth import get_user_model +from django.contrib.auth.forms import UserCreationForm, AuthenticationForm as _AuthenticationForm + +from api.utils import send_activation_email + +User = get_user_model() + + +class AuthenticationForm(_AuthenticationForm): + + def confirm_login_allowed(self, user): + if not user.is_active and user.last_login is None: + send_activation_email(self.request, user) + raise ValidationError( + _('The account is not activated, please check the activation email.'), + code="inactive", + ) + return super().confirm_login_allowed(user) + + +class RegistrationForm(UserCreationForm): + + h_captcha_token = forms.CharField( + label=_("h-captcha token"), + widget=forms.HiddenInput(attrs={"name": "h-captcha-response"}), + strip=False, + required=False, + help_text=_("Google recaptcha token hidden field"), + ) + + def clean_h_captcha_token(self): + h_captcha_token = self.data.get("h-captcha-response") + if settings.H_CAPTCHA_KEY and settings.H_CAPTCHA_SECRET: + success = requests.post('https://hcaptcha.com/siteverify', data={ + 'secret': settings.H_CAPTCHA_SECRET, + 'response': h_captcha_token, + }).json()["success"] + if not success: + raise ValidationError( + _('Error verifying HCAPTCHA, please try again.'), + code="captcha_invalid", + ) + return h_captcha_token + + class Meta(UserCreationForm.Meta): + model = User + fields = ('username', 'email', 'password1', 'password2') diff --git a/rootfs/api/management/commands/create_oauth2_application.py b/rootfs/api/management/commands/create_oauth2_application.py index 5353790..bd01a6c 100644 --- a/rootfs/api/management/commands/create_oauth2_application.py +++ b/rootfs/api/management/commands/create_oauth2_application.py @@ -1,49 +1,111 @@ import os -from django.contrib.auth.models import User +import json +import random +import string +import pathlib +from django.contrib.auth import get_user_model +from django.contrib.auth.hashers import check_password from django.core.management.base import BaseCommand -from oauth2_provider.models import Application +from oauth2_provider.models import get_application_model + + +User = get_user_model() +Application = get_application_model() +secrets_path = "/var/run/secrets/drycc/passport" class Command(BaseCommand): - """Management command for create Oauth2 application""" + """Management command for create Oauth2 application. + + Credential resolution order for ``client_id`` / ``client_secret``: + + 1. Explicit value from the init-applications JSON file (highest priority, + lets operators pin credentials via ``--set initApplications[...]``). + 2. Mounted Kubernetes secret file at + ``/var/run/secrets/drycc/passport/drycc-passport--``. + This is the source of truth for credentials that the chart's + ``passport-creds`` Secret already exposes to every consumer (controller, + grafana, builder, manager, ...). Reading it here keeps the DB and the + Secret consistent for *every* application, including m2m apps that + have no public sub-domain (``prefix == ""``). + 3. Newly generated random string (only when neither of the above is + available, e.g. local dev without the volume mount). + + Note: ``prefix`` only controls how ``redirect_uri`` is composed. It is + intentionally NOT used to gate credential discovery -- m2m applications + legitimately have an empty prefix. + """ + + def add_arguments(self, parser): + super(Command, self).add_arguments(parser) + parser.add_argument( + '--path', dest='path', default=None, + help='Specifies the path for the secret.', + ) def handle(self, *args, **options): - app_list = [{ - "name": "CONTROLLER", - "redirect_uri": f"{os.environ.get('DRYCC_CONTROLLER_DOMAIN')}/v2/complete/drycc/" # noqa - }] - if os.environ.get('GRAFANA_ON_CLUSTER') == "true": - app_list.append({ - "name": "GRAFANA", - "redirect_uri": f"{os.environ.get('DRYCC_MONITOR_GRAFANA_DOMAIN')}/login/generic_oauth" # noqa - }) - - for app in app_list: - client_id = os.environ.get( - f'SOCIAL_AUTH_DRYCC_{app["name"]}_KEY') if os.environ.get( - f'SOCIAL_AUTH_DRYCC_{app["name"]}_KEY') else None - client_secret = os.environ.get( - f'SOCIAL_AUTH_DRYCC_{app["name"]}_SECRET') if os.environ.get( - f'SOCIAL_AUTH_DRYCC_{app["name"]}_SECRET') else None - if not all([client_id, client_secret]): - self.stdout.write('client_id or client_secret non-existent') - return - user = User.objects.filter(is_superuser=True).first() - if not user: - self.stdout.write("Cannot create because there is no superuser") - application, updated = Application.objects.update_or_create( - name='Drycc ' + app["name"].title(), - defaults={ - 'client_id': client_id, - 'client_secret': client_secret, - 'user': user, - 'redirect_uris': app["redirect_uri"], - 'authorization_grant_type': 'authorization-code', - 'client_type': 'Public', - 'algorithm': 'RS256' - } + base_path = options.get('path', '') + user = User.objects.filter(is_superuser=True).first() + for item in json.loads(pathlib.Path(base_path).read_text()): + name = item["name"] + client_id = self._get_creds(item, "key", 40) + client_secret = self._get_creds(item, "secret", 60) + defaults = { + 'client_id': client_id, + 'user': user, + 'redirect_uris': self._get_redirect_uri(item), + 'authorization_grant_type': item.get('grant_type', 'public'), + 'client_type': item.get('client_type', 'public'), + 'allowed_scopes': item.get('allowed_scopes', ''), + 'algorithm': 'RS256', + } + existing = Application.objects.filter(name=name.lower()).first() + secret_unchanged = ( + existing is not None + and check_password(client_secret, existing.client_secret) ) - if updated: - self.stdout.write(f'Drycc {app["name"]} app created') + if not secret_unchanged: + defaults['client_secret'] = client_secret + _, created = Application.objects.update_or_create( + name=name.lower(), defaults=defaults, + ) + if created: + self.stdout.write('Drycc %s app created' % name) + else: + self.stdout.write('Drycc %s app updated' % name) + + def _get_creds(self, item, suffix, size): + name = item["name"] + secret = item.get(suffix) + if secret: + self.stdout.write( + '[%s/%s] credential source: init-config' % (name, suffix)) + return secret + + default_secret_path = os.path.join( + secrets_path, "drycc-passport-%s-%s" % (name, suffix)) + if os.path.exists(default_secret_path): + # ``.strip()`` defends against trailing newlines that some + # tooling adds when materialising secrets onto disk. + secret = pathlib.Path(default_secret_path).read_text().strip() + self.stdout.write( + '[%s/%s] credential source: mounted-file (%s)' + % (name, suffix, default_secret_path)) + return secret + + secret = ''.join(random.choice(string.ascii_letters) for _ in range(size)) + self.stdout.write( + '[%s/%s] credential source: generated-random ' + '(no init value, no mounted file)' % (name, suffix)) + return secret + + def _get_redirect_uri(self, item): + prefix = item["prefix"] + domain = os.environ.get("PLATFORM_DOMAIN") + redirect_uri = item["redirect_uri"] + if prefix: + if os.environ.get("CERT_MANAGER_ENABLED") == "true": + redirect_uri = f"https://{prefix}.{domain}{redirect_uri}" else: - self.stdout.write(f'Drycc {app["name"]} app updated') + redirect_uri = f"http://{prefix}.{domain}{redirect_uri}" + return redirect_uri diff --git a/rootfs/api/migrations/0001_initial.py b/rootfs/api/migrations/0001_initial.py new file mode 100644 index 0000000..656f747 --- /dev/null +++ b/rootfs/api/migrations/0001_initial.py @@ -0,0 +1,44 @@ +# Generated by Django 3.2.5 on 2021-12-16 03:45 + +import django.contrib.auth.models +import django.contrib.auth.validators +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('email', models.EmailField(max_length=254, unique=True, verbose_name='email address')), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), + ], + options={ + 'verbose_name': 'user', + 'verbose_name_plural': 'users', + 'abstract': False, + }, + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + ] diff --git a/rootfs/api/migrations/0002_application.py b/rootfs/api/migrations/0002_application.py new file mode 100644 index 0000000..5a147e4 --- /dev/null +++ b/rootfs/api/migrations/0002_application.py @@ -0,0 +1,42 @@ +# Generated by Django 4.2.10 on 2024-04-11 08:22 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import oauth2_provider.generators +import oauth2_provider.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0001_initial'), + ] + + run_before = [ + ('oauth2_provider', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Application', + fields=[ + ('id', models.BigAutoField(primary_key=True, serialize=False)), + ('client_id', models.CharField(db_index=True, default=oauth2_provider.generators.generate_client_id, max_length=100, unique=True)), + ('redirect_uris', models.TextField(blank=True, help_text='Allowed URIs list, space separated')), + ('post_logout_redirect_uris', models.TextField(blank=True, help_text='Allowed Post Logout URIs list, space separated')), + ('client_type', models.CharField(choices=[('confidential', 'Confidential'), ('public', 'Public')], max_length=32)), + ('authorization_grant_type', models.CharField(choices=[('authorization-code', 'Authorization code'), ('implicit', 'Implicit'), ('password', 'Resource owner password-based'), ('client-credentials', 'Client credentials'), ('openid-hybrid', 'OpenID connect hybrid')], max_length=32)), + ('client_secret', oauth2_provider.models.ClientSecretField(blank=True, db_index=True, default=oauth2_provider.generators.generate_client_secret, help_text='Hashed on Save. Copy it now if this is a new secret.', max_length=255)), + ('name', models.CharField(blank=True, max_length=255)), + ('skip_authorization', models.BooleanField(default=False)), + ('created', models.DateTimeField(auto_now_add=True)), + ('updated', models.DateTimeField(auto_now=True)), + ('algorithm', models.CharField(blank=True, choices=[('', 'No OIDC support'), ('RS256', 'RSA with SHA-2 256'), ('HS256', 'HMAC with SHA-2 256')], default='', max_length=5)), + ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/rootfs/api/migrations/0003_application_allowed_origins_and_more.py b/rootfs/api/migrations/0003_application_allowed_origins_and_more.py new file mode 100644 index 0000000..4e30289 --- /dev/null +++ b/rootfs/api/migrations/0003_application_allowed_origins_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.16 on 2024-11-14 05:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0002_application'), + ] + + operations = [ + migrations.AddField( + model_name='application', + name='allowed_origins', + field=models.TextField(blank=True, default='', help_text='Allowed origins list to enable CORS, space separated'), + ), + migrations.AddField( + model_name='application', + name='hash_client_secret', + field=models.BooleanField(default=True), + ), + migrations.AlterField( + model_name='application', + name='post_logout_redirect_uris', + field=models.TextField(blank=True, default='', help_text='Allowed Post Logout URIs list, space separated'), + ), + ] diff --git a/rootfs/api/migrations/0004_alter_application_authorization_grant_type_message_and_more.py b/rootfs/api/migrations/0004_alter_application_authorization_grant_type_message_and_more.py new file mode 100644 index 0000000..3e7d8bd --- /dev/null +++ b/rootfs/api/migrations/0004_alter_application_authorization_grant_type_message_and_more.py @@ -0,0 +1,61 @@ +# Generated by Django 5.2.13 on 2026-04-23 03:45 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0003_application_allowed_origins_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='application', + name='authorization_grant_type', + field=models.CharField(choices=[('authorization-code', 'Authorization code'), ('urn:ietf:params:oauth:grant-type:device_code', 'Device Code'), ('implicit', 'Implicit'), ('password', 'Resource owner password-based'), ('client-credentials', 'Client credentials'), ('openid-hybrid', 'OpenID connect hybrid')], max_length=44), + ), + migrations.CreateModel( + name='Message', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('category', models.CharField(choices=[('system', 'System'), ('product', 'Product Updates'), ('security', 'Security'), ('alert', 'Alerts'), ('service', 'Service')], default='system', max_length=20, verbose_name='category')), + ('title', models.CharField(max_length=255, verbose_name='title')), + ('content', models.TextField(verbose_name='content')), + ('full_content', models.TextField(blank=True, verbose_name='full content')), + ('severity', models.CharField(choices=[('info', 'Info'), ('warning', 'Warning'), ('error', 'Error'), ('success', 'Success')], default='info', max_length=20, verbose_name='severity')), + ('is_read', models.BooleanField(default=False, verbose_name='is read')), + ('action_link', models.CharField(blank=True, max_length=500, verbose_name='action link')), + ('action_text', models.CharField(blank=True, max_length=255, verbose_name='action text')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='updated at')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='messages', to=settings.AUTH_USER_MODEL, verbose_name='user')), + ], + options={ + 'verbose_name': 'message', + 'verbose_name_plural': 'messages', + 'ordering': ['-created_at'], + }, + ), + migrations.CreateModel( + name='MessagePreference', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('email_alerts', models.BooleanField(default=True, verbose_name='email alerts')), + ('push_alerts', models.BooleanField(default=False, verbose_name='push alerts')), + ('webhook_url', models.URLField(blank=True, max_length=500, verbose_name='webhook url')), + ('notify_security', models.BooleanField(default=True, verbose_name='notify security')), + ('notify_system', models.BooleanField(default=True, verbose_name='notify system')), + ('notify_product', models.BooleanField(default=False, verbose_name='notify product')), + ('notify_alert', models.BooleanField(default=True, verbose_name='notify alert')), + ('notify_service', models.BooleanField(default=True, verbose_name='notify service')), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='message_preference', to=settings.AUTH_USER_MODEL, verbose_name='user')), + ], + options={ + 'verbose_name': 'message preference', + 'verbose_name_plural': 'message preferences', + }, + ), + ] diff --git a/rootfs/api/migrations/0005_application_allowed_scopes_and_internal_grant.py b/rootfs/api/migrations/0005_application_allowed_scopes_and_internal_grant.py new file mode 100644 index 0000000..a5be209 --- /dev/null +++ b/rootfs/api/migrations/0005_application_allowed_scopes_and_internal_grant.py @@ -0,0 +1,35 @@ +# Generated by Django 5.2.13 on 2026-05-09 12:00 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + +def forward_data_migration(apps, schema_editor): + Application = apps.get_model('api', 'Application') + oauth2_settings = getattr(settings, 'OAUTH2_PROVIDER', {}) + default_provider_scopes_list = oauth2_settings.get("DEFAULT_SCOPES", ['openid', 'email', 'profile']) + default_provider_scopes = " ".join(default_provider_scopes_list) + + for app in Application.objects.all(): + if not app.allowed_scopes: + app.allowed_scopes = default_provider_scopes + + if app.name.lower() in ("controller", "grafana"): + app.authorization_grant_type = "internal" + + app.save() + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0004_alter_application_authorization_grant_type_message_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='application', + name='allowed_scopes', + field=models.TextField(blank=True, default=''), + ), + migrations.RunPython(forward_data_migration, reverse_code=migrations.RunPython.noop), + ] \ No newline at end of file diff --git a/rootfs/api/migrations/__init__.py b/rootfs/api/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rootfs/api/models.py b/rootfs/api/models.py new file mode 100644 index 0000000..567844b --- /dev/null +++ b/rootfs/api/models.py @@ -0,0 +1,137 @@ +from django.db import models +from django.contrib.auth.models import AbstractUser +from django.utils.translation import gettext_lazy as _ +from oauth2_provider.models import AbstractApplication +from .validators import UsernameValidator + + +class User(AbstractUser): + username_validator = UsernameValidator() + email = models.EmailField(_('email address'), unique=True) + + +class Application(AbstractApplication): + GRANT_INTERNAL = "internal" + GRANT_TYPES = AbstractApplication.GRANT_TYPES + ( + (GRANT_INTERNAL, _("Internal")), + ) + allowed_scopes = models.TextField(blank=True, default="") + + def allows_grant_type(self, *grant_types): + if self.authorization_grant_type == self.GRANT_INTERNAL: + return True + return super().allows_grant_type(*grant_types) + + def validate_grant_type(self, client_id, grant_type, client, request, *args, **kwargs): + if self.authorization_grant_type == self.GRANT_INTERNAL: + return True + return super().validate_grant_type(client_id, grant_type, client, request, *args, **kwargs) + + +class Message(models.Model): + CATEGORY_CHOICES = [ + ('system', _('System')), + ('product', _('Product Updates')), + ('security', _('Security')), + ('alert', _('Alerts')), + ('service', _('Service')), + ] + + SEVERITY_CHOICES = [ + ('info', _('Info')), + ('warning', _('Warning')), + ('error', _('Error')), + ('success', _('Success')), + ] + + user = models.ForeignKey( + User, + on_delete=models.CASCADE, + related_name='messages', + verbose_name=_('user') + ) + category = models.CharField( + _('category'), + max_length=20, + choices=CATEGORY_CHOICES, + default='system' + ) + title = models.CharField(_('title'), max_length=255) + content = models.TextField(_('content')) + full_content = models.TextField(_('full content'), blank=True) + severity = models.CharField( + _('severity'), + max_length=20, + choices=SEVERITY_CHOICES, + default='info' + ) + is_read = models.BooleanField(_('is read'), default=False) + action_link = models.CharField( + _('action link'), + max_length=500, + blank=True + ) + action_text = models.CharField( + _('action text'), + max_length=255, + blank=True + ) + created_at = models.DateTimeField(_('created at'), auto_now_add=True) + updated_at = models.DateTimeField(_('updated at'), auto_now=True) + + class Meta: + ordering = ['-created_at'] + verbose_name = _('message') + verbose_name_plural = _('messages') + + def __str__(self): + return f"[{self.category}] {self.title}" + + +class MessagePreference(models.Model): + user = models.OneToOneField( + User, + on_delete=models.CASCADE, + related_name='message_preference', + verbose_name=_('user') + ) + email_alerts = models.BooleanField( + _('email alerts'), + default=True + ) + push_alerts = models.BooleanField( + _('push alerts'), + default=False + ) + webhook_url = models.URLField( + _('webhook url'), + max_length=500, + blank=True + ) + notify_security = models.BooleanField( + _('notify security'), + default=True + ) + notify_system = models.BooleanField( + _('notify system'), + default=True + ) + notify_product = models.BooleanField( + _('notify product'), + default=True + ) + notify_alert = models.BooleanField( + _('notify alert'), + default=True + ) + notify_service = models.BooleanField( + _('notify service'), + default=True + ) + + class Meta: + verbose_name = _('message preference') + verbose_name_plural = _('message preferences') + + def __str__(self): + return f"{self.user.username}'s message preference" diff --git a/rootfs/api/oauth2_validators.py b/rootfs/api/oauth2_validators.py new file mode 100644 index 0000000..d968276 --- /dev/null +++ b/rootfs/api/oauth2_validators.py @@ -0,0 +1,39 @@ +from oauth2_provider.oauth2_validators import OAuth2Validator + + +class CustomOAuth2Validator(OAuth2Validator): + + def validate_scopes(self, client_id, scopes, client, request, *args, **kwargs): + if client.allowed_scopes: + allowed = set(client.allowed_scopes.split()) + if not set(scopes).issubset(allowed): + return False + return super().validate_scopes(client_id, scopes, client, request, *args, **kwargs) + + oidc_claim_scope = OAuth2Validator.oidc_claim_scope + oidc_claim_scope.update({ + "id": "profile", + "name": "profile", + "username": "profile", + "email": "email", + "first_name": "profile", + "last_name": "profile", + "is_staff": "profile", + "is_active": "profile", + "is_superuser": "profile", + "preferred_username": "profile", + }) + + def get_additional_claims(self, request): + claims = super().get_additional_claims(request) + claims["id"] = request.user.id + claims["name"] = request.user.username + claims["username"] = request.user.username + claims["email"] = request.user.email + claims["first_name"] = request.user.first_name + claims["last_name"] = request.user.last_name + claims["is_staff"] = request.user.is_staff + claims["is_active"] = request.user.is_active + claims["is_superuser"] = request.user.is_superuser + claims["preferred_username"] = request.user.username + return claims diff --git a/rootfs/api/permissions.py b/rootfs/api/permissions.py new file mode 100644 index 0000000..cb8ad2e --- /dev/null +++ b/rootfs/api/permissions.py @@ -0,0 +1,32 @@ +from django.utils import timezone +from rest_framework import permissions + +from oauth2_provider.models import AccessToken + + +class HasOAuthScope(permissions.BasePermission): + """ + Object-level permission to allow only requests with specific OAuth scopes. + The required scopes are defined on the view as `required_oauth_scopes = ['scope1', 'scope2']` + """ + def has_permission(self, request, view): + required_oauth_scopes = getattr(view, 'required_oauth_scopes', []) + if not required_oauth_scopes: + return True + + auth_header = request.META.get('HTTP_AUTHORIZATION', '') + parts = auth_header.split() + if len(parts) == 2 and parts[0].lower() == 'bearer': + token_string = parts[1] + else: + return False + + scopes = self.get_token_scopes(token_string) + return set(required_oauth_scopes).issubset(scopes) + + def get_token_scopes(self, token_string): + try: + access_token = AccessToken.objects.get(token=token_string, expires__gt=timezone.now()) + return set(access_token.scope.split()) + except AccessToken.DoesNotExist: + return set() diff --git a/rootfs/api/routers.py b/rootfs/api/routers.py new file mode 100644 index 0000000..3e5e981 --- /dev/null +++ b/rootfs/api/routers.py @@ -0,0 +1,39 @@ +from asgiref.local import Local +from django.conf import settings + + +class DefaultReplicaRouter(object): + """ + If a model of the current thread or coroutine has used the master db, + the model will also use the master in the future. + This can avoid the problem that the slave database is not synchronized + because a transaction is not committed. + """ + thread_critical = False + + def __init__(self): + self._tracker = Local(self.thread_critical) + + def db_for_read(self, model, **hints): + tracker_key = ".".join([model.__module__, model.__name__]) + if hasattr(self._tracker, tracker_key): + return getattr(self._tracker, tracker_key) + elif 'replica' in settings.DATABASES: + return 'replica' + return 'default' + + def db_for_write(self, model, **hints): + tracker_key = ".".join([model.__module__, model.__name__]) + if 'replica' in settings.DATABASES: + setattr(self._tracker, tracker_key, 'default') + return 'default' + + def allow_relation(self, obj1, obj2, **hints): + return True + + def allow_migrate(self, db, app_label, model_name=None, **hints): + if 'replica' in settings.DATABASES and 'model' in hints: + model = hints['model'] + tracker_key = ".".join([model.__module__, model.__name__]) + setattr(self._tracker, tracker_key, 'default') + return True diff --git a/rootfs/api/serializers.py b/rootfs/api/serializers.py index c1fca79..4ba083f 100644 --- a/rootfs/api/serializers.py +++ b/rootfs/api/serializers.py @@ -3,49 +3,25 @@ """ import logging -from django.conf import settings from django.contrib.admin.models import LogEntry -from django.contrib.auth.forms import UserCreationForm -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from oauth2_provider.models import Grant, AccessToken -from oauth2_provider.oauth2_validators import OAuth2Validator from rest_framework import serializers -from api.exceptions import DryccException +from api.models import Message, MessagePreference from api.utils import timestamp2datetime +User = get_user_model() logger = logging.getLogger(__name__) -class RegistrationForm(UserCreationForm): - class Meta(UserCreationForm.Meta): - model = User - fields = ('username', 'email', 'password1', 'password2') - - class UserSerializer(serializers.ModelSerializer): - username = serializers.CharField(max_length=150, required=False) - email = serializers.CharField(max_length=254, required=False) - class Meta: model = User - fields = ('id', 'username', 'email', "first_name", "last_name", - "is_staff", "is_active", "is_superuser") - - def update(self, instance, validated_data): - if settings.LDAP_ENDPOINT: - raise DryccException( - "You cannot change user info when ldap is enabled.") - if validated_data.get('username'): - qs = User.objects.filter(username=validated_data.get('username')).\ - exclude(username=instance.username) - if qs: - raise DryccException("new username already exists.") - instance.username = validated_data.get('username') - if validated_data.get('email'): - instance.email = validated_data.get('email') - instance.save() - return instance + fields = ('id', 'username', 'email', 'first_name', 'last_name', + 'is_staff', 'is_active', 'is_superuser') + read_only_fields = ('id', 'username', 'is_staff', 'is_active', + 'is_superuser') class UserEmailSerializer(serializers.ModelSerializer): @@ -81,6 +57,7 @@ class Meta: class UserTokensSerializer(serializers.ModelSerializer): """Serialize user status for a AccessToken model.""" application = serializers.ReadOnlyField(source='application.name') + token_checksum = serializers.ReadOnlyField(required=False) class Meta: model = AccessToken @@ -100,17 +77,42 @@ class Meta: 'object_repr', 'action_flag', 'change_message'] -class CustomOAuth2Validator(OAuth2Validator): - - def get_additional_claims(self, request): - claims = super().get_additional_claims(request) - claims["id"] = request.user.id - claims["name"] = request.user.username - claims["username"] = request.user.username - claims["email"] = request.user.email - claims["first_name"] = request.user.first_name - claims["last_name"] = request.user.last_name - claims["is_staff"] = request.user.is_staff - claims["is_active"] = request.user.is_active - claims["is_superuser"] = request.user.is_superuser - return claims +class MessageSerializer(serializers.ModelSerializer): + """Serialize message model.""" + date = serializers.DateTimeField( + source='created_at', format='%b %d, %Y, %H:%M', read_only=True + ) + + class Meta: + model = Message + fields = ['id', 'category', 'title', 'content', 'full_content', + 'severity', 'is_read', 'action_link', 'action_text', 'date'] + read_only_fields = ['id', 'date'] + + +class MessagePreferenceSerializer(serializers.ModelSerializer): + """Serialize message preference model.""" + + class Meta: + model = MessagePreference + fields = ['email_alerts', 'push_alerts', 'webhook_url', + 'notify_security', 'notify_system', 'notify_product', + 'notify_alert', 'notify_service'] + + +class ServiceMessageSerializer(MessageSerializer): + username = serializers.CharField(write_only=True) + + class Meta(MessageSerializer.Meta): + fields = MessageSerializer.Meta.fields + ['username'] + + def create(self, validated_data): + from django.contrib.auth import get_user_model + User = get_user_model() + username = validated_data.pop('username') + try: + user = User.objects.get(username=username) + except User.DoesNotExist: + raise serializers.ValidationError({"username": "User not found."}) + validated_data['user'] = user + return super().create(validated_data) diff --git a/rootfs/api/settings/celery.py b/rootfs/api/settings/celery.py new file mode 100644 index 0000000..30af003 --- /dev/null +++ b/rootfs/api/settings/celery.py @@ -0,0 +1,56 @@ +import os + +from kombu import Exchange, Queue +from celery import Celery + + +class Config(object): + # Celery Configuration Options + enable_utc = True + task_serializer = 'pickle' + accept_content = frozenset([ + 'application/data', + 'application/json', + 'application/text', + 'application/x-python-serialize', + ]) + task_track_started = True + task_time_limit = 5 * 60 + worker_max_tasks_per_child = 200 + worker_prefetch_multiplier = 1 + result_expires = 24 * 60 * 60 + cache_backend = 'django-cache' + task_default_queue = 'passport.notifications' + task_default_exchange = 'passport.priority' + task_default_routing_key = 'passport.priority.notifications' + broker_transport_options = {"queue_order_strategy": "sorted"} + task_create_missing_queues = True + task_inherit_parent_priority = True + broker_connection_retry_on_startup = True + worker_cancel_long_running_tasks_on_connection_loss = True + + +app = Celery('passport') +app.config_from_object(Config()) +app.conf.update( + timezone=os.environ.get('TZ', 'UTC'), + task_routes={ + 'api.tasks.send_notification': { + 'queue': 'passport.notifications', + 'exchange': 'passport.priority', 'routing_key': 'passport.priority.notifications', + }, + }, + task_queues=( + Queue( + 'passport.notifications', exchange=Exchange('passport.priority', type="direct"), + routing_key='passport.priority.notifications', + ), + ), +) +DRYCC_VALKEY_URL = os.environ.get('DRYCC_VALKEY_URL', 'redis://:@127.0.0.1:6379') +app.conf.update( + broker_url=DRYCC_VALKEY_URL, + result_backend=DRYCC_VALKEY_URL, + broker_transport_options={"queue_order_strategy": "sorted", "visibility_timeout": 43200}, +) +app.autodiscover_tasks() diff --git a/rootfs/api/settings/production.py b/rootfs/api/settings/production.py index 42a93c9..40418ec 100644 --- a/rootfs/api/settings/production.py +++ b/rootfs/api/settings/production.py @@ -6,30 +6,45 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/2.2/ref/settings/ """ +import uuid import os.path import ldap import dj_database_url - from django_auth_ldap.config import LDAPSearch, GroupOfNamesType BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# drycc passport app version. +VERSION = os.environ.get('VERSION', uuid.uuid1().hex[:8]) + # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = bool(os.environ.get('DRYCC_DEBUG', False)) +DEBUG = os.environ.get('DRYCC_DEBUG', 'false').lower() == "true" # If set to True, Django's normal exception handling of view functions # will be suppressed, and exceptions will propagate upwards # https://docs.djangoproject.com/en/2.2/ref/settings/#debug-propagate-exceptions DEBUG_PROPAGATE_EXCEPTIONS = True + # Enable Django admin -ADMIN_ENABLED = bool(os.environ.get('ADMIN_ENABLED', False)) -# Enable Registration -# If this function is enabled, please set Django email related parameters -REGISTRATION_ENABLED = bool(os.environ.get('REGISTRATION_ENABLED', False)) +ADMIN_ENABLED = os.environ.get('ADMIN_ENABLED', 'false').lower() == "true" + +# The following information is for configuring app settings +# Enable Legal +LEGAL_ENABLED = os.environ.get('LEGAL_ENABLED', 'false').lower() == "true" +# Enable Registration, email configuration is required +REGISTRATION_ENABLED = os.environ.get('REGISTRATION_ENABLED', 'false').lower() == "true" +# URLs for the application +DASHBOARD_URL = os.environ.get('DASHBOARD_URL', '/') +# Contact support URL, which can be a mailto: link or a link to a support ticket system +CONTACT_SUPPORT_URL = os.environ.get('CONTACT_SUPPORT_URL', 'https://community.drycc.cc/') + # Silence two security messages around SSL as router takes care of them # https://docs.djangoproject.com/en/2.2/ref/checks/#security SILENCED_SYSTEM_CHECKS = [ 'security.W004', - 'security.W008' + 'security.W008', + 'security.W012', + 'security.W016', ] CONN_MAX_AGE = 60 * 3 @@ -62,6 +77,7 @@ 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ + "api.context_processors.legal", "django.contrib.auth.context_processors.auth", "django.template.context_processors.debug", "django.template.context_processors.i18n", @@ -103,17 +119,23 @@ 'django.contrib.humanize', # Third-party apps 'corsheaders', - 'guardian', 'gunicorn', 'rest_framework', 'oauth2_provider', + 'social_django', # passport apps 'api' ) +AUTH_USER_MODEL = "api.User" +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + AUTHENTICATION_BACKENDS = ( - "django.contrib.auth.backends.ModelBackend", - "guardian.backends.ObjectPermissionBackend", + "api.apps_extra.social_core.backends.FeiShuOAuth2", + "api.apps_extra.social_core.backends.WeixinOAuth2", + "api.apps_extra.social_core.backends.GithubOAuth2", + "api.apps_extra.social_core.backends.GoogleOAuth2", + "django.contrib.auth.backends.AllowAllUsersModelBackend", ) ANONYMOUS_USER_ID = -1 @@ -155,8 +177,9 @@ CSRF_COOKIE_SAMESITE = None SECURE_CONTENT_TYPE_NOSNIFF = True SECURE_BROWSER_XSS_FILTER = True -CSRF_COOKIE_SECURE = bool(os.environ.get('CSRF_COOKIE_SECURE', False)) -SESSION_COOKIE_SECURE = bool(os.environ.get('SESSION_COOKIE_SECURE', False)) +CSRF_COOKIE_SECURE = os.environ.get('CSRF_COOKIE_SECURE', 'false').lower() == "true" +SESSION_COOKIE_SECURE = os.environ.get('SESSION_COOKIE_SECURE', 'false').lower() == "true" +CSRF_TRUSTED_ORIGINS = [r for r in os.environ.get('CSRF_TRUSTED_ORIGINS', '').split(',') if r] # Honor HTTPS from a trusted proxy # see https://docs.djangoproject.com/en/2.2/ref/settings/#secure-proxy-ssl-header @@ -170,12 +193,16 @@ REST_FRAMEWORK = { 'DATETIME_FORMAT': DRYCC_DATETIME_FORMAT, 'DEFAULT_MODEL_SERIALIZER_CLASS': 'rest_framework.serializers.ModelSerializer', - 'DEFAULT_PERMISSION_CLASSES': ( + 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', - ), - 'DEFAULT_RENDERER_CLASSES': ( + ], + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'rest_framework.authentication.SessionAuthentication', + 'oauth2_provider.contrib.rest_framework.OAuth2Authentication', + ], + 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', - ), + ], 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', 'PAGE_SIZE': 30, 'TEST_REQUEST_DEFAULT_FORMAT': 'json', @@ -248,32 +275,48 @@ 'handlers': ['console'], 'propagate': True, }, + 'oauth2_provider': { + 'handlers': ['console'], + 'propagate': True, + }, } } # security keys and auth tokens random_secret = ')u_jckp95wule8#wxd8sm!0tj2j&aveozu!nnpgl)2x&&16gfj' SECRET_KEY = os.environ.get('DRYCC_SECRET_KEY', random_secret) -# database setting -DRYCC_DATABASE_URL = os.environ.get('DRYCC_DATABASE_URL', 'postgres://:@:5432/passport') # noqa +# database default setting +DRYCC_DATABASE_URL = os.environ.get('DRYCC_DATABASE_URL', 'postgres://postgres:@:5432/passport') DATABASES = { - 'default': dj_database_url.config(default=DRYCC_DATABASE_URL, - conn_max_age=600) + 'default': dj_database_url.config(default=DRYCC_DATABASE_URL) } +# database replica setting +DRYCC_DATABASE_REPLICA_URL = os.environ.get('DRYCC_DATABASE_REPLICA_URL', None) +if DRYCC_DATABASE_REPLICA_URL is not None: + DATABASES["replica"] = dj_database_url.config(default=DRYCC_DATABASE_REPLICA_URL) + +# database routers +DATABASE_ROUTERS = ['api.routers.DefaultReplicaRouter', ] # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.2/howto/static-files/ STATIC_URL = '/assets/' STATIC_ROOT = os.path.abspath(os.path.join(BASE_DIR, '..', 'web', 'dist', 'assets')) -STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' +STATICFILES_STORAGE = 'whitenoise.storage.CompressedStaticFilesStorage' # see: https://django-oauth-toolkit.readthedocs.io/en/latest/oidc.html?highlight=oidc.key#creating-rsa-private-key # noqa -with open('/var/run/secrets/drycc/passport/oidc-rsa-private-key') as f: - OIDC_RSA_PRIVATE_KEY = f.read() +OIDC_ENABLED = False +OIDC_RSA_PRIVATE_KEY = None +OIDC_RSA_PRIVATE_KEY_FILE = '/var/run/secrets/drycc/passport/oidc-rsa-private-key' +if os.path.exists(OIDC_RSA_PRIVATE_KEY_FILE): + with open('/var/run/secrets/drycc/passport/oidc-rsa-private-key') as f: + OIDC_RSA_PRIVATE_KEY = f.read() + OIDC_ENABLED = True + OAUTH2_PROVIDER = { "OIDC_ENABLED": True, "OIDC_RSA_PRIVATE_KEY": OIDC_RSA_PRIVATE_KEY, - "OAUTH2_VALIDATOR_CLASS": "api.serializers.CustomOAuth2Validator", + "OAUTH2_VALIDATOR_CLASS": "api.oauth2_validators.CustomOAuth2Validator", "PKCE_REQUIRED": False, "ALLOWED_REDIRECT_URI_SCHEMES": ["http", "https"], "ACCESS_TOKEN_EXPIRE_SECONDS": int(os.environ.get('ACCESS_TOKEN_EXPIRE_SECONDS', 30 * 86400)), # noqa @@ -283,17 +326,30 @@ "REFRESH_TOKEN_EXPIRE_SECONDS": int(os.environ.get('REFRESH_TOKEN_EXPIRE_SECONDS', 60 * 86400)), # noqa "ROTATE_REFRESH_TOKEN": True, "SCOPES": { + "email": "Email", "profile": "Profile", "openid": "OpenID Connect scope", + "controller:hook": "Controller Hook", + "controller:blocklist": "Controller Blocklist", + "controller:logs": "Controller Logs", + "controller:alerts": "Controller Alerts", + "controller:metrics": "Controller Metrics", + "manager:workspace": "Manager Workspace", + "manager:usage": "Manager Usage", + "passport:message": "Passport Message", }, - "DEFAULT_SCOPES": ['openid', ], + "DEFAULT_SCOPES": ['openid', 'email', 'profile'], "DEFAULT_CODE_CHALLENGE_METHOD": 'S256', } -REST_FRAMEWORK['DEFAULT_AUTHENTICATION_CLASSES'] = ( - 'oauth2_provider.contrib.rest_framework.OAuth2Authentication', - 'rest_framework.authentication.SessionAuthentication', - 'rest_framework.authentication.BasicAuthentication', -) +OAUTH2_PROVIDER_APPLICATION_MODEL = 'api.Application' + +# Cache Valkey Configuration +CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.redis.RedisCache", + "LOCATION": os.environ.get('DRYCC_VALKEY_URL', 'redis://:@127.0.0.1:6379'), + } +} # LDAP settings taken from environment variables. LDAP_ENDPOINT = os.environ.get('LDAP_ENDPOINT', '') @@ -307,6 +363,42 @@ LDAP_STAFF_GROUP = os.environ.get('LDAP_STAFF_GROUP', '') LDAP_SUPERUSER_GROUP = os.environ.get('LDAP_SUPERUSER_GROUP', '') +# Social Auth settings for OAuth2 providers +SOCIAL_AUTH_FEISHU_KEY = os.environ.get('SOCIAL_AUTH_FEISHU_KEY', '') +SOCIAL_AUTH_FEISHU_SECRET = os.environ.get('SOCIAL_AUTH_FEISHU_SECRET', '') + +SOCIAL_AUTH_WEIXIN_KEY = os.environ.get('SOCIAL_AUTH_WEIXIN_KEY', '') +SOCIAL_AUTH_WEIXIN_SECRET = os.environ.get('SOCIAL_AUTH_WEIXIN_SECRET', '') + +SOCIAL_AUTH_GITHUB_KEY = os.environ.get('SOCIAL_AUTH_GITHUB_KEY', '') +SOCIAL_AUTH_GITHUB_SECRET = os.environ.get('SOCIAL_AUTH_GITHUB_SECRET', '') + +SOCIAL_AUTH_GOOGLE_KEY = os.environ.get('SOCIAL_AUTH_GOOGLE_KEY', '') +SOCIAL_AUTH_GOOGLE_SECRET = os.environ.get('SOCIAL_AUTH_GOOGLE_SECRET', '') + +# Social Auth Pipeline +SOCIAL_AUTH_PIPELINE = ( + 'social_core.pipeline.social_auth.social_details', + 'social_core.pipeline.social_auth.social_uid', + 'social_core.pipeline.social_auth.auth_allowed', + 'api.apps_extra.social_core.pipelines.handle_authenticated_binding', + 'social_core.pipeline.social_auth.social_user', + 'api.apps_extra.social_core.pipelines.require_username_password', + 'social_core.pipeline.social_auth.associate_user', + 'social_core.pipeline.social_auth.load_extra_data', + 'social_core.pipeline.user.user_details', +) + +# Social Auth settings +SOCIAL_AUTH_URL_NAMESPACE = 'social' +SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/access-tokens' +SOCIAL_AUTH_LOGIN_CALLBACK_URL = '/oauth/callback' +SOCIAL_AUTH_LOGIN_ERROR_URL = f'{SOCIAL_AUTH_LOGIN_CALLBACK_URL}?status=error' +SOCIAL_AUTH_NEW_USER_REDIRECT_URL = f'{SOCIAL_AUTH_LOGIN_CALLBACK_URL}?status=pending' +SOCIAL_AUTH_USER_MODEL = 'api.User' +SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL = True +SOCIAL_AUTH_PROTECTED_USER_FIELDS = ['email',] + # Django LDAP backend configuration. # See https://pythonhosted.org/django-auth-ldap/reference.html # for variables' details. @@ -354,5 +446,21 @@ DEFAULT_FROM_EMAIL = os.environ.get('DEFAULT_FROM_EMAIL', '') EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER', '') EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD', '') -EMAIL_USE_TLS = os.environ.get('EMAIL_USE_TLS', True) -EMAIL_USE_SSL = os.environ.get('EMAIL_USE_SSL', True) +EMAIL_USE_TLS = os.environ.get('EMAIL_USE_TLS', 'false').lower() == "true" +EMAIL_USE_SSL = os.environ.get('EMAIL_USE_SSL', 'false').lower() == "true" + +# username regex +USERNAME_REGEX = os.environ.get('USERNAME_REGEX', '^[a-z][a-z0-9]{4,}$') + +# names which apps cannot reserve for routing +RESERVED_NAME_PATTERNS_PATH = os.environ.get( + 'RESERVED_NAME_PATTERNS_PATH', '/etc/controller/reserved-name-patterns.txt') +if os.path.exists(RESERVED_NAME_PATTERNS_PATH): + with open(RESERVED_NAME_PATTERNS_PATH) as f: + RESERVED_NAME_PATTERNS = [line.strip() for line in f if line.strip()] +else: + RESERVED_NAME_PATTERNS = [r"^drycc(?:-[\w-]+)?$", r"^kube(?:-[\w-]+)?$", r"^default$"] + +# hcaptcha config +H_CAPTCHA_KEY = os.environ.get("H_CAPTCHA_KEY") +H_CAPTCHA_SECRET = os.environ.get("H_CAPTCHA_SECRET") diff --git a/rootfs/api/settings/testing.py b/rootfs/api/settings/testing.py index ffb1527..7f3331c 100644 --- a/rootfs/api/settings/testing.py +++ b/rootfs/api/settings/testing.py @@ -2,9 +2,18 @@ import string import os +from api.settings.celery import app + from api.settings.production import * # noqa from api.settings.production import DATABASES + +app.conf.update(task_always_eager=True) +OAUTH2_PROVIDER_ACCESS_TOKEN_MODEL = 'oauth2_provider.AccessToken' +OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL = 'oauth2_provider.RefreshToken' +OAUTH2_PROVIDER_GRANT_MODEL = 'oauth2_provider.Grant' +OAUTH2_PROVIDER_ID_TOKEN_MODEL = 'oauth2_provider.IDToken' + # A boolean that turns on/off debug mode. # https://docs.djangoproject.com/en/2.2/ref/settings/#debug DEBUG = True diff --git a/rootfs/api/signals.py b/rootfs/api/signals.py new file mode 100644 index 0000000..e13a018 --- /dev/null +++ b/rootfs/api/signals.py @@ -0,0 +1,15 @@ +from django.db.models.signals import post_save +from django.dispatch import receiver +from django.contrib.auth import get_user_model + +from api.models import Message + +User = get_user_model() + + +@receiver(post_save, sender=Message) +def message_changed_handle(sender, instance, created, **kwargs): + """Queue async notification dispatch when a new message is created.""" + if created: + from api.tasks import send_notification + send_notification.delay(instance) diff --git a/rootfs/api/static/css/main.css b/rootfs/api/static/css/main.css index 16bdb8a..685b23d 100644 --- a/rootfs/api/static/css/main.css +++ b/rootfs/api/static/css/main.css @@ -1,29 +1,77 @@ +:root { + --ui-color-bg: #ffffff; + --ui-color-surface: #ffffff; + --ui-color-text: #3f3f44; + --ui-color-text-secondary: #62748e; + --ui-color-primary: #409eff; + --ui-color-primary-hover: #337ecc; + --ui-color-border: #e2e8f0; + --ui-color-muted-bg: #f1f5f9; + --ui-color-danger: #c20707; + + --ui-font-family-base: benton-sans, 'Helvetica Neue', helvetica, arial, sans-serif; + --ui-font-size-base: 14px; + --ui-line-height-base: 1.42857; + + --ui-radius-sm: 6px; + --ui-radius-md: 8px; + --ui-radius-lg: 12px; + + --ui-shadow-sm: 0 2px 4px rgba(64, 158, 255, 0.3); + --ui-shadow-md: 0 4px 8px rgba(64, 158, 255, 0.4); + --ui-shadow-card: 0 4px 6px rgba(0, 0, 0, 0.1); + + --ui-space-1: 4px; + --ui-space-2: 8px; + --ui-space-3: 12px; + --ui-space-4: 16px; + --ui-space-5: 20px; + --ui-space-6: 24px; + --ui-space-7: 32px; +} + +*, *::before, *::after { + box-sizing: border-box; +} + +html,body { + height: 100%; +} + body { - font-family: benton-sans,'Helvetica Neue',helvetica,arial,sans-serif; - font-size: 14px; - line-height: 1.42857; - color: #3f3f44; - background-color: #fff; + font-family: var(--ui-font-family-base); + font-size: var(--ui-font-size-base); + line-height: var(--ui-line-height-base); + color: var(--ui-color-text); + background-color: var(--ui-color-bg); margin: 0; } +.privacy { + text-align: justify; +} + .page-wrap { - min-height: 100%; + min-height: 100vh; display: flex; flex-direction: column; - justify-content: space-between } .gradient-primary { - background-image: linear-gradient(to bottom,#654a86,#534292); - background-color: #534292 + background-image: linear-gradient(to bottom, var(--ui-color-primary), var(--ui-color-primary-hover)); + background-color: var(--ui-color-primary-hover) } .container { position: relative; - height: 100%; - text-align: center; - padding-top: 60px + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 20px; + box-sizing: border-box; + flex: 1; + width: 100%; } h1.logo { @@ -47,31 +95,30 @@ h1.logo a:before { } .panel { - max-width: 430px; - margin: 0 auto 20px; - border-radius: 8px; - background-color: rgb(255, 255, 255); - box-shadow: rgba(0, 0, 0, 0.05) 0px 1px 1px; - border-width: 1px; - border-style: solid; - border-color: transparent; - border-image: initial; + min-width: 0; + width: 100%; + max-width: 520px; + margin: 0 auto; + border-radius: var(--ui-radius-lg); + background-color: var(--ui-color-surface); + box-shadow: var(--ui-shadow-card); + border: none; } .panel .h3 { - margin: 40px 20px 0; + margin: 40px 30px 20px; line-height: 1.5; font-size: 24px; - color: rgb(102, 73, 134); + color: var(--ui-color-primary); } h2 { font-family: inherit; font-weight: 200; - color: #664986; + color: var(--ui-color-primary); } .panel form { - padding: 40px + padding: 0px 30px 30px 30px } form { @@ -94,7 +141,7 @@ label { form label { text-align: left; width: 100%; - color: rgb(98, 116, 142); + color: var(--ui-color-text-secondary); font-size: 12px; font-weight: bold; } @@ -110,19 +157,22 @@ input:-webkit-autofill { box-shadow: inset 0 1px 2px rgba(203,203,210,0.4), inset 0 0 10px 1000px #fffedb; } -.form-control { - padding-right: 8px; -} - .form-control { display: block; width: 100%; - padding: 6px 12px; + padding: 10px 16px; font-size: 14px; line-height: 1.42857; - border: 1px solid #cbcbd2; - border-radius: 4px; + border: 1px solid var(--ui-color-border); + border-radius: var(--ui-radius-sm); transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s; + background-color: var(--ui-color-surface); +} + +.form-control:focus { + outline: none; + border-color: var(--ui-color-primary); + box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.1); } input, button, select, textarea { @@ -138,7 +188,7 @@ button, input, optgroup, select, textarea { } input { - -webkit-writing-mode: horizontal-tb !important; + writing-mode: horizontal-tb !important; text-rendering: auto; letter-spacing: normal; word-spacing: normal; @@ -146,12 +196,17 @@ input { text-indent: 0px; text-shadow: none; text-align: start; - -webkit-appearance: textfield; + appearance: textfield; background-color: white; -webkit-rtl-ordering: logical; cursor: text; } +input[disabled], input[readonly] { + background: var(--ui-color-muted-bg); + cursor: not-allowed; +} + form .btn { border: 1px solid transparent; } @@ -165,16 +220,82 @@ form .btn { .btn-primary { color: #fff; - background-color: #60467e; - background-image: -webkit-linear-gradient(left bottom,rgba(159,88,150,0) 0,rgba(159,88,150,0.6) 100%); + background-color: var(--ui-color-primary); + background-image: none; + border: none; + box-shadow: var(--ui-shadow-sm); + transition: all 0.2s ease; +} + +.btn-primary:hover { + background-color: var(--ui-color-primary-hover); + box-shadow: var(--ui-shadow-md); + transform: translateY(-1px); +} + +.btn-primary:active { + transform: translateY(0); + box-shadow: 0 1px 2px rgba(64, 158, 255, 0.3); } .btn { - border-radius: 5px; + border-radius: var(--ui-radius-sm); padding-left: 18px; padding-right: 18px; } +@media (max-width: 576px) { + .panel { + max-width: 100%; + } + + .panel .h3 { + margin: 30px 20px 16px; + font-size: 22px; + } + + .panel form, + .oauth2-container { + padding-left: 20px; + padding-right: 20px; + } + + .oauth2-btn { + flex: 1 0 100%; + width: 100%; + } + + .panel-footer { + font-size: 15px; + padding: 16px; + } + + .inverted-wrapper { + padding: 20px 20px 0 20px; + } + + .legal li { + display: block; + margin: 8px 0; + } +} + +@media (min-width: 577px) and (max-width: 768px) { + .panel { + max-width: 490px; + } +} + +/* hCaptcha responsive */ +.h-captcha { + display: flex; + justify-content: center; +} + +.h-captcha iframe { + max-width: 100%; +} + .btn-block { display: block; width: 100%; @@ -191,6 +312,88 @@ form .btn { user-select: none; } +/* OAuth2 buttons styles */ +.oauth2-container { + padding: 30px 30px 10px; +} + +.oauth2-buttons { + display: flex; + flex-wrap: wrap; + gap: 15px; + margin-bottom: 24px; + justify-content: space-between; +} + +.oauth2-btn { + display: flex; + align-items: center; + gap: 8px; + padding: 12px 16px; + border: 1px solid #e2e8f0; + border-radius: 6px; + background-color: #ffffff; + color: #4a5568; + text-decoration: none; + font-size: 14px; + font-weight: 500; + transition: all 0.2s ease; + flex: 1 0 calc(50% - 10px); + width: calc(50% - 10px); + min-width: 140px; + max-width: none; + justify-content: center; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); +} + +.oauth2-btn:hover { + border-color: #cbd5e0; + background-color: #f7fafc; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08); + transform: translateY(-1px); +} + +.oauth2-btn:focus { + outline: none; + box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.1); +} + +.oauth2-icon { + width: 20px; + height: 20px; + display: inline-block; + flex-shrink: 0; +} + +.oauth2-icon svg { + width: 100%; + height: 100%; + fill: currentColor; +} + +.oauth2-email { + background: #f1f5f9; +} + +.oauth2-divider { + display: flex; + align-items: center; + text-align: center; +} + +.oauth2-divider .divider-line { + flex: 1; + height: 1px; + background-color: #e2e8f0; +} + +.oauth2-divider .divider-text { + padding: 0 16px; + color: #a0aec0; + font-size: 14px; + font-weight: 500; +} + .panel-footer { background-color: #f5f5f5; border-top: 1px solid #ddd; @@ -203,6 +406,7 @@ form .btn { display: block; font-size: 17px; color: #4a5568; + text-align: center; } a.panel-footer { @@ -252,4 +456,47 @@ form li { .white-link { margin-left: 25px; color: #fff +} + +.logo-sfdc { + display: block; + margin: 0 auto; + width: 100%; + max-width: 430px; + padding: 26.6666666667px 0; + text-align: center; + background: -webkit-linear-gradient(-360deg,rgba(255,255,255,0) 0,rgba(255,255,255,0.2) 50%,rgba(255,255,255,0) 100%); + background: linear-gradient(90deg,rgba(255,255,255,0) 0,rgba(255,255,255,0.2) 50%,rgba(255,255,255,0) 100%); + background-size: 100% 1px; + background-repeat: no-repeat; +} + +.logo-sfdc a { + display: block; + color: #dcdae9; + text-decoration: none; + text-transform: uppercase; + letter-spacing: .05em; + font-size: 10px; + font-weight: bold; +} + +.legal { + list-style: none; + margin-top: 40px; + padding: 0; + text-align: center; +} + +.legal li, .legal a { + font-size: 12px; + font-weight: bold; + text-transform: none; + letter-spacing: 0; + color: #dcdae9; +} + +.legal li { + display: inline-block; + margin: 5px; } \ No newline at end of file diff --git a/rootfs/api/static/icons/logo.svg b/rootfs/api/static/icons/logo.svg new file mode 100644 index 0000000..d970da0 --- /dev/null +++ b/rootfs/api/static/icons/logo.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rootfs/api/tasks.py b/rootfs/api/tasks.py new file mode 100644 index 0000000..e52abef --- /dev/null +++ b/rootfs/api/tasks.py @@ -0,0 +1,27 @@ +"""Celery tasks for Drycc Passport.""" +import logging + +from django.conf import settings +from celery import shared_task +from api.utils import send_email_notification, send_webhook_notification +from api.models import MessagePreference + +logger = logging.getLogger(__name__) + + +@shared_task(bind=True, max_retries=3, default_retry_delay=10) +def send_notification(self, message) -> None: + use_email, use_webhook = False, False + try: + preference = message.user.message_preference + except MessagePreference.DoesNotExist: + use_email = True + logger.info("Send email notification for message %s without user preference", message.id) + else: + if getattr(preference, f"notify_{message.category}", True): + use_email = preference.email_alerts + use_webhook = preference.push_alerts and preference.webhook_url + if use_email and message.user.email and getattr(settings, 'EMAIL_HOST', ''): + send_email_notification(message) + if use_webhook: + send_webhook_notification(message, preference.webhook_url) diff --git a/rootfs/api/templates/base/footer.html b/rootfs/api/templates/base/footer.html new file mode 100644 index 0000000..3b3a62c --- /dev/null +++ b/rootfs/api/templates/base/footer.html @@ -0,0 +1,19 @@ + \ No newline at end of file diff --git a/rootfs/api/templates/base/layout.html b/rootfs/api/templates/base/layout.html new file mode 100644 index 0000000..11e1c35 --- /dev/null +++ b/rootfs/api/templates/base/layout.html @@ -0,0 +1,20 @@ +{% load static %} + + + + + + {% block title %}Drycc CaaS{% endblock %} + + {% block extra_head %}{% endblock %} + + +
+
+ {% block content %}{% endblock %} +
+ {% include "base/footer.html" %} +
+ {% block extra_scripts %}{% endblock %} + + diff --git a/rootfs/api/templates/notifications/email_message.html b/rootfs/api/templates/notifications/email_message.html new file mode 100644 index 0000000..5c1c6a7 --- /dev/null +++ b/rootfs/api/templates/notifications/email_message.html @@ -0,0 +1,99 @@ + + + + + + {{ message.title }} + + + +
+
+
+

{{ message.title }}

+ {{ message.get_category_display }} +
+
+

{{ message.content }}

+ {% if message.action_link and message.action_text %} + {{ message.action_text }} + {% endif %} +
+ +
+
+ + diff --git a/rootfs/api/templates/oauth2_provider/authorize.html b/rootfs/api/templates/oauth2_provider/authorize.html index a43753d..36c33e6 100644 --- a/rootfs/api/templates/oauth2_provider/authorize.html +++ b/rootfs/api/templates/oauth2_provider/authorize.html @@ -1,34 +1,41 @@ +{% extends 'base/layout.html' %} {% load i18n %} -{% load static %} - - - - Authorize - -
-
-

Drycc

-
- {% if not error %} -

{% trans "Authorize" %} {{ application.name }}?

- {{ updated }} -
- {% csrf_token %} - {% for field in form %} - {% if field.is_hidden %} - {{ field }} - {% endif %} - {% endfor %} - {{ form.errors }} - {{ form.non_field_errors }} -
- -
- {% else %} -

{{ error.error }}

-

{{ error.description }}

-
- {% endif %} +{% block title %}Authorize{% endblock %} +{% block content %} +
+ {% if not error %} +

{% trans "Authorize" %} {{ application.name }}?

+ {{ updated }} +
+
+

{{ application.name }} wants to access your {{ request.user.username }} account

-
-
\ No newline at end of file + {% csrf_token %} + {% for field in form %} + {% if field.is_hidden %} + {{ field }} + {% endif %} + {% endfor %} + {{ form.errors }} + {{ form.non_field_errors }} +
+ + + With another account?  Sign In + {% else %} +

{{ error.error }}

+

{{ error.description }}

+
+ {% endif %} +
+{% endblock %} +{% block extra_scripts %} + +{% endblock %} \ No newline at end of file diff --git a/rootfs/api/templates/user/account_activation_done.html b/rootfs/api/templates/user/account_activation_done.html index d6c8bc1..e9c7095 100644 --- a/rootfs/api/templates/user/account_activation_done.html +++ b/rootfs/api/templates/user/account_activation_done.html @@ -1,6 +1,6 @@ {% extends 'user/message.html' %} -{% block title %}Account activite successful{% endblock %} +{% block heading %}Account activate successful{% endblock %} {% block message %} Your account has been activated successfully. -please go to the login page. +Please go to the login page. {% endblock %} diff --git a/rootfs/api/templates/user/account_activation_fail.html b/rootfs/api/templates/user/account_activation_fail.html index b2e6e43..15235d5 100644 --- a/rootfs/api/templates/user/account_activation_fail.html +++ b/rootfs/api/templates/user/account_activation_fail.html @@ -1,5 +1,5 @@ {% extends 'user/message.html' %} -{% block title %}Account activite fail{% endblock %} +{% block heading %}Account activate fail{% endblock %} {% block message %} The confirmation link was invalid, possibly it has already been used, go back Sign Up {% endblock %} \ No newline at end of file diff --git a/rootfs/api/templates/user/account_update_done.html b/rootfs/api/templates/user/account_update_done.html new file mode 100644 index 0000000..7991945 --- /dev/null +++ b/rootfs/api/templates/user/account_update_done.html @@ -0,0 +1,6 @@ +{% extends 'user/message.html' %} +{% block heading %}Account update successful{% endblock %} +{% block message %} +Your account has been updated successfully. +Please go to the main page. +{% endblock %} diff --git a/rootfs/api/templates/user/account_update_email.html b/rootfs/api/templates/user/account_update_email.html new file mode 100644 index 0000000..a5162e1 --- /dev/null +++ b/rootfs/api/templates/user/account_update_email.html @@ -0,0 +1,7 @@ +{% autoescape off %} +Hi {{ user.username }}, + +Please click on the link below to confirm your update: + +{{ domain }}{% url 'user_update_account' uidb64=uid token=token%} +{% endautoescape %} \ No newline at end of file diff --git a/rootfs/api/templates/user/account_update_fail.html b/rootfs/api/templates/user/account_update_fail.html new file mode 100644 index 0000000..cec93ea --- /dev/null +++ b/rootfs/api/templates/user/account_update_fail.html @@ -0,0 +1,6 @@ +{% extends 'user/message.html' %} +{% block heading %}Account update fail{% endblock %} +{% block message %} +The confirmation link was invalid, possibly it has already been expired. +Please go to the main page. +{% endblock %} \ No newline at end of file diff --git a/rootfs/api/templates/user/login.html b/rootfs/api/templates/user/login.html index f1f1aa8..1fa860d 100644 --- a/rootfs/api/templates/user/login.html +++ b/rootfs/api/templates/user/login.html @@ -1,33 +1,83 @@ -{% load static %} +{% extends 'base/layout.html' %} +{% block title %}{% if identity_linking %}Identity Linking{% else %}Login{% endif %}{% endblock %} +{% block content %} +
+

{% if identity_linking %}Identity Linking{% else %}Log in to your account{% endif %}

- - - - Login - -
-
-

Drycc

-
-

Log in to your account

-
- {% csrf_token %} - {% if form.errors %} -
There was a problem with your login.
- {% endif %} -
- - -
-
- - -
- - -
- Sign Up + {% if not identity_linking %} +
+
+
+
+ + or +
- Forgot your password?
+ {% endif %} + +
+ {% csrf_token %} + {% if form.errors %} + {% if identity_linking_error %} + + {% endif %} + {% for error in form.non_field_errors %} + + {% endfor %} + {% endif %} +
+ + +
+
+ + +
+ + + {% if identity_linking %} + + {% endif %} +
+ {% if registration_enabled %} + New to Drycc? Sign Up + {% endif %}
+{% if password_reset_enabled %} + +{% endif %} +{% endblock %} +{% block extra_scripts %} + +{% endblock %} diff --git a/rootfs/api/templates/user/login_done.html b/rootfs/api/templates/user/login_done.html index 357cb84..1b738fa 100644 --- a/rootfs/api/templates/user/login_done.html +++ b/rootfs/api/templates/user/login_done.html @@ -1,5 +1,5 @@ {% extends 'user/message.html' %} -{% block title %}Login done{% endblock %} +{% block heading %}Login done{% endblock %} {% block message %} You can close this page and return to your CLI. It should now be logged in. {% endblock %} \ No newline at end of file diff --git a/rootfs/api/templates/user/logout.html b/rootfs/api/templates/user/logout.html index 0c25d7f..7840f14 100644 --- a/rootfs/api/templates/user/logout.html +++ b/rootfs/api/templates/user/logout.html @@ -1,8 +1,8 @@ {% extends 'user/message.html' %} -{% block title %}Logout{% endblock %} +{% block heading %}Logout{% endblock %} {% block message %} Logout successfully. Return to the login later. {% endblock %} \ No newline at end of file diff --git a/rootfs/api/templates/user/message.html b/rootfs/api/templates/user/message.html index 78c9706..d600ddc 100644 --- a/rootfs/api/templates/user/message.html +++ b/rootfs/api/templates/user/message.html @@ -1,19 +1,9 @@ -{% load static %} - - - - - - Drycc | Message - - -
-
-

Drycc

-
-

{% block title %}{% endblock %}

-

{% block message %}{% endblock %}

-
-
-
-
\ No newline at end of file +{% extends 'base/layout.html' %} +{% block title %}Drycc | Message{% endblock %} +{% block content %} +
+

{% block heading %}{% endblock %}

+

{% block message %}{% endblock %}

+
+
+{% endblock %} \ No newline at end of file diff --git a/rootfs/api/templates/user/oauth_callback.html b/rootfs/api/templates/user/oauth_callback.html new file mode 100644 index 0000000..48a04d5 --- /dev/null +++ b/rootfs/api/templates/user/oauth_callback.html @@ -0,0 +1,82 @@ +{% extends 'base/layout.html' %} +{% block title %}Identity Linking{% endblock %} +{% block content %} +
+

Identity Linking

+ + {% if status == 'pending' %} +
+ {% csrf_token %} +
+

+ This {{ display_name|default:'OAuth' }} identity is not linked yet. Create a new account to continue. +

+
+ {% if error %} +
+ +
+ {% endif %} +
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ I already have an account + + {% elif status == 'linked' %} +
+
+

Identity linked successfully.

+
+ +
+ + {% elif status == 'already_linked' %} +
+
+

This identity is already linked to your account.

+
+ +
+ + {% elif status == 'conflict' %} +
+
+ +
+ +
+ + {% elif status == 'missing_email' %} +
+
+ +
+ +
+ + {% else %} +
+
+ +
+ +
+ {% endif %} +
+{% endblock %} \ No newline at end of file diff --git a/rootfs/api/templates/user/password_reset_complete.html b/rootfs/api/templates/user/password_reset_complete.html index 7903242..2a0afc4 100644 --- a/rootfs/api/templates/user/password_reset_complete.html +++ b/rootfs/api/templates/user/password_reset_complete.html @@ -1,5 +1,5 @@ {% extends 'user/message.html' %} -{% block title %}Password reset successful{% endblock %} +{% block heading %}Password reset successful{% endblock %} {% block message %} Your password has been set. You may go ahead and log in now. {% endblock %} diff --git a/rootfs/api/templates/user/password_reset_confirm.html b/rootfs/api/templates/user/password_reset_confirm.html index 171eda2..794cfa7 100644 --- a/rootfs/api/templates/user/password_reset_confirm.html +++ b/rootfs/api/templates/user/password_reset_confirm.html @@ -1,42 +1,32 @@ -{% load static %} - - - - - Reset Password - - +{% extends 'base/layout.html' %} +{% block title %}Reset Password{% endblock %} +{% block content %} {% if validlink %} - - -
-
-

Drycc

-
-

{{ title }}

-

Please enter your new password twice so we can verify you typed it in correctly.

-
- {% csrf_token %} -
- - -
{{ form.new_password1.errors }}
-
-
- - -
{{ form.new_password2.errors }}
-
- -
+
+

{{ title }}

+

Please enter your new password twice so we can verify you typed it in correctly.

+
+ {% csrf_token %} +
+ + +
-
+
+ + + +
+ +
- {% else %} - -

The password reset link was invalid, possibly because it has already been used. Please request a new password reset.

- +
+

The password reset link was invalid

+

Possibly because it has already been used. Please request a new password reset.

+
+
{% endif %} +{% endblock %} diff --git a/rootfs/api/templates/user/password_reset_done.html b/rootfs/api/templates/user/password_reset_done.html index e1b0931..04f49c5 100644 --- a/rootfs/api/templates/user/password_reset_done.html +++ b/rootfs/api/templates/user/password_reset_done.html @@ -1,5 +1,5 @@ {% extends 'user/message.html' %} -{% block title %}Email send successful{% endblock %} +{% block heading %}Email send successful{% endblock %} {% block message %} Please check your inbox. It may be in spam. {% endblock %} \ No newline at end of file diff --git a/rootfs/api/templates/user/password_reset_fail.html b/rootfs/api/templates/user/password_reset_fail.html new file mode 100644 index 0000000..ec506eb --- /dev/null +++ b/rootfs/api/templates/user/password_reset_fail.html @@ -0,0 +1,5 @@ +{% extends 'user/message.html' %} +{% block heading %}The password reset link was invalid{% endblock %} +{% block message %} +Possibly because it has already been used. Please request a new password reset. +{% endblock %} \ No newline at end of file diff --git a/rootfs/api/templates/user/password_reset_form.html b/rootfs/api/templates/user/password_reset_form.html index 14e8725..00803a0 100644 --- a/rootfs/api/templates/user/password_reset_form.html +++ b/rootfs/api/templates/user/password_reset_form.html @@ -1,27 +1,18 @@ -{% load static %} - - - - Reset Password - -
-
-

Drycc

-
-

{{ title }}

-

Forgotten your password? Enter your email address below, and we'll email instructions for setting a new one.

-
- {% csrf_token %} -
- - -
{{ form.email.errors }}
- -
- -
+{% extends 'base/layout.html' %} +{% block title %}Reset Password{% endblock %} +{% block content %} +
+

{{ title }}

+

Forgotten your password? Enter your email address below, and we'll email instructions for setting a new one.

+
+ {% csrf_token %} +
+ + +
-
+ +
- +{% endblock %} diff --git a/rootfs/api/templates/user/registration.html b/rootfs/api/templates/user/registration.html index 5e30e3a..058ff41 100644 --- a/rootfs/api/templates/user/registration.html +++ b/rootfs/api/templates/user/registration.html @@ -1,55 +1,52 @@ -{% load static %} - - - - - - Registration - - -
-
-
-

Registration

-
- {% csrf_token %} -
- - -
{{ form.username.errors }}
-
- -
- - - -
{{ form.password1.errors }}
- {% if form.password1.help_text %} -
{{ form.password1.help_text|safe }}
- {% endif %} -
- -
- - -
{{ form.password2.errors }}
- {% if form.password2.help_text %} -
{{ form.password2.help_text|safe }}
- {% endif %} -
- -
- - -
{{ form.email.errors }}
- -
- - -
+{% extends 'base/layout.html' %} +{% block title %}Registration{% endblock %} +{% block content %} +
+

Registration

+
+ {% csrf_token %} +
+ + +
-
+
+ + + +
+
+ + + +
+
+ + + +
+ {% if h_captcha_key %} +
+
+ +
+ {% endif %} + + {% if LEGAL_ENABLED %} +
+

+ Signing up signifies that you have read and agree to the Terms of Service and our Privacy Policy. +

+
+ {% endif %} +
+{% endblock %} +{% block extra_head %} +{% if h_captcha_key %} + +{% endif %} +{% endblock %} diff --git a/rootfs/api/templates/user/registration_disable.html b/rootfs/api/templates/user/registration_disable.html index 8dfc922..4f4bbaf 100644 --- a/rootfs/api/templates/user/registration_disable.html +++ b/rootfs/api/templates/user/registration_disable.html @@ -1,5 +1,5 @@ {% extends 'user/message.html' %} -{% block title %}Registration fail{% endblock %} +{% block heading %}Registration fail{% endblock %} {% block message %} The registration function of drycc passport is not enabled. Please contact the administrator to sign up. {% endblock %} \ No newline at end of file diff --git a/rootfs/api/templates/user/registration_done.html b/rootfs/api/templates/user/registration_done.html index e6467c5..29497d0 100644 --- a/rootfs/api/templates/user/registration_done.html +++ b/rootfs/api/templates/user/registration_done.html @@ -1,5 +1,5 @@ {% extends 'user/message.html' %} -{% block title %}Registration successful{% endblock %} +{% block heading %}Registration successful{% endblock %} {% block message %} We have sent an email to your mailbox, please log in the email to activate your account. {% endblock %} \ No newline at end of file diff --git a/rootfs/api/tests/__init__.py b/rootfs/api/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rootfs/api/tests/test_create_oauth2_application.py b/rootfs/api/tests/test_create_oauth2_application.py new file mode 100644 index 0000000..cead11f --- /dev/null +++ b/rootfs/api/tests/test_create_oauth2_application.py @@ -0,0 +1,139 @@ +import json +import os +import tempfile +from io import StringIO +from unittest import mock + +from django.contrib.auth import get_user_model +from django.contrib.auth.hashers import check_password +from django.core.management import call_command +from django.test import TestCase +from oauth2_provider.models import get_application_model + +from api.management.commands import create_oauth2_application as cmd_module + +User = get_user_model() +Application = get_application_model() + + +class CreateOauth2ApplicationTestCase(TestCase): + def setUp(self): + self.admin = User.objects.create_superuser( + username='create-oauth2-admin', + email='create-oauth2-admin@example.com', + password='password123', + ) + self.tmpdir = tempfile.mkdtemp() + self.secrets_dir = tempfile.mkdtemp() + self._secrets_patch = mock.patch.object( + cmd_module, 'secrets_path', self.secrets_dir, + ) + self._secrets_patch.start() + self.addCleanup(self._secrets_patch.stop) + + def _write_init_file(self, items): + path = os.path.join(self.tmpdir, 'init-applications.json') + with open(path, 'w') as f: + json.dump(items, f) + return path + + def _write_secret_file(self, name, suffix, value): + path = os.path.join( + self.secrets_dir, 'drycc-passport-%s-%s' % (name, suffix)) + with open(path, 'w') as f: + f.write(value) + return path + + def _run(self, items): + path = self._write_init_file(items) + out = StringIO() + call_command('create_oauth2_application', '--path', path, stdout=out) + return out.getvalue() + + def _m2m_app(self, **overrides): + item = { + 'name': 'builder', + 'key': '', + 'secret': '', + 'prefix': '', + 'grant_type': 'client-credentials', + 'client_type': 'confidential', + 'allowed_scopes': 'controller:hook', + 'redirect_uri': '', + } + item.update(overrides) + return item + + def test_m2m_reads_credentials_from_mounted_secret_files(self): + self._write_secret_file('builder', 'key', 'mounted-key-value') + self._write_secret_file('builder', 'secret', 'mounted-secret-value\n') + + self._run([self._m2m_app()]) + + app = Application.objects.get(name='builder') + self.assertEqual(app.client_id, 'mounted-key-value') + self.assertTrue(check_password('mounted-secret-value', app.client_secret)) + + def test_subdomain_app_reads_credentials_from_mounted_secret_files(self): + self._write_secret_file('grafana', 'key', 'gf-key') + self._write_secret_file('grafana', 'secret', 'gf-secret') + + self._run([{ + 'name': 'grafana', + 'key': '', + 'secret': '', + 'prefix': 'drycc-grafana', + 'grant_type': 'internal', + 'client_type': 'confidential', + 'allowed_scopes': 'openid profile email', + 'redirect_uri': '/oauth2/callback', + }]) + + app = Application.objects.get(name='grafana') + self.assertEqual(app.client_id, 'gf-key') + self.assertTrue(check_password('gf-secret', app.client_secret)) + + def test_falls_back_to_random_when_no_mount_and_no_init_value(self): + self._run([self._m2m_app()]) + + app = Application.objects.get(name='builder') + self.assertEqual(len(app.client_id), 40) + self.assertNotEqual(app.client_id, '') + self.assertNotEqual(app.client_secret, '') + + def test_init_config_value_takes_precedence_over_mount(self): + self._write_secret_file('builder', 'key', 'mount-key') + self._write_secret_file('builder', 'secret', 'mount-secret') + + self._run([self._m2m_app(key='cfg-key', secret='cfg-secret')]) + + app = Application.objects.get(name='builder') + self.assertEqual(app.client_id, 'cfg-key') + self.assertTrue(check_password('cfg-secret', app.client_secret)) + + def test_idempotent_when_mount_unchanged(self): + self._write_secret_file('builder', 'key', 'stable-key') + self._write_secret_file('builder', 'secret', 'stable-secret') + + self._run([self._m2m_app()]) + first = Application.objects.get(name='builder') + first_id = first.client_id + first_hashed_secret = first.client_secret + + self._run([self._m2m_app()]) + second = Application.objects.get(name='builder') + + self.assertEqual(second.client_id, first_id) + self.assertEqual(second.client_secret, first_hashed_secret) + self.assertTrue(check_password('stable-secret', second.client_secret)) + self.assertEqual(Application.objects.filter(name='builder').count(), 1) + + def test_logs_credential_source(self): + self._write_secret_file('builder', 'key', 'k') + self._write_secret_file('builder', 'secret', 's') + + out = self._run([self._m2m_app()]) + + self.assertIn('[builder/key] credential source: mounted-file', out) + self.assertIn('[builder/secret] credential source: mounted-file', out) + self.assertIn('Drycc builder app created', out) diff --git a/rootfs/api/tests/test_pipelines.py b/rootfs/api/tests/test_pipelines.py new file mode 100644 index 0000000..78b6a62 --- /dev/null +++ b/rootfs/api/tests/test_pipelines.py @@ -0,0 +1,117 @@ +from unittest.mock import Mock, patch + +from django.contrib.auth import get_user_model +from django.test import RequestFactory, TestCase +from social_django.models import UserSocialAuth + +from api.apps_extra.social_core.pipelines import ( + handle_authenticated_binding, require_username_password +) + +User = get_user_model() + + +class PipelineTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + self.user = User.objects.create_user( + username='pipe-user', + email='pipe@example.com', + password='password123', + ) + + def _make_backend(self, request, name='feishu'): + strategy = Mock() + strategy.request = request + strategy.session_set = Mock() + backend = Mock() + backend.name = name + backend.strategy = strategy + return backend + + @patch( + 'api.apps_extra.social_core.pipelines.get_oauth_callback', + return_value='/oauth/callback?status=linked' + ) + def test_handle_authenticated_binding_creates_identity(self, _mock_callback): + request = self.factory.get('/oauth/callback') + request.user = self.user + backend = self._make_backend(request) + + response = handle_authenticated_binding( + backend, 'uid-1', {}, {'email': 'pipe@example.com'} + ) + + self.assertEqual(response.status_code, 302) + self.assertTrue(UserSocialAuth.objects.filter( + user=self.user, provider='feishu', uid='uid-1' + ).exists()) + + @patch( + 'api.apps_extra.social_core.pipelines.get_oauth_callback', + return_value='/oauth/callback?status=conflict' + ) + def test_handle_authenticated_binding_conflict(self, _mock_callback): + other = User.objects.create_user( + username='other', email='other@example.com', password='password123' + ) + UserSocialAuth.objects.create( + user=other, provider='feishu', uid='uid-1', extra_data={} + ) + request = self.factory.get('/oauth/callback') + request.user = self.user + backend = self._make_backend(request) + + response = handle_authenticated_binding( + backend, 'uid-1', {}, {'email': 'pipe@example.com'} + ) + + self.assertEqual(response.status_code, 302) + + @patch( + 'api.apps_extra.social_core.pipelines.get_oauth_callback', + return_value='/oauth/callback?status=already_linked' + ) + def test_handle_authenticated_binding_already_linked(self, _mock_callback): + UserSocialAuth.objects.create( + user=self.user, provider='feishu', uid='uid-1', extra_data={} + ) + request = self.factory.get('/oauth/callback') + request.user = self.user + backend = self._make_backend(request) + + response = handle_authenticated_binding( + backend, 'uid-1', {}, {'email': 'pipe@example.com'} + ) + + self.assertEqual(response.status_code, 302) + + @patch( + 'api.apps_extra.social_core.pipelines.get_oauth_callback', + return_value='/oauth/callback?status=pending' + ) + def test_require_username_password_sets_pending_session(self, _mock_callback): + request = self.factory.get('/oauth/callback') + request.user = Mock(is_authenticated=False) + backend = self._make_backend(request) + + response = require_username_password( + backend, 'uid-1', {'email': 'pipe@example.com'}, + {'email': 'pipe@example.com'} + ) + + self.assertEqual(response.status_code, 302) + backend.strategy.session_set.assert_called_once() + + @patch( + 'api.apps_extra.social_core.pipelines.get_oauth_callback', + return_value='/oauth/callback?status=missing_email' + ) + def test_require_username_password_requires_email(self, _mock_callback): + request = self.factory.get('/oauth/callback') + request.user = Mock(is_authenticated=False) + backend = self._make_backend(request) + + response = require_username_password(backend, 'uid-1', {}, {}) + + self.assertEqual(response.status_code, 302) diff --git a/rootfs/api/tests/test_serializers.py b/rootfs/api/tests/test_serializers.py new file mode 100644 index 0000000..a25ddf8 --- /dev/null +++ b/rootfs/api/tests/test_serializers.py @@ -0,0 +1,50 @@ +from django.contrib.auth import get_user_model +from django.test import TestCase + +from api.models import Message, MessagePreference +from api.serializers import ListSerializer, MessagePreferenceSerializer, MessageSerializer + +User = get_user_model() + + +class SerializerTestCase(TestCase): + def setUp(self): + self.user = User.objects.create_user( + username='serializer-user', + email='serializer@example.com', + password='password123', + ) + self.message = Message.objects.create( + user=self.user, + category='system', + title='Serializer message', + content='Serializer content', + full_content='Serializer full content', + severity='info', + ) + self.preference = MessagePreference.objects.create( + user=self.user, + email_alerts=True, + push_alerts=False, + webhook_url='', + notify_security=True, + notify_system=True, + notify_product=True, + notify_alert=True, + notify_service=True, + ) + + def test_list_serializer_validate_section(self): + result = ListSerializer.validate_section('1,2') + self.assertEqual(len(result), 2) + + def test_message_serializer_contains_expected_fields(self): + data = MessageSerializer(self.message).data + self.assertEqual(data['category'], 'system') + self.assertEqual(data['title'], 'Serializer message') + self.assertIn('date', data) + + def test_message_preference_serializer_contains_singular_alert_field(self): + data = MessagePreferenceSerializer(self.preference).data + self.assertIn('notify_alert', data) + self.assertTrue(data['notify_alert']) diff --git a/rootfs/api/tests/test_tasks.py b/rootfs/api/tests/test_tasks.py new file mode 100644 index 0000000..87fffb6 --- /dev/null +++ b/rootfs/api/tests/test_tasks.py @@ -0,0 +1,118 @@ +from unittest.mock import patch + +from django.contrib.auth import get_user_model +from django.test import TestCase, override_settings + +from api.models import Message, MessagePreference +from api.tasks import send_notification + +User = get_user_model() + + +@override_settings(EMAIL_HOST='smtp.example.com') +class NotificationTaskTestCase(TestCase): + def setUp(self): + delay_patcher = patch('api.tasks.send_notification.delay') + self.addCleanup(delay_patcher.stop) + self.mock_delay = delay_patcher.start() + + self.user = User.objects.create_user( + username='task-user', + email='task@example.com', + password='password123', + ) + self.preference = MessagePreference.objects.create( + user=self.user, + email_alerts=True, + push_alerts=True, + webhook_url='https://example.com/webhook', + notify_security=True, + notify_system=True, + notify_product=True, + notify_alert=True, + notify_service=True, + ) + self.message = Message.objects.create( + user=self.user, + category='security', + title='Security event', + content='A security event occurred', + full_content='A security event occurred in detail', + severity='warning', + ) + + @patch('api.tasks.send_email_notification') + @patch('api.tasks.send_webhook_notification') + def test_send_notification_uses_enabled_channels(self, mock_webhook, mock_email): + send_notification.run(self.message) + + mock_email.assert_called_once() + mock_webhook.assert_called_once_with( + mock_email.call_args[0][0], 'https://example.com/webhook' + ) + + @patch('api.tasks.send_email_notification') + @patch('api.tasks.send_webhook_notification') + def test_send_notification_respects_category_preference(self, mock_webhook, mock_email): + self.preference.notify_security = False + self.preference.save(update_fields=['notify_security']) + + send_notification.run(self.message) + + mock_email.assert_not_called() + mock_webhook.assert_not_called() + + @patch('api.tasks.send_email_notification') + @patch('api.tasks.send_webhook_notification') + def test_send_notification_uses_default_true_for_unknown_category( + self, mock_webhook, mock_email + ): + self.message.category = 'unknown' + self.message.save(update_fields=['category']) + + send_notification.run(self.message) + + mock_email.assert_called_once() + mock_webhook.assert_called_once_with( + mock_email.call_args[0][0], 'https://example.com/webhook' + ) + + @patch('api.tasks.send_email_notification') + @patch('api.tasks.send_webhook_notification') + @patch('api.tasks.logger') + def test_send_notification_without_preference_sends_email_only( + self, mock_logger, mock_webhook, mock_email + ): + self.preference.delete() + # Refresh to clear cached related object + self.message.refresh_from_db() + self.message.user = User.objects.get(pk=self.user.pk) + + send_notification.run(self.message) + + mock_email.assert_called_once() + mock_webhook.assert_not_called() + mock_logger.info.assert_called_once_with( + 'Send email notification for message %s without user preference', + self.message.id, + ) + + @patch('api.tasks.send_webhook_notification', side_effect=RuntimeError('boom')) + def test_send_notification_propagates_dispatch_error(self, _mock_webhook): + with self.assertRaises(RuntimeError): + send_notification.run(self.message) + + @patch('api.tasks.send_email_notification') + @patch('api.tasks.send_webhook_notification') + def test_send_notification_supports_alert_category_with_singular_field( + self, mock_webhook, mock_email + ): + self.message.category = 'alert' + self.message.save(update_fields=['category']) + self.preference.notify_alert = False + self.preference.save(update_fields=['notify_alert']) + + send_notification.run(self.message) + + mock_email.assert_not_called() + mock_webhook.assert_not_called() diff --git a/rootfs/api/tests/test_utils.py b/rootfs/api/tests/test_utils.py new file mode 100644 index 0000000..fd9201e --- /dev/null +++ b/rootfs/api/tests/test_utils.py @@ -0,0 +1,105 @@ +from unittest.mock import Mock, patch + +from django.contrib.auth import get_user_model +from django.test import RequestFactory, TestCase, override_settings +from social_django.models import UserSocialAuth +from rest_framework.exceptions import ValidationError + +from api.models import Message +from api.utils import ( + get_local_host, + get_oauth_callback, + get_user_socials, + send_activation_email, + send_email_notification, + send_webhook_notification, + timestamp2datetime, + validate_reserved_names, +) + +User = get_user_model() + + +class UtilsTestCase(TestCase): + def setUp(self): + self.factory = RequestFactory() + self.user = User.objects.create_user( + username='util-user', + email='util@example.com', + password='password123', + ) + self.message = Message.objects.create( + user=self.user, + category='security', + title='Utility message', + content='Utility content', + full_content='Utility content full', + severity='warning', + ) + + def test_timestamp2datetime(self): + dt = timestamp2datetime(0) + self.assertEqual(dt.year, 1970) + + def test_get_local_host(self): + request = self.factory.get('/user/info', secure=True, HTTP_HOST='example.com') + self.assertEqual(get_local_host(request), 'https://example.com') + + @override_settings(SOCIAL_AUTH_LOGIN_CALLBACK_URL='/oauth/callback') + def test_get_oauth_callback(self): + request = self.factory.get('/user/login', secure=True, HTTP_HOST='example.com') + callback = get_oauth_callback(request, 'linked', 'feishu') + self.assertEqual( + callback, + 'https://example.com/oauth/callback?status=linked&provider=feishu' + ) + + @override_settings(RESERVED_NAME_PATTERNS=[r'^admin$', r'^root$']) + def test_validate_reserved_names_rejects_reserved(self): + with self.assertRaises(ValidationError): + validate_reserved_names('admin') + + @override_settings(RESERVED_NAME_PATTERNS=[r'^admin$', r'^root$']) + def test_validate_reserved_names_accepts_normal_name(self): + validate_reserved_names('normal-user') + + @override_settings(EMAIL_HOST='smtp.example.com') + @patch('api.utils.render_to_string', return_value='rendered body') + def test_send_activation_email(self, mock_render): + request = self.factory.get('/user/registration', secure=True, HTTP_HOST='example.com') + with patch.object(self.user, 'email_user') as mock_email_user: + send_activation_email(request, self.user) + + mock_render.assert_called_once() + mock_email_user.assert_called_once() + + @override_settings(EMAIL_HOST='smtp.example.com') + @patch('api.utils.render_to_string', return_value='Hello') + def test_send_email_notification(self, mock_render): + with patch.object(self.user, 'email_user') as mock_email_user: + send_email_notification(self.message) + + mock_render.assert_called_once() + mock_email_user.assert_called_once() + + @patch('api.utils.requests.post') + def test_send_webhook_notification(self, mock_post): + mock_post.return_value.raise_for_status = Mock() + + send_webhook_notification(self.message, 'https://example.com/webhook') + + mock_post.assert_called_once() + + @patch('api.apps_extra.social_core.backends.__all__', new=[]) + def test_get_user_socials_without_backend_metadata(self): + UserSocialAuth.objects.create( + user=self.user, + provider='feishu', + uid='uid-1', + extra_data={'email': 'social@example.com'}, + ) + + results = get_user_socials(self.user) + + self.assertEqual(len(results), 1) + self.assertEqual(results[0]['email'], 'social@example.com') diff --git a/rootfs/api/tests/test_views.py b/rootfs/api/tests/test_views.py new file mode 100644 index 0000000..52017a4 --- /dev/null +++ b/rootfs/api/tests/test_views.py @@ -0,0 +1,867 @@ +""" +Test cases for API views +""" +from unittest.mock import patch + +from django.test import TestCase, RequestFactory +from django.contrib.auth import get_user_model +from django.urls import reverse +from rest_framework.test import APITestCase +from rest_framework import status +from oauth2_provider.models import AccessToken +from social_django.models import UserSocialAuth +from django.core.cache import cache + +from api.views import ( + ReadinessCheckView, LivenessCheckView, ActivateAccount +) +from api.forms import RegistrationForm +from api.models import Message, MessagePreference + +User = get_user_model() + + +class TestReadinessCheckView(TestCase): + """Test readiness check view""" + + def test_readiness_check_get(self): + request = RequestFactory().get('/readiness/') + response = ReadinessCheckView.as_view()(request) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content.decode(), 'OK') + + def test_readiness_check_head(self): + request = RequestFactory().head('/readiness/') + response = ReadinessCheckView.as_view()(request) + self.assertEqual(response.status_code, 200) + + +class TestLivenessCheckView(TestCase): + """Test liveness check view""" + + def test_liveness_check_get(self): + request = RequestFactory().get('/liveness/') + response = LivenessCheckView.as_view()(request) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content.decode(), 'OK') + + def test_liveness_check_head(self): + request = RequestFactory().head('/liveness/') + response = LivenessCheckView.as_view()(request) + self.assertEqual(response.status_code, 200) + + +class TestRegistrationView(TestCase): + """Test registration view""" + + def setUp(self): + self.factory = RequestFactory() + + def test_registration_form_valid(self): + form_data = { + 'username': 'testuser', + 'email': 'test@example.com', + 'password1': 'testpassword123', + 'password2': 'testpassword123' + } + form = RegistrationForm(data=form_data) + self.assertTrue(form.is_valid()) + + @patch('api.views.web.settings.REGISTRATION_ENABLED', False) + def test_registration_get_disabled(self): + response = self.client.get(reverse('registration')) + + self.assertEqual(response.status_code, 200) + self.assertContains( + response, + 'The registration function of drycc passport is not enabled.', + status_code=200, + ) + + @patch('api.views.web.settings.REGISTRATION_ENABLED', True) + @patch('api.views.web.settings.EMAIL_HOST', '') + def test_registration_post_creates_active_user_when_email_disabled(self): + response = self.client.post(reverse('registration'), { + 'username': 'newuser', + 'email': 'new@example.com', + 'password1': 'testpassword123', + 'password2': 'testpassword123', + 'h-captcha-response': 'PASSED', + }) + + self.assertEqual(response.status_code, 302) + user = User.objects.get(username='newuser') + self.assertTrue(user.is_active) + + @patch('api.views.web.settings.REGISTRATION_ENABLED', True) + @patch('api.views.web.settings.EMAIL_HOST', 'smtp.example.com') + @patch('api.views.web.send_activation_email') + def test_registration_post_sends_activation_email_when_email_enabled( + self, mock_send_activation_email + ): + response = self.client.post(reverse('registration'), { + 'username': 'inactiveuser', + 'email': 'inactive@example.com', + 'password1': 'testpassword123', + 'password2': 'testpassword123', + 'h-captcha-response': 'PASSED', + }) + + self.assertEqual(response.status_code, 302) + user = User.objects.get(username='inactiveuser') + self.assertFalse(user.is_active) + mock_send_activation_email.assert_called_once() + + +class TestActivateAccount(TestCase): + """Test account activation view""" + + def setUp(self): + self.user = User.objects.create_user( + username='testuser', + email='test@example.com', + password='testpass123', + is_active=False + ) + self.factory = RequestFactory() + + def test_activate_account_invalid_token(self): + from django.utils.http import urlsafe_base64_encode + from django.utils.encoding import force_bytes + from django.contrib.messages.storage.fallback import FallbackStorage + + uid = urlsafe_base64_encode(force_bytes(self.user.pk)) + request = self.factory.get(f'/activate/{uid}/invalid-token/') + setattr(request, 'session', 'session') + messages = FallbackStorage(request) + setattr(request, '_messages', messages) + response = ActivateAccount.as_view()(request, uidb64=uid, token='invalid-token') + + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, '/user/activate/fail/') + + def test_activate_account_valid_token(self): + from django.utils.http import urlsafe_base64_encode + from django.utils.encoding import force_bytes + from django.contrib.messages.storage.fallback import FallbackStorage + from api.utils import token_generator + + uid = urlsafe_base64_encode(force_bytes(self.user.pk)) + token = token_generator.make_token(self.user) + request = self.factory.get(f'/activate/{uid}/{token}/') + request.session = self.client.session + messages = FallbackStorage(request) + setattr(request, '_messages', messages) + + response = ActivateAccount.as_view()(request, uidb64=uid, token=token) + + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, '/user/activate/done/') + self.user.refresh_from_db() + self.assertTrue(self.user.is_active) + + +class TestUserDetailView(APITestCase): + """Test user detail viewset""" + + def setUp(self): + self.user = User.objects.create_user( + username='testuser', + email='test@example.com', + password='testpass123' + ) + self.client.force_authenticate(user=self.user) + + def test_get_user_detail(self): + url = '/user/info' + response = self.client.get(url) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['username'], 'testuser') + + @patch('api.views.api.settings.EMAIL_HOST', 'smtp.example.com') + @patch('api.views.api.render_to_string', return_value='mail-body') + def test_update_user_detail_sends_confirmation_email_and_caches_data(self, _mock_render): + url = '/user/info' + response = self.client.put(url, {'first_name': 'Updated'}) + + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + self.user.refresh_from_db() + self.assertEqual(self.user.first_name, '') + self.assertEqual(cache.get(f'user:serializer:{self.user.pk}'), {'first_name': 'Updated'}) + + def test_update_user_detail_fails_validation(self): + url = '/user/info' + response = self.client.put(url, {'email': 'invalid-email'}) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertIn('email', response.data) + + +class TestUserTokensView(APITestCase): + """Test user tokens viewset""" + + def setUp(self): + self.user = User.objects.create_user( + username='testuser', + email='test@example.com', + password='testpass123' + ) + self.client.force_authenticate(user=self.user) + self.token = AccessToken.objects.create( + user=self.user, + token='tokentest', + application=None, + expires='9999-01-01T00:00:00Z', + scope='read write' + ) + + def test_list_user_tokens(self): + url = reverse('user_tokens') + response = self.client.get(url) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_delete_user_token(self): + url = reverse('user_grants', args=[self.token.id]) + response = self.client.delete(url) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + self.assertFalse(AccessToken.objects.filter(id=self.token.id).exists()) + + +class TestUserAccountPasswordView(APITestCase): + """Test user account password view""" + + def setUp(self): + self.user = User.objects.create_user( + username='testuser', + email='test@example.com', + password='oldpassword123' + ) + self.client.force_authenticate(user=self.user) + + def test_update_password_valid(self): + url = '/user/password' + data = { + 'password': 'oldpassword123', + 'new_password': 'newpassword123' + } + response = self.client.put(url, data) + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + + self.user.refresh_from_db() + self.assertTrue(self.user.check_password('newpassword123')) + + +class TestIdentityProviderView(APITestCase): + + @patch('api.views.api.settings.SOCIAL_AUTH_FEISHU_KEY', 'key') + @patch('api.views.api.settings.SOCIAL_AUTH_FEISHU_SECRET', 'secret') + @patch('api.views.api.settings.SOCIAL_AUTH_GOOGLE_KEY', '') + @patch('api.views.api.settings.SOCIAL_AUTH_GOOGLE_SECRET', '') + def test_only_configured_identity_providers_are_returned(self): + response = self.client.get(reverse('user_identity_providers')) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertGreaterEqual(response.data['count'], 1) + provider_names = [item['name'] for item in response.data['results']] + self.assertIn('feishu', provider_names) + self.assertNotIn('google', provider_names) + + +class TestUserIdentityView(APITestCase): + + def setUp(self): + self.user = User.objects.create_user( + username='identity-user', + email='identity@example.com', + password='testpass123' + ) + self.other_user = User.objects.create_user( + username='other-user', + email='other@example.com', + password='testpass123' + ) + self.identity = UserSocialAuth.objects.create( + user=self.user, + provider='feishu', + uid='uid-1', + extra_data={'email': 'identity@example.com'} + ) + self.other_identity = UserSocialAuth.objects.create( + user=self.other_user, + provider='github', + uid='uid-2', + extra_data={'email': 'other@example.com'} + ) + self.client.force_authenticate(user=self.user) + + def test_list_user_identities(self): + response = self.client.get(reverse('user_identities-list')) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data['results'][0]['provider'], 'feishu') + + def test_delete_own_identity(self): + response = self.client.delete(reverse('user_identities-detail', args=[self.identity.id])) + + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + self.assertFalse(UserSocialAuth.objects.filter(id=self.identity.id).exists()) + + def test_cannot_delete_other_user_identity(self): + response = self.client.delete( + reverse('user_identities-detail', args=[self.other_identity.id]) + ) + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + +class TestOAuthPendingAndCreateView(APITestCase): + + def setUp(self): + self.client_handler = self.client.handler + + def test_oauth_pending_without_session_data(self): + response = self.client.get(reverse('user_oauth_pending')) + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_oauth_pending_with_session_data(self): + session = self.client.session + session['oauth_pending'] = { + 'provider': 'feishu', + 'email': 'pending@example.com', + 'uid': 'pending-uid', + 'extra_data': {'email': 'pending@example.com'}, + } + session.save() + + response = self.client.get(reverse('user_oauth_pending')) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['provider'], 'feishu') + self.assertEqual(response.data['email'], 'pending@example.com') + + def test_oauth_create_user_success(self): + session = self.client.session + session['oauth_pending'] = { + 'provider': 'feishu', + 'email': 'new@example.com', + 'uid': 'pending-uid', + 'extra_data': {'email': 'new@example.com'}, + } + session.save() + + response = self.client.post(reverse('user_oauth_create'), { + 'username': 'oauth-user', + 'password': 'password123', + }) + + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertTrue( + User.objects.filter(username='oauth-user', email='new@example.com').exists() + ) + self.assertTrue( + UserSocialAuth.objects.filter(provider='feishu', uid='pending-uid').exists() + ) + + def test_oauth_create_user_requires_pending(self): + response = self.client.post(reverse('user_oauth_create'), { + 'username': 'oauth-user', + 'password': 'password123', + }) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_oauth_create_user_requires_username(self): + session = self.client.session + session['oauth_pending'] = { + 'provider': 'feishu', + 'email': 'new@example.com', + 'uid': 'pending-uid', + 'extra_data': {'email': 'new@example.com'}, + } + session.save() + + response = self.client.post(reverse('user_oauth_create'), { + 'password': 'password123', + }) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_oauth_create_user_rejects_existing_email(self): + User.objects.create_user( + username='exists', email='new@example.com', password='password123' + ) + session = self.client.session + session['oauth_pending'] = { + 'provider': 'feishu', + 'email': 'new@example.com', + 'uid': 'pending-uid', + 'extra_data': {'email': 'new@example.com'}, + } + session.save() + + response = self.client.post(reverse('user_oauth_create'), { + 'username': 'oauth-user', + 'password': 'password123', + }) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_oauth_create_user_rejects_existing_identity(self): + existing_user = User.objects.create_user( + username='exists', email='exists@example.com', password='password123' + ) + UserSocialAuth.objects.create( + user=existing_user, + provider='feishu', + uid='pending-uid', + extra_data={'email': 'exists@example.com'} + ) + session = self.client.session + session['oauth_pending'] = { + 'provider': 'feishu', + 'email': 'new@example.com', + 'uid': 'pending-uid', + 'extra_data': {'email': 'new@example.com'}, + } + session.save() + + response = self.client.post(reverse('user_oauth_create'), { + 'username': 'oauth-user', + 'password': 'password123', + }) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + +class TestUserMessageViews(APITestCase): + + def setUp(self): + self.user = User.objects.create_user( + username='message-user', + email='message@example.com', + password='testpass123' + ) + self.other_user = User.objects.create_user( + username='other-message-user', + email='other-message@example.com', + password='testpass123' + ) + self.client.force_authenticate(user=self.user) + self.message1 = Message.objects.create( + user=self.user, + category='system', + title='System message', + content='System content', + severity='info' + ) + self.message2 = Message.objects.create( + user=self.user, + category='security', + title='Security message', + content='Security content', + severity='warning' + ) + self.other_message = Message.objects.create( + user=self.other_user, + category='system', + title='Other message', + content='Other content', + severity='info' + ) + + def test_list_messages(self): + response = self.client.get(reverse('user_messages-list')) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['count'], 2) + self.assertIn('results', response.data) + + def test_filter_messages_by_category(self): + response = self.client.get(reverse('user_messages-list'), {'category': 'security'}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data['results'][0]['category'], 'security') + + def test_list_messages_supports_limit_offset_pagination(self): + response = self.client.get(reverse('user_messages-list'), {'limit': 1, 'offset': 0}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(len(response.data['results']), 1) + self.assertEqual(response.data['count'], 2) + + def test_service_message_create(self): + from api.models import Application + from urllib.parse import urlencode + + # Setup application + Application.objects.create( + name='test_app', + client_type='confidential', + client_id='my_test_client_id', + client_secret='my_test_client_secret', + authorization_grant_type='client-credentials', + user=self.user + ) + + # 1. Fetch access token via client-credentials flow + data = urlencode({ + 'grant_type': 'client_credentials', + 'client_id': 'my_test_client_id', + 'client_secret': 'my_test_client_secret', + 'scope': 'passport:message' + }) + + token_response = self.client.post( + '/oauth/token/', + data=data, + content_type='application/x-www-form-urlencoded' + ) + + self.assertEqual(token_response.status_code, 200, token_response.json()) + access_token = token_response.json()['access_token'] + + # 2. Use the access token to create a message + response = self.client.post('/messages/', { + 'username': self.user.username, + 'category': 'alert', + 'title': 'Created from API', + 'content': 'API created content', + 'full_content': 'API created full content', + 'severity': 'warning', + 'is_read': False, + 'action_link': '/messages', + 'action_text': 'Open', + }, HTTP_AUTHORIZATION=f'Bearer {access_token}') + + self.assertEqual(response.status_code, 201) + self.assertTrue(Message.objects.filter(user=self.user, title='Created from API').exists()) + + def test_mark_all_messages_as_read(self): + response = self.client.put(reverse('user_messages-mark-all-read')) + + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + self.assertFalse(Message.objects.filter(user=self.user, is_read=False).exists()) + + def test_get_message_detail_marks_message_as_read(self): + response = self.client.get(reverse('user_messages-detail', args=[self.message1.id])) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.message1.refresh_from_db() + self.assertTrue(self.message1.is_read) + + def test_cannot_get_other_users_message(self): + response = self.client.get(reverse('user_messages-detail', args=[self.other_message.id])) + + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_filter_messages_by_is_read_false(self): + # message1 defaults to is_read=False; mark message2 as read + self.message2.is_read = True + self.message2.save() + response = self.client.get(reverse('user_messages-list'), {'is_read': 'false'}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data['results'][0]['id'], self.message1.id) + self.assertFalse(response.data['results'][0]['is_read']) + + def test_filter_messages_by_is_read_true(self): + # mark message1 as read while message2 remains unread + self.message1.is_read = True + self.message1.save() + response = self.client.get(reverse('user_messages-list'), {'is_read': 'true'}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data['results'][0]['id'], self.message1.id) + self.assertTrue(response.data['results'][0]['is_read']) + + def test_filter_messages_by_category_and_is_read(self): + # message1: category=system is_read=False;message2: category=security is_read=True + self.message2.is_read = True + self.message2.save() + response = self.client.get( + reverse('user_messages-list'), + {'category': 'system', 'is_read': 'false'} + ) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data['results'][0]['category'], 'system') + self.assertFalse(response.data['results'][0]['is_read']) + + def test_filter_messages_without_is_read_returns_all(self): + # returns all messages when is_read is not provided + self.message1.is_read = True + self.message1.save() + response = self.client.get(reverse('user_messages-list')) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['count'], 2) + + def test_search_by_title(self): + response = self.client.get(reverse('user_messages-list'), {'search': 'System'}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data['results'][0]['id'], self.message1.id) + + def test_search_by_content(self): + response = self.client.get(reverse('user_messages-list'), {'search': 'Security content'}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data['results'][0]['id'], self.message2.id) + + def test_search_case_insensitive(self): + response = self.client.get(reverse('user_messages-list'), {'search': 'SYSTEM MESSAGE'}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data['results'][0]['id'], self.message1.id) + + def test_search_no_match_returns_empty(self): + response = self.client.get(reverse('user_messages-list'), {'search': 'zzznomatch'}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['count'], 0) + + def test_search_with_category_applies_and(self): + # search matches title+content, but category filter should restrict results to system + response = self.client.get( + reverse('user_messages-list'), + {'search': 'content', 'category': 'system'} + ) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data['results'][0]['id'], self.message1.id) + + def test_search_empty_string_returns_all(self): + response = self.client.get(reverse('user_messages-list'), {'search': ''}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['count'], 2) + + +class TestUserMessagePreferenceView(APITestCase): + + def setUp(self): + self.user = User.objects.create_user( + username='preference-user', + email='preference@example.com', + password='testpass123' + ) + self.client.force_authenticate(user=self.user) + + def test_get_creates_preference_if_missing(self): + response = self.client.get(reverse('user_message_preferences')) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertTrue(MessagePreference.objects.filter(user=self.user).exists()) + + def test_put_updates_preference(self): + response = self.client.put(reverse('user_message_preferences'), { + 'email_alerts': False, + 'notify_alert': False, + }) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + preference = MessagePreference.objects.get(user=self.user) + self.assertFalse(preference.email_alerts) + self.assertFalse(preference.notify_alert) + + +class TestUserLoginIdentityLinking(TestCase): + + def setUp(self): + self.user = User.objects.create_user( + username='login-user', + email='login@example.com', + password='password123' + ) + + def test_login_links_pending_identity(self): + session = self.client.session + session['oauth_pending'] = { + 'provider': 'feishu', + 'uid': 'uid-100', + 'extra_data': {'email': 'login@example.com'}, + } + session.save() + + response = self.client.post(reverse('user_login') + '?identity_linking=1', { + 'username': 'login-user', + 'password': 'password123', + }) + + self.assertEqual(response.status_code, 302) + self.assertIn('status=linked', response.url) + self.assertTrue(UserSocialAuth.objects.filter( + user=self.user, provider='feishu', uid='uid-100' + ).exists()) + + def test_login_identity_linking_conflict_redirects(self): + other_user = User.objects.create_user( + username='other-login-user', + email='other-login@example.com', + password='password123' + ) + UserSocialAuth.objects.create( + user=other_user, + provider='feishu', + uid='uid-100', + extra_data={'email': 'other-login@example.com'} + ) + session = self.client.session + session['oauth_pending'] = { + 'provider': 'feishu', + 'uid': 'uid-100', + 'extra_data': {'email': 'login@example.com'}, + } + session.save() + + response = self.client.post(reverse('user_login') + '?identity_linking=1', { + 'username': 'login-user', + 'password': 'password123', + }) + + self.assertEqual(response.status_code, 302) + self.assertIn('status=conflict', response.url) + + @patch('api.views.web.settings.EMAIL_HOST', 'smtp.example.com') + @patch('api.views.web.settings.REGISTRATION_ENABLED', True) + def test_login_page_context_shows_identity_linking_error(self): + response = self.client.post(reverse('user_login') + '?identity_linking=1', { + 'username': 'login-user', + 'password': 'wrong-password', + }) + + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'Identity linking login failed. Please try again.') + + @patch('api.views.web.settings.EMAIL_HOST', '') + @patch('api.views.web.settings.REGISTRATION_ENABLED', False) + def test_login_page_context_flags_follow_settings(self): + response = self.client.get(reverse('user_login') + '?identity_linking=1') + + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'Identity Linking') + + +class TestOAuthCallbackTemplateView(TestCase): + + def test_get_without_pending_renders_error_state(self): + response = self.client.get(reverse('oauth_callback') + '?status=pending') + + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'OAuth flow error. Please try again.') + + @patch('api.views.api.OAuthCreateUserView._create_oauth_user') + def test_post_password_mismatch_renders_error(self, _mock_create): + session = self.client.session + session['oauth_pending'] = { + 'provider': 'feishu', + 'email': 'pending@example.com', + } + session.save() + + response = self.client.post(reverse('oauth_callback'), { + 'username': 'oauth-user', + 'password': 'password123', + 'confirm_password': 'different123', + }) + + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'Password confirmation does not match') + + @patch('api.views.api.OAuthCreateUserView._create_oauth_user') + def test_post_success_redirects_account_setting(self, mock_create): + session = self.client.session + session['oauth_pending'] = { + 'provider': 'feishu', + 'email': 'pending@example.com', + } + session.save() + + response = self.client.post(reverse('oauth_callback'), { + 'username': 'oauth-user', + 'password': 'password123', + 'confirm_password': 'password123', + }) + + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, '/account-setting') + mock_create.assert_called_once() + + +class TestUpdateAccountView(TestCase): + + def setUp(self): + self.user = User.objects.create_user( + username='update-user', + email='update@example.com', + password='password123' + ) + + def test_update_account_applies_cached_serializer_data(self): + from django.utils.http import urlsafe_base64_encode + from django.utils.encoding import force_bytes + from api.utils import token_generator + + cache.set(f'user:serializer:{self.user.pk}', {'first_name': 'Cached'}, 1800) + uid = urlsafe_base64_encode(force_bytes(self.user.pk)) + token = token_generator.make_token(self.user) + + response = self.client.get(reverse('user_update_account', args=[uid, token])) + + self.assertEqual(response.status_code, 200) + self.user.refresh_from_db() + self.assertEqual(self.user.first_name, 'Cached') + self.assertIsNone(cache.get(f'user:serializer:{self.user.pk}')) + + def test_update_account_invalid_token_renders_fail(self): + from django.utils.http import urlsafe_base64_encode + from django.utils.encoding import force_bytes + + uid = urlsafe_base64_encode(force_bytes(self.user.pk)) + response = self.client.get(reverse('user_update_account', args=[uid, 'invalid-token'])) + + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'update fail', status_code=200) + + def test_update_account_without_cached_data_renders_fail(self): + from django.utils.http import urlsafe_base64_encode + from django.utils.encoding import force_bytes + from api.utils import token_generator + + uid = urlsafe_base64_encode(force_bytes(self.user.pk)) + token = token_generator.make_token(self.user) + response = self.client.get(reverse('user_update_account', args=[uid, token])) + + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'update fail', status_code=200) + + +class TestPasswordResetViews(TestCase): + + def test_password_reset_form_page_loads(self): + response = self.client.get(reverse('user_password_reset')) + self.assertEqual(response.status_code, 200) + + def test_password_reset_done_page_loads(self): + response = self.client.get(reverse('user_password_reset_done')) + self.assertEqual(response.status_code, 200) + + def test_password_reset_complete_page_loads(self): + response = self.client.get(reverse('user_password_reset_complete')) + self.assertEqual(response.status_code, 200) + + def test_password_reset_confirm_invalid_token_page_loads(self): + response = self.client.get( + reverse('user_password_reset_confirm', args=['invalid', 'invalid-token']) + ) + self.assertEqual(response.status_code, 200) diff --git a/rootfs/api/urls.py b/rootfs/api/urls.py index ec8d05a..5d34651 100644 --- a/rootfs/api/urls.py +++ b/rootfs/api/urls.py @@ -1,50 +1,75 @@ -from django.conf.urls import include -from django.urls import re_path -from rest_framework.routers import DefaultRouter +from django.urls import re_path, include +from rest_framework.routers import SimpleRouter -from api import views -from api.views import RegistrationView, ActivateAccount, RegistrationDoneView, \ - ActivateAccountDoneView, ActivateAccountFailView, LoginDoneView +from api.views import web, api +from passport.views import AppSettingsViewSet -router = DefaultRouter(trailing_slash=False) + +class OptionalSlashRouter(SimpleRouter): + """Router that accepts both trailing-slash and no-trailing-slash URLs.""" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.trailing_slash = '/?' + + +router = OptionalSlashRouter() +router.register(r'user/messages', api.UserMessageViewSet, basename='user_messages') +router.register(r'messages', api.ServiceMessageViewSet, basename='service_messages') +router.register(r'user/identities', api.UserIdentityViewSet, basename='user_identities') urlpatterns = [ re_path(r'^', include(router.urls)), - re_path(r'^info/?$', - views.UserDetailView.as_view({'get': 'retrieve', 'put': 'update'})), - re_path(r'registration/?$', RegistrationView.as_view(), name='registration'), - re_path(r'activate/(?P.+)/(?P.+)/?$', - ActivateAccount.as_view(), name='user_activate_account'), - re_path(r'registration/done/?$', RegistrationDoneView.as_view(), + # Settings URL (moved from main urls.py) + re_path(r'^settings/?$', AppSettingsViewSet.as_view({'get': 'retrieve'})), + # User URLs (add user prefix) + re_path(r'^user/info/?$', + api.UserDetailView.as_view({'get': 'retrieve', 'put': 'update'})), + re_path(r'^user/update/(?P.+)/(?P.+)/?$', + web.UpdateAccount.as_view(), name='user_update_account'), + re_path(r'^user/registration/?$', web.RegistrationView.as_view(), name='registration'), + re_path(r'^user/activate/(?P.+)/(?P.+)/?$', + web.ActivateAccount.as_view(), name='user_activate_account'), + re_path(r'^user/registration/done/?$', web.RegistrationDoneView.as_view(), name='user_registration_done'), - re_path(r'activate/done/?$', ActivateAccountDoneView.as_view(), + re_path(r'^user/activate/done/?$', web.ActivateAccountDoneView.as_view(), name='user_activate_account_done'), - re_path(r'activate/fail/?$', ActivateAccountFailView.as_view(), + re_path(r'^user/activate/fail/?$', web.ActivateAccountFailView.as_view(), name='user_activate_account_done'), - re_path(r'password_reset/?$', views.UserPasswordResetView.as_view(), + re_path(r'^oauth/callback/?$', web.OAuthCallbackTemplateView.as_view(), + name='oauth_callback'), + re_path(r'^user/password_reset/?$', web.UserPasswordResetView.as_view(), name='user_password_reset'), - re_path(r'password_reset/done/?$', - views.UserPasswordResetDoneView.as_view(), + re_path(r'^user/password_reset/done/?$', + web.UserPasswordResetDoneView.as_view(), name='user_password_reset_done'), - re_path(r'reset///?$', - views.UserPasswordResetConfirmView.as_view(), + re_path(r'^user/reset/(?P.+)/(?P.+)/?$', + web.UserPasswordResetConfirmView.as_view(), name='user_password_reset_confirm'), - re_path(r'reset/done/?$', - views.UserPasswordResetCompleteView.as_view(), + re_path(r'^user/reset/done/?$', + web.UserPasswordResetCompleteView.as_view(), name='user_password_reset_complete'), - re_path(r'login/?$', views.UserLoginView.as_view(), name='user_login'), - re_path(r'login/done/?$', LoginDoneView.as_view(), name='login_done'), - re_path(r'logout/?$', views.UserLogoutView.as_view(), name='user_logout'), - - re_path(r'tokens/?$', - views.UserTokensTemplateView.as_view({'get': 'retrieve'}), + re_path(r'^user/login/?$', web.UserLoginView.as_view(), name='user_login'), + re_path(r'^user/login/done/?$', web.LoginDoneView.as_view(), name='login_done'), + re_path(r'^user/logout/?$', web.UserLogoutView.as_view(), name='user_logout'), + re_path(r'^user/tokens/?$', + api.UserTokensView.as_view({'get': 'list'}), name='user_tokens'), - re_path(r'tokens/(?P.+)/?$', - views.UserTokenDeleteView.as_view({'delete': 'destroy'}), + re_path(r'^user/tokens/(?P.+)/?$', + api.UserTokensView.as_view({'delete': 'destroy'}), name='user_grants'), - re_path(r'email/?$', views.UserEmailView.as_view({'get': 'retrieve'})), - re_path(r'password/?$', - views.UserAccountPasswordView.as_view({'put': 'update'}), + re_path(r'^user/email/?$', api.UserEmailView.as_view({'get': 'retrieve'})), + re_path(r'^user/password/?$', + api.UserAccountPasswordView.as_view(), name='user_account_update_password'), - + re_path(r'^user/identity-providers/?$', + api.IdentityProviderView.as_view(), name='user_identity_providers'), + re_path(r'^user/oauth/pending/?$', + api.OAuthPendingView.as_view(), name='user_oauth_pending'), + re_path(r'^user/oauth/create/?$', + api.OAuthCreateUserView.as_view(), name='user_oauth_create'), + re_path(r'^user/message-preferences/?$', + api.UserMessagePreferenceViewSet.as_view( + {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update'}), + name='user_message_preferences'), ] diff --git a/rootfs/api/utils.py b/rootfs/api/utils.py index 3542659..5eeefeb 100644 --- a/rootfs/api/utils.py +++ b/rootfs/api/utils.py @@ -1,13 +1,24 @@ """ Helper functions used by the Drycc Passport server. """ +import re import logging -import six import datetime +import requests +from django.conf import settings + +from urllib.parse import urlencode + +from django.utils.html import strip_tags +from django.utils.encoding import force_bytes +from django.template.loader import render_to_string +from django.utils.http import urlsafe_base64_encode from django.contrib.auth.tokens import PasswordResetTokenGenerator from django.shortcuts import render +from rest_framework.exceptions import ValidationError + logger = logging.getLogger(__name__) @@ -34,13 +45,10 @@ def __decorator(request, *args, **kwargs): class TokenGenerator(PasswordResetTokenGenerator): def _make_hash_value(self, user, timestamp): - return ( - six.text_type(user.pk) + six.text_type(timestamp) + - six.text_type(user.is_active) - ) + return f"{user.pk}{timestamp}{user.is_active}" -account_activation_token = TokenGenerator() +token_generator = TokenGenerator() def get_local_host(request): @@ -48,6 +56,135 @@ def get_local_host(request): return uri[0:uri.find(request.path)] +def get_user_socials(user): + from api.apps_extra.social_core import backends + provider_map = { + backend_cls.name: backend_cls + for backend_cls in backends.__all__ + } + results = [] + for social in user.social_auth.all(): + backend_cls = provider_map.get(social.provider) + email = None + if social.extra_data: + email = social.extra_data.get('email') or social.extra_data.get('user_email') + results.append({ + 'id': social.id, + 'provider': social.provider, + 'display_name': social.provider.title(), + 'uid': social.uid, + 'icon': backend_cls.icon if backend_cls else '', + 'email': email or user.email, + }) + return results + + +def get_oauth_callback(request, status, provider=None): + query = {'status': status} + domain = get_local_host(request) + if provider: + query['provider'] = provider + return f"{domain}{settings.SOCIAL_AUTH_LOGIN_CALLBACK_URL}?{urlencode(query)}" + + +def validate_reserved_names(value): + """A value cannot use some reserved names.""" + for reserved_name_pattern in settings.RESERVED_NAME_PATTERNS: + if re.match(reserved_name_pattern, value): + raise ValidationError('{} is a reserved name.'.format(value)) + + +def send_activation_email(request, user): + if not user.email: + logger.warning( + "Activation email skipped for user %s due to missing email address", + user.username + ) + return + if not getattr(settings, 'EMAIL_HOST', ''): + logger.warning( + "Activation email skipped for user %s due to missing SMTP configuration", + user.username + ) + return + domain = get_local_host(request) + mail_subject = 'Activate your account.' + message = render_to_string( + 'user/account_activation_email.html', { + 'user': user, + 'domain': domain, + 'uid': urlsafe_base64_encode(force_bytes(user.pk)), + 'token': token_generator.make_token(user), + }) + user.email_user(mail_subject, message, fail_silently=True) + + +def send_email_notification(message) -> None: + """Send an email notification for a message. + + Silently skips when SMTP / DEFAULT_FROM_EMAIL is not configured, or + when the target user has no email address. This avoids triggering + endless Celery retries in environments without a configured mail + server (e.g. local development). + """ + if message.user.email is None: + logger.info( + "Email notification skipped for message %s due to missing user email", + message.id + ) + return + if not getattr(settings, 'EMAIL_HOST', ''): + logger.info( + "Email notification skipped for message %s due to missing SMTP configuration", + message.id + ) + return + mail_subject = f"[{message.get_category_display()}] {message.title}" + html_message = render_to_string( + 'notifications/email_message.html', + { + 'message': message, + 'user': message.user, + 'domain': getattr(settings, 'DASHBOARD_URL', '/'), + } + ) + plain_message = strip_tags(html_message) + message.user.email_user( + subject=mail_subject, + message=plain_message, + html_message=html_message, + fail_silently=False, + ) + logger.info("Email notification sent to %s for message %s", message.user.email, message.id) + + +def send_webhook_notification(message, webhook_url) -> None: + """Send a webhook notification for a message.""" + if not webhook_url: + return + payload = { + 'id': str(message.id), + 'category': message.category, + 'title': message.title, + 'content': message.content, + 'severity': message.severity, + 'created_at': message.created_at.isoformat() if message.created_at else None, + 'user': { + 'id': message.user.id, + 'username': message.user.username, + 'email': message.user.email, + }, + } + response = requests.post( + webhook_url, + json=payload, + headers={'Content-Type': 'application/json'}, + timeout=10, + ) + response.raise_for_status() + logger.info("Webhook notification sent for message %s to %s", message.id, webhook_url) + + if __name__ == "__main__": import doctest diff --git a/rootfs/api/validators.py b/rootfs/api/validators.py new file mode 100644 index 0000000..b05be8a --- /dev/null +++ b/rootfs/api/validators.py @@ -0,0 +1,19 @@ + +from django.contrib.auth.validators import UnicodeUsernameValidator +from django.utils.translation import gettext_lazy as _ +from django.conf import settings +from django.utils.deconstruct import deconstructible + +from api.utils import validate_reserved_names + + +@deconstructible +class UsernameValidator(UnicodeUsernameValidator): + regex = settings.USERNAME_REGEX + message = _( + f"Enter a valid username. This value may match the regex {regex}." + ) + + def __call__(self, value): + super().__call__(value) + validate_reserved_names(value) diff --git a/rootfs/api/views.py b/rootfs/api/views.py deleted file mode 100644 index 0a63a08..0000000 --- a/rootfs/api/views.py +++ /dev/null @@ -1,251 +0,0 @@ -import logging - -from django.conf import settings -from django.contrib import messages, auth -from django.contrib.auth import login -from django.contrib.auth.models import User -from django.contrib.auth import views -from django.db.models import Q -from django.shortcuts import redirect, get_object_or_404, render -from django.template.loader import render_to_string -from django.http import HttpResponse -from django.utils.encoding import force_bytes, force_text -from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode -from django.views.generic import View -from django.views.generic.edit import CreateView -from django.utils.translation import gettext_lazy as _ -from django.views.generic.base import TemplateView -from django.urls import reverse_lazy -from rest_framework import status -from rest_framework.exceptions import AuthenticationFailed -from rest_framework.response import Response -from rest_framework.viewsets import ModelViewSet - -from api import serializers -from api.exceptions import ServiceUnavailable, DryccException -from api.serializers import RegistrationForm -from api.utils import account_activation_token, get_local_host -from api.viewset import NormalUserViewSet - -logger = logging.getLogger(__name__) - - -class ReadinessCheckView(View): - """ - Simple readiness check view to determine DB connection / query. - """ - - def get(self, request): - try: - import django.db - with django.db.connection.cursor() as c: - c.execute("SELECT 0") - except django.db.Error as e: - raise ServiceUnavailable("Database health check failed") from e - - return HttpResponse("OK") - - head = get - - -class LivenessCheckView(View): - """ - Simple liveness check view to determine if the server - is responding to HTTP requests. - """ - - def get(self, request): - return HttpResponse("OK") - - head = get - - -class RegistrationView(CreateView): - form_class = RegistrationForm - template_name = 'user/registration.html' - success_url = reverse_lazy('registration_done') - - def get(self, request, *args, **kwargs): - if settings.LDAP_ENDPOINT or not settings.REGISTRATION_ENABLED: - return render(request, template_name='user/registration_disable.html') - return CreateView.get(self, request, *args, **kwargs) - - def post(self, request, *args, **kwargs): - if settings.LDAP_ENDPOINT or not settings.REGISTRATION_ENABLED: - return render(request, template_name='user/registration_disable.html') - form = self.form_class(request.POST) - self.object = None - if form.is_valid(): - user = form.save(commit=False) - user.is_staff = False - user.is_active = False - user.save() - domain = get_local_host(request) - mail_subject = 'Activate your account.' - message = render_to_string( - 'user/account_activation_email.html', { - 'user': user, - 'domain': domain, - 'uid': urlsafe_base64_encode(force_bytes(user.pk)), - 'token': account_activation_token.make_token(user), - }) - user.email_user(mail_subject, message) - messages.success(request, ( - 'Please Confirm your email to complete registration.')) - return self.form_valid(form) - else: - return self.form_invalid(form) - - -class RegistrationDoneView(TemplateView): - template_name = 'user/registration_done.html' - title = _('Activate email sent') - - -class ActivateAccount(View): - - def get(self, request, uidb64, token, *args, **kwargs): - try: - uid = force_text(urlsafe_base64_decode(uidb64)) - user = User.objects.get(pk=uid) - except (TypeError, ValueError, OverflowError, User.DoesNotExist): - user = None - if user is not None and account_activation_token.check_token( - user, token): - user.is_active = True - user.is_staff = True - user.save() - login(request, user, - backend='django.contrib.auth.backends.ModelBackend') - messages.success(request, 'Your account have been confirmed.') - return redirect('/user/activate/done/') - else: - messages.warning(request, ( - 'The confirmation link was invalid, possibly because it has already been used.')) # noqa - return redirect('/user/activate/fail/') - - -class ActivateAccountDoneView(TemplateView): - template_name = 'user/account_activation_done.html' - title = _('Activate account done') - - -class ActivateAccountFailView(TemplateView): - template_name = 'user/account_activation_fail.html' - title = _('Activate account fail') - - -class UserLoginView(views.LoginView): - template_name = 'user/login.html' - - -class UserDetailView(NormalUserViewSet): - serializer_class = serializers.UserSerializer - required_scopes = ['openid'] - - def get_object(self): - return self.request.user - - def update(self, request, *args, **kwargs): - user = serializers.UserSerializer(data=request.data, - instance=request.user, - partial=True) - if user.is_valid(): - user.save() - return Response(status=status.HTTP_204_NO_CONTENT) - - -class UserEmailView(NormalUserViewSet): - serializer_class = serializers.UserEmailSerializer - required_scopes = ['openid'] - - def get_object(self): - return self.request.user - - -class LoginDoneView(TemplateView): - template_name = 'user/login_done.html' - - -class UserPasswordResetView(views.PasswordResetView): - email_template_name = 'user/password_reset_email.html' - success_url = reverse_lazy('user_password_reset_done') - template_name = 'user/password_reset_form.html' - - -class UserPasswordResetDoneView(views.PasswordResetDoneView): - template_name = 'user/password_reset_done.html' - - -class UserPasswordResetConfirmView(views.PasswordResetConfirmView): - success_url = reverse_lazy('user_password_reset_complete') - template_name = 'user/password_reset_confirm.html' - - -class UserPasswordResetCompleteView(views.PasswordResetCompleteView): - template_name = 'user/password_reset_complete.html' - - -class UserLogoutView(views.LogoutView): - template_name = 'user/logout.html' - - -class ListViewSet(ModelViewSet): - - def get_queryset(self, *args, **kwargs): - serializer = self.serializer_class(data=self.request.query_params) - serializer.is_valid(raise_exception=True) - - serializerlist = serializers.ListSerializer( - data=self.request.query_params) - serializerlist.is_valid(raise_exception=True) - q = Q(user=self.request.user) - if serializerlist.validated_data.get('section'): - q &= Q(created__range=serializerlist.validated_data.get('section')) - return self.model.objects.filter( - q, **serializer.validated_data).order_by(self.order_by)[0:100] - - -class UserTokensTemplateView(ListViewSet): - from oauth2_provider.models import AccessToken - model = AccessToken - serializer_class = serializers.UserTokensSerializer - order_by = '-created' - - def retrieve(self, request, *args, **kwargs): - tokens = self.get_queryset(*args, **kwargs) - serializer = self.get_serializer(tokens, many=True) - return Response(serializer.data) - - -class UserTokenDeleteView(ListViewSet): - from oauth2_provider.models import AccessToken - model = AccessToken - - def destroy(self, request, *args, **kwargs): - token = get_object_or_404(self.model, - id=self.kwargs['pk'], - user=request.user) - - token.delete() - return Response(status=status.HTTP_204_NO_CONTENT) - - -class UserAccountPasswordView(ListViewSet): - - def update(self, request, *args, **kwargs): - if settings.LDAP_ENDPOINT: - raise DryccException( - "You cannot change user info when ldap is enabled.") - if not request.data.get('new_password'): - raise DryccException("new_password is a required field") - if not request.data.get('password'): - raise DryccException("password is a required field") - if len(request.data.get('new_password')) < 8: - raise DryccException("password must be 8 or more characters. ") - if not request.user.check_password(request.data['password']): - raise AuthenticationFailed('Current password does not match') - request.user.set_password(request.data['new_password']) - request.user.save() - auth.logout(request) - return HttpResponse(status=204) diff --git a/rootfs/api/views/__init__.py b/rootfs/api/views/__init__.py new file mode 100644 index 0000000..5d77f0a --- /dev/null +++ b/rootfs/api/views/__init__.py @@ -0,0 +1,2 @@ +from .api import * # noqa +from .web import * # noqa diff --git a/rootfs/api/views/api.py b/rootfs/api/views/api.py new file mode 100644 index 0000000..477e397 --- /dev/null +++ b/rootfs/api/views/api.py @@ -0,0 +1,326 @@ +from django.conf import settings +from django.core.cache import cache +from django.contrib import auth +from django.contrib.auth import get_user_model +from django.db import IntegrityError, connection, Error +from django.db.models import Q +from django.shortcuts import get_object_or_404 +from django.template.loader import render_to_string +from django.http import HttpResponse +from django.utils.encoding import force_bytes +from django.utils.http import urlsafe_base64_encode +from django.urls import reverse_lazy +from django.views.generic import View + +from rest_framework import status, viewsets +from rest_framework.exceptions import AuthenticationFailed, ValidationError +from rest_framework.permissions import AllowAny, IsAuthenticated +from rest_framework.response import Response +from rest_framework.views import APIView +from rest_framework.viewsets import GenericViewSet +from rest_framework.decorators import action +from rest_framework.mixins import ListModelMixin, DestroyModelMixin + +from oauth2_provider.models import AccessToken +from social_django.models import UserSocialAuth + +from api.permissions import HasOAuthScope + +from api import serializers +from api.exceptions import ServiceUnavailable, DryccException +from api.models import Message, MessagePreference +from api.utils import get_local_host, get_user_socials, token_generator + + +User = get_user_model() + + +class NormalUserViewSet(viewsets.ModelViewSet): + permission_classes = [IsAuthenticated] + + +class ReadinessCheckView(View): + """Simple readiness check view to determine DB connection and Migrations.""" + migrations_completed = False + + def get(self, request): + try: + with connection.cursor() as c: + c.execute("SELECT 0") + if not ReadinessCheckView.migrations_completed: + from django.db.migrations.executor import MigrationExecutor + executor = MigrationExecutor(connection) + targets = executor.loader.graph.leaf_nodes() + if executor.migration_plan(targets): + raise ServiceUnavailable("Migrations are not yet applied") + ReadinessCheckView.migrations_completed = True + except Error as e: + raise ServiceUnavailable(f"Database health check failed: {e}") from e + return HttpResponse("OK") + head = get + + +class LivenessCheckView(View): + """Simple liveness check view to determine if the server is alive.""" + + def get(self, request): + return HttpResponse("OK") + + head = get + + +class IdentityProviderView(APIView): + permission_classes = (AllowAny, ) + + def get(self, request, *args, **kwargs): + from api.apps_extra.social_core import backends + + results = [] + for backend_cls in backends.__all__: + key_setting = f'SOCIAL_AUTH_{backend_cls.name.upper()}_KEY' + secret_setting = f'SOCIAL_AUTH_{backend_cls.name.upper()}_SECRET' + if getattr(settings, key_setting, None) and getattr(settings, secret_setting, None): + results.append({ + 'name': backend_cls.name, + 'icon': backend_cls.icon, + 'login_url': reverse_lazy('social:begin', args=(backend_cls.name,)), + }) + + return Response({'count': len(results), 'results': results}) + + +class UserIdentityViewSet(NormalUserViewSet): + serializer_class = serializers.UserEmailSerializer + http_method_names = ['get', 'delete'] + + def get_queryset(self): + return UserSocialAuth.objects.filter(user=self.request.user).order_by('id') + + def list(self, request, *args, **kwargs): + results = get_user_socials(request.user) + return Response({'count': len(results), 'results': results}) + + def destroy(self, request, *args, **kwargs): + identity = self.get_object() + identity.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + + +class OAuthPendingView(APIView): + permission_classes = (AllowAny, ) + + def get(self, request, *args, **kwargs): + pending = request.session.get('oauth_pending') + if not pending: + return Response( + {'detail': 'No pending OAuth request'}, status=status.HTTP_404_NOT_FOUND + ) + + from api.apps_extra.social_core import backends + + backend_map = {backend_cls.name: backend_cls for backend_cls in backends.__all__} + backend_cls = backend_map.get(pending.get('provider')) + return Response({ + 'provider': pending.get('provider'), + 'email': pending.get('email'), + 'icon': backend_cls.icon if backend_cls else '', + 'display_name': pending.get('provider', '').title(), + }) + + +class UserMessageViewSet(NormalUserViewSet): + http_method_names = ['get', 'put', 'delete', 'head', 'options'] + serializer_class = serializers.MessageSerializer + + def get_queryset(self): + queryset = Message.objects.filter(user=self.request.user) + category = self.request.query_params.get('category') + if category and category != 'all': + queryset = queryset.filter(category=category) + is_read = self.request.query_params.get('is_read') + if is_read is not None: + queryset = queryset.filter(is_read=is_read.lower() not in ('false', '0', 'no')) + search = self.request.query_params.get('search') + if search: + queryset = queryset.filter( + Q(title__icontains=search) | Q(content__icontains=search) + ) + return queryset.order_by('-created_at') + + def retrieve(self, request, *args, **kwargs): + message = self.get_object() + if not message.is_read: + message.is_read = True + message.save(update_fields=['is_read']) + serializer = self.get_serializer(message) + return Response(serializer.data) + + @action(detail=False, methods=['put'], url_path='mark-all-read') + def mark_all_read(self, request, *args, **kwargs): + self.get_queryset().filter(is_read=False).update(is_read=True) + return Response(status=status.HTTP_204_NO_CONTENT) + + +class OAuthCreateUserView(APIView): + permission_classes = (AllowAny, ) + + def _create_oauth_user(self, request, username, password): + pending = request.session.get('oauth_pending') + if not pending: + raise ValidationError('No pending OAuth request') + + if not username: + raise ValidationError('username is a required field') + if not password: + raise ValidationError('password is a required field') + if len(password) < 8: + raise ValidationError('password must be 8 or more characters') + + email = pending.get('email') + if not email: + raise ValidationError('email is missing from oauth provider') + if User.objects.filter(email=email).exists(): + raise ValidationError('email is already registered') + + provider = pending.get('provider') + uid = pending.get('uid') + extra_data = pending.get('extra_data') or {} + + if not provider or not uid: + request.session.pop('oauth_pending', None) + raise ValidationError('invalid oauth pending data') + + existing = UserSocialAuth.objects.filter(provider=provider, uid=uid).first() + if existing: + request.session.pop('oauth_pending', None) + raise ValidationError('identity is already linked to another account') + + try: + user = User.objects.create_user(username=username, email=email, password=password) + except IntegrityError: + raise ValidationError('username is already taken') + + UserSocialAuth.objects.create( + user=user, + provider=provider, + uid=uid, + extra_data=extra_data, + ) + + auth.login(request, user, backend='django.contrib.auth.backends.ModelBackend') + request.session.pop('oauth_pending', None) + return user + + def post(self, request, *args, **kwargs): + username = request.data.get('username') + password = request.data.get('password') + self._create_oauth_user(request, username, password) + return Response({'status': 'created'}, status=status.HTTP_201_CREATED) + + +class UserDetailView(NormalUserViewSet): + serializer_class = serializers.UserSerializer + required_scopes = ['openid'] + email_template_name = 'user/account_update_email.html' + + def get_object(self): + return self.request.user + + def update(self, request, *args, **kwargs): + user_serializer = self.serializer_class( + data=request.data, + instance=request.user, + partial=True, + ) + user_serializer.is_valid(raise_exception=True) + if getattr(settings, 'EMAIL_HOST', ''): + user = self.get_object() + mail_subject = 'Update your account.' + uid = urlsafe_base64_encode(force_bytes(user.pk)) + token = token_generator.make_token(user) + message = render_to_string( + self.email_template_name, + { + 'uid': uid, + 'user': user, + 'token': token, + 'domain': get_local_host(request), + }, + ) + cache_key = "user:serializer:%s" % user.pk + cache.set(cache_key, request.data, 60 * 30) + user.email_user(mail_subject, message, fail_silently=True) + else: + user_serializer.save() + return Response(status=status.HTTP_204_NO_CONTENT) + + +class UserEmailView(NormalUserViewSet): + serializer_class = serializers.UserEmailSerializer + required_scopes = ['openid'] + + def get_object(self): + return self.request.user + + +class UserTokensView(ListModelMixin, DestroyModelMixin, GenericViewSet): + serializer_class = serializers.UserTokensSerializer + permission_classes = [IsAuthenticated] + + def get_queryset(self): + return AccessToken.objects.filter(user=self.request.user).order_by('-created') + + def get_object(self): + return get_object_or_404(self.get_queryset(), id=self.kwargs['pk']) + + +class UserAccountPasswordView(APIView): + permission_classes = [IsAuthenticated] + + def update(self, request, *args, **kwargs): + if settings.LDAP_ENDPOINT: + raise DryccException("You cannot change user info when ldap is enabled.") + if not request.data.get('new_password'): + raise DryccException("new_password is a required field") + if not request.data.get('password'): + raise DryccException("password is a required field") + if len(request.data.get('new_password')) < 8: + raise DryccException("password must be 8 or more characters. ") + if not request.user.check_password(request.data['password']): + raise AuthenticationFailed('Current password does not match') + request.user.set_password(request.data['new_password']) + request.user.save() + auth.logout(request) + return HttpResponse(status=204) + + def put(self, request, *args, **kwargs): + return self.update(request, *args, **kwargs) + + +class UserMessagePreferenceViewSet(NormalUserViewSet): + serializer_class = serializers.MessagePreferenceSerializer + http_method_names = ['get', 'put', 'patch'] + + def get_object(self): + preference, _ = MessagePreference.objects.get_or_create(user=self.request.user) + return preference + + def retrieve(self, request, *args, **kwargs): + serializer = self.get_serializer(self.get_object()) + return Response(serializer.data) + + def update(self, request, *args, **kwargs): + partial = kwargs.pop('partial', False) + serializer = self.get_serializer(self.get_object(), data=request.data, partial=partial) + serializer.is_valid(raise_exception=True) + serializer.save() + return Response(serializer.data) + + +class ServiceMessageViewSet(viewsets.ModelViewSet): + serializer_class = serializers.ServiceMessageSerializer + permission_classes = [HasOAuthScope] + required_oauth_scopes = ['passport:message'] + + def get_queryset(self): + return Message.objects.all().order_by('-created_at') diff --git a/rootfs/api/views/web.py b/rootfs/api/views/web.py new file mode 100644 index 0000000..b3104f8 --- /dev/null +++ b/rootfs/api/views/web.py @@ -0,0 +1,259 @@ +from django.conf import settings +from django.contrib import messages +from django.contrib.auth import get_user_model, login, views +from django.shortcuts import get_object_or_404, redirect, render +from django.utils.encoding import force_str +from django.utils.http import urlsafe_base64_decode +from django.views.generic import View +from django.views.generic.base import TemplateView +from django.views.generic.edit import CreateView +from django.urls import reverse_lazy +from django.utils.translation import gettext_lazy as _ + +from rest_framework.exceptions import ValidationError +from social_django.models import UserSocialAuth + +from api import serializers +from api.forms import AuthenticationForm, RegistrationForm +from api.utils import get_oauth_callback, send_activation_email, token_generator + + +User = get_user_model() + + +class RegistrationView(CreateView): + form_class = RegistrationForm + template_name = 'user/registration.html' + success_url = reverse_lazy('user_registration_done') + + def get(self, request, *args, **kwargs): + if settings.LDAP_ENDPOINT or not settings.REGISTRATION_ENABLED: + return render(request, template_name='user/registration_disable.html') + return super().get(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + if settings.LDAP_ENDPOINT or not settings.REGISTRATION_ENABLED: + return render(request, template_name='user/registration_disable.html') + form = self.form_class(request.POST) + self.object = None + if form.is_valid(): + user = form.save(commit=False) + if getattr(settings, 'EMAIL_HOST', ''): + user.is_active = False + user.save() + send_activation_email(request, user) + messages.success(request, 'Please Confirm your email to complete registration.') + else: + user.is_active = True + user.save() + return self.form_valid(form) + return self.form_invalid(form) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["h_captcha_key"] = settings.H_CAPTCHA_KEY + return context + + +class RegistrationDoneView(TemplateView): + template_name = 'user/registration_done.html' + title = _('Activate email sent') + + +class ActivateAccount(View): + + def get(self, request, uidb64, token, *args, **kwargs): + try: + uid = force_str(urlsafe_base64_decode(uidb64)) + user = User.objects.get(pk=uid) + except (TypeError, ValueError, OverflowError, User.DoesNotExist): + user = None + if user is not None and token_generator.check_token(user, token): + user.is_active = True + user.save() + login(request, user, backend='django.contrib.auth.backends.ModelBackend') + messages.success(request, 'Your account have been confirmed.') + return redirect('/user/activate/done/') + + messages.warning( + request, + 'The confirmation link was invalid, possibly because it has already been used.', + ) + return redirect('/user/activate/fail/') + + +class ActivateAccountDoneView(TemplateView): + template_name = 'user/account_activation_done.html' + title = _('Activate account done') + + +class ActivateAccountFailView(TemplateView): + template_name = 'user/account_activation_fail.html' + title = _('Activate account fail') + + +class UserLoginView(views.LoginView): + form_class = AuthenticationForm + template_name = 'user/login.html' + + def _get_identity_linking(self): + identity_linking = self.request.POST.get('identity_linking') + if identity_linking is None: + identity_linking = self.request.GET.get('identity_linking') + return identity_linking == '1' + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + identity_linking = self._get_identity_linking() + form = kwargs.get('form') + context.update({ + 'identity_linking': identity_linking, + 'registration_enabled': settings.REGISTRATION_ENABLED, + 'password_reset_enabled': True if getattr(settings, 'EMAIL_HOST', '') else False, + 'identity_linking_error': ( + _('Identity linking login failed. Please try again.') + if identity_linking and form is not None and form.errors else None + ), + }) + return context + + def form_valid(self, form): + response = super().form_valid(form) + pending = self.request.session.get('oauth_pending') + if not pending: + return response + + provider = pending.get('provider') + uid = pending.get('uid') + extra_data = pending.get('extra_data') or {} + if not provider or not uid: + self.request.session.pop('oauth_pending', None) + raise ValidationError('invalid oauth pending data') + + existing = UserSocialAuth.objects.filter( + provider=provider, + uid=uid, + ).select_related('user').first() + if existing and existing.user_id != self.request.user.id: + self.request.session.pop('oauth_pending', None) + return redirect(get_oauth_callback(self.request, 'conflict', provider)) + + if not existing: + UserSocialAuth.objects.create( + user=self.request.user, + provider=provider, + uid=uid, + extra_data=extra_data, + ) + + self.request.session.pop('oauth_pending', None) + return redirect(get_oauth_callback(self.request, 'linked', provider)) + + +class OAuthCallbackTemplateView(TemplateView): + template_name = 'user/oauth_callback.html' + + def _build_context(self, request, status_value=None, error=None): + pending = request.session.get('oauth_pending') + provider = request.GET.get('provider') + email = None + display_name = None + + if pending: + provider = pending.get('provider') or provider + email = pending.get('email') + + if provider: + display_name = provider.title() + + status_value = status_value or request.GET.get('status') or 'error' + if status_value == 'pending' and not pending: + status_value = 'error' + error = error or 'No pending OAuth request' + + return { + 'status': status_value, + 'provider': provider, + 'display_name': display_name, + 'email': email, + 'error': error, + } + + def get(self, request, *args, **kwargs): + context = self._build_context(request) + return render(request, self.template_name, context) + + def post(self, request, *args, **kwargs): + username = request.POST.get('username') + password = request.POST.get('password') + confirm_password = request.POST.get('confirm_password') + + if password != confirm_password: + context = self._build_context( + request, + status_value='pending', + error='Password confirmation does not match', + ) + return render(request, self.template_name, context) + + from api.views.api import OAuthCreateUserView + + try: + OAuthCreateUserView()._create_oauth_user(request, username, password) + except ValidationError as exc: + error_text = exc.detail + if isinstance(error_text, (list, tuple)): + error_text = error_text[0] + context = self._build_context(request, status_value='pending', error=error_text) + return render(request, self.template_name, context) + + return redirect('/account-setting') + + +class UpdateAccount(View): + fail_template_name = 'user/account_update_fail.html' + success_template_name = 'user/account_update_done.html' + + def get(self, request, uidb64, token, *args, **kwargs): + user = get_object_or_404(User, pk=force_str(urlsafe_base64_decode(uidb64))) + if user is not None and token_generator.check_token(user, token): + cache_key = "user:serializer:%s" % user.pk + from django.core.cache import cache + data = cache.get(cache_key, None) + if data: + user_serializer = serializers.UserSerializer( + data=data, instance=user, partial=True + ) + if user_serializer.is_valid(): + user_serializer.save() + login(request, user, backend='django.contrib.auth.backends.ModelBackend') + cache.delete(cache_key) + return render(request, template_name=self.success_template_name) + return render(request, template_name=self.fail_template_name) + + +class LoginDoneView(TemplateView): + template_name = 'user/login_done.html' + + +class UserPasswordResetView(views.PasswordResetView): + email_template_name = 'user/password_reset_email.html' + success_url = reverse_lazy('user_password_reset_done') + template_name = 'user/password_reset_form.html' + + +class UserPasswordResetDoneView(views.PasswordResetDoneView): + template_name = 'user/password_reset_done.html' + + +class UserPasswordResetConfirmView(views.PasswordResetConfirmView): + success_url = reverse_lazy('user_password_reset_complete') + template_name = 'user/password_reset_confirm.html' + + +class UserPasswordResetCompleteView(views.PasswordResetCompleteView): + template_name = 'user/password_reset_complete.html' + + +class UserLogoutView(views.LogoutView): + template_name = 'user/logout.html' diff --git a/rootfs/api/viewset.py b/rootfs/api/viewset.py deleted file mode 100644 index 9ccba36..0000000 --- a/rootfs/api/viewset.py +++ /dev/null @@ -1,12 +0,0 @@ -from rest_framework import viewsets -from rest_framework.permissions import IsAuthenticated - - -class NormalUserViewSet(viewsets.ModelViewSet): - """ - A simple ViewSet for objects filtered by their 'owner' attribute. - - To use it, at minimum you'll need to provide the `serializer_class` attribute and - the `model` attribute shortcut. - """ - permission_classes = [IsAuthenticated] diff --git a/rootfs/api/wsgi.py b/rootfs/api/wsgi.py index c0b656a..eb05278 100644 --- a/rootfs/api/wsgi.py +++ b/rootfs/api/wsgi.py @@ -1,10 +1,10 @@ """ -WSGI config for mysite project. +WSGI config for passport project. It exposes the WSGI callable as a module-level variable named ``application``. For more information on this file, see -https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/ +https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/ """ import os diff --git a/rootfs/bin/boot b/rootfs/bin/boot index 4a54261..d6967f0 100755 --- a/rootfs/bin/boot +++ b/rootfs/bin/boot @@ -5,7 +5,6 @@ # fail hard and fast even on pipelines set -eo pipefail - # set debug based on envvar [[ $DRYCC_DEBUG == "true" ]] && set -x @@ -13,38 +12,24 @@ echo system information: echo "Django Version: $(./manage.py --version)" python --version -mkdir -p /app/data/logs -chmod -R 777 /app/data/logs +mkdir -p /workspace/data/logs +chmod -R 777 /workspace/data/logs echo "Django checks:" -python /app/manage.py check --deploy api +python /workspace/manage.py check --deploy api echo "" echo "Health Checks:" -python /app/manage.py healthchecks - -echo "" -echo "Database Migrations:" -python /app/manage.py migrate --noinput +python /workspace/manage.py healthchecks echo "" echo "Collect static files in a single location:" python manage.py collectstatic --noinput -echo "" -if [ "${ADMIN_USERNAME}" ] && [ "${ADMIN_PASSWORD}" ] && [ "${ADMIN_EMAIL}" ]; then - echo "Create administrator" - python /app/manage.py createadminuser --username "${ADMIN_USERNAME}" --password "${ADMIN_PASSWORD}" --noinput --email "${ADMIN_EMAIL}" -fi - -echo "" -echo "Create application for drycc controller " -python /app/manage.py create_oauth2_application - # spawn a gunicorn server in the background echo "" echo "Starting up Gunicorn" -gunicorn -c /app/passport/gunicorn/config.py api.wsgi & +gunicorn -c /workspace/passport/gunicorn/config.py api.asgi & # smart shutdown on SIGTERM (SIGINT is handled by gunicorn) function on_exit() { diff --git a/rootfs/bin/test-unit b/rootfs/bin/test-unit index 8ab0a9d..de37e50 100755 --- a/rootfs/bin/test-unit +++ b/rootfs/bin/test-unit @@ -6,13 +6,19 @@ # fail hard and fast even on pipelines set -eou pipefail +function start_valkey() { + cd /tmp + nohup valkey-server > /var/log/valkey.log 2>&1 & + cd - +} + function creating_rsa_key() { mkdir -p /var/run/secrets/drycc/passport/ \ && openssl genrsa -out /var/run/secrets/drycc/passport/oidc-rsa-private-key 4096 } -su-exec postgres pg_ctl -D "$PGDATA" start +gosu postgres pg_ctl -D "$PGDATA" start && ln -s /tmp/.s.PGSQL.5432 /var/run/postgresql/.s.PGSQL.5432 +start_valkey creating_rsa_key python3 manage.py check coverage run manage.py test --settings=api.settings.testing --noinput api -coverage report -m diff --git a/rootfs/bin/upload-coverage b/rootfs/bin/upload-coverage new file mode 100755 index 0000000..492452b --- /dev/null +++ b/rootfs/bin/upload-coverage @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# +# This script is designed to be run inside the container +# + +# fail hard and fast even on pipelines +set -eou pipefail + +coverage report -m > coverage.txt + +if [[ -n $CODECOV_TOKEN ]]; then + codecov upload-process --plugin=noop -t "$CODECOV_TOKEN" +fi diff --git a/rootfs/dev_requirements.txt b/rootfs/dev_requirements.txt index 84bd797..ef0abcb 100644 --- a/rootfs/dev_requirements.txt +++ b/rootfs/dev_requirements.txt @@ -1,16 +1,10 @@ # test module # test # Run "make test-unit" for the % of code exercised during tests -coverage==5.3 +coverage==7.10.6 # Run "make test-style" to check python syntax and style -flake8==3.8.3 - -# code coverage report at https://codecov.io/github/drycc/passport -codecov==2.1.9 +flake8==7.3.0 # mock out python-requests, mostly k8s -requests-mock==1.8.0 - -# tail a log and pipe into tbgrep to find all tracebacks -tbgrep==0.3.0 +requests-mock==1.12.1 diff --git a/rootfs/passport/gunicorn/config.py b/rootfs/passport/gunicorn/config.py index 96c8933..58acdbe 100644 --- a/rootfs/passport/gunicorn/config.py +++ b/rootfs/passport/gunicorn/config.py @@ -5,7 +5,8 @@ faulthandler.enable() bind = '0.0.0.0' -workers = int(os.environ.get('GUNICORN_WORKERS', 4)) +workers = int(os.environ.get('GUNICORN_WORKERS', 2)) +worker_class = "uvicorn.workers.UvicornWorker" pythonpath = dirname(dirname(dirname(realpath(__file__)))) timeout = 1200 diff --git a/rootfs/passport/urls.py b/rootfs/passport/urls.py index 8dfa5e2..a3a0dbf 100644 --- a/rootfs/passport/urls.py +++ b/rootfs/passport/urls.py @@ -13,9 +13,8 @@ 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ -from django.urls import path +from django.urls import path, re_path, include from django.conf import settings -from django.conf.urls import include, url, re_path from django.contrib import admin from django.views.generic.base import TemplateView from api.views import LivenessCheckView, ReadinessCheckView @@ -26,10 +25,11 @@ urlpatterns = [] urlpatterns += [ - url(r'^healthz$', LivenessCheckView.as_view()), - url(r'^readiness$', ReadinessCheckView.as_view()), - re_path(r"^user/", include('api.urls')), + re_path(r'^healthz$', LivenessCheckView.as_view()), + re_path(r'^readiness$', ReadinessCheckView.as_view()), + re_path(r"^", include('api.urls')), re_path(r'^oauth/', include('oauth2_provider.urls', namespace='oauth2_provider')), re_path(r'^accounts/', include('django.contrib.auth.urls')), + re_path(r'^auth/', include('social_django.urls', namespace='social')), re_path(r'.*', TemplateView.as_view(template_name="index.html")), ] diff --git a/rootfs/passport/views.py b/rootfs/passport/views.py new file mode 100644 index 0000000..ede1bf9 --- /dev/null +++ b/rootfs/passport/views.py @@ -0,0 +1,20 @@ +from django.conf import settings +from rest_framework.viewsets import GenericViewSet +from rest_framework.permissions import AllowAny +from rest_framework.response import Response + + +class AppSettingsViewSet(GenericViewSet): + + permission_classes = (AllowAny, ) + + def retrieve(self, request, *args, **kwargs): + return Response(data={ + "legal": getattr(settings, 'LEGAL_ENABLED', False), + "dashboard_url": getattr(settings, 'DASHBOARD_URL', '/'), + "contact_support_url": getattr( + settings, 'CONTACT_SUPPORT_URL', + 'https://community.drycc.cc/' + ), + "registration_enabled": getattr(settings, 'REGISTRATION_ENABLED', False), + }) diff --git a/rootfs/requirements.txt b/rootfs/requirements.txt index 648f25a..2b6f940 100644 --- a/rootfs/requirements.txt +++ b/rootfs/requirements.txt @@ -1,15 +1,19 @@ # Drycc passport requirements -django==3.2.5 -django-auth-ldap==3.0.0 -django-cors-headers==3.7.0 -django-guardian==2.4.0 -djangorestframework==3.12.4 -gunicorn==20.1.0 -psycopg2-binary==2.9.1 -requests==2.26.0 -requests-toolbelt==0.9.1 -django_redis==5.0.0 -dj-database-url==0.5.0 -django-oauth-toolkit==1.5.0 -whitenoise==5.3.0 - +django==5.2.14 +pytz==2026.1 +django-auth-ldap==5.3.0 +django-cors-headers==4.9.0 +djangorestframework==3.17.0 +gunicorn==25.1.0 +uvicorn==0.42.0 +asgiref==3.11.1 +psycopg[binary]==3.3.3 +requests==2.33.0 +requests-toolbelt==1.0.0 +redis==6.3.0 +celery[redis]==5.6.3 +hiredis==3.3.1 +dj-database-url==3.1.2 +django-oauth-toolkit==3.2.0 +social-auth-app-django==5.7.0 +whitenoise==6.12.0 diff --git a/rootfs/web/README.md b/rootfs/web/README.md new file mode 100644 index 0000000..3d51350 --- /dev/null +++ b/rootfs/web/README.md @@ -0,0 +1,83 @@ +# Passport Web Frontend + +This is the web frontend for the Passport authentication system, built with Vue.js and Vite. + +## Prerequisites + +Before running the web frontend, ensure you have the following installed: +- Node.js (v23 or higher) +- npm or yarn +- Python environment with Django backend + +## Setup Instructions + +### 1. Backend Setup + +First, ensure the Django backend is properly set up: + +```bash +# Install Django and dependencies +pip install -r requirements.txt + +# Set environment variables +export DRYCC_DATABASE_URL=postgres://postgres:@127.0.0.1:5432/passport +export VUE_APP_BASE_URL=http://localhost:8000/ +export CSRF_TRUSTED_ORIGINS=http://localhost:5173 + +# Start the Django development server +python manage.py runserver +``` + +### 2. Frontend Setup + +Navigate to the web directory and install dependencies: + +```bash +cd web +npm install +``` + +### 3. Development Server + +Start the development server: + +```bash +npm run dev -- --port 5173 +``` + +The application will be available at `http://localhost:5173`. + +## Available Scripts + +- `npm run dev` - Start the development server +- `npm run build` - Build the application for production +- `npm run preview` - Preview the production build +- `npm run lint` - Run ESLint + +## Environment Variables + +The following environment variables are required: + +- `VUE_APP_BASE_URL` - The base URL of the Django backend API +- `CSRF_TRUSTED_ORIGINS` - Trusted origins for CSRF protection + +## Project Structure + +``` +web/ +├── public/ # Static assets +├── src/ +│ ├── assets/ # Images and other assets +│ ├── components/ # Vue components +│ ├── views/ # Page components +│ ├── services/ # API service modules +│ ├── router/ # Vue Router configuration +│ ├── utils/ # Utility functions +│ └── lang/ # Internationalization +├── package.json # Project dependencies +└── vite.config.js # Vite configuration +``` + +## Contributing + +Please refer to the main project documentation for contribution guidelines. diff --git a/rootfs/web/index.html b/rootfs/web/index.html index 26dc6ed..369b5fa 100644 --- a/rootfs/web/index.html +++ b/rootfs/web/index.html @@ -2,18 +2,11 @@ - - - Vite App + Drycc CaaS - - +
- + diff --git a/rootfs/web/package-lock.json b/rootfs/web/package-lock.json new file mode 100644 index 0000000..41980a8 --- /dev/null +++ b/rootfs/web/package-lock.json @@ -0,0 +1,2371 @@ +{ + "name": "web", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "web", + "version": "0.0.0", + "license": "Apache-2.0", + "dependencies": { + "axios": "^1.15.2", + "vue": "^3.5.30", + "vue-i18n": "^11.3.0", + "vue-router": "^5.0.4", + "yarn": "^1.22.22" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.2.2", + "@vitejs/plugin-vue": "^6.0.5", + "@vue/compiler-sfc": "^3.5.30", + "lucide-vue-next": "^1.0.0", + "tailwindcss": "^4.2.2", + "typescript": "^6.0.3", + "vite": "^8.0.8", + "vue-tsc": "^3.2.6" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@intlify/core-base": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-11.3.0.tgz", + "integrity": "sha512-NNX5jIwF4TJBe7RtSKDMOA6JD9mp2mRcBHAwt2X+Q8PvnZub0yj5YYXlFu2AcESdgQpEv/5Yx2uOCV/yh7YkZg==", + "license": "MIT", + "dependencies": { + "@intlify/devtools-types": "11.3.0", + "@intlify/message-compiler": "11.3.0", + "@intlify/shared": "11.3.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/devtools-types": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@intlify/devtools-types/-/devtools-types-11.3.0.tgz", + "integrity": "sha512-G9CNL4WpANWVdUjubOIIS7/D2j/0j+1KJmhBJxHilWNKr9mmt3IjFV3Hq4JoBP23uOoC5ynxz/FHZ42M+YxfGw==", + "license": "MIT", + "dependencies": { + "@intlify/core-base": "11.3.0", + "@intlify/shared": "11.3.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/message-compiler": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-11.3.0.tgz", + "integrity": "sha512-RAJp3TMsqohg/Wa7bVF3cChRhecSYBLrTCQSj7j0UtWVFLP+6iEJoE2zb7GU5fp+fmG5kCbUdzhmlAUCWXiUJw==", + "license": "MIT", + "dependencies": { + "@intlify/shared": "11.3.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/shared": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-11.3.0.tgz", + "integrity": "sha512-LC6P/uay7rXL5zZ5+5iRJfLs/iUN8apu9tm8YqQVmW3Uq3X4A0dOFUIDuAmB7gAC29wTHOS3EiN/IosNSz0eNQ==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.3.tgz", + "integrity": "sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.124.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz", + "integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz", + "integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz", + "integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz", + "integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz", + "integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz", + "integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz", + "integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.9.2", + "@emnapi/runtime": "1.9.2", + "@napi-rs/wasm-runtime": "^1.1.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz", + "integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz", + "integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.2", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", + "integrity": "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tailwindcss/node": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.2.tgz", + "integrity": "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.19.0", + "jiti": "^2.6.1", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.2.2" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.2.tgz", + "integrity": "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.2.2", + "@tailwindcss/oxide-darwin-arm64": "4.2.2", + "@tailwindcss/oxide-darwin-x64": "4.2.2", + "@tailwindcss/oxide-freebsd-x64": "4.2.2", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", + "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", + "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", + "@tailwindcss/oxide-linux-x64-musl": "4.2.2", + "@tailwindcss/oxide-wasm32-wasi": "4.2.2", + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", + "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.2.tgz", + "integrity": "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.2.tgz", + "integrity": "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.2.tgz", + "integrity": "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.2.tgz", + "integrity": "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.2.tgz", + "integrity": "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.2.tgz", + "integrity": "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.2.tgz", + "integrity": "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.2.tgz", + "integrity": "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.2.tgz", + "integrity": "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.2.tgz", + "integrity": "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.8.1", + "@emnapi/runtime": "^1.8.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.1", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.2.tgz", + "integrity": "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.2.tgz", + "integrity": "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.2.tgz", + "integrity": "sha512-mEiF5HO1QqCLXoNEfXVA1Tzo+cYsrqV7w9Juj2wdUFyW07JRenqMG225MvPwr3ZD9N1bFQj46X7r33iHxLUW0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.2.2", + "@tailwindcss/oxide": "4.2.2", + "tailwindcss": "4.2.2" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7 || ^8" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.5.tgz", + "integrity": "sha512-bL3AxKuQySfk1iGcBsQnoRVexTPJq0Z/ixFVM8OhVJAP6ZXXXLtM7NFKWhLl30Kg7uTBqIaPXbh+nuQCuBDedg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-rc.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/language-core": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.28" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@vue-macros/common": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.1.2.tgz", + "integrity": "sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==", + "license": "MIT", + "dependencies": { + "@vue/compiler-sfc": "^3.5.22", + "ast-kit": "^2.1.2", + "local-pkg": "^1.1.2", + "magic-string-ast": "^1.0.2", + "unplugin-utils": "^0.3.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/vue-macros" + }, + "peerDependencies": { + "vue": "^2.7.0 || ^3.2.25" + }, + "peerDependenciesMeta": { + "vue": { + "optional": true + } + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.30.tgz", + "integrity": "sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@vue/shared": "3.5.30", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.30.tgz", + "integrity": "sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.30", + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.30.tgz", + "integrity": "sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@vue/compiler-core": "3.5.30", + "@vue/compiler-dom": "3.5.30", + "@vue/compiler-ssr": "3.5.30", + "@vue/shared": "3.5.30", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.8", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.30.tgz", + "integrity": "sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.30", + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/@vue/devtools-kit": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.1.1.tgz", + "integrity": "sha512-gVBaBv++i+adg4JpH71k9ppl4soyR7Y2McEqO5YNgv0BI1kMZ7BDX5gnwkZ5COYgiCyhejZG+yGNrBAjj6Coqg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^8.1.1", + "birpc": "^2.6.1", + "hookable": "^5.5.3", + "perfect-debounce": "^2.0.0" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.1.1.tgz", + "integrity": "sha512-+h4ttmJYl/txpxHKaoZcaKpC+pvckgLzIDiSQlaQ7kKthKh8KuwoLW2D8hPJEnqKzXOvu15UHEoGyngAXCz0EQ==", + "license": "MIT" + }, + "node_modules/@vue/language-core": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.2.6.tgz", + "integrity": "sha512-xYYYX3/aVup576tP/23sEUpgiEnujrENaoNRbaozC1/MA9I6EGFQRJb4xrt/MmUCAGlxTKL2RmT8JLTPqagCkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "@vue/compiler-dom": "^3.5.0", + "@vue/shared": "^3.5.0", + "alien-signals": "^3.0.0", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1", + "picomatch": "^4.0.2" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.30.tgz", + "integrity": "sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.30.tgz", + "integrity": "sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.30", + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.30.tgz", + "integrity": "sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.30", + "@vue/runtime-core": "3.5.30", + "@vue/shared": "3.5.30", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.30.tgz", + "integrity": "sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.30", + "@vue/shared": "3.5.30" + }, + "peerDependencies": { + "vue": "3.5.30" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.30.tgz", + "integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==", + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/alien-signals": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.1.2.tgz", + "integrity": "sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ast-kit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz", + "integrity": "sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "pathe": "^2.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/ast-walker-scope": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.8.3.tgz", + "integrity": "sha512-cbdCP0PGOBq0ASG+sjnKIoYkWMKhhz+F/h9pRexUdX2Hd38+WOlBkRKlqkGOSm0YQpcFMQBJeK4WspUAkwsEdg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.4", + "ast-kit": "^2.1.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.2.tgz", + "integrity": "sha512-wLrXxPtcrPTsNlJmKjkPnNPK2Ihe0hn0wGSaTEiHRPxwjvJwT3hKmXF4dpqxmPO9SoNb2FsYXj/xEo0gHN+D5A==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", + "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "license": "MIT" + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/local-pkg": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/lucide-vue-next": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lucide-vue-next/-/lucide-vue-next-1.0.0.tgz", + "integrity": "sha512-V6SPvx1IHTj/UY+FrIYWV5faISsPSb8BnWSFDxAtezWKvWc9ZZ40PDrdu1/Qb5vg4lHWr1hs1BAMGVGm6V1Xdg==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "vue": ">=3.0.1" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magic-string-ast": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/magic-string-ast/-/magic-string-ast-1.0.3.tgz", + "integrity": "sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==", + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.19" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mlly": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", + "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz", + "integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.124.0", + "@rolldown/pluginutils": "1.0.0-rc.15" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.15", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", + "@rolldown/binding-darwin-x64": "1.0.0-rc.15", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz", + "integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==", + "dev": true, + "license": "MIT" + }, + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "license": "MIT" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tailwindcss": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz", + "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.2.tgz", + "integrity": "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "license": "MIT" + }, + "node_modules/unplugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", + "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/unplugin-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.1.tgz", + "integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==", + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/vite": { + "version": "8.0.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz", + "integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.8", + "rolldown": "1.0.0-rc.15", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.30.tgz", + "integrity": "sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.30", + "@vue/compiler-sfc": "3.5.30", + "@vue/runtime-dom": "3.5.30", + "@vue/server-renderer": "3.5.30", + "@vue/shared": "3.5.30" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-i18n": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-11.3.0.tgz", + "integrity": "sha512-1J+xDfDJTLhDxElkd3+XUhT7FYSZd2b8pa7IRKGxhWH/8yt6PTvi3xmWhGwhYT5EaXdatui11pF2R6tL73/zPA==", + "license": "MIT", + "dependencies": { + "@intlify/core-base": "11.3.0", + "@intlify/devtools-types": "11.3.0", + "@intlify/shared": "11.3.0", + "@vue/devtools-api": "^6.5.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/vue-router": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.0.4.tgz", + "integrity": "sha512-lCqDLCI2+fKVRl2OzXuzdSWmxXFLQRxQbmHugnRpTMyYiT+hNaycV0faqG5FBHDXoYrZ6MQcX87BvbY8mQ20Bg==", + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.28.6", + "@vue-macros/common": "^3.1.1", + "@vue/devtools-api": "^8.0.6", + "ast-walker-scope": "^0.8.3", + "chokidar": "^5.0.0", + "json5": "^2.2.3", + "local-pkg": "^1.1.2", + "magic-string": "^0.30.21", + "mlly": "^1.8.0", + "muggle-string": "^0.4.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "scule": "^1.3.0", + "tinyglobby": "^0.2.15", + "unplugin": "^3.0.0", + "unplugin-utils": "^0.3.1", + "yaml": "^2.8.2" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "@pinia/colada": ">=0.21.2", + "@vue/compiler-sfc": "^3.5.17", + "pinia": "^3.0.4", + "vue": "^3.5.0" + }, + "peerDependenciesMeta": { + "@pinia/colada": { + "optional": true + }, + "@vue/compiler-sfc": { + "optional": true + }, + "pinia": { + "optional": true + } + } + }, + "node_modules/vue-router/node_modules/@vue/devtools-api": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.1.1.tgz", + "integrity": "sha512-bsDMJ07b3GN1puVwJb/fyFnj/U2imyswK5UQVLZwVl7O05jDrt6BHxeG5XffmOOdasOj/bOmIjxJvGPxU7pcqw==", + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^8.1.1" + } + }, + "node_modules/vue-tsc": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.2.6.tgz", + "integrity": "sha512-gYW/kWI0XrwGzd0PKc7tVB/qpdeAkIZLNZb10/InizkQjHjnT8weZ/vBarZoj4kHKbUTZT/bAVgoOr8x4NsQ/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/typescript": "2.4.28", + "@vue/language-core": "3.2.6" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "license": "MIT" + }, + "node_modules/yaml": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yarn": { + "version": "1.22.22", + "resolved": "https://registry.npmjs.org/yarn/-/yarn-1.22.22.tgz", + "integrity": "sha512-prL3kGtyG7o9Z9Sv8IPfBNrWTDmXB4Qbes8A9rEzt6wkJV8mUvoirjU0Mp3GGAU06Y0XQyA3/2/RQFVuK7MTfg==", + "hasInstallScript": true, + "license": "BSD-2-Clause", + "bin": { + "yarn": "bin/yarn.js", + "yarnpkg": "bin/yarn.js" + }, + "engines": { + "node": ">=4.0.0" + } + } + } +} diff --git a/rootfs/web/package.json b/rootfs/web/package.json index 65085d3..82a5d5e 100644 --- a/rootfs/web/package.json +++ b/rootfs/web/package.json @@ -1,21 +1,27 @@ { "name": "web", "version": "0.0.0", + "license": "Apache-2.0", "scripts": { "dev": "vite", "build": "vite build", "serve": "vite preview" }, "dependencies": { - "vue": "^3.0.5", - "axios": "^0.21.1", - "vant": "^3.0.17", - "vue-i18n": "^9.0.0-alpha.16", - "vue-router": "^4.0.0-rc.1" + "axios": "^1.15.2", + "vue": "^3.5.30", + "vue-i18n": "^11.3.0", + "vue-router": "^5.0.4", + "yarn": "^1.22.22" }, "devDependencies": { - "@vitejs/plugin-vue": "^1.3.0", - "@vue/compiler-sfc": "^3.0.5", - "vite": "^2.4.4" + "@tailwindcss/vite": "^4.2.2", + "@vitejs/plugin-vue": "^6.0.5", + "@vue/compiler-sfc": "^3.5.30", + "lucide-vue-next": "^1.0.0", + "tailwindcss": "^4.2.2", + "typescript": "^6.0.3", + "vite": "^8.0.8", + "vue-tsc": "^3.2.6" } -} \ No newline at end of file +} diff --git a/rootfs/web/src/.env b/rootfs/web/src/.env deleted file mode 100644 index cba474f..0000000 --- a/rootfs/web/src/.env +++ /dev/null @@ -1 +0,0 @@ -VITE_APP_BASE_API=/ \ No newline at end of file diff --git a/rootfs/web/src/assets/bashboard.css b/rootfs/web/src/assets/bashboard.css deleted file mode 100644 index 2622238..0000000 --- a/rootfs/web/src/assets/bashboard.css +++ /dev/null @@ -1,16106 +0,0 @@ -@charset "UTF-8"; - -.checkbox-inline, .img-thumbnail, .list-inline > li, .radio-inline, audio, canvas, label, progress, video { - display: inline-block -} - -.label, audio, canvas, progress, sub, sup, video { - vertical-align: baseline -} - -.btn, .btn-group, .btn-group-vertical, .caret, .checkbox-inline, .input-group-addon, .input-group-btn, .radio-inline, img { - vertical-align: middle -} - -hr, img { - border: 0 -} - -html { - font-family: sans-serif; - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100% -} - -article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { - display: block -} - -audio:not([controls]) { - display: none; - height: 0 -} - -[hidden], template { - display: none -} - -a { - background-color: transparent; - color: #79589F; - text-decoration: none -} - -a:active, a:hover { - outline: 0 -} - -b, optgroup, strong { - font-weight: 700 -} - -dfn { - font-style: italic -} - -h1 { - margin: .67em 0 -} - -mark { - background: #ff0; - color: #000 -} - -.img-thumbnail, body { - background-color: #fff -} - -sub, sup { - font-size: 75%; - line-height: 0; - position: relative -} - -sup { - top: -.5em -} - -sub { - bottom: -.25em -} - -svg:not(:root) { - overflow: hidden -} - -hr { - box-sizing: content-box; - height: 0 -} - -pre, textarea { - overflow: auto -} - -code, kbd, pre, samp { - font-size: 1em -} - -button, input, optgroup, select, textarea { - color: inherit; - font: inherit; - margin: 0 -} - -button { - overflow: visible -} - -button, select { - text-transform: none -} - -button, html input[type=button], input[type=reset], input[type=submit] { - -webkit-appearance: button; - cursor: pointer -} - -button[disabled], html input[disabled] { - cursor: default -} - -button::-moz-focus-inner, input::-moz-focus-inner { - border: 0; - padding: 0 -} - -input[type=checkbox], input[type=radio] { - box-sizing: border-box; - padding: 0 -} - -input[type=number]::-webkit-inner-spin-button, input[type=number]::-webkit-outer-spin-button { - height: auto -} - -input[type=search]::-webkit-search-cancel-button, input[type=search]::-webkit-search-decoration { - -webkit-appearance: none -} - -td, th { - padding: 0 -} - -*, :after, :before { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box -} - -html { - font-size: 10px; - -webkit-tap-highlight-color: transparent -} - -body { - margin: 0; - font-size: 14px; - line-height: 1.42857; - color: #3F3F44 -} - -button, input, select, textarea { - font-family: inherit; - font-size: inherit; - line-height: inherit -} - -a:focus { - outline: -webkit-focus-ring-color auto 5px; - outline-offset: -2px -} - -figure { - margin: 0 -} - -.img-responsive { - display: block; - max-width: 100%; - height: auto -} - -.img-rounded { - border-radius: 6px -} - -.img-thumbnail { - padding: 4px; - line-height: 1.42857; - border: 1px solid #ddd; - border-radius: 4px; - -webkit-transition: all .2s ease-in-out; - -o-transition: all .2s ease-in-out; - transition: all .2s ease-in-out; - max-width: 100%; - height: auto -} - -.img-circle { - border-radius: 50% -} - -hr { - margin-top: 20px; - margin-bottom: 20px; - border-top: 1px solid #EEF1F6 -} - -.sr-only, .two-factor-required label { - position: absolute; - width: 1px; - height: 1px; - margin: -1px; - padding: 0; - overflow: hidden; - clip: rect(0, 0, 0, 0); - border: 0 -} - -.sr-only-focusable:active, .sr-only-focusable:focus { - position: static; - width: auto; - height: auto; - margin: 0; - overflow: visible; - clip: auto -} - -[role=button] { - cursor: pointer -} - -.dyno-tier-picker-item-size-name, .panel-section .panel-title, .pipeline-dropdown .dropdown-menu-scroll > li .btn-link, .pipeline-dropdown > li .btn-link, h1, h2, h3, h4, h5, h6 { - font-family: inherit; - font-weight: 200; - line-height: 1.1; - color: #79589F -} - -.dyno-tier-picker-item-size-name .panel-section .panel-details, .dyno-tier-picker-item-size-name .small, .dyno-tier-picker-item-size-name small, .panel-section .dyno-tier-picker-item-size-name .panel-details, .panel-section .panel-title .panel-details, .panel-section .panel-title .small, .panel-section .panel-title small, .panel-section .pipeline-dropdown .dropdown-menu-scroll > li .btn-link .panel-details, .panel-section .pipeline-dropdown > li .btn-link .panel-details, .panel-section h1 .panel-details, .panel-section h2 .panel-details, .panel-section h3 .panel-details, .panel-section h4 .panel-details, .panel-section h5 .panel-details, .panel-section h6 .panel-details, .pipeline-dropdown .dropdown-menu-scroll > li .btn-link .panel-section .panel-details, .pipeline-dropdown .dropdown-menu-scroll > li .btn-link .small, .pipeline-dropdown .dropdown-menu-scroll > li .btn-link small, .pipeline-dropdown > li .btn-link .panel-section .panel-details, .pipeline-dropdown > li .btn-link .small, .pipeline-dropdown > li .btn-link small, h1 .panel-section .panel-details, h1 .small, h1 small, h2 .panel-section .panel-details, h2 .small, h2 small, h3 .panel-section .panel-details, h3 .small, h3 small, h4 .panel-section .panel-details, h4 .small, h4 small, h5 .panel-section .panel-details, h5 .small, h5 small, h6 .panel-section .panel-details, h6 .small, h6 small { - font-weight: 400; - line-height: 1; - color: #96A3B6 -} - -h1, h2, h3 { - margin-top: 20px; - margin-bottom: 10px -} - -.panel-section h1 .panel-details, .panel-section h2 .panel-details, .panel-section h3 .panel-details, h1 .panel-section .panel-details, h1 .small, h1 small, h2 .panel-section .panel-details, h2 .small, h2 small, h3 .panel-section .panel-details, h3 .small, h3 small { - font-size: 65% -} - -.dyno-tier-picker-item-size-name .panel-section .panel-details, .dyno-tier-picker-item-size-name .small, .dyno-tier-picker-item-size-name small, .label, .panel-section .dyno-tier-picker-item-size-name .panel-details, .panel-section .panel-title .panel-details, .panel-section .panel-title .small, .panel-section .panel-title small, .panel-section .pipeline-dropdown .dropdown-menu-scroll > li .btn-link .panel-details, .panel-section .pipeline-dropdown > li .btn-link .panel-details, .panel-section h4 .panel-details, .panel-section h5 .panel-details, .panel-section h6 .panel-details, .pipeline-dropdown .dropdown-menu-scroll > li .btn-link .panel-section .panel-details, .pipeline-dropdown .dropdown-menu-scroll > li .btn-link .small, .pipeline-dropdown .dropdown-menu-scroll > li .btn-link small, .pipeline-dropdown > li .btn-link .panel-section .panel-details, .pipeline-dropdown > li .btn-link .small, .pipeline-dropdown > li .btn-link small, h4 .panel-section .panel-details, h4 .small, h4 small, h5 .panel-section .panel-details, h5 .small, h5 small, h6 .panel-section .panel-details, h6 .small, h6 small { - font-size: 75% -} - -.dyno-tier-picker-item-size-name, .panel-section .panel-title, .pipeline-dropdown .dropdown-menu-scroll > li .btn-link, .pipeline-dropdown > li .btn-link, h4, h5, h6 { - margin-top: 10px; - margin-bottom: 10px -} - -h1 { - font-size: 36px -} - -h2 { - font-size: 30px -} - -h3 { - font-size: 24px -} - -h5 { - font-size: 14px -} - -.pipeline-dropdown .dropdown-menu-scroll > li .btn-link, .pipeline-dropdown > li .btn-link, h6 { - font-size: 12px -} - -.panel-section .panel-details, p { - margin: 0 0 10px -} - -.error-text .panel-section .panel-details:first-of-type, .error-text p:first-of-type, .lead, .panel-section .error-text .panel-details:first-of-type { - margin-bottom: 20px; - font-size: 16px; - font-weight: 300; - line-height: 1.4 -} - -.badge, .close, .label, dt, kbd kbd { - font-weight: 700 -} - -@media (min-width: 768px) { - .error-text .panel-section .panel-details:first-of-type, .error-text p:first-of-type, .lead, .panel-section .error-text .panel-details:first-of-type { - font-size: 21px - } -} - -.panel-section .panel-details, .small, small { - font-size: 85% -} - -.mark, mark { - background-color: #fffaf6; - padding: .2em -} - -.text-left { - text-align: left -} - -.text-right { - text-align: right -} - -.text-center { - text-align: center -} - -.text-justify { - text-align: justify -} - -.text-nowrap { - white-space: nowrap -} - -.text-lowercase { - text-transform: lowercase -} - -.initialism, .text-uppercase { - text-transform: uppercase -} - -.text-capitalize { - text-transform: capitalize -} - -.text-muted { - color: #CFD7E6 -} - -.text-primary { - color: #79589F -} - -a.text-primary:focus, a.text-primary:hover { - color: #60467e -} - -a.text-success:focus, a.text-success:hover { - color: #51b060 -} - -a.text-info:focus, a.text-info:hover { - color: #1774e2 -} - -a.text-warning:focus, a.text-warning:hover { - color: #f98515 -} - -a.text-danger:focus, a.text-danger:hover { - color: #bc2929 -} - -.bg-primary { - color: #fff; - background-color: #79589F -} - -a.bg-primary:focus, a.bg-primary:hover { - background-color: #60467e -} - -.bg-success { - background-color: #f8fcf9 -} - -a.bg-success:focus, a.bg-success:hover { - background-color: #d4edda -} - -.bg-info { - background-color: #f5f9fe -} - -a.bg-info:focus, a.bg-info:hover { - background-color: #c7ddf9 -} - -.bg-warning { - background-color: #fffaf6 -} - -a.bg-warning:focus, a.bg-warning:hover { - background-color: #ffdec3 -} - -.bg-danger { - background-color: #fdf6f6 -} - -a.bg-danger:focus, a.bg-danger:hover { - background-color: #f4cccc -} - -pre code, table { - background-color: transparent -} - -.page-header { - padding-bottom: 9px; - margin: 40px 0 20px; - border-bottom: 1px solid #EEF1F6 -} - -dl, ol, ul { - margin-top: 0 -} - -ol, ul { - margin-bottom: 10px -} - -ol ol, ol ul, ul ol, ul ul { - margin-bottom: 0 -} - -.flash-messages .flash-message .content, .list-unstyled { - padding-left: 0; - list-style: none -} - -.list-inline { - padding-left: 0; - list-style: none; - margin-left: -5px -} - -.list-inline > li { - padding-left: 5px; - padding-right: 5px -} - -dl { - margin-bottom: 20px -} - -dd, dt { - line-height: 1.42857 -} - -dd { - margin-left: 0 -} - -.dl-horizontal dd:after, .dl-horizontal dd:before { - content: " "; - display: table -} - -.dl-horizontal dd:after { - clear: both -} - -@media (min-width: 768px) { - .dl-horizontal dt { - float: left; - width: 160px; - clear: left; - text-align: right; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap - } - - .dl-horizontal dd { - margin-left: 180px - } - - .container { - width: 750px - } -} - -pre, pre code { - white-space: pre-wrap -} - -abbr[data-original-title], abbr[title] { - cursor: help; - border-bottom: 1px dotted #d7cde2 -} - -.initialism { - font-size: 90% -} - -blockquote { - padding: 10px 20px; - margin: 0 0 20px; - font-size: 17.5px; - border-left: 5px solid #EEF1F6 -} - -.panel-section blockquote .panel-details:last-child, blockquote .panel-section .panel-details:last-child, blockquote ol:last-child, blockquote p:last-child, blockquote ul:last-child { - margin-bottom: 0 -} - -.panel-section blockquote .panel-details, blockquote .panel-section .panel-details, blockquote .small, blockquote footer, blockquote small { - display: block; - font-size: 80%; - line-height: 1.42857; - color: #96A3B6 -} - -legend, pre { - color: #596981 -} - -.panel-section blockquote .panel-details:before, blockquote .panel-section .panel-details:before, blockquote .small:before, blockquote footer:before, blockquote small:before { - content: '\2014 \00A0' -} - -.blockquote-reverse, blockquote.pull-right { - padding-right: 15px; - padding-left: 0; - border-right: 5px solid #EEF1F6; - border-left: 0; - text-align: right -} - -code, kbd { - padding: 2px 4px; - font-size: 90% -} - -caption, th { - text-align: left -} - -.blockquote-reverse .panel-section .panel-details:before, .blockquote-reverse .small:before, .blockquote-reverse footer:before, .blockquote-reverse small:before, .panel-section .blockquote-reverse .panel-details:before, .panel-section blockquote.pull-right .panel-details:before, blockquote.pull-right .panel-section .panel-details:before, blockquote.pull-right .small:before, blockquote.pull-right footer:before, blockquote.pull-right small:before { - content: '' -} - -.blockquote-reverse .panel-section .panel-details:after, .blockquote-reverse .small:after, .blockquote-reverse footer:after, .blockquote-reverse small:after, .panel-section .blockquote-reverse .panel-details:after, .panel-section blockquote.pull-right .panel-details:after, blockquote.pull-right .panel-section .panel-details:after, blockquote.pull-right .small:after, blockquote.pull-right footer:after, blockquote.pull-right small:after { - content: '\00A0 \2014' -} - -address { - margin-bottom: 20px; - font-style: normal; - line-height: 1.42857 -} - -code, kbd, pre, samp { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace -} - -code { - border-radius: 4px -} - -kbd { - color: #EEF1F6; - background-color: #596981; - border-radius: 3px -} - -kbd kbd { - padding: 0; - font-size: 100%; - box-shadow: none -} - -.form-control, .has-success .form-control { - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075) -} - -pre { - display: block; - padding: 9.5px; - margin: 0 0 10px; - font-size: 13px; - line-height: 1.42857; - background-color: #f5f7fa; - border: 1px solid #EEF1F6; - border-radius: 4px -} - -.container-fluid:after, .container-fluid:before, .container:after, .container:before, .panel-section:after, .panel-section:before, .row:after, .row:before { - display: table; - content: " " -} - -.container, .container-fluid { - margin-right: auto; - margin-left: auto -} - -.btn-group-vertical > .btn:not(:first-child):not(:last-child), .btn-group > .btn-group:not(:first-child):not(:last-child) > .btn, .btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle):not(.drop-down__toggle), .btn-link, pre code { - border-radius: 0 -} - -pre code { - padding: 0; - font-size: inherit; - color: inherit -} - -.pre-scrollable { - max-height: 340px; - overflow-y: scroll -} - -.container { - padding-left: 15px; - padding-right: 15px -} - -.container:after { - clear: both -} - -@media (min-width: 992px) { - .container { - width: 970px - } -} - -@media (min-width: 1200px) { - .container { - width: 1170px - } -} - -.container-fluid { - padding-left: 15px; - padding-right: 15px -} - -.container-fluid:after { - clear: both -} - -.panel-section, .row { - margin-left: -15px; - margin-right: -15px -} - -.panel-section:after, .row:after { - clear: both -} - -.col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-xs-1, .col-xs-10, .col-xs-11, .col-xs-12, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .panel-section .panel-content, .panel-section .panel-description, .panel-section .section-description { - position: relative; - min-height: 1px; - padding-left: 15px; - padding-right: 15px -} - -.col-xs-1, .col-xs-10, .col-xs-11, .col-xs-12, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9 { - float: left -} - -.col-xs-1 { - width: 8.33333% -} - -.col-xs-2 { - width: 16.66667% -} - -.col-xs-3 { - width: 25% -} - -.col-xs-4 { - width: 33.33333% -} - -.col-xs-5 { - width: 41.66667% -} - -.col-xs-6 { - width: 50% -} - -.col-xs-7 { - width: 58.33333% -} - -.col-xs-8 { - width: 66.66667% -} - -.col-xs-9 { - width: 75% -} - -.col-xs-10 { - width: 83.33333% -} - -.col-xs-11 { - width: 91.66667% -} - -.col-xs-12 { - width: 100% -} - -.col-xs-pull-0 { - right: auto -} - -.col-xs-pull-1 { - right: 8.33333% -} - -.col-xs-pull-2 { - right: 16.66667% -} - -.col-xs-pull-3 { - right: 25% -} - -.col-xs-pull-4 { - right: 33.33333% -} - -.col-xs-pull-5 { - right: 41.66667% -} - -.col-xs-pull-6 { - right: 50% -} - -.col-xs-pull-7 { - right: 58.33333% -} - -.col-xs-pull-8 { - right: 66.66667% -} - -.col-xs-pull-9 { - right: 75% -} - -.col-xs-pull-10 { - right: 83.33333% -} - -.col-xs-pull-11 { - right: 91.66667% -} - -.col-xs-pull-12 { - right: 100% -} - -.col-xs-push-0 { - left: auto -} - -.col-xs-push-1 { - left: 8.33333% -} - -.col-xs-push-2 { - left: 16.66667% -} - -.col-xs-push-3 { - left: 25% -} - -.col-xs-push-4 { - left: 33.33333% -} - -.col-xs-push-5 { - left: 41.66667% -} - -.col-xs-push-6 { - left: 50% -} - -.col-xs-push-7 { - left: 58.33333% -} - -.col-xs-push-8 { - left: 66.66667% -} - -.col-xs-push-9 { - left: 75% -} - -.col-xs-push-10 { - left: 83.33333% -} - -.col-xs-push-11 { - left: 91.66667% -} - -.col-xs-push-12 { - left: 100% -} - -.col-xs-offset-0 { - margin-left: 0 -} - -.col-xs-offset-1 { - margin-left: 8.33333% -} - -.col-xs-offset-2 { - margin-left: 16.66667% -} - -.col-xs-offset-3 { - margin-left: 25% -} - -.col-xs-offset-4 { - margin-left: 33.33333% -} - -.col-xs-offset-5 { - margin-left: 41.66667% -} - -.col-xs-offset-6 { - margin-left: 50% -} - -.col-xs-offset-7 { - margin-left: 58.33333% -} - -.col-xs-offset-8 { - margin-left: 66.66667% -} - -.col-xs-offset-9 { - margin-left: 75% -} - -.col-xs-offset-10 { - margin-left: 83.33333% -} - -.col-xs-offset-11 { - margin-left: 91.66667% -} - -.col-xs-offset-12 { - margin-left: 100% -} - -@media (min-width: 768px) { - .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .panel-section .panel-content, .panel-section .panel-description, .panel-section .section-description { - float: left - } - - .col-sm-1 { - width: 8.33333% - } - - .col-sm-2 { - width: 16.66667% - } - - .col-sm-3 { - width: 25% - } - - .col-sm-4, .panel-section .panel-description, .panel-section .section-description { - width: 33.33333% - } - - .col-sm-5 { - width: 41.66667% - } - - .col-sm-6 { - width: 50% - } - - .col-sm-7 { - width: 58.33333% - } - - .col-sm-8, .panel-section .panel-content { - width: 66.66667% - } - - .col-sm-9 { - width: 75% - } - - .col-sm-10 { - width: 83.33333% - } - - .col-sm-11 { - width: 91.66667% - } - - .col-sm-12 { - width: 100% - } - - .col-sm-pull-0 { - right: auto - } - - .col-sm-pull-1 { - right: 8.33333% - } - - .col-sm-pull-2 { - right: 16.66667% - } - - .col-sm-pull-3 { - right: 25% - } - - .col-sm-pull-4 { - right: 33.33333% - } - - .col-sm-pull-5 { - right: 41.66667% - } - - .col-sm-pull-6 { - right: 50% - } - - .col-sm-pull-7 { - right: 58.33333% - } - - .col-sm-pull-8 { - right: 66.66667% - } - - .col-sm-pull-9 { - right: 75% - } - - .col-sm-pull-10 { - right: 83.33333% - } - - .col-sm-pull-11 { - right: 91.66667% - } - - .col-sm-pull-12 { - right: 100% - } - - .col-sm-push-0 { - left: auto - } - - .col-sm-push-1 { - left: 8.33333% - } - - .col-sm-push-2 { - left: 16.66667% - } - - .col-sm-push-3 { - left: 25% - } - - .col-sm-push-4 { - left: 33.33333% - } - - .col-sm-push-5 { - left: 41.66667% - } - - .col-sm-push-6 { - left: 50% - } - - .col-sm-push-7 { - left: 58.33333% - } - - .col-sm-push-8 { - left: 66.66667% - } - - .col-sm-push-9 { - left: 75% - } - - .col-sm-push-10 { - left: 83.33333% - } - - .col-sm-push-11 { - left: 91.66667% - } - - .col-sm-push-12 { - left: 100% - } - - .col-sm-offset-0 { - margin-left: 0 - } - - .col-sm-offset-1 { - margin-left: 8.33333% - } - - .col-sm-offset-2 { - margin-left: 16.66667% - } - - .col-sm-offset-3 { - margin-left: 25% - } - - .col-sm-offset-4 { - margin-left: 33.33333% - } - - .col-sm-offset-5 { - margin-left: 41.66667% - } - - .col-sm-offset-6 { - margin-left: 50% - } - - .col-sm-offset-7 { - margin-left: 58.33333% - } - - .col-sm-offset-8 { - margin-left: 66.66667% - } - - .col-sm-offset-9 { - margin-left: 75% - } - - .col-sm-offset-10 { - margin-left: 83.33333% - } - - .col-sm-offset-11 { - margin-left: 91.66667% - } - - .col-sm-offset-12 { - margin-left: 100% - } -} - -@media (min-width: 992px) { - .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .panel-section .panel-content, .panel-section .panel-description, .panel-section .section-description { - float: left - } - - .col-md-1 { - width: 8.33333% - } - - .col-md-2 { - width: 16.66667% - } - - .col-md-3, .panel-section .panel-description, .panel-section .section-description { - width: 25% - } - - .col-md-4 { - width: 33.33333% - } - - .col-md-5 { - width: 41.66667% - } - - .col-md-6 { - width: 50% - } - - .col-md-7 { - width: 58.33333% - } - - .col-md-8, .panel-section .panel-content { - width: 66.66667% - } - - .col-md-9 { - width: 75% - } - - .col-md-10 { - width: 83.33333% - } - - .col-md-11 { - width: 91.66667% - } - - .col-md-12 { - width: 100% - } - - .col-md-pull-0 { - right: auto - } - - .col-md-pull-1 { - right: 8.33333% - } - - .col-md-pull-2 { - right: 16.66667% - } - - .col-md-pull-3 { - right: 25% - } - - .col-md-pull-4 { - right: 33.33333% - } - - .col-md-pull-5 { - right: 41.66667% - } - - .col-md-pull-6 { - right: 50% - } - - .col-md-pull-7 { - right: 58.33333% - } - - .col-md-pull-8 { - right: 66.66667% - } - - .col-md-pull-9 { - right: 75% - } - - .col-md-pull-10 { - right: 83.33333% - } - - .col-md-pull-11 { - right: 91.66667% - } - - .col-md-pull-12 { - right: 100% - } - - .col-md-push-0 { - left: auto - } - - .col-md-push-1 { - left: 8.33333% - } - - .col-md-push-2 { - left: 16.66667% - } - - .col-md-push-3 { - left: 25% - } - - .col-md-push-4 { - left: 33.33333% - } - - .col-md-push-5 { - left: 41.66667% - } - - .col-md-push-6 { - left: 50% - } - - .col-md-push-7 { - left: 58.33333% - } - - .col-md-push-8 { - left: 66.66667% - } - - .col-md-push-9 { - left: 75% - } - - .col-md-push-10 { - left: 83.33333% - } - - .col-md-push-11 { - left: 91.66667% - } - - .col-md-push-12 { - left: 100% - } - - .col-md-offset-0 { - margin-left: 0 - } - - .col-md-offset-1, .panel-section .panel-content { - margin-left: 8.33333% - } - - .col-md-offset-2 { - margin-left: 16.66667% - } - - .col-md-offset-3 { - margin-left: 25% - } - - .col-md-offset-4 { - margin-left: 33.33333% - } - - .col-md-offset-5 { - margin-left: 41.66667% - } - - .col-md-offset-6 { - margin-left: 50% - } - - .col-md-offset-7 { - margin-left: 58.33333% - } - - .col-md-offset-8 { - margin-left: 66.66667% - } - - .col-md-offset-9 { - margin-left: 75% - } - - .col-md-offset-10 { - margin-left: 83.33333% - } - - .col-md-offset-11 { - margin-left: 91.66667% - } - - .col-md-offset-12 { - margin-left: 100% - } -} - -@media (min-width: 1200px) { - .col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9 { - float: left - } - - .col-lg-1 { - width: 8.33333% - } - - .col-lg-2 { - width: 16.66667% - } - - .col-lg-3 { - width: 25% - } - - .col-lg-4 { - width: 33.33333% - } - - .col-lg-5 { - width: 41.66667% - } - - .col-lg-6 { - width: 50% - } - - .col-lg-7 { - width: 58.33333% - } - - .col-lg-8 { - width: 66.66667% - } - - .col-lg-9 { - width: 75% - } - - .col-lg-10 { - width: 83.33333% - } - - .col-lg-11 { - width: 91.66667% - } - - .col-lg-12 { - width: 100% - } - - .col-lg-pull-0 { - right: auto - } - - .col-lg-pull-1 { - right: 8.33333% - } - - .col-lg-pull-2 { - right: 16.66667% - } - - .col-lg-pull-3 { - right: 25% - } - - .col-lg-pull-4 { - right: 33.33333% - } - - .col-lg-pull-5 { - right: 41.66667% - } - - .col-lg-pull-6 { - right: 50% - } - - .col-lg-pull-7 { - right: 58.33333% - } - - .col-lg-pull-8 { - right: 66.66667% - } - - .col-lg-pull-9 { - right: 75% - } - - .col-lg-pull-10 { - right: 83.33333% - } - - .col-lg-pull-11 { - right: 91.66667% - } - - .col-lg-pull-12 { - right: 100% - } - - .col-lg-push-0 { - left: auto - } - - .col-lg-push-1 { - left: 8.33333% - } - - .col-lg-push-2 { - left: 16.66667% - } - - .col-lg-push-3 { - left: 25% - } - - .col-lg-push-4 { - left: 33.33333% - } - - .col-lg-push-5 { - left: 41.66667% - } - - .col-lg-push-6 { - left: 50% - } - - .col-lg-push-7 { - left: 58.33333% - } - - .col-lg-push-8 { - left: 66.66667% - } - - .col-lg-push-9 { - left: 75% - } - - .col-lg-push-10 { - left: 83.33333% - } - - .col-lg-push-11 { - left: 91.66667% - } - - .col-lg-push-12 { - left: 100% - } - - .col-lg-offset-0 { - margin-left: 0 - } - - .col-lg-offset-1 { - margin-left: 8.33333% - } - - .col-lg-offset-2 { - margin-left: 16.66667% - } - - .col-lg-offset-3 { - margin-left: 25% - } - - .col-lg-offset-4 { - margin-left: 33.33333% - } - - .col-lg-offset-5 { - margin-left: 41.66667% - } - - .col-lg-offset-6 { - margin-left: 50% - } - - .col-lg-offset-7 { - margin-left: 58.33333% - } - - .col-lg-offset-8 { - margin-left: 66.66667% - } - - .col-lg-offset-9 { - margin-left: 75% - } - - .col-lg-offset-10 { - margin-left: 83.33333% - } - - .col-lg-offset-11 { - margin-left: 91.66667% - } - - .col-lg-offset-12 { - margin-left: 100% - } -} - -table { - border-collapse: collapse; - border-spacing: 0 -} - -caption { - padding-top: 8px; - padding-bottom: 8px; - color: #CFD7E6 -} - -.table { - width: 100%; - max-width: 100%; - margin-bottom: 20px -} - -.table > tbody > tr > td, .table > tbody > tr > th, .table > tfoot > tr > td, .table > tfoot > tr > th, .table > thead > tr > td, .table > thead > tr > th { - padding: 8px; - line-height: 1.42857; - vertical-align: top; - border-top: 1px solid #e7ebf3 -} - -.table > thead > tr > th { - vertical-align: bottom -} - -.table > caption + thead > tr:first-child > td, .table > caption + thead > tr:first-child > th, .table > colgroup + thead > tr:first-child > td, .table > colgroup + thead > tr:first-child > th, .table > thead:first-child > tr:first-child > td, .table > thead:first-child > tr:first-child > th { - border-top: 0 -} - -.table > tbody + tbody { - border-top: 2px solid #e7ebf3 -} - -.table .table { - background-color: #fff -} - -.table-condensed > tbody > tr > td, .table-condensed > tbody > tr > th, .table-condensed > tfoot > tr > td, .table-condensed > tfoot > tr > th, .table-condensed > thead > tr > td, .table-condensed > thead > tr > th { - padding: 5px -} - -.table-bordered, .table-bordered > tbody > tr > td, .table-bordered > tbody > tr > th, .table-bordered > tfoot > tr > td, .table-bordered > tfoot > tr > th, .table-bordered > thead > tr > td, .table-bordered > thead > tr > th { - border: 1px solid #e7ebf3 -} - -.table-bordered > thead > tr > td, .table-bordered > thead > tr > th { - border-bottom-width: 2px -} - -.table-hover > tbody > tr:hover, .table-striped > tbody > tr:nth-of-type(odd) { - background-color: #fafbfc -} - -table col[class*=col-] { - position: static; - float: none; - display: table-column -} - -table td[class*=col-], table th[class*=col-] { - position: static; - float: none; - display: table-cell -} - -.table-hover > tbody > tr.active:hover > td, .table-hover > tbody > tr.active:hover > th, .table-hover > tbody > tr:hover > .active, .table-hover > tbody > tr > td.active:hover, .table-hover > tbody > tr > th.active:hover { - background-color: #eaeef2 -} - -.table > tbody > tr.success > td, .table > tbody > tr.success > th, .table > tbody > tr > td.success, .table > tbody > tr > th.success, .table > tfoot > tr.success > td, .table > tfoot > tr.success > th, .table > tfoot > tr > td.success, .table > tfoot > tr > th.success, .table > thead > tr.success > td, .table > thead > tr.success > th, .table > thead > tr > td.success, .table > thead > tr > th.success { - background-color: #f8fcf9 -} - -.table-hover > tbody > tr.success:hover > td, .table-hover > tbody > tr.success:hover > th, .table-hover > tbody > tr:hover > .success, .table-hover > tbody > tr > td.success:hover, .table-hover > tbody > tr > th.success:hover { - background-color: #e6f4ea -} - -.table > tbody > tr.info > td, .table > tbody > tr.info > th, .table > tbody > tr > td.info, .table > tbody > tr > th.info, .table > tfoot > tr.info > td, .table > tfoot > tr.info > th, .table > tfoot > tr > td.info, .table > tfoot > tr > th.info, .table > thead > tr.info > td, .table > thead > tr.info > th, .table > thead > tr > td.info, .table > thead > tr > th.info { - background-color: #f5f9fe -} - -.table-hover > tbody > tr.info:hover > td, .table-hover > tbody > tr.info:hover > th, .table-hover > tbody > tr:hover > .info, .table-hover > tbody > tr > td.info:hover, .table-hover > tbody > tr > th.info:hover { - background-color: #deebfc -} - -.table > tbody > tr.warning > td, .table > tbody > tr.warning > th, .table > tbody > tr > td.warning, .table > tbody > tr > th.warning, .table > tfoot > tr.warning > td, .table > tfoot > tr.warning > th, .table > tfoot > tr > td.warning, .table > tfoot > tr > th.warning, .table > thead > tr.warning > td, .table > thead > tr.warning > th, .table > thead > tr > td.warning, .table > thead > tr > th.warning { - background-color: #fffaf6 -} - -.table-hover > tbody > tr.warning:hover > td, .table-hover > tbody > tr.warning:hover > th, .table-hover > tbody > tr:hover > .warning, .table-hover > tbody > tr > td.warning:hover, .table-hover > tbody > tr > th.warning:hover { - background-color: #ffecdd -} - -.table > tbody > tr.danger > td, .table > tbody > tr.danger > th, .table > tbody > tr > td.danger, .table > tbody > tr > th.danger, .table > tfoot > tr.danger > td, .table > tfoot > tr.danger > th, .table > tfoot > tr > td.danger, .table > tfoot > tr > th.danger, .table > thead > tr.danger > td, .table > thead > tr.danger > th, .table > thead > tr > td.danger, .table > thead > tr > th.danger { - background-color: #fdf6f6 -} - -.table-hover > tbody > tr.danger:hover > td, .table-hover > tbody > tr.danger:hover > th, .table-hover > tbody > tr:hover > .danger, .table-hover > tbody > tr > td.danger:hover, .table-hover > tbody > tr > th.danger:hover { - background-color: #f8e1e1 -} - -.table-responsive { - overflow-x: auto; - min-height: .01% -} - -@media screen and (max-width: 767px) { - .table-responsive { - width: 100%; - margin-bottom: 15px; - overflow-y: hidden; - -ms-overflow-style: -ms-autohiding-scrollbar; - border: 1px solid #e7ebf3 - } - - .table-responsive > .table { - margin-bottom: 0 - } - - .table-responsive > .table > tbody > tr > td, .table-responsive > .table > tbody > tr > th, .table-responsive > .table > tfoot > tr > td, .table-responsive > .table > tfoot > tr > th, .table-responsive > .table > thead > tr > td, .table-responsive > .table > thead > tr > th { - white-space: nowrap - } - - .table-responsive > .table-bordered { - border: 0 - } - - .table-responsive > .table-bordered > tbody > tr > td:first-child, .table-responsive > .table-bordered > tbody > tr > th:first-child, .table-responsive > .table-bordered > tfoot > tr > td:first-child, .table-responsive > .table-bordered > tfoot > tr > th:first-child, .table-responsive > .table-bordered > thead > tr > td:first-child, .table-responsive > .table-bordered > thead > tr > th:first-child { - border-left: 0 - } - - .table-responsive > .table-bordered > tbody > tr > td:last-child, .table-responsive > .table-bordered > tbody > tr > th:last-child, .table-responsive > .table-bordered > tfoot > tr > td:last-child, .table-responsive > .table-bordered > tfoot > tr > th:last-child, .table-responsive > .table-bordered > thead > tr > td:last-child, .table-responsive > .table-bordered > thead > tr > th:last-child { - border-right: 0 - } - - .table-responsive > .table-bordered > tbody > tr:last-child > td, .table-responsive > .table-bordered > tbody > tr:last-child > th, .table-responsive > .table-bordered > tfoot > tr:last-child > td, .table-responsive > .table-bordered > tfoot > tr:last-child > th { - border-bottom: 0 - } -} - -fieldset, legend { - padding: 0; - border: 0 -} - -fieldset { - margin: 0; - min-width: 0 -} - -legend { - display: block; - width: 100%; - margin-bottom: 20px; - font-size: 21px; - line-height: inherit; - border-bottom: 1px solid #e5e5e5 -} - -label { - max-width: 100%; - margin-bottom: 5px -} - -input[type=search] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - -webkit-appearance: none -} - -input[type=checkbox], input[type=radio] { - margin: 4px 0 0; - margin-top: 1px \9; - line-height: normal -} - -.form-control, output { - font-size: 14px; - line-height: 1.42857; - color: #3F3F44; - display: block -} - -input[type=file] { - display: block -} - -select[multiple], select[size] { - height: auto -} - -input[type=file]:focus, input[type=checkbox]:focus, input[type=radio]:focus { - outline: -webkit-focus-ring-color auto 5px; - outline-offset: -2px -} - -output { - padding-top: 7px -} - -.form-control { - width: 100%; - height: 34px; - padding: 6px 12px; - background-color: #fff; - background-image: none; - border: 1px solid #CFD7E6; - border-radius: 4px; - -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; - -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; - transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s -} - -.form-control:focus { - border-color: #79589F; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(121, 88, 159, .6) -} - -.form-control::-ms-expand { - border: 0; - background-color: transparent -} - -.form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control { - background-color: #fafbfc; - opacity: 1 -} - -textarea.form-control { - height: auto -} - -@media screen and (-webkit-min-device-pixel-ratio: 0) { - input[type=date].form-control, input[type=time].form-control, input[type=datetime-local].form-control, input[type=month].form-control { - line-height: 34px - } - - .input-group-sm input[type=date], .input-group-sm input[type=time], .input-group-sm input[type=datetime-local], .input-group-sm input[type=month], .input-group-sm > .input-group-btn > input.btn[type=date], .input-group-sm > .input-group-btn > input.btn[type=time], .input-group-sm > .input-group-btn > input.btn[type=datetime-local], .input-group-sm > .input-group-btn > input.btn[type=month], .input-group-sm > input.form-control[type=date], .input-group-sm > input.form-control[type=time], .input-group-sm > input.form-control[type=datetime-local], .input-group-sm > input.form-control[type=month], .input-group-sm > input.input-group-addon[type=date], .input-group-sm > input.input-group-addon[type=time], .input-group-sm > input.input-group-addon[type=datetime-local], .input-group-sm > input.input-group-addon[type=month], input[type=date].input-sm, input[type=time].input-sm, input[type=datetime-local].input-sm, input[type=month].input-sm { - line-height: 30px - } - - .input-group-lg input[type=date], .input-group-lg input[type=time], .input-group-lg input[type=datetime-local], .input-group-lg input[type=month], .input-group-lg > .input-group-btn > input.btn[type=date], .input-group-lg > .input-group-btn > input.btn[type=time], .input-group-lg > .input-group-btn > input.btn[type=datetime-local], .input-group-lg > .input-group-btn > input.btn[type=month], .input-group-lg > input.form-control[type=date], .input-group-lg > input.form-control[type=time], .input-group-lg > input.form-control[type=datetime-local], .input-group-lg > input.form-control[type=month], .input-group-lg > input.input-group-addon[type=date], .input-group-lg > input.input-group-addon[type=time], .input-group-lg > input.input-group-addon[type=datetime-local], .input-group-lg > input.input-group-addon[type=month], input[type=date].input-lg, input[type=time].input-lg, input[type=datetime-local].input-lg, input[type=month].input-lg { - line-height: 46px - } -} - -.form-group { - margin-bottom: 15px -} - -.checkbox, .radio { - position: relative; - display: block; - margin-top: 10px; - margin-bottom: 10px -} - -.checkbox label, .radio label { - min-height: 20px; - padding-left: 20px; - margin-bottom: 0; - font-weight: 400; - cursor: pointer -} - -.checkbox input[type=checkbox], .checkbox-inline input[type=checkbox], .radio input[type=radio], .radio-inline input[type=radio] { - position: absolute; - margin-left: -20px; - margin-top: 4px \9 -} - -.checkbox-inline, .collapsing, .dropdown, .dropup, .has-feedback, .radio-inline { - position: relative -} - -.checkbox + .checkbox, .radio + .radio { - margin-top: -5px -} - -.checkbox-inline, .radio-inline { - padding-left: 20px; - margin-bottom: 0; - font-weight: 400; - cursor: pointer -} - -.btn-block, .collapse.in, .form-control-feedback, .help-block { - display: block -} - -.checkbox-inline + .checkbox-inline, .radio-inline + .radio-inline { - margin-top: 0; - margin-left: 10px -} - -.btn-block + .btn-block, .help-block { - margin-top: 5px -} - -.checkbox-inline.disabled, .checkbox.disabled label, .radio-inline.disabled, .radio.disabled label, fieldset[disabled] .checkbox label, fieldset[disabled] .checkbox-inline, fieldset[disabled] .radio label, fieldset[disabled] .radio-inline, fieldset[disabled] input[type=checkbox], fieldset[disabled] input[type=radio], input[type=checkbox].disabled, input[type=checkbox][disabled], input[type=radio].disabled, input[type=radio][disabled] { - cursor: not-allowed -} - -.form-control-static { - padding-top: 7px; - padding-bottom: 7px; - margin-bottom: 0; - min-height: 34px -} - -.form-control-static.input-lg, .form-control-static.input-sm, .input-group-lg > .form-control-static.form-control, .input-group-lg > .form-control-static.input-group-addon, .input-group-lg > .input-group-btn > .form-control-static.btn, .input-group-sm > .form-control-static.form-control, .input-group-sm > .form-control-static.input-group-addon, .input-group-sm > .input-group-btn > .form-control-static.btn { - padding-left: 0; - padding-right: 0 -} - -.input-group-sm > .form-control, .input-group-sm > .input-group-addon, .input-group-sm > .input-group-btn > .btn, .input-sm { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px -} - -.input-group-sm > .input-group-btn > select.btn, .input-group-sm > select.form-control, .input-group-sm > select.input-group-addon, select.input-sm { - height: 30px; - line-height: 30px -} - -.input-group-sm > .input-group-btn > select.btn[multiple], .input-group-sm > .input-group-btn > textarea.btn, .input-group-sm > select.form-control[multiple], .input-group-sm > select.input-group-addon[multiple], .input-group-sm > textarea.form-control, .input-group-sm > textarea.input-group-addon, select[multiple].input-sm, textarea.input-sm { - height: auto -} - -.form-group-sm .form-control { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px -} - -.form-group-sm select.form-control { - height: 30px; - line-height: 30px -} - -.form-group-sm select[multiple].form-control, .form-group-sm textarea.form-control { - height: auto -} - -.form-group-sm .form-control-static { - height: 30px; - min-height: 32px; - padding: 6px 10px; - font-size: 12px; - line-height: 1.5 -} - -.input-group-lg > .form-control, .input-group-lg > .input-group-addon, .input-group-lg > .input-group-btn > .btn, .input-lg { - height: 46px; - padding: 10px 16px; - font-size: 18px; - line-height: 1.33333; - border-radius: 6px -} - -.input-group-lg > .input-group-btn > select.btn, .input-group-lg > select.form-control, .input-group-lg > select.input-group-addon, select.input-lg { - height: 46px; - line-height: 46px -} - -.input-group-lg > .input-group-btn > select.btn[multiple], .input-group-lg > .input-group-btn > textarea.btn, .input-group-lg > select.form-control[multiple], .input-group-lg > select.input-group-addon[multiple], .input-group-lg > textarea.form-control, .input-group-lg > textarea.input-group-addon, select[multiple].input-lg, textarea.input-lg { - height: auto -} - -.form-group-lg .form-control { - height: 46px; - padding: 10px 16px; - font-size: 18px; - line-height: 1.33333; - border-radius: 6px -} - -.form-group-lg select.form-control { - height: 46px; - line-height: 46px -} - -.form-group-lg select[multiple].form-control, .form-group-lg textarea.form-control { - height: auto -} - -.form-group-lg .form-control-static { - height: 46px; - min-height: 38px; - padding: 11px 16px; - font-size: 18px; - line-height: 1.33333 -} - -.has-feedback .form-control { - padding-right: 42.5px -} - -.form-control-feedback { - position: absolute; - top: 0; - right: 0; - z-index: 2; - width: 34px; - height: 34px; - line-height: 34px; - text-align: center; - pointer-events: none -} - -.form-group-lg .form-control + .form-control-feedback, .input-group-lg + .form-control-feedback, .input-group-lg > .form-control + .form-control-feedback, .input-group-lg > .input-group-addon + .form-control-feedback, .input-group-lg > .input-group-btn > .btn + .form-control-feedback, .input-lg + .form-control-feedback { - width: 46px; - height: 46px; - line-height: 46px -} - -.form-group-sm .form-control + .form-control-feedback, .input-group-sm + .form-control-feedback, .input-group-sm > .form-control + .form-control-feedback, .input-group-sm > .input-group-addon + .form-control-feedback, .input-group-sm > .input-group-btn > .btn + .form-control-feedback, .input-sm + .form-control-feedback { - width: 30px; - height: 30px; - line-height: 30px -} - -.has-success .checkbox, .has-success .checkbox-inline, .has-success .control-label, .has-success .help-block, .has-success .radio, .has-success .radio-inline, .has-success.checkbox label, .has-success.checkbox-inline label, .has-success.radio label, .has-success.radio-inline label { - color: #74C080 -} - -.has-success .form-control { - border-color: #74C080; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075) -} - -.has-success .form-control:focus { - border-color: #51b060; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #bae0c0; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #bae0c0 -} - -.has-success .input-group-addon { - color: #74C080; - border-color: #74C080; - background-color: #f8fcf9 -} - -.has-success .form-control-feedback { - color: #74C080 -} - -.has-warning .checkbox, .has-warning .checkbox-inline, .has-warning .control-label, .has-warning .help-block, .has-warning .radio, .has-warning .radio-inline, .has-warning.checkbox label, .has-warning.checkbox-inline label, .has-warning.radio label, .has-warning.radio-inline label { - color: #FA9F47 -} - -.has-warning .form-control { - border-color: #FA9F47; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075) -} - -.has-warning .form-control:focus { - border-color: #f98515; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #fdd3aa; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #fdd3aa -} - -.has-warning .input-group-addon { - color: #FA9F47; - border-color: #FA9F47; - background-color: #fffaf6 -} - -.has-warning .form-control-feedback { - color: #FA9F47 -} - -.has-error .checkbox, .has-error .checkbox-inline, .has-error .control-label, .has-error .help-block, .has-error .radio, .has-error .radio-inline, .has-error.checkbox label, .has-error.checkbox-inline label, .has-error.radio label, .has-error.radio-inline label { - color: #D64242 -} - -.has-error .form-control { - border-color: #D64242; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075) -} - -.has-error .form-control:focus { - border-color: #bc2929; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #e89696; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #e89696 -} - -.has-error .input-group-addon { - color: #D64242; - border-color: #D64242; - background-color: #fdf6f6 -} - -.has-error .form-control-feedback { - color: #D64242 -} - -.has-feedback label ~ .form-control-feedback { - top: 25px -} - -.has-feedback .two-factor-required label ~ .form-control-feedback, .has-feedback label.sr-only ~ .form-control-feedback, .two-factor-required .has-feedback label ~ .form-control-feedback { - top: 0 -} - -.help-block { - margin-bottom: 10px; - color: #7c7c86 -} - -@media (min-width: 768px) { - .form-inline .form-control, .form-inline .form-control-static, .form-inline .form-group { - display: inline-block - } - - .form-inline .checkbox, .form-inline .control-label, .form-inline .form-group, .form-inline .radio { - margin-bottom: 0; - vertical-align: middle - } - - .form-inline .form-control { - width: auto; - vertical-align: middle - } - - .form-inline .input-group { - display: inline-table; - vertical-align: middle - } - - .form-inline .input-group .form-control, .form-inline .input-group .input-group-addon, .form-inline .input-group .input-group-btn { - width: auto - } - - .form-inline .input-group > .form-control { - width: 100% - } - - .form-inline .checkbox, .form-inline .radio { - display: inline-block; - margin-top: 0 - } - - .form-inline .checkbox label, .form-inline .radio label { - padding-left: 0 - } - - .form-inline .checkbox input[type=checkbox], .form-inline .radio input[type=radio] { - position: relative; - margin-left: 0 - } - - .form-inline .has-feedback .form-control-feedback { - top: 0 - } - - .form-horizontal .control-label { - text-align: right; - margin-bottom: 0; - padding-top: 7px - } -} - -.btn-block, input[type=button].btn-block, input[type=reset].btn-block, input[type=submit].btn-block { - width: 100% -} - -.form-horizontal .checkbox, .form-horizontal .checkbox-inline, .form-horizontal .radio, .form-horizontal .radio-inline { - margin-top: 0; - margin-bottom: 0; - padding-top: 7px -} - -.form-horizontal .checkbox, .form-horizontal .radio { - min-height: 27px -} - -.form-horizontal .form-group { - margin-left: -15px; - margin-right: -15px -} - -.form-horizontal .form-group:after, .form-horizontal .form-group:before { - content: " "; - display: table -} - -.form-horizontal .form-group:after { - clear: both -} - -.form-horizontal .has-feedback .form-control-feedback { - right: 15px -} - -@media (min-width: 768px) { - .form-horizontal .form-group-lg .control-label { - padding-top: 11px; - font-size: 18px - } - - .form-horizontal .form-group-sm .control-label { - padding-top: 6px; - font-size: 12px - } -} - -.btn { - display: inline-block; - margin-bottom: 0; - text-align: center; - touch-action: manipulation; - cursor: pointer; - background-image: none; - white-space: nowrap; - padding: 6px 12px; - font-size: 14px; - line-height: 1.42857; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none -} - -.btn.active.focus, .btn.active:focus, .btn.focus, .btn:active.focus, .btn:active:focus, .btn:focus { - outline: -webkit-focus-ring-color auto 5px; - outline-offset: -2px -} - -.btn.focus, .btn:focus, .btn:hover { - color: #79589F; - text-decoration: none -} - -.btn.active, .btn:active { - background-image: none; - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125) -} - -.btn.disabled, .btn[disabled], fieldset[disabled] .btn { - cursor: not-allowed; - filter: alpha(opacity=65); - -webkit-box-shadow: none -} - -a.btn.disabled, fieldset[disabled] a.btn { - pointer-events: none -} - -.btn-default { - color: #79589F; - background-color: #fff; - border-color: #79589F -} - -.btn-default.focus, .btn-default:focus { - color: #79589F; - background-color: #e6e6e6; - border-color: #3b2b4d -} - -.actions-button .btn-default:focus, .btn-default.active, .btn-default:active, .btn-default:hover, .open > .btn-default.drop-down__toggle, .open > .btn-default.dropdown-toggle { - color: #79589F; - background-color: #e6e6e6; - border-color: #5b4278 -} - -.actions-button .btn-default:focus, .actions-button .btn-default:hover:focus, .actions-button .focus.btn-default:focus, .btn-default.active.focus, .btn-default.active:focus, .btn-default.active:hover, .btn-default:active.focus, .btn-default:active:focus, .btn-default:active:hover, .open > .btn-default.drop-down__toggle:focus, .open > .btn-default.drop-down__toggle:hover, .open > .btn-default.dropdown-toggle.focus, .open > .btn-default.dropdown-toggle:focus, .open > .btn-default.dropdown-toggle:hover, .open > .btn-default.focus.drop-down__toggle { - color: #79589F; - background-color: #d4d4d4; - border-color: #3b2b4d -} - -.actions-button .btn-default:focus, .btn-default.active, .btn-default:active, .open > .btn-default.drop-down__toggle, .open > .btn-default.dropdown-toggle { - background-image: none -} - -.btn-default.disabled.focus, .btn-default.disabled:focus, .btn-default.disabled:hover, .btn-default[disabled].focus, .btn-default[disabled]:focus, .btn-default[disabled]:hover, fieldset[disabled] .btn-default.focus, fieldset[disabled] .btn-default:focus, fieldset[disabled] .btn-default:hover { - background-color: #fff; - border-color: #79589F -} - -.btn-default .badge { - color: #fff; - background-color: #79589F -} - -.btn-primary { - border-color: #79589F -} - -.btn-primary.focus, .btn-primary:focus { - color: #fff; - background-color: #60467e; - border-color: #3b2b4d -} - -.btn-primary.active, .btn-primary:active, .btn-primary:hover, .open > .btn-primary.drop-down__toggle, .open > .btn-primary.dropdown-toggle { - border-color: #5b4278 -} - -.btn-primary.active.focus, .btn-primary.active:focus, .btn-primary.active:hover, .btn-primary:active.focus, .btn-primary:active:focus, .btn-primary:active:hover, .open > .btn-primary.drop-down__toggle:focus, .open > .btn-primary.drop-down__toggle:hover, .open > .btn-primary.dropdown-toggle.focus, .open > .btn-primary.dropdown-toggle:focus, .open > .btn-primary.dropdown-toggle:hover, .open > .btn-primary.focus.drop-down__toggle { - color: #fff; - background-color: #4f3967; - border-color: #3b2b4d -} - -.btn-primary.active, .btn-primary:active, .open > .btn-primary.drop-down__toggle, .open > .btn-primary.dropdown-toggle { - background-image: none -} - -.btn-primary.disabled.focus, .btn-primary.disabled:focus, .btn-primary.disabled:hover, .btn-primary[disabled].focus, .btn-primary[disabled]:focus, .btn-primary[disabled]:hover, fieldset[disabled] .btn-primary.focus, fieldset[disabled] .btn-primary:focus, fieldset[disabled] .btn-primary:hover { - background-color: #79589F; - border-color: #79589F -} - -.btn-success { - border-color: #74C080 -} - -.btn-success.focus, .btn-success:focus { - color: #fff; - background-color: #51b060; - border-color: #387c43 -} - -.btn-success.active, .btn-success:active, .btn-success:hover, .open > .btn-success.drop-down__toggle, .open > .btn-success.dropdown-toggle { - border-color: #4daa5c -} - -.btn-success.active.focus, .btn-success.active:focus, .btn-success.active:hover, .btn-success:active.focus, .btn-success:active:focus, .btn-success:active:hover, .open > .btn-success.drop-down__toggle:focus, .open > .btn-success.drop-down__toggle:hover, .open > .btn-success.dropdown-toggle.focus, .open > .btn-success.dropdown-toggle:focus, .open > .btn-success.dropdown-toggle:hover, .open > .btn-success.focus.drop-down__toggle { - color: #fff; - background-color: #459852; - border-color: #387c43 -} - -.btn-success.active, .btn-success:active, .open > .btn-success.drop-down__toggle, .open > .btn-success.dropdown-toggle { - background-image: none -} - -.btn-success.disabled.focus, .btn-success.disabled:focus, .btn-success.disabled:hover, .btn-success[disabled].focus, .btn-success[disabled]:focus, .btn-success[disabled]:hover, fieldset[disabled] .btn-success.focus, fieldset[disabled] .btn-success:focus, fieldset[disabled] .btn-success:hover { - background-color: #74C080; - border-color: #74C080 -} - -.btn-info { - border-color: #408FEC -} - -.btn-info.focus, .btn-info:focus { - color: #fff; - background-color: #1774e2; - border-color: #10519d -} - -.btn-info.active, .btn-info:active, .btn-info:hover, .open > .btn-info.drop-down__toggle, .open > .btn-info.dropdown-toggle { - border-color: #166fd9 -} - -.btn-info.active.focus, .btn-info.active:focus, .btn-info.active:hover, .btn-info:active.focus, .btn-info:active:focus, .btn-info:active:hover, .open > .btn-info.drop-down__toggle:focus, .open > .btn-info.drop-down__toggle:hover, .open > .btn-info.dropdown-toggle.focus, .open > .btn-info.dropdown-toggle:focus, .open > .btn-info.dropdown-toggle:hover, .open > .btn-info.focus.drop-down__toggle { - color: #fff; - background-color: #1364c2; - border-color: #10519d -} - -.btn-info.active, .btn-info:active, .open > .btn-info.drop-down__toggle, .open > .btn-info.dropdown-toggle { - background-image: none -} - -.btn-info.disabled.focus, .btn-info.disabled:focus, .btn-info.disabled:hover, .btn-info[disabled].focus, .btn-info[disabled]:focus, .btn-info[disabled]:hover, fieldset[disabled] .btn-info.focus, fieldset[disabled] .btn-info:focus, fieldset[disabled] .btn-info:hover { - background-color: #408FEC; - border-color: #408FEC -} - -.btn-warning { - border-color: #FA9F47 -} - -.btn-warning.focus, .btn-warning:focus { - color: #fff; - background-color: #f98515; - border-color: #bc5f05 -} - -.btn-warning.active, .btn-warning:active, .btn-warning:hover, .open > .btn-warning.drop-down__toggle, .open > .btn-warning.dropdown-toggle { - border-color: #f8800b -} - -.btn-warning.active.focus, .btn-warning.active:focus, .btn-warning.active:hover, .btn-warning:active.focus, .btn-warning:active:focus, .btn-warning:active:hover, .open > .btn-warning.drop-down__toggle:focus, .open > .btn-warning.drop-down__toggle:hover, .open > .btn-warning.dropdown-toggle.focus, .open > .btn-warning.dropdown-toggle:focus, .open > .btn-warning.dropdown-toggle:hover, .open > .btn-warning.focus.drop-down__toggle { - color: #fff; - background-color: #e47306; - border-color: #bc5f05 -} - -.btn-warning.active, .btn-warning:active, .open > .btn-warning.drop-down__toggle, .open > .btn-warning.dropdown-toggle { - background-image: none -} - -.btn-warning.disabled.focus, .btn-warning.disabled:focus, .btn-warning.disabled:hover, .btn-warning[disabled].focus, .btn-warning[disabled]:focus, .btn-warning[disabled]:hover, fieldset[disabled] .btn-warning.focus, fieldset[disabled] .btn-warning:focus, fieldset[disabled] .btn-warning:hover { - background-color: #FA9F47; - border-color: #FA9F47 -} - -.btn-danger { - border-color: #D64242 -} - -.btn-danger.focus, .btn-danger:focus { - color: #fff; - background-color: #bc2929; - border-color: #7d1b1b -} - -.btn-danger.active, .btn-danger:active, .btn-danger:hover, .open > .btn-danger.drop-down__toggle, .open > .btn-danger.dropdown-toggle { - border-color: #b42727 -} - -.btn-danger.active.focus, .btn-danger.active:focus, .btn-danger.active:hover, .btn-danger:active.focus, .btn-danger:active:focus, .btn-danger:active:hover, .open > .btn-danger.drop-down__toggle:focus, .open > .btn-danger.drop-down__toggle:hover, .open > .btn-danger.dropdown-toggle.focus, .open > .btn-danger.dropdown-toggle:focus, .open > .btn-danger.dropdown-toggle:hover, .open > .btn-danger.focus.drop-down__toggle { - color: #fff; - background-color: #9f2222; - border-color: #7d1b1b -} - -.btn-danger.active, .btn-danger:active, .open > .btn-danger.drop-down__toggle, .open > .btn-danger.dropdown-toggle { - background-image: none -} - -.btn-danger.disabled.focus, .btn-danger.disabled:focus, .btn-danger.disabled:hover, .btn-danger[disabled].focus, .btn-danger[disabled]:focus, .btn-danger[disabled]:hover, fieldset[disabled] .btn-danger.focus, fieldset[disabled] .btn-danger:focus, fieldset[disabled] .btn-danger:hover { - background-color: #D64242; - border-color: #D64242 -} - -.btn-link { - color: #79589F -} - -.btn-link, .btn-link.active, .btn-link:active, .btn-link[disabled], fieldset[disabled] .btn-link { - background-color: transparent; - -webkit-box-shadow: none; - box-shadow: none -} - -.btn-link, .btn-link:active, .btn-link:focus, .btn-link:hover { - border-color: transparent -} - -.btn-link:focus, .btn-link:hover { - color: #61467f; - text-decoration: underline; - background-color: transparent -} - -.btn-link[disabled]:focus, .btn-link[disabled]:hover, fieldset[disabled] .btn-link:focus, fieldset[disabled] .btn-link:hover { - color: #EEF1F6; - text-decoration: none -} - -.btn-group-lg > .btn, .btn-lg { - padding: 10px 16px; - font-size: 18px; - line-height: 1.33333 -} - -.btn-group-sm > .btn, .btn-sm { - padding: 5px 10px; - line-height: 1.5; - border-radius: 3px -} - -.btn-group-xs > .btn, .btn-xs { - padding: 1px 5px; - font-size: 12px; - border-radius: 3px -} - -.fade { - opacity: 0; - -webkit-transition: opacity .15s linear; - -o-transition: opacity .15s linear; - transition: opacity .15s linear -} - -.fade.in { - opacity: 1 -} - -tr.collapse.in { - display: table-row -} - -tbody.collapse.in { - display: table-row-group -} - -.collapsing { - height: 0; - overflow: hidden; - -webkit-transition-property: height, visibility; - transition-property: height, visibility; - -webkit-transition-duration: .35s; - transition-duration: .35s; - -webkit-transition-timing-function: ease; - transition-timing-function: ease -} - -.caret { - display: inline-block; - width: 0; - height: 0; - margin-left: 2px; - border-top: 4px dashed; - border-top: 4px solid \9; - border-right: 4px solid transparent; - border-left: 4px solid transparent -} - -.drop-down__toggle:focus, .dropdown-toggle:focus { - outline: 0 -} - -.context-switcher__list, .drop-down__menu, .dropdown-menu { - position: absolute; - top: 100%; - left: 0; - display: none; - float: left; - min-width: 160px; - padding: 5px 0; - list-style: none; - text-align: left; - background-color: #fff; - border-radius: 4px; - -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175); - background-clip: padding-box -} - -.dropdown-menu-right, .dropdown-menu.pull-right, .pull-right.context-switcher__list, .pull-right.drop-down__menu { - left: auto; - right: 0 -} - -.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child, .btn-group > .btn:last-child:not(:first-child), .btn-group > .drop-down__toggle:not(:first-child), .btn-group > .dropdown-toggle:not(:first-child) { - border-bottom-left-radius: 0; - border-top-left-radius: 0 -} - -.context-switcher__list .divider, .drop-down__menu .divider, .dropdown-menu .divider { - height: 1px; - margin: 9px 0; - overflow: hidden; - background-color: #e7ebf3 -} - -.context-switcher__list > li > a, .drop-down__menu > li > a, .dropdown-menu > li > a { - display: block; - clear: both; - font-weight: 400; - line-height: 1.42857; - color: #596981; - white-space: nowrap -} - -.context-switcher__list > li > a:focus, .context-switcher__list > li > a:hover, .drop-down__menu > li > a:focus, .drop-down__menu > li > a:hover, .dropdown-menu > li > a:focus, .dropdown-menu > li > a:hover { - text-decoration: none; - color: #3F3F44; - background-color: #f7f8fb -} - -.context-switcher__list > .active > a, .context-switcher__list > .active > a:focus, .context-switcher__list > .active > a:hover, .drop-down__menu > .active > a, .drop-down__menu > .active > a:focus, .drop-down__menu > .active > a:hover, .dropdown-menu > .active > a, .dropdown-menu > .active > a:focus, .dropdown-menu > .active > a:hover { - color: #fff; - text-decoration: none; - outline: 0; - background-color: #79589F -} - -.context-switcher__list > .disabled > a, .context-switcher__list > .disabled > a:focus, .context-switcher__list > .disabled > a:hover, .drop-down__menu > .disabled > a, .drop-down__menu > .disabled > a:focus, .drop-down__menu > .disabled > a:hover, .dropdown-menu > .disabled > a, .dropdown-menu > .disabled > a:focus, .dropdown-menu > .disabled > a:hover { - color: #CFD7E6 -} - -.context-switcher__list > .disabled > a:focus, .context-switcher__list > .disabled > a:hover, .drop-down__menu > .disabled > a:focus, .drop-down__menu > .disabled > a:hover, .dropdown-menu > .disabled > a:focus, .dropdown-menu > .disabled > a:hover { - text-decoration: none; - background-color: transparent; - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); - cursor: not-allowed -} - -.open > .context-switcher__list, .open > .drop-down__menu, .open > .dropdown-menu { - display: block -} - -.open > a { - outline: 0 -} - -.dropdown-menu-left { - left: 0; - right: auto -} - -.dropdown-header { - display: block; - padding: 3px 20px; - font-size: 12px; - line-height: 1.42857; - color: #CFD7E6; - white-space: nowrap -} - -.badge, .input-group-addon, .label { - line-height: 1; - text-align: center -} - -.dropdown-backdrop { - position: fixed; - left: 0; - right: 0; - bottom: 0; - top: 0; - z-index: 990 -} - -.pull-right > .context-switcher__list, .pull-right > .drop-down__menu, .pull-right > .dropdown-menu { - right: 0; - left: auto -} - -.dropup .caret, .navbar-fixed-bottom .dropdown .caret { - border-top: 0; - border-bottom: 4px dashed; - border-bottom: 4px solid \9; - content: "" -} - -.dropup .context-switcher__list, .dropup .drop-down__menu, .dropup .dropdown-menu, .navbar-fixed-bottom .dropdown .context-switcher__list, .navbar-fixed-bottom .dropdown .drop-down__menu, .navbar-fixed-bottom .dropdown .dropdown-menu { - top: auto; - bottom: 100%; - margin-bottom: 2px -} - -@media (min-width: 768px) { - .navbar-right .context-switcher__list, .navbar-right .drop-down__menu, .navbar-right .dropdown-menu { - right: 0; - left: auto - } - - .navbar-right .dropdown-menu-left { - left: 0; - right: auto - } -} - -.btn-group, .btn-group-vertical { - position: relative; - display: inline-block -} - -.btn-group-vertical > .btn, .btn-group > .btn { - position: relative; - float: left -} - -.btn-group-vertical > .btn.active, .btn-group-vertical > .btn:active, .btn-group-vertical > .btn:focus, .btn-group-vertical > .btn:hover, .btn-group > .btn.active, .btn-group > .btn:active, .btn-group > .btn:focus, .btn-group > .btn:hover { - z-index: 2 -} - -.btn-group .btn + .btn, .btn-group .btn + .btn-group, .btn-group .btn-group + .btn, .btn-group .btn-group + .btn-group { - margin-left: -1px -} - -.btn-toolbar { - margin-left: -5px -} - -.btn-toolbar:after, .btn-toolbar:before { - content: " "; - display: table -} - -.btn-toolbar:after { - clear: both -} - -.btn-toolbar .btn, .btn-toolbar .btn-group, .btn-toolbar .input-group { - float: left -} - -.btn-toolbar > .btn, .btn-toolbar > .btn-group, .btn-toolbar > .input-group { - margin-left: 5px -} - -.btn-group > .btn:first-child { - margin-left: 0 -} - -.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle):not(.drop-down__toggle) { - border-bottom-right-radius: 0; - border-top-right-radius: 0 -} - -.btn-group > .btn-group { - float: left -} - -.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child, .btn-group > .btn-group:first-child:not(:last-child) > .drop-down__toggle, .btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle { - border-bottom-right-radius: 0; - border-top-right-radius: 0 -} - -.btn-group .drop-down__toggle:active, .btn-group .dropdown-toggle:active, .btn-group.open .drop-down__toggle, .btn-group.open .dropdown-toggle { - outline: 0 -} - -.btn-group > .btn + .drop-down__toggle, .btn-group > .btn + .dropdown-toggle { - padding-left: 8px; - padding-right: 8px -} - -.btn-group-lg.btn-group > .btn + .drop-down__toggle, .btn-group-lg.btn-group > .btn + .dropdown-toggle, .btn-group > .btn-lg + .drop-down__toggle, .btn-group > .btn-lg + .dropdown-toggle { - padding-left: 12px; - padding-right: 12px -} - -.btn-group.open .drop-down__toggle, .btn-group.open .dropdown-toggle { - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125) -} - -.btn-group.open .btn-link.drop-down__toggle, .btn-group.open .dropdown-toggle.btn-link { - -webkit-box-shadow: none; - box-shadow: none -} - -.btn .caret { - margin-left: 0 -} - -.btn-group-lg > .btn .caret, .btn-lg .caret { - border-width: 5px 5px 0 -} - -.dropup .btn-group-lg > .btn .caret, .dropup .btn-lg .caret { - border-width: 0 5px 5px -} - -.btn-group-vertical > .btn, .btn-group-vertical > .btn-group, .btn-group-vertical > .btn-group > .btn { - display: block; - float: none; - width: 100%; - max-width: 100% -} - -.media-object.img-thumbnail, .metrics__datastore-chart-switcher .metrics__process-switcher__item-link.active .metrics__process-switcher__item-header, .metrics__datastore-chart-switcher button.metrics__process-switcher__btn, .metrics__datastore-chart-switcher ul.metrics__process-switcher__menu, .nav > li > a > img { - max-width: none -} - -.btn-group-vertical > .btn-group:after, .btn-group-vertical > .btn-group:before { - content: " "; - display: table -} - -.btn-group-vertical > .btn-group:after { - clear: both -} - -.btn-group-vertical > .btn-group > .btn { - float: none -} - -.btn-group-vertical > .btn + .btn, .btn-group-vertical > .btn + .btn-group, .btn-group-vertical > .btn-group + .btn, .btn-group-vertical > .btn-group + .btn-group { - margin-top: -1px; - margin-left: 0 -} - -.btn-group-vertical > .btn:first-child:not(:last-child) { - border-radius: 4px 4px 0 0 -} - -.btn-group-vertical > .btn:last-child:not(:first-child) { - border-radius: 0 0 4px 4px -} - -.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn, .input-group .form-control:not(:first-child):not(:last-child), .input-group-addon:not(:first-child):not(:last-child), .input-group-btn:not(:first-child):not(:last-child) { - border-radius: 0 -} - -.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child, .btn-group-vertical > .btn-group:first-child:not(:last-child) > .drop-down__toggle, .btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle { - border-bottom-right-radius: 0; - border-bottom-left-radius: 0 -} - -.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { - border-top-right-radius: 0; - border-top-left-radius: 0 -} - -.btn-group-justified { - display: table; - width: 100%; - table-layout: fixed; - border-collapse: separate -} - -.btn-group-justified > .btn, .btn-group-justified > .btn-group { - float: none; - display: table-cell; - width: 1% -} - -.btn-group-justified > .btn-group .btn { - width: 100% -} - -.btn-group-justified > .btn-group .context-switcher__list, .btn-group-justified > .btn-group .drop-down__menu, .btn-group-justified > .btn-group .dropdown-menu { - left: auto -} - -[data-toggle=buttons] > .btn input[type=checkbox], [data-toggle=buttons] > .btn input[type=radio], [data-toggle=buttons] > .btn-group > .btn input[type=checkbox], [data-toggle=buttons] > .btn-group > .btn input[type=radio] { - position: absolute; - clip: rect(0, 0, 0, 0); - pointer-events: none -} - -.input-group { - position: relative; - display: table; - border-collapse: separate -} - -.input-group[class*=col-] { - float: none; - padding-left: 0; - padding-right: 0 -} - -.input-group .form-control { - position: relative; - z-index: 2; - float: left; - width: 100%; - margin-bottom: 0 -} - -.input-group .form-control:focus { - z-index: 3 -} - -.input-group .form-control, .input-group-addon, .input-group-btn { - display: table-cell -} - -.input-group-addon, .input-group-btn { - width: 1%; - white-space: nowrap -} - -.input-group-addon { - padding: 6px 12px; - font-size: 14px; - font-weight: 400; - color: #3F3F44; - background-color: #EEF1F6; - border: 1px solid #CFD7E6; - border-radius: 4px -} - -.input-group-addon.input-sm, .input-group-sm > .input-group-addon, .input-group-sm > .input-group-btn > .input-group-addon.btn { - padding: 5px 10px; - font-size: 12px; - border-radius: 3px -} - -.input-group-addon.input-lg, .input-group-lg > .input-group-addon, .input-group-lg > .input-group-btn > .input-group-addon.btn { - padding: 10px 16px; - font-size: 18px; - border-radius: 6px -} - -.input-group-addon input[type=checkbox], .input-group-addon input[type=radio] { - margin-top: 0 -} - -.input-group .form-control:first-child, .input-group-addon:first-child, .input-group-btn:first-child > .btn, .input-group-btn:first-child > .btn-group > .btn, .input-group-btn:first-child > .drop-down__toggle, .input-group-btn:first-child > .dropdown-toggle, .input-group-btn:last-child > .btn-group:not(:last-child) > .btn, .input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle):not(.drop-down__toggle) { - border-bottom-right-radius: 0; - border-top-right-radius: 0 -} - -.input-group-addon:first-child { - border-right: 0 -} - -.input-group .form-control:last-child, .input-group-addon:last-child, .input-group-btn:first-child > .btn-group:not(:first-child) > .btn, .input-group-btn:first-child > .btn:not(:first-child), .input-group-btn:last-child > .btn, .input-group-btn:last-child > .btn-group > .btn, .input-group-btn:last-child > .drop-down__toggle, .input-group-btn:last-child > .dropdown-toggle { - border-bottom-left-radius: 0; - border-top-left-radius: 0 -} - -.input-group-addon:last-child { - border-left: 0 -} - -.input-group-btn { - position: relative; - font-size: 0; - white-space: nowrap -} - -.input-group-btn > .btn { - position: relative -} - -.input-group-btn > .btn + .btn { - margin-left: -1px -} - -.input-group-btn > .btn:active, .input-group-btn > .btn:focus, .input-group-btn > .btn:hover { - z-index: 2 -} - -.input-group-btn:first-child > .btn, .input-group-btn:first-child > .btn-group { - margin-right: -1px -} - -.input-group-btn:last-child > .btn, .input-group-btn:last-child > .btn-group { - z-index: 2; - margin-left: -1px -} - -.nav { - margin-bottom: 0; - padding-left: 0; - list-style: none -} - -.nav:after, .nav:before { - content: " "; - display: table -} - -.nav > li, .nav > li > a { - display: block; - position: relative -} - -.nav:after { - clear: both -} - -.nav > li > a { - padding: 10px 15px -} - -.nav > li > a:focus, .nav > li > a:hover { - text-decoration: none; - background-color: #EEF1F6 -} - -.nav > li.disabled > a { - color: #CFD7E6 -} - -.nav > li.disabled > a:focus, .nav > li.disabled > a:hover { - color: #CFD7E6; - text-decoration: none; - background-color: transparent; - cursor: not-allowed -} - -.nav .open > a, .nav .open > a:focus, .nav .open > a:hover { - background-color: #EEF1F6; - border-color: #79589F -} - -.nav .nav-divider { - height: 1px; - margin: 9px 0; - overflow: hidden; - background-color: #e5e5e5 -} - -.btn-group-sm > .btn .icon, .btn-sm .icon, .nav-tabs > li > a { - margin-right: 2px -} - -.nav-tabs { - border-bottom: 1px solid #ddd -} - -.nav-tabs > li { - float: left; - margin-bottom: -1px -} - -.nav-tabs > li > a { - line-height: 1.42857; - border: 1px solid transparent; - border-radius: 4px 4px 0 0 -} - -.nav-tabs > li > a:hover { - border-color: #EEF1F6 #EEF1F6 #ddd -} - -.nav-tabs > li.active > a, .nav-tabs > li.active > a:focus, .nav-tabs > li.active > a:hover { - color: #96A3B6; - background-color: #fff; - border: 1px solid #ddd; - border-bottom-color: transparent; - cursor: default -} - -.nav-pills > li { - float: left -} - -.nav-justified > li, .nav-stacked > li, .nav-tabs.nav-justified > li { - float: none -} - -.nav-pills > li > a { - border-radius: 4px -} - -.nav-pills > li + li { - margin-left: 2px -} - -.nav-pills > li.active > a, .nav-pills > li.active > a:focus, .nav-pills > li.active > a:hover { - color: #fff; - background-color: #79589F -} - -.nav-stacked > li + li { - margin-top: 2px; - margin-left: 0 -} - -.nav-justified, .nav-tabs.nav-justified { - width: 100% -} - -.nav-justified > li > a, .nav-tabs.nav-justified > li > a { - text-align: center; - margin-bottom: 5px -} - -.nav-justified > .dropdown .context-switcher__list, .nav-justified > .dropdown .drop-down__menu, .nav-justified > .dropdown .dropdown-menu { - top: auto; - left: auto -} - -@media (min-width: 768px) { - .nav-justified > li, .nav-tabs.nav-justified > li { - display: table-cell; - width: 1% - } - - .nav-justified > li > a, .nav-tabs.nav-justified > li > a { - margin-bottom: 0 - } -} - -.alert, .breadcrumb { - margin-bottom: 20px -} - -.nav-tabs-justified, .nav-tabs.nav-justified { - border-bottom: 0 -} - -.nav-tabs-justified > li > a, .nav-tabs.nav-justified > li > a { - margin-right: 0; - border-radius: 4px -} - -.nav-tabs-justified > .active > a, .nav-tabs-justified > .active > a:focus, .nav-tabs-justified > .active > a:hover, .nav-tabs.nav-justified > .active > a, .nav-tabs.nav-justified > .active > a:focus, .nav-tabs.nav-justified > .active > a:hover { - border: 1px solid #ddd -} - -@media (min-width: 768px) { - .nav-tabs-justified > li > a, .nav-tabs.nav-justified > li > a { - border-bottom: 1px solid #ddd; - border-radius: 4px 4px 0 0 - } - - .nav-tabs-justified > .active > a, .nav-tabs-justified > .active > a:focus, .nav-tabs-justified > .active > a:hover, .nav-tabs.nav-justified > .active > a, .nav-tabs.nav-justified > .active > a:focus, .nav-tabs.nav-justified > .active > a:hover { - border-bottom-color: #fff - } -} - -.tab-content > .tab-pane { - display: none -} - -.tab-content > .active { - display: block -} - -.breadcrumb > li, .pagination { - display: inline-block -} - -.nav-tabs .context-switcher__list, .nav-tabs .drop-down__menu, .nav-tabs .dropdown-menu { - margin-top: -1px; - border-top-right-radius: 0; - border-top-left-radius: 0 -} - -.breadcrumb { - padding: 8px 15px; - list-style: none; - background-color: #f5f5f5; - border-radius: 4px -} - -.breadcrumb > li + li:before { - content: "/ "; - padding: 0 5px; - color: #ccc -} - -.breadcrumb > .active { - color: #CFD7E6 -} - -.pagination { - padding-left: 0; - margin: 20px 0; - border-radius: 4px -} - -.pagination > li { - display: inline -} - -.pagination > li > a, .pagination > li > span { - position: relative; - float: left; - padding: 6px 12px; - line-height: 1.42857; - text-decoration: none; - color: #79589F; - background-color: #fff; - border: 1px solid #ddd; - margin-left: -1px -} - -.pagination > li:first-child > a, .pagination > li:first-child > span { - margin-left: 0; - border-bottom-left-radius: 4px; - border-top-left-radius: 4px -} - -.pagination > li:last-child > a, .pagination > li:last-child > span { - border-bottom-right-radius: 4px; - border-top-right-radius: 4px -} - -.pagination > li > a:focus, .pagination > li > a:hover, .pagination > li > span:focus, .pagination > li > span:hover { - z-index: 2; - color: #61467f; - background-color: #EEF1F6; - border-color: #ddd -} - -.pagination > .active > a, .pagination > .active > a:focus, .pagination > .active > a:hover, .pagination > .active > span, .pagination > .active > span:focus, .pagination > .active > span:hover { - z-index: 3; - color: #fff; - background-color: #79589F; - border-color: #79589F; - cursor: default -} - -.pagination > .disabled > a, .pagination > .disabled > a:focus, .pagination > .disabled > a:hover, .pagination > .disabled > span, .pagination > .disabled > span:focus, .pagination > .disabled > span:hover { - color: #CFD7E6; - background-color: #fff; - border-color: #ddd; - cursor: not-allowed -} - -.pagination-lg > li > a, .pagination-lg > li > span { - padding: 10px 16px; - font-size: 18px; - line-height: 1.33333 -} - -.hk-braintree-hosted-fields, .pagination-sm > li > a, .pagination-sm > li > span { - padding: 5px 10px; - padding: 5px 10px; - padding: 5px 10px -} - -.pagination-lg > li:first-child > a, .pagination-lg > li:first-child > span { - border-bottom-left-radius: 6px; - border-top-left-radius: 6px -} - -.pagination-lg > li:last-child > a, .pagination-lg > li:last-child > span { - border-bottom-right-radius: 6px; - border-top-right-radius: 6px -} - -.pagination-sm > li > a, .pagination-sm > li > span { - font-size: 12px; - line-height: 1.5 -} - -.pagination-sm > li:first-child > a, .pagination-sm > li:first-child > span { - border-bottom-left-radius: 3px; - border-top-left-radius: 3px -} - -.pagination-sm > li:last-child > a, .pagination-sm > li:last-child > span { - border-bottom-right-radius: 3px; - border-top-right-radius: 3px -} - -.pager { - padding-left: 0; - margin: 20px 0; - list-style: none; - text-align: center -} - -.pager:after, .pager:before { - content: " "; - display: table -} - -.pager:after { - clear: both -} - -.pager li { - display: inline -} - -.pager li > a, .pager li > span { - display: inline-block; - padding: 5px 14px; - background-color: #fff; - border: 1px solid #ddd; - border-radius: 15px -} - -.pager li > a:focus, .pager li > a:hover { - text-decoration: none; - background-color: #EEF1F6 -} - -.pager .next > a, .pager .next > span { - float: right -} - -.pager .previous > a, .pager .previous > span { - float: left -} - -.pager .disabled > a, .pager .disabled > a:focus, .pager .disabled > a:hover, .pager .disabled > span { - color: #CFD7E6; - background-color: #fff; - cursor: not-allowed -} - -.label { - display: inline; - padding: .2em .6em .3em; - color: #fff; - white-space: nowrap; - border-radius: .25em -} - -.label:empty { - display: none -} - -.btn .label { - position: relative; - top: -1px -} - -a.label:focus, a.label:hover { - color: #fff; - text-decoration: none; - cursor: pointer -} - -.label-default[href]:focus, .label-default[href]:hover { - background-color: #adbbd5 -} - -.label-primary[href]:focus, .label-primary[href]:hover { - background-color: #60467e -} - -.label-success[href]:focus, .label-success[href]:hover { - background-color: #51b060 -} - -.label-info[href]:focus, .label-info[href]:hover { - background-color: #1774e2 -} - -.label-warning[href]:focus, .label-warning[href]:hover { - background-color: #f98515 -} - -.label-danger[href]:focus, .label-danger[href]:hover { - background-color: #bc2929 -} - -.badge { - display: inline-block; - min-width: 10px; - padding: 3px 7px; - font-size: 12px; - color: #fff; - vertical-align: middle; - white-space: nowrap; - background-color: #CFD7E6; - border-radius: 10px -} - -.badge:empty, .modal { - display: none -} - -.btn .badge { - position: relative; - top: -1px -} - -.btn-group-xs > .btn .badge, .btn-xs .badge { - top: 0; - padding: 1px 5px -} - -.list-group-item.active > .badge, .nav-pills > .active > a > .badge { - color: #79589F; - background-color: #fff -} - -.list-group-item > .badge { - float: right -} - -.list-group-item > .badge + .badge { - margin-right: 5px -} - -.nav-pills > li > a > .badge { - margin-left: 3px -} - -a.badge:focus, a.badge:hover { - color: #fff; - text-decoration: none; - cursor: pointer -} - -.alert { - padding: 10px; - border: 1px solid transparent; - border-radius: 4px -} - -.alert .dyno-tier-picker-item-size-name, .alert .panel-section .panel-title, .alert h4, .panel-section .alert .panel-title { - margin-top: 0; - color: inherit -} - -.alert > p + p, .panel-group .panel + .panel, .panel-section .alert > .panel-details + .panel-details, .panel-section .alert > .panel-details + p, .panel-section .alert > p + .panel-details { - margin-top: 5px -} - -.alert .alert-link { - font-weight: 400 -} - -.alert > p, .alert > ul, .panel-section .alert > .panel-details { - margin-bottom: 0 -} - -.alert-dismissable, .alert-dismissible { - padding-right: 30px -} - -.alert-dismissable .close, .alert-dismissible .close { - position: relative; - top: -2px; - right: -21px; - color: inherit -} - -.modal, .modal-backdrop { - top: 0; - right: 0; - bottom: 0; - left: 0 -} - -.alert-success { - background-color: #f8fcf9; - border-color: #c7e6cc -} - -.alert-success hr { - border-top-color: #b5debc -} - -.alert-success .alert-link { - color: #51b060 -} - -.alert-info { - background-color: #f5f9fe; - border-color: #b3d2f7 -} - -.alert-info hr { - border-top-color: #9cc4f5 -} - -.alert-info .alert-link { - color: #1774e2 -} - -.alert-warning { - background-color: #fffaf6; - border-color: #fdd9b5 -} - -.alert-warning hr { - border-top-color: #fccc9c -} - -.alert-warning .alert-link { - color: #f98515 -} - -.alert-danger { - background-color: #fdf6f6; - border-color: #efb3b3 -} - -.alert-danger hr { - border-top-color: #eb9e9e -} - -.alert-danger .alert-link { - color: #bc2929 -} - -.media { - margin-top: 15px -} - -.media:first-child { - margin-top: 0 -} - -.media, .media-body { - zoom: 1; - overflow: hidden -} - -.media-body { - width: 10000px -} - -.media-object { - display: block -} - -.media-right, .media > .pull-right { - padding-left: 10px -} - -.media-left, .media > .pull-left { - padding-right: 10px -} - -.media-body, .media-left, .media-right { - display: table-cell; - vertical-align: top -} - -.btn .icon, .loading-spinner, .media-middle, .nav.sub-nav a i, .nav.sub-nav a > a, .spinner, table.editable-list tr > td, table.static-list tr > td { - vertical-align: middle -} - -.media-bottom { - vertical-align: bottom -} - -.media-heading { - margin-top: 0; - margin-bottom: 5px -} - -.media-list { - padding-left: 0; - list-style: none -} - -.list-group { - margin-bottom: 20px; - padding-left: 0 -} - -.list-group-item { - position: relative; - display: block; - margin-bottom: -1px; - background-color: #fff; - border: 1px solid #e7ebf3 -} - -.list-group-item:first-child { - border-top-right-radius: none; - border-top-left-radius: none -} - -.list-group-item:last-child { - margin-bottom: 0; - border-bottom-right-radius: none; - border-bottom-left-radius: none -} - -a.list-group-item, button.list-group-item { - color: #555 -} - -a.list-group-item .list-group-item-heading, button.list-group-item .list-group-item-heading { - color: #3F3F44 -} - -a.list-group-item:focus, a.list-group-item:hover, button.list-group-item:focus, button.list-group-item:hover { - text-decoration: none; - color: #555; - background-color: #f7f8fb -} - -button.list-group-item { - width: 100%; - text-align: left -} - -.list-group-item.disabled, .list-group-item.disabled:focus, .list-group-item.disabled:hover { - background-color: #EEF1F6; - color: #CFD7E6; - cursor: not-allowed -} - -.list-group-item.disabled .list-group-item-heading, .list-group-item.disabled:focus .list-group-item-heading, .list-group-item.disabled:hover .list-group-item-heading { - color: inherit -} - -.list-group-item.disabled .list-group-item-text, .list-group-item.disabled:focus .list-group-item-text, .list-group-item.disabled:hover .list-group-item-text { - color: #CFD7E6 -} - -.list-group-item.active, .list-group-item.active:focus, .list-group-item.active:hover { - z-index: 2; - color: #408FEC; - background-color: #fff; - border-color: #e7ebf3 -} - -.list-group-item.active .list-group-item-heading, .list-group-item.active .list-group-item-heading > .small, .list-group-item.active .list-group-item-heading > small, .list-group-item.active .panel-section .list-group-item-heading > .panel-details, .list-group-item.active:focus .list-group-item-heading, .list-group-item.active:focus .list-group-item-heading > .small, .list-group-item.active:focus .list-group-item-heading > small, .list-group-item.active:focus .panel-section .list-group-item-heading > .panel-details, .list-group-item.active:hover .list-group-item-heading, .list-group-item.active:hover .list-group-item-heading > .small, .list-group-item.active:hover .list-group-item-heading > small, .list-group-item.active:hover .panel-section .list-group-item-heading > .panel-details, .panel-section .list-group-item.active .list-group-item-heading > .panel-details, .panel-section .list-group-item.active:focus .list-group-item-heading > .panel-details, .panel-section .list-group-item.active:hover .list-group-item-heading > .panel-details { - color: inherit -} - -.list-group-item.active .list-group-item-text, .list-group-item.active:focus .list-group-item-text, .list-group-item.active:hover .list-group-item-text { - color: #408FEC -} - -.list-group-item-success { - color: #74C080; - background-color: #f8fcf9 -} - -a.list-group-item-success, button.list-group-item-success { - color: #74C080 -} - -a.list-group-item-success .list-group-item-heading, button.list-group-item-success .list-group-item-heading { - color: inherit -} - -a.list-group-item-success:focus, a.list-group-item-success:hover, button.list-group-item-success:focus, button.list-group-item-success:hover { - color: #74C080; - background-color: #e6f4ea -} - -a.list-group-item-success.active, a.list-group-item-success.active:focus, a.list-group-item-success.active:hover, button.list-group-item-success.active, button.list-group-item-success.active:focus, button.list-group-item-success.active:hover { - color: #fff; - background-color: #74C080; - border-color: #74C080 -} - -.list-group-item-info { - color: #408FEC; - background-color: #f5f9fe -} - -a.list-group-item-info, button.list-group-item-info { - color: #408FEC -} - -a.list-group-item-info .list-group-item-heading, button.list-group-item-info .list-group-item-heading { - color: inherit -} - -a.list-group-item-info:focus, a.list-group-item-info:hover, button.list-group-item-info:focus, button.list-group-item-info:hover { - color: #408FEC; - background-color: #deebfc -} - -a.list-group-item-info.active, a.list-group-item-info.active:focus, a.list-group-item-info.active:hover, button.list-group-item-info.active, button.list-group-item-info.active:focus, button.list-group-item-info.active:hover { - color: #fff; - background-color: #408FEC; - border-color: #408FEC -} - -.list-group-item-warning { - color: #FA9F47; - background-color: #fffaf6 -} - -a.list-group-item-warning, button.list-group-item-warning { - color: #FA9F47 -} - -a.list-group-item-warning .list-group-item-heading, button.list-group-item-warning .list-group-item-heading { - color: inherit -} - -a.list-group-item-warning:focus, a.list-group-item-warning:hover, button.list-group-item-warning:focus, button.list-group-item-warning:hover { - color: #FA9F47; - background-color: #ffecdd -} - -a.list-group-item-warning.active, a.list-group-item-warning.active:focus, a.list-group-item-warning.active:hover, button.list-group-item-warning.active, button.list-group-item-warning.active:focus, button.list-group-item-warning.active:hover { - color: #fff; - background-color: #FA9F47; - border-color: #FA9F47 -} - -.list-group-item-danger { - color: #D64242; - background-color: #fdf6f6 -} - -a.list-group-item-danger, button.list-group-item-danger { - color: #D64242 -} - -a.list-group-item-danger .list-group-item-heading, button.list-group-item-danger .list-group-item-heading { - color: inherit -} - -a.list-group-item-danger:focus, a.list-group-item-danger:hover, button.list-group-item-danger:focus, button.list-group-item-danger:hover { - color: #D64242; - background-color: #f8e1e1 -} - -a.list-group-item-danger.active, a.list-group-item-danger.active:focus, a.list-group-item-danger.active:hover, button.list-group-item-danger.active, button.list-group-item-danger.active:focus, button.list-group-item-danger.active:hover { - color: #fff; - background-color: #D64242; - border-color: #D64242 -} - -.panel-heading > .dropdown .drop-down__toggle, .panel-heading > .dropdown .dropdown-toggle, .panel-section .panel-title > .panel-details, .panel-section .panel-title > .panel-details > a, .panel-title, .panel-title > .small, .panel-title > .small > a, .panel-title > a, .panel-title > small, .panel-title > small > a { - color: inherit -} - -.list-group-item-heading { - margin-top: 0; - margin-bottom: 5px -} - -.list-group-item-text { - margin-bottom: 0; - line-height: 1.3 -} - -.panel { - margin-bottom: 20px; - background-color: #fff; - border: 1px solid transparent; - border-radius: 4px; - -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05); - box-shadow: 0 1px 1px rgba(0, 0, 0, .05) -} - -.panel-title, .panel > .list-group, .panel > .panel-collapse > .list-group, .panel > .panel-collapse > .table, .panel > .table, .panel > .table-responsive, .panel > .table-responsive > .table { - margin-bottom: 0 -} - -.panel-body { - padding: 15px -} - -.panel-body:after, .panel-body:before { - content: " "; - display: table -} - -.panel-body:after { - clear: both -} - -.panel-heading { - padding: 10px 15px; - border-bottom: 1px solid transparent; - border-top-right-radius: 3px; - border-top-left-radius: 3px -} - -.panel-title { - margin-top: 0; - font-size: 16px -} - -.panel-footer { - padding: 10px 15px; - background-color: #f5f5f5; - border-top: 1px solid #ddd; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px -} - -.panel > .list-group .list-group-item, .panel > .panel-collapse > .list-group .list-group-item { - border-width: 1px 0; - border-radius: 0 -} - -.panel > .list-group:first-child .list-group-item:first-child, .panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { - border-top: 0; - border-top-right-radius: 3px; - border-top-left-radius: 3px -} - -.panel > .list-group:last-child .list-group-item:last-child, .panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { - border-bottom: 0; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px -} - -.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child { - border-top-right-radius: 0; - border-top-left-radius: 0 -} - -.list-group + .panel-footer, .panel-heading + .list-group .list-group-item:first-child { - border-top-width: 0 -} - -.panel > .panel-collapse > .table caption, .panel > .table caption, .panel > .table-responsive > .table caption { - padding-left: 15px; - padding-right: 15px -} - -.panel > .table-responsive:first-child > .table:first-child, .panel > .table:first-child { - border-top-right-radius: 3px; - border-top-left-radius: 3px -} - -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, .panel > .table:first-child > tbody:first-child > tr:first-child, .panel > .table:first-child > thead:first-child > tr:first-child { - border-top-left-radius: 3px; - border-top-right-radius: 3px -} - -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, .panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, .panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, .panel > .table:first-child > thead:first-child > tr:first-child td:first-child, .panel > .table:first-child > thead:first-child > tr:first-child th:first-child { - border-top-left-radius: 3px -} - -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, .panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, .panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, .panel > .table:first-child > thead:first-child > tr:first-child td:last-child, .panel > .table:first-child > thead:first-child > tr:first-child th:last-child { - border-top-right-radius: 3px -} - -.panel > .table-responsive:last-child > .table:last-child, .panel > .table:last-child { - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px -} - -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child, .panel > .table:last-child > tbody:last-child > tr:last-child, .panel > .table:last-child > tfoot:last-child > tr:last-child { - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px -} - -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child, .panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, .panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, .panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, .panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child { - border-bottom-left-radius: 3px -} - -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child, .panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, .panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, .panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, .panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child { - border-bottom-right-radius: 3px -} - -.panel > .panel-body + .table, .panel > .panel-body + .table-responsive, .panel > .table + .panel-body, .panel > .table-responsive + .panel-body { - border-top: 1px solid #e7ebf3 -} - -.panel > .table > tbody:first-child > tr:first-child td, .panel > .table > tbody:first-child > tr:first-child th { - border-top: 0 -} - -.panel > .table-bordered, .panel > .table-responsive > .table-bordered { - border: 0 -} - -.panel > .table-bordered > tbody > tr > td:first-child, .panel > .table-bordered > tbody > tr > th:first-child, .panel > .table-bordered > tfoot > tr > td:first-child, .panel > .table-bordered > tfoot > tr > th:first-child, .panel > .table-bordered > thead > tr > td:first-child, .panel > .table-bordered > thead > tr > th:first-child, .panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, .panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, .panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child, .panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, .panel > .table-responsive > .table-bordered > thead > tr > td:first-child, .panel > .table-responsive > .table-bordered > thead > tr > th:first-child { - border-left: 0 -} - -.panel > .table-bordered > tbody > tr > td:last-child, .panel > .table-bordered > tbody > tr > th:last-child, .panel > .table-bordered > tfoot > tr > td:last-child, .panel > .table-bordered > tfoot > tr > th:last-child, .panel > .table-bordered > thead > tr > td:last-child, .panel > .table-bordered > thead > tr > th:last-child, .panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, .panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, .panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child, .panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, .panel > .table-responsive > .table-bordered > thead > tr > td:last-child, .panel > .table-responsive > .table-bordered > thead > tr > th:last-child { - border-right: 0 -} - -.panel > .table-bordered > tbody > tr:first-child > td, .panel > .table-bordered > tbody > tr:first-child > th, .panel > .table-bordered > tbody > tr:last-child > td, .panel > .table-bordered > tbody > tr:last-child > th, .panel > .table-bordered > tfoot > tr:last-child > td, .panel > .table-bordered > tfoot > tr:last-child > th, .panel > .table-bordered > thead > tr:first-child > td, .panel > .table-bordered > thead > tr:first-child > th, .panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, .panel > .table-responsive > .table-bordered > tbody > tr:first-child > th, .panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, .panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th, .panel > .table-responsive > .table-bordered > thead > tr:first-child > td, .panel > .table-responsive > .table-bordered > thead > tr:first-child > th { - border-bottom: 0 -} - -.panel > .table-responsive { - border: 0 -} - -.panel-group { - margin-bottom: 20px -} - -.panel-group .panel { - margin-bottom: 0; - border-radius: 4px -} - -.panel-group .panel-heading { - border-bottom: 0 -} - -.panel-group .panel-heading + .panel-collapse > .list-group, .panel-group .panel-heading + .panel-collapse > .panel-body { - border-top: 1px solid #ddd -} - -.panel-group .panel-footer { - border-top: 0 -} - -.panel-group .panel-footer + .panel-collapse .panel-body { - border-bottom: 1px solid #ddd -} - -.panel-default { - border-color: #ddd -} - -.panel-default > .panel-heading { - color: #596981; - background-color: #f5f5f5; - border-color: #ddd -} - -.panel-default > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #ddd -} - -.panel-default > .panel-heading .badge { - color: #f5f5f5; - background-color: #596981 -} - -.panel-default > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #ddd -} - -.panel-primary { - border-color: #79589F -} - -.panel-primary > .panel-heading { - color: #fff; - background-color: #79589F; - border-color: #79589F -} - -.panel-primary > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #79589F -} - -.panel-primary > .panel-heading .badge { - color: #79589F; - background-color: #fff -} - -.panel-primary > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #79589F -} - -.panel-success { - border-color: #c7e6cc -} - -.panel-success > .panel-heading { - color: #74C080; - background-color: #f8fcf9; - border-color: #c7e6cc -} - -.panel-success > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #c7e6cc -} - -.panel-success > .panel-heading .badge { - color: #f8fcf9; - background-color: #74C080 -} - -.panel-success > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #c7e6cc -} - -.panel-info { - border-color: #b3d2f7 -} - -.panel-info > .panel-heading { - color: #408FEC; - background-color: #f5f9fe; - border-color: #b3d2f7 -} - -.panel-info > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #b3d2f7 -} - -.panel-info > .panel-heading .badge { - color: #f5f9fe; - background-color: #408FEC -} - -.panel-info > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #b3d2f7 -} - -.panel-warning { - border-color: #fdd9b5 -} - -.panel-warning > .panel-heading { - color: #FA9F47; - background-color: #fffaf6; - border-color: #fdd9b5 -} - -.panel-warning > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #fdd9b5 -} - -.panel-warning > .panel-heading .badge { - color: #fffaf6; - background-color: #FA9F47 -} - -.panel-warning > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #fdd9b5 -} - -.panel-danger { - border-color: #efb3b3 -} - -.panel-danger > .panel-heading { - color: #D64242; - background-color: #fdf6f6; - border-color: #efb3b3 -} - -.panel-danger > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #efb3b3 -} - -.panel-danger > .panel-heading .badge { - color: #fdf6f6; - background-color: #D64242 -} - -.panel-danger > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #efb3b3 -} - -.close { - float: right; - font-size: 21px; - line-height: 1; - color: #000; - text-shadow: 0 1px 0 #fff; - opacity: .2; - filter: alpha(opacity=20) -} - -.close:focus, .close:hover { - color: #000; - text-decoration: none; - cursor: pointer; - opacity: .5; - filter: alpha(opacity=50) -} - -button.close { - padding: 0; - cursor: pointer; - background: 0 0; - border: 0; - -webkit-appearance: none -} - -.modal-content, .popover, .tt-menu { - background-clip: padding-box -} - -.modal-open { - overflow: hidden -} - -.modal { - overflow: hidden; - position: fixed; - z-index: 1050; - -webkit-overflow-scrolling: touch; - outline: 0 -} - -.modal-footer:after, .modal-footer:before, .modal-header:after, .modal-header:before { - display: table; - content: " " -} - -.modal-content, .modal-dialog { - position: relative; - border-radius: 4px -} - -.modal.fade .modal-dialog { - -webkit-transform: translate(0, -25%); - -ms-transform: translate(0, -25%); - -o-transform: translate(0, -25%); - transform: translate(0, -25%); - -webkit-transition: -webkit-transform .3s ease-out; - -moz-transition: -moz-transform .3s ease-out; - -o-transition: -o-transform .3s ease-out; - transition: transform .3s ease-out -} - -.modal.in .modal-dialog { - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - -o-transform: translate(0, 0); - transform: translate(0, 0) -} - -.modal-open .modal { - overflow-x: hidden; - overflow-y: auto -} - -.modal-dialog { - position: relative; - width: auto; - margin: 10px -} - -.modal-content { - position: relative; - background-color: #fff; - -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5); - outline: 0 -} - -.modal-backdrop { - position: fixed; - z-index: 1040; - background-color: #596981 -} - -.modal-backdrop.fade { - opacity: 0; - filter: alpha(opacity=0) -} - -.modal-backdrop.in { - opacity: .85; - filter: alpha(opacity=85) -} - -.modal-header { - padding: 15px; - border-bottom: 1px solid #e5e5e5 -} - -.modal-header:after { - clear: both -} - -.modal-header .close { - margin-top: -2px -} - -.modal-title { - margin: 0; - line-height: 1.42857 -} - -.modal-body { - position: relative; - padding: 15px -} - -.modal-footer { - padding: 15px; - text-align: right; - border-top: 1px solid #e5e5e5 -} - -.popover, .tooltip { - font-weight: 400; - line-break: auto; - line-height: 1.42857; - text-align: left; - text-transform: none; - word-spacing: normal; - text-shadow: none; - text-decoration: none; - position: absolute; - font-family: benton-sans, "Helvetica Neue", helvetica, arial, sans-serif; - font-style: normal; - white-space: normal; - word-wrap: normal; - word-break: normal -} - -.modal-footer:after { - clear: both -} - -.modal-footer .btn + .btn { - margin-left: 5px; - margin-bottom: 0 -} - -.modal-footer .btn-group .btn + .btn { - margin-left: -1px -} - -.modal-footer .btn-block + .btn-block { - margin-left: 0 -} - -.modal-scrollbar-measure { - position: absolute; - top: -9999px; - width: 50px; - height: 50px; - overflow: scroll -} - -@media (min-width: 768px) { - .modal-dialog { - width: 600px; - margin: 30px auto - } - - .modal-content { - -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5); - box-shadow: 0 5px 15px rgba(0, 0, 0, .5) - } - - .modal-sm { - width: 300px - } -} - -@media (min-width: 992px) { - .modal-lg { - width: 900px - } -} - -.tooltip { - z-index: 1070; - display: block; - letter-spacing: normal; - text-align: start; - font-size: 12px; - opacity: 0; - filter: alpha(opacity=0) -} - -.loading-spinner, .modal-title, .nav.sub-nav, .spinner, .tooltip-inner, .u-text-center { - text-align: center -} - -.tooltip.in { - opacity: .9; - filter: alpha(opacity=90) -} - -.tooltip.top { - margin-top: -3px; - padding: 5px 0 -} - -.tooltip.right { - margin-left: 3px; - padding: 0 5px -} - -.tooltip.bottom { - margin-top: 3px; - padding: 5px 0 -} - -.tooltip.left { - margin-left: -3px; - padding: 0 5px -} - -.tooltip-inner { - max-width: 200px; - padding: 3px 8px; - color: #fff; - background-color: #000; - border-radius: 4px -} - -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid -} - -.tooltip.top-left .tooltip-arrow, .tooltip.top-right .tooltip-arrow { - bottom: 0; - margin-bottom: -5px; - border-width: 5px 5px 0; - border-top-color: #000 -} - -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -5px; - border-width: 5px 5px 0 -} - -.tooltip.top-left .tooltip-arrow { - right: 5px -} - -.tooltip.top-right .tooltip-arrow { - left: 5px -} - -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -5px; - border-width: 5px 5px 5px 0 -} - -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -5px; - border-width: 5px 0 5px 5px -} - -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -5px; - border-width: 0 5px 5px -} - -.tooltip.bottom-left .tooltip-arrow { - top: 0; - right: 5px; - margin-top: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000 -} - -.tooltip.bottom-right .tooltip-arrow { - top: 0; - left: 5px; - margin-top: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000 -} - -.popover { - top: 0; - left: 0; - z-index: 1060; - display: none; - max-width: 276px; - padding: 1px; - letter-spacing: normal; - text-align: start; - font-size: 14px; - background-color: #fff; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, .2); - border-radius: 6px; - -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2); - box-shadow: 0 5px 10px rgba(0, 0, 0, .2) -} - -label code, pre code { - box-shadow: none -} - -.popover.top { - margin-top: -10px -} - -.popover.right { - margin-left: 10px -} - -.popover.bottom { - margin-top: 10px -} - -.popover.left { - margin-left: -10px -} - -.popover-title { - margin: 0; - padding: 8px 14px; - font-size: 14px; - background-color: #f7f7f7; - border-bottom: 1px solid #ebebeb; - border-radius: 5px 5px 0 0 -} - -.popover-content { - padding: 9px 14px -} - -.popover > .arrow, .popover > .arrow:after { - position: absolute; - display: block; - width: 0; - height: 0; - border-color: transparent; - border-style: solid -} - -.popover > .arrow { - border-width: 11px -} - -.popover > .arrow:after { - border-width: 10px; - content: "" -} - -.popover.top > .arrow { - left: 50%; - margin-left: -11px; - border-bottom-width: 0; - border-top-color: #999; - border-top-color: rgba(0, 0, 0, .25); - bottom: -11px -} - -.popover.top > .arrow:after { - content: " "; - bottom: 1px; - margin-left: -10px; - border-bottom-width: 0; - border-top-color: #fff -} - -.popover.right > .arrow { - top: 50%; - left: -11px; - margin-top: -11px; - border-left-width: 0; - border-right-color: #999; - border-right-color: rgba(0, 0, 0, .25) -} - -.popover.right > .arrow:after { - content: " "; - left: 1px; - bottom: -10px; - border-left-width: 0; - border-right-color: #fff -} - -.popover.bottom > .arrow { - left: 50%; - margin-left: -11px; - border-top-width: 0; - border-bottom-color: #999; - border-bottom-color: rgba(0, 0, 0, .25); - top: -11px -} - -.popover.bottom > .arrow:after { - content: " "; - top: 1px; - margin-left: -10px; - border-top-width: 0; - border-bottom-color: #fff -} - -.popover.left > .arrow { - top: 50%; - right: -11px; - margin-top: -11px; - border-right-width: 0; - border-left-color: #999; - border-left-color: rgba(0, 0, 0, .25) -} - -.popover.left > .arrow:after { - content: " "; - right: 1px; - border-right-width: 0; - border-left-color: #fff; - bottom: -10px -} - -.clearfix:after, .clearfix:before, .deploy-steps > li:after, .deploy-steps > li:before, .deploy-steps > li > .icon:after, .deploy-steps > li > .icon:before, .deploy-steps > li > .loading-spinner:after, .deploy-steps > li > .loading-spinner:before, .deploy-steps > li > i:after, .deploy-steps > li > i:before, .deploy-steps > li > img:after, .deploy-steps > li > img:before { - content: " "; - display: table -} - -.clearfix:after, .deploy-steps > li:after, .deploy-steps > li > .icon:after, .deploy-steps > li > .loading-spinner:after, .deploy-steps > li > i:after, .deploy-steps > li > img:after { - clear: both -} - -.center-block { - display: block; - margin-left: auto; - margin-right: auto -} - -.pull-right { - float: right !important -} - -.pull-left { - float: left !important -} - -.hide { - display: none !important -} - -.show { - display: block !important -} - -.hidden, .visible-lg, .visible-lg-block, .visible-lg-inline, .visible-lg-inline-block, .visible-md, .visible-md-block, .visible-md-inline, .visible-md-inline-block, .visible-sm, .visible-sm-block, .visible-sm-inline, .visible-sm-inline-block, .visible-xs, .visible-xs-block, .visible-xs-inline, .visible-xs-inline-block { - display: none !important -} - -.invisible { - visibility: hidden -} - -.text-hide { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0 -} - -.affix { - position: fixed -} - -@-ms-viewport { - width: device-width -} - -@media (max-width: 767px) { - .visible-xs { - display: block !important - } - - table.visible-xs { - display: table !important - } - - tr.visible-xs { - display: table-row !important - } - - td.visible-xs, th.visible-xs { - display: table-cell !important - } - - .visible-xs-block { - display: block !important - } - - .visible-xs-inline { - display: inline !important - } - - .visible-xs-inline-block { - display: inline-block !important - } -} - -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm { - display: block !important - } - - table.visible-sm { - display: table !important - } - - tr.visible-sm { - display: table-row !important - } - - td.visible-sm, th.visible-sm { - display: table-cell !important - } - - .visible-sm-block { - display: block !important - } - - .visible-sm-inline { - display: inline !important - } - - .visible-sm-inline-block { - display: inline-block !important - } -} - -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md { - display: block !important - } - - table.visible-md { - display: table !important - } - - tr.visible-md { - display: table-row !important - } - - td.visible-md, th.visible-md { - display: table-cell !important - } - - .visible-md-block { - display: block !important - } - - .visible-md-inline { - display: inline !important - } - - .visible-md-inline-block { - display: inline-block !important - } -} - -@media (min-width: 1200px) { - .visible-lg { - display: block !important - } - - table.visible-lg { - display: table !important - } - - tr.visible-lg { - display: table-row !important - } - - td.visible-lg, th.visible-lg { - display: table-cell !important - } - - .visible-lg-block { - display: block !important - } - - .visible-lg-inline { - display: inline !important - } - - .visible-lg-inline-block { - display: inline-block !important - } - - .hidden-lg { - display: none !important - } -} - -@media (max-width: 767px) { - .hidden-xs { - display: none !important - } -} - -@media (min-width: 768px) and (max-width: 991px) { - .hidden-sm { - display: none !important - } -} - -@media (min-width: 992px) and (max-width: 1199px) { - .hidden-md { - display: none !important - } -} - -.visible-print { - display: none !important -} - -@media print { - .visible-print { - display: block !important - } - - table.visible-print { - display: table !important - } - - tr.visible-print { - display: table-row !important - } - - td.visible-print, th.visible-print { - display: table-cell !important - } -} - -.visible-print-block { - display: none !important -} - -@media print { - .visible-print-block { - display: block !important - } -} - -.visible-print-inline { - display: none !important -} - -@media print { - .visible-print-inline { - display: inline !important - } -} - -.u-is-hidden, .visible-print-inline-block { - display: none !important -} - -@media print { - .visible-print-inline-block { - display: inline-block !important - } - - .hidden-print { - display: none !important - } -} - -.context-switcher__list a, .drop-down__menu a, .dropdown a, .dropdown-menu a, .list-group-item-link a, .nav a, .navbar a, a.btn, a.list-group-item { - text-decoration: none -} - -@font-face { - font-family: benton-sans; - font-style: normal; - font-weight: 200; - src: url(/src/assets/style/bentonsans-book.eot) format("embedded-opentype"), url(/src/assets/style/bentonsans-book.woff) format("woff"), url(/src/assets/style/bentonsans-book.ttf) format("truetype") -} - -@font-face { - font-family: benton-sans; - font-style: normal; - font-weight: 400; - src: url(/src/assets/style/bentonsans-regular.eot) format("embedded-opentype"), url(/src/assets/style/bentonsans-regular.woff) format("woff"), url(/src/assets/style/bentonsans-regular.ttf) format("truetype") -} - -@font-face { - font-family: benton-sans; - font-style: normal; - font-weight: 700; - src: url(/src/assets/style/bentonsans-medium.eot?#iefix) format("embedded-opentype"), url(/src/assets/style/bentonsans-medium.woff) format("woff"), url(/src/assets/style/bentonsans-medium.ttf) format("truetype") -} - -.dyno-tier-picker-item-size-name, .panel-section .panel-title, h4 { - font-size: 16px; - font-weight: 200 -} - -.pipeline-dropdown .dropdown-menu-scroll > li .btn-link, .pipeline-dropdown > li .btn-link, dl dt, h5, h6 { - font-weight: 400; - color: #596981 -} - -.pipeline-dropdown .dropdown-menu-scroll > li .btn-link, .pipeline-dropdown > li .btn-link, h6 { - text-transform: uppercase -} - -.error-text .panel-section .panel-details:first-of-type, .error-text p:first-of-type, .lead, .panel-section .error-text .panel-details:first-of-type { - color: #596981 -} - -dl dt { - font-size: 13px -} - -dl dd { - margin-bottom: 12px -} - -dl dd:last-of-type { - margin-bottom: 0 -} - -dl.dl-horizontal dt { - text-align: left -} - -abbr { - color: #596981 -} - -blockquote { - border-width: 3px -} - -code, kbd { - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1) -} - -label code { - background: 0 0; - border: none; - color: #96A3B6; - padding-left: 12px; - padding-right: 12px -} - -.formations-list-item, .metrics__magic-chart-context__group, .table > tbody > tr > th, .table > tfoot > tr > th, .table > thead > tr > th { - border-bottom: 1px solid #CFD7E6 -} - -.table th { - color: #596981; - font-weight: 700; - font-size: 90%; - position: relative; - z-index: 2 -} - -.table > tbody > tr:first-of-type > td, .table > tfoot > tr:first-of-type > td, .table > thead > tr:first-of-type > td { - border-top: none -} - -.table-striped > tbody > tr:nth-child(odd) { - background-color: transparent -} - -.table-striped > tbody > tr:nth-child(even) { - background-color: #fafbfc -} - -.table-bordered { - border: none; - border-collapse: separate -} - -.table-bordered td { - border-top: none !important -} - -.table-bordered td:not(:last-of-type), .table-bordered th:not(:last-of-type) { - border-right: none !important -} - -.table-bordered > thead:first-child > tr:first-child > th { - border-top: 1px solid #e7ebf3 -} - -.table-bordered > thead:first-child > tr:first-child > th:first-of-type { - border-top-left-radius: 4px -} - -.table-bordered > thead:first-child > tr:first-child > th:last-of-type { - border-top-right-radius: 4px -} - -.table-bordered > tbody > tr:last-child > td:first-of-type, .table-bordered > tfoot > tr:last-child > td:first-of-type { - border-bottom-left-radius: 4px -} - -.table-bordered > tbody > tr:last-child > td:last-of-type, .table-bordered > tfoot > tr:last-child > td:last-of-type { - border-bottom-right-radius: 4px -} - -.editable-table-component.table-responsive, .table-responsive { - border: none -} - -.table > tbody > tr.active > td, .table > tbody > tr.active > th, .table > tbody > tr > td.active, .table > tbody > tr > th.active, .table > tfoot > tr.active > td, .table > tfoot > tr.active > th, .table > tfoot > tr > td.active, .table > tfoot > tr > th.active, .table > thead > tr.active > td, .table > thead > tr.active > th, .table > thead > tr > td.active, .table > thead > tr > th.active { - background-color: #fff; - color: #596981 -} - -.table-hover > tbody > tr.active:hover > td, .table-hover > tbody > tr.active:hover > th, .table-hover > tbody > tr > td.active:hover, .table-hover > tbody > tr > th.active:hover { - background-color: #f9f9f9 -} - -.table > tbody > tr.success > td, .table > tbody > tr.success > th, .table > tbody > tr > td.success, .table > tbody > tr > th.success, .table > tfoot > tr.success > td, .table > tfoot > tr.success > th, .table > tfoot > tr > td.success, .table > tfoot > tr > th.success, .table > thead > tr.success > td, .table > thead > tr.success > th, .table > thead > tr > td.success, .table > thead > tr > th.success { - color: #63a36d -} - -.table-hover > tbody > tr.success:hover > td, .table-hover > tbody > tr.success:hover > th, .table-hover > tbody > tr > td.success:hover, .table-hover > tbody > tr > th.success:hover { - background-color: #eff8f1 -} - -.table > tbody > tr.info > td, .table > tbody > tr.info > th, .table > tbody > tr > td.info, .table > tbody > tr > th.info, .table > tfoot > tr.info > td, .table > tfoot > tr.info > th, .table > tfoot > tr > td.info, .table > tfoot > tr > th.info, .table > thead > tr.info > td, .table > thead > tr.info > th, .table > thead > tr > td.info, .table > thead > tr > th.info { - color: #367ac9 -} - -.table-hover > tbody > tr.info:hover > td, .table-hover > tbody > tr.info:hover > th, .table-hover > tbody > tr > td.info:hover, .table-hover > tbody > tr > th.info:hover { - background-color: #e9f2fd -} - -.table > tbody > tr.warning > td, .table > tbody > tr.warning > th, .table > tbody > tr > td.warning, .table > tbody > tr > th.warning, .table > tfoot > tr.warning > td, .table > tfoot > tr.warning > th, .table > tfoot > tr > td.warning, .table > tfoot > tr > th.warning, .table > thead > tr.warning > td, .table > thead > tr.warning > th, .table > thead > tr > td.warning, .table > thead > tr > th.warning { - color: #d5873c -} - -.table-hover > tbody > tr.warning:hover > td, .table-hover > tbody > tr.warning:hover > th, .table-hover > tbody > tr > td.warning:hover, .table-hover > tbody > tr > th.warning:hover { - background-color: #fff3e9 -} - -.table > tbody > tr.danger > td, .table > tbody > tr.danger > th, .table > tbody > tr > td.danger, .table > tbody > tr > th.danger, .table > tfoot > tr.danger > td, .table > tfoot > tr.danger > th, .table > tfoot > tr > td.danger, .table > tfoot > tr > th.danger, .table > thead > tr.danger > td, .table > thead > tr.danger > th, .table > thead > tr > td.danger, .table > thead > tr > th.danger { - color: #b63838 -} - -.table-hover > tbody > tr.danger:hover > td, .table-hover > tbody > tr.danger:hover > th, .table-hover > tbody > tr > td.danger:hover, .table-hover > tbody > tr > th.danger:hover { - background-color: #fbecec -} - -.form-control { - box-shadow: inset 0 1px 2px rgba(207, 215, 230, .4); - padding-left: 8px; - padding-right: 8px -} - -.form-control:focus { - box-shadow: inset 0 1px 2px rgba(207, 215, 230, .2), 0 0 4px rgba(121, 88, 159, .3) -} - -.form-control[disabled], fieldset[disabled] .form-control { - cursor: default; - background: rgba(238, 241, 246, .3); - border: 1px solid #CFD7E6; - color: #CFD7E6 -} - -.form-control[readonly] { - color: #3F3F44 -} - -.form-control[readonly]:focus { - border: 1px solid #96A3B6; - box-shadow: inset 0 1px 2px rgba(207, 215, 230, .2), 0 0 4px rgba(150, 163, 182, .3) -} - -select.form-control:not([multiple]) { - -webkit-appearance: none; - border: 1px solid #CFD7E6; - box-shadow: 0 1px 2px rgba(0, 0, 0, .05) -} - -@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2 / 1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { - body, button, html, input { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale - } - - .h5, .h6, .pipeline-dropdown .dropdown-menu-scroll > li .btn-link, .pipeline-dropdown > li .btn-link, h5, h6 { - font-weight: 700 - } - - select.form-control:not([multiple]) { - background: url(data:image/png; base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAWCAYAAADwza0nAAAABGdBTUEAALGPC/xhBQAAAh9JREFUOBHtUz1MU1EUPucW+gNEBmhigmFxkcSBxE5uRGMLtgMDL+ojMSyUqgsODi5sDAzKog9YINAXzYuJA/1FDYPrM2EwkYVBExIDOmhMC6XvXc957W1LZXTkJu/dc77zfffm3PtdhDOGZUnfj0rhOZf6/bFZTUOnnYbtgGVt9/yslF9JCXGuIUKmzx+6q2kjf1q5p4SG9WFAVo4zIGG4lQQIO+gPxFPajX2FN4Qr5taw41YzEmCAiwi4x7MEebmWw75PdMSn9Vs7nAv+GelivCqdj00R2NAtrvNHK9vM4RpzmMs5Ghv5JKB8QT35GCCo0B8ITqieaj0fvZFSRr0qggMSH/KOi00RrA9dCiaUiIkciyvhBIXrnNe5ix3UQ4GO7ibt9OzBZGyOi+0jGYmcEHbfMHNfpcRZit+1c87z/3ECbIAsGcC7jhk99hQRyST/DjIALpmFebrJx2SA9/gynSuRn0JMJX+aYig8Vb+3hnrZtjvd3YM1uvx7HohQFuTFR2SAKgNkBt39cpBlmykVx4w1RVhljfc6DDMfpYJFfrpQWxE/YZcY8xYruTnCr9Xx3/Q+tZQ+WvSEDBqvi1fhxMlSg4Ocn/GsvkGn73bqTvRzrc7/+li1ti8eHZc3SRxRGM+0uh0MhBJT2sh3hTd2VMDypt3l/jpM0ymOeyLEt6I3PJlMREqK4+GtiYpJJJbM/ALnM/roE7oiV9XU/Bf++9SHJrpj1gAAAABJRU5ErkJggg==) right 8 px center no-repeat; - background-size: 7px 11px - } -} - -fieldset[disabled] select.form-control:not([multiple]), select.form-control:not([multiple])[disabled], select.form-control:not([multiple])[readonly] { - color: #CFD7E6; - background: url(data:image/png; base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAALCAYAAACzkJeoAAAABGdBTUEAALGPC/xhBQAAANlJREFUGBljZICCmcs2i/z7x2LLxPTncHqU7xuQMCOImLJ0qzzzH0bnf4yM/5j+/2f6y/J/b06090PGWct2aP/9x2DF8O/fXabvYof/cb6yZWBiUmZmYjjG8vfvP4O///9fyo71OsXIyPgfCPZPXbztK8N/RgOQqTQAjDOWbI/5x/D/Tma050monYzTl243Z2JgVAFKbtP6z8BkDXct71tbhn//lRkZ/h0F+3Pmos1yfxlZnUFOBepmZP7/e296nO8jsCTIuVMW7hFmYvpl++8f2+GceJe3IDEA4o9hPCTLQFwAAAAASUVORK5CYII=) right 8 px center no-repeat #fafbfc -} - -@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2 / 1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { - fieldset[disabled] select.form-control:not([multiple]), select.form-control:not([multiple])[disabled], select.form-control:not([multiple])[readonly] { - background: url(data:image/png; base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAWCAYAAADwza0nAAAABGdBTUEAALGPC/xhBQAAAiRJREFUOBHtU81PE1EQn9l9EAWiUUtMLH4cMJEeCAfUGGO0graE9Gpim3DRBIz+Ef0jBLeJiUmFknhtpF0EqzHGqD1xgIMeVOjBtGr8AE3ZfePM1m1YqDePzuHtm9/8ZmbffCC0kHQ6bRzsPXVGTB/fvnrBut5Ow+1Aplxuo5XakAY6IjYD8AP2hRbHBwc3t3IDjtms3bmOFCegA0ESfuokLI6NxdZ9vOmYyeVDrlZxIOgQIxrwTb6kYY98AWHDNJzieDJRa6h83p55eNR0cIgMVAISQa17196C3Ku/vo4gQkjuqMlxFS3eSo2+R2t6LkJgnCUiL7tBsIaR7kf+m7w3L1cvaYQezxmRifo5WtnCNQZNATnjm2oy9jSNGKgiBzWmcvZ5znhceBzcVWiYq+g6PRxoaSI1WoaUmIKCjUAla3b+O9WdfteEtSDjv/ZvKoBT03Mj3MAwj9jSRDL2mktPrULLgFg5+ySPYD+PUEWRxkPMNRgYsO4Xupjw5E/fmv4yANzDC6SpV0DPJ3PPPqFN9xwxu8HEitkXmt86cu5K7TLTw2JHieKazzzy5Kx9GB1nmIepTYx/G3IAvUlKLdy8GlttrtXdB8X99TrwWlGXF3nHWuGP9nYoXr8S/+zZ5fAlk893OF9U3F8jH5c/UPt4FxOJDR9rZvSBUqmklis/L/LyHBOMkN5FwrsfR6NRR3RfdjiKQUp/Z2bhtNxvpIZftmrRb4iZ7Qd3Ct+jAAAAAElFTkSuQmCC) right 8 px center no-repeat #fafbfc; - background-size: 7px 11px - } -} - -input:-webkit-autofill { - box-shadow: inset 0 1px 2px rgba(207, 215, 230, .4), inset 0 0 10px 1000px #FFFEDB -} - -input:-webkit-autofill:focus { - box-shadow: inset 0 1px 2px rgba(207, 215, 230, .2), 0 0 4px rgba(121, 88, 159, .3), inset 0 0 10px 1000px #FFFEDB -} - -label { - font-weight: 400 -} - -.btn, form label { - font-weight: 700 -} - -form label { - color: #596981; - font-size: 12px -} - -.checkbox label, .radio label { - line-height: 1.9 -} - -.radio-inline, .tag-toggle-list { - line-height: 1.8 -} - -.bg-success { - color: #74C080 -} - -.bg-info { - color: #408FEC -} - -.bg-warning { - color: #FA9F47 -} - -.bg-danger { - color: #D64242 -} - -.alert a { - color: inherit -} - -.alert-default { - background-color: #f8f7fa; - border-color: #c9bcd9; - color: #79589F -} - -.alert.flash-danger { - background: #D64242; - border: none; - color: #fff; - box-shadow: 0 1px 6px rgba(0, 0, 0, .1) -} - -.btn { - border-radius: 4px; - border: none; - padding-left: 15px; - padding-right: 15px; - -webkit-transition: background-color ease .2s; - -o-transition: background-color ease .2s; - transition: background-color ease .2s -} - -.btn.active, .btn:active { - box-shadow: none; - outline: 0 -} - -.btn:focus { - outline: 0 -} - -.btn.disabled, .btn[disabled], fieldset[disabled] .btn { - color: #CFD7E6; - background-color: rgba(238, 241, 246, .3); - box-shadow: inset 0 0 0 1px #CFD7E6; - opacity: 1 -} - -.btn-default, .btn-default:hover { - box-shadow: inset 0 0 0 1px rgba(121, 88, 159, .6) -} - -.btn .icon { - display: inline-block; - margin-top: -3px; - margin-right: 4px; - margin-left: -2px -} - -.btn .caret { - position: relative; - top: -1px; - width: 7px; - height: 10px; - display: inline-block; - border: none; - background: url(data:image/png; base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAKCAYAAAB4zEQNAAAABGdBTUEAALGPC/xhBQAAAHhJREFUGBmdj8EJgDAMRevZXcQ1Cg5ScBFxDXUVwTkKHj3oVajvlxT0auHl85M2SZ2zk1JqYZOWXFYSHVxwmHal0JO4YYLaVL53hAgDVLotNR/z63+BFjuMavdqK79rRgAtMIMWWsyHPA7j4QR9Reo/e5BoYJWWwgNOyZST/q/QUQAAAABJRU5ErkJggg==) no-repeat -} - -@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2 / 1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { - .btn .caret { - background: url(data:image/png; base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAUCAYAAAC9BQwsAAAABGdBTUEAALGPC/xhBQAAASZJREFUOBHdkk1qAkEQRh1/NuJaBK/gwlu48RRuvIF7swlkmRsEkq1ZBInkChG8gJtALhACSkjI+L6xv9jTTi5gwbOqq17pjHStVhF5njfgNtCoUM5byB14AofqzrkZdRD6sPFGlNXrR+qpZDCE90jeUguHZsPTBhWNMXzaIL9CN6DaIWdcLFNM4ccT8jP8vZNqWIFD7lS/tneHfAfN0uMcn6gVZlb3WnwEPcI8XUjPOFfBXaSzizzzskv4gmvI/ntJzYIjd6l/dQeOe4pWuqwePFgi77Q4ge+o+UKdXgD1HHInxZdTjODDE/IafOVUO+SMSk9EYwBvNsjpJddsUFrygUEP4kvNsQj1evYqM0IbFoV+/FDdTuXKvx+xjngT5FmWZb/p4gHik/DofGR3LQAAAABJRU5ErkJggg==) no-repeat; - background-size: 7px 10px - } -} - -.btn-default:hover { - background: #FAF7FD; - color: #79589F -} - -.actions-button .btn-default:focus, .btn-default.active, .btn-default:active, .open > .btn-default.drop-down__toggle, .open > .btn-default.dropdown-toggle { - background: #EEE7F6 !important; - box-shadow: inset 0 0 0 1px rgba(121, 88, 159, .8) -} - -.btn-default.disabled, .btn-default.disabled:hover, .btn-default[disabled], .btn-default[disabled]:hover, fieldset[disabled] .btn-default, fieldset[disabled] .btn-default:hover { - color: #CFD7E6; - background-color: rgba(238, 241, 246, .3); - box-shadow: inset 0 0 0 1px #CFD7E6 -} - -.btn-default .caret { - background: url(data:image/png; base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAKCAYAAAB4zEQNAAAABGdBTUEAALGPC/xhBQAAANRJREFUGBmdTj1OAmEUnPnYE3gG7QzhBDZWJhZ0sEBAK0ikB3ZpdxMTSgqgYZfoqom9B/ACxjtoR2hN0G/8vg0nYIr3M2/evEccELXWNYhLUP20uP3wtPFh2s6vYfku4Mznsnd8JWpmd1bISbyeBObyRzq1FsnFeX0biBhTmiXFzYR0ldSNw+xL5Ni7HgdGYfYN8CEpuqODLePW5h5Qh3FzPbDgHMSze6i/2/+tBDYMNKQ/GLXzK1n74hx+3UZAYxrpY++tHJaCMK8KWhAcpE+9T8/9A50YUm6gIA0oAAAAAElFTkSuQmCC) no-repeat -} - -@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2 / 1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { - .btn-default .caret { - background: url(data:image/png; base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAUCAYAAAC9BQwsAAAABGdBTUEAALGPC/xhBQAAAg9JREFUOBHdU79rE1Ecf59Lk6PFCOpSKLSCQ5cKgXZycREKmgwOHm2KSbNYUJd2EBoL3mAzOFQXC7okd2IKR6GDiVR0c40QqIuDQ4SCk0LVliTtff1+7/JiEvoX+OC97/f7+XHv50Gd0jzPi9R3jp4Klbg5vGxZ1smgDIOAfdc70/xxuKUUJUMOFfP8yLy9af3u1fYZH2acMWpThYgSfSKgjiiS6252X+NdYz5dTCgfFVI0JiQUvkrk+lKn3lcGJQvlXF1qQ4a1BSfJpo9dE1CLRY0r0sG5aAKONYGWa6zOO0uK6DlTEREoYNc8N3JL70n23Pr5Z5tIzQa8wglr7hlQ9Eyb+OuuOTmR0iYRSj4Rv5wSLjRSRDxDXOzyfq4BamN9a/FRSPaPSy9n2oxk83NOgydZ5vx9v+L/rPg6ilWQHA42HpczeY502lb5NWEt7RY4rhDoA1bnSod8UsOBGHh9MT6V65xi1//iTi3aONgr8RfTIYgjvkfc534cAEQLjV97Vbl07ZJcMG0SbehhRT7tziryPV7G2cAAfDKHjOuSN4/9t/yypiXnbRwoGFahnHn375Hfdqeo7Vd52eOBaOCRs+0bosaNwqvM55CXsdPsxeJoq4k3PPOMxiTyTLWYSSm7lPuu8eDv0IUQsfiFqyzc0ZjkgvWahOsuVQsl2jYZrS/OE8ljk9kHtg1f8t72F5HJzIBJBfCCAAAAAElFTkSuQmCC) no-repeat; - background-size: 7px 10px - } -} - -.btn-primary { - color: #fff !important; - background-color: #79589F; - background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0, rgba(171, 142, 205, 0)), color-stop(1, #ab8ecd)); - background-image: -o-linear-gradient(left top, rgba(171, 142, 205, 0) 0, #ab8ecd 100%); - background-image: -moz-linear-gradient(left top, rgba(171, 142, 205, 0) 0, #ab8ecd 100%); - background-image: -webkit-linear-gradient(left top, rgba(171, 142, 205, 0) 0, #ab8ecd 100%); - background-image: -ms-linear-gradient(left top, rgba(171, 142, 205, 0) 0, #ab8ecd 100%); - background-image: linear-gradient(to left top, rgba(171, 142, 205, 0) 0, #ab8ecd 100%) -} - -.btn-primary.active, .btn-primary:active, .btn-primary:focus, .btn-primary:hover, .open > .btn-primary.drop-down__toggle, .open > .btn-primary.dropdown-toggle { - color: #fff; - background-color: #8669a9 !important -} - -.btn-primary.active, .btn-primary:active, .open > .btn-primary.drop-down__toggle, .open > .btn-primary.dropdown-toggle { - background-color: #78579d !important; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1) !important -} - -.btn-primary.disabled, .btn-primary.disabled.active, .btn-primary.disabled:active, .btn-primary.disabled:focus, .btn-primary.disabled:hover, .btn-primary[disabled], .btn-primary[disabled].active, .btn-primary[disabled]:active, .btn-primary[disabled]:focus, .btn-primary[disabled]:hover, fieldset[disabled] .btn-primary, fieldset[disabled] .btn-primary.active, fieldset[disabled] .btn-primary:active, fieldset[disabled] .btn-primary:focus, fieldset[disabled] .btn-primary:hover { - background: rgba(238, 241, 246, .3) !important; - box-shadow: inset 0 0 0 1px #CFD7E6 !important; - color: #CFD7E6 !important -} - -.btn-primary .badge { - color: #79589F; - background-color: #fff -} - -.btn-success { - color: #fff !important; - background-color: #74C080; - background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0, rgba(173, 226, 143, 0)), color-stop(1, #ade28f)); - background-image: -o-linear-gradient(left top, rgba(173, 226, 143, 0) 0, #ade28f 100%); - background-image: -moz-linear-gradient(left top, rgba(173, 226, 143, 0) 0, #ade28f 100%); - background-image: -webkit-linear-gradient(left top, rgba(173, 226, 143, 0) 0, #ade28f 100%); - background-image: -ms-linear-gradient(left top, rgba(173, 226, 143, 0) 0, #ade28f 100%); - background-image: linear-gradient(to left top, rgba(173, 226, 143, 0) 0, #ade28f 100%) -} - -.btn-success.active, .btn-success:active, .btn-success:focus, .btn-success:hover, .open > .btn-success.drop-down__toggle, .open > .btn-success.dropdown-toggle { - color: #fff; - background-color: #82c68d !important -} - -.btn-success.active, .btn-success:active, .open > .btn-success.drop-down__toggle, .open > .btn-success.dropdown-toggle { - background-color: #73be7f !important; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1) !important -} - -.btn-success.disabled, .btn-success.disabled.active, .btn-success.disabled:active, .btn-success.disabled:focus, .btn-success.disabled:hover, .btn-success[disabled], .btn-success[disabled].active, .btn-success[disabled]:active, .btn-success[disabled]:focus, .btn-success[disabled]:hover, fieldset[disabled] .btn-success, fieldset[disabled] .btn-success.active, fieldset[disabled] .btn-success:active, fieldset[disabled] .btn-success:focus, fieldset[disabled] .btn-success:hover { - background: rgba(238, 241, 246, .3) !important; - box-shadow: inset 0 0 0 1px #CFD7E6 !important; - color: #CFD7E6 !important -} - -.btn-success .badge { - color: #74C080; - background-color: #fff -} - -.btn-success.btn-default { - color: #74C080 !important; - background: 0 0 !important; - box-shadow: inset 0 0 0 1px rgba(116, 192, 128, .6) -} - -.btn-success.btn-default:hover { - background: rgba(116, 192, 128, .1) !important; - box-shadow: inset 0 0 0 1px rgba(116, 192, 128, .6) -} - -.actions-button .btn-success.btn-default:focus, .btn-success.btn-default.active, .btn-success.btn-default:active { - background: rgba(116, 192, 128, .2) !important; - box-shadow: inset 0 0 0 1px rgba(116, 192, 128, .8) !important -} - -.actions-button .btn-success.btn-default[disabled]:focus, .actions-button .btn-success.disabled.btn-default:focus, .actions-button fieldset[disabled] .btn-success.btn-default:focus, .btn-success.btn-default.disabled, .btn-success.btn-default.disabled.active, .btn-success.btn-default.disabled:active, .btn-success.btn-default.disabled:focus, .btn-success.btn-default.disabled:hover, .btn-success.btn-default[disabled], .btn-success.btn-default[disabled].active, .btn-success.btn-default[disabled]:active, .btn-success.btn-default[disabled]:focus, .btn-success.btn-default[disabled]:hover, fieldset[disabled] .actions-button .btn-success.btn-default:focus, fieldset[disabled] .btn-success.btn-default, fieldset[disabled] .btn-success.btn-default.active, fieldset[disabled] .btn-success.btn-default:active, fieldset[disabled] .btn-success.btn-default:focus, fieldset[disabled] .btn-success.btn-default:hover { - background: rgba(207, 215, 230, .1) !important; - box-shadow: inset 0 0 0 1px #CFD7E6 !important; - color: #CFD7E6 !important -} - -.btn-success.btn-default .badge { - color: #fff; - background-color: #74C080 -} - -.btn-info { - color: #fff !important; - background-color: #408FEC; - background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0, rgba(161, 202, 249, 0)), color-stop(1, #a1caf9)); - background-image: -o-linear-gradient(left top, rgba(161, 202, 249, 0) 0, #a1caf9 100%); - background-image: -moz-linear-gradient(left top, rgba(161, 202, 249, 0) 0, #a1caf9 100%); - background-image: -webkit-linear-gradient(left top, rgba(161, 202, 249, 0) 0, #a1caf9 100%); - background-image: -ms-linear-gradient(left top, rgba(161, 202, 249, 0) 0, #a1caf9 100%); - background-image: linear-gradient(to left top, rgba(161, 202, 249, 0) 0, #a1caf9 100%) -} - -.btn-info.active, .btn-info:active, .btn-info:focus, .btn-info:hover, .open > .btn-info.drop-down__toggle, .open > .btn-info.dropdown-toggle { - color: #fff; - background-color: #539aee !important -} - -.btn-info.active, .btn-info:active, .open > .btn-info.drop-down__toggle, .open > .btn-info.dropdown-toggle { - background-color: #3f8eea !important; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1) !important -} - -.btn-info.disabled, .btn-info.disabled.active, .btn-info.disabled:active, .btn-info.disabled:focus, .btn-info.disabled:hover, .btn-info[disabled], .btn-info[disabled].active, .btn-info[disabled]:active, .btn-info[disabled]:focus, .btn-info[disabled]:hover, fieldset[disabled] .btn-info, fieldset[disabled] .btn-info.active, fieldset[disabled] .btn-info:active, fieldset[disabled] .btn-info:focus, fieldset[disabled] .btn-info:hover { - background: rgba(238, 241, 246, .3) !important; - box-shadow: inset 0 0 0 1px #CFD7E6 !important; - color: #CFD7E6 !important -} - -.btn-info .badge { - color: #408FEC; - background-color: #fff -} - -.btn-info.btn-default { - color: #408FEC !important; - background: 0 0 !important; - box-shadow: inset 0 0 0 1px rgba(64, 143, 236, .6) -} - -.btn-info.btn-default:hover { - background: rgba(64, 143, 236, .1) !important; - box-shadow: inset 0 0 0 1px rgba(64, 143, 236, .6) -} - -.actions-button .btn-info.btn-default:focus, .btn-info.btn-default.active, .btn-info.btn-default:active { - background: rgba(64, 143, 236, .2) !important; - box-shadow: inset 0 0 0 1px rgba(64, 143, 236, .8) !important -} - -.actions-button .btn-info.btn-default[disabled]:focus, .actions-button .btn-info.disabled.btn-default:focus, .actions-button fieldset[disabled] .btn-info.btn-default:focus, .btn-info.btn-default.disabled, .btn-info.btn-default.disabled.active, .btn-info.btn-default.disabled:active, .btn-info.btn-default.disabled:focus, .btn-info.btn-default.disabled:hover, .btn-info.btn-default[disabled], .btn-info.btn-default[disabled].active, .btn-info.btn-default[disabled]:active, .btn-info.btn-default[disabled]:focus, .btn-info.btn-default[disabled]:hover, fieldset[disabled] .actions-button .btn-info.btn-default:focus, fieldset[disabled] .btn-info.btn-default, fieldset[disabled] .btn-info.btn-default.active, fieldset[disabled] .btn-info.btn-default:active, fieldset[disabled] .btn-info.btn-default:focus, fieldset[disabled] .btn-info.btn-default:hover { - background: rgba(207, 215, 230, .1) !important; - box-shadow: inset 0 0 0 1px #CFD7E6 !important; - color: #CFD7E6 !important -} - -.btn-info.btn-default .badge { - color: #fff; - background-color: #408FEC -} - -.btn-warning { - color: #fff !important; - background-color: #FA9F47; - background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0, rgba(255, 211, 160, 0)), color-stop(1, #ffd3a0)); - background-image: -o-linear-gradient(left top, rgba(255, 211, 160, 0) 0, #ffd3a0 100%); - background-image: -moz-linear-gradient(left top, rgba(255, 211, 160, 0) 0, #ffd3a0 100%); - background-image: -webkit-linear-gradient(left top, rgba(255, 211, 160, 0) 0, #ffd3a0 100%); - background-image: -ms-linear-gradient(left top, rgba(255, 211, 160, 0) 0, #ffd3a0 100%); - background-image: linear-gradient(to left top, rgba(255, 211, 160, 0) 0, #ffd3a0 100%) -} - -.btn-warning.active, .btn-warning:active, .btn-warning:focus, .btn-warning:hover, .open > .btn-warning.drop-down__toggle, .open > .btn-warning.dropdown-toggle { - color: #fff; - background-color: #fba959 !important -} - -.btn-warning.active, .btn-warning:active, .open > .btn-warning.drop-down__toggle, .open > .btn-warning.dropdown-toggle { - background-color: #f89d46 !important; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1) !important -} - -.btn-warning.disabled, .btn-warning.disabled.active, .btn-warning.disabled:active, .btn-warning.disabled:focus, .btn-warning.disabled:hover, .btn-warning[disabled], .btn-warning[disabled].active, .btn-warning[disabled]:active, .btn-warning[disabled]:focus, .btn-warning[disabled]:hover, fieldset[disabled] .btn-warning, fieldset[disabled] .btn-warning.active, fieldset[disabled] .btn-warning:active, fieldset[disabled] .btn-warning:focus, fieldset[disabled] .btn-warning:hover { - background: rgba(238, 241, 246, .3) !important; - box-shadow: inset 0 0 0 1px #CFD7E6 !important; - color: #CFD7E6 !important -} - -.btn-warning .badge { - color: #FA9F47; - background-color: #fff -} - -.btn-warning.btn-default { - color: #FA9F47 !important; - background: 0 0 !important; - box-shadow: inset 0 0 0 1px rgba(250, 159, 71, .6) -} - -.btn-warning.btn-default:hover { - background: rgba(250, 159, 71, .1) !important; - box-shadow: inset 0 0 0 1px rgba(250, 159, 71, .6) -} - -.actions-button .btn-warning.btn-default:focus, .btn-warning.btn-default.active, .btn-warning.btn-default:active { - background: rgba(250, 159, 71, .2) !important; - box-shadow: inset 0 0 0 1px rgba(250, 159, 71, .8) !important -} - -.actions-button .btn-warning.btn-default[disabled]:focus, .actions-button .btn-warning.disabled.btn-default:focus, .actions-button fieldset[disabled] .btn-warning.btn-default:focus, .btn-warning.btn-default.disabled, .btn-warning.btn-default.disabled.active, .btn-warning.btn-default.disabled:active, .btn-warning.btn-default.disabled:focus, .btn-warning.btn-default.disabled:hover, .btn-warning.btn-default[disabled], .btn-warning.btn-default[disabled].active, .btn-warning.btn-default[disabled]:active, .btn-warning.btn-default[disabled]:focus, .btn-warning.btn-default[disabled]:hover, fieldset[disabled] .actions-button .btn-warning.btn-default:focus, fieldset[disabled] .btn-warning.btn-default, fieldset[disabled] .btn-warning.btn-default.active, fieldset[disabled] .btn-warning.btn-default:active, fieldset[disabled] .btn-warning.btn-default:focus, fieldset[disabled] .btn-warning.btn-default:hover { - background: rgba(207, 215, 230, .1) !important; - box-shadow: inset 0 0 0 1px #CFD7E6 !important; - color: #CFD7E6 !important -} - -.btn-warning.btn-default .badge { - color: #fff; - background-color: #FA9F47 -} - -.btn-danger { - color: #fff !important; - background-color: #D64242; - background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0, rgba(243, 122, 101, 0)), color-stop(1, #f37a65)); - background-image: -o-linear-gradient(left top, rgba(243, 122, 101, 0) 0, #f37a65 100%); - background-image: -moz-linear-gradient(left top, rgba(243, 122, 101, 0) 0, #f37a65 100%); - background-image: -webkit-linear-gradient(left top, rgba(243, 122, 101, 0) 0, #f37a65 100%); - background-image: -ms-linear-gradient(left top, rgba(243, 122, 101, 0) 0, #f37a65 100%); - background-image: linear-gradient(to left top, rgba(243, 122, 101, 0) 0, #f37a65 100%) -} - -.btn-danger.active, .btn-danger:active, .btn-danger:focus, .btn-danger:hover, .open > .btn-danger.drop-down__toggle, .open > .btn-danger.dropdown-toggle { - color: #fff; - background-color: #da5555 !important -} - -.btn-danger.active, .btn-danger:active, .open > .btn-danger.drop-down__toggle, .open > .btn-danger.dropdown-toggle { - background-color: #d44141 !important; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1) !important -} - -.btn-danger.disabled, .btn-danger.disabled.active, .btn-danger.disabled:active, .btn-danger.disabled:focus, .btn-danger.disabled:hover, .btn-danger[disabled], .btn-danger[disabled].active, .btn-danger[disabled]:active, .btn-danger[disabled]:focus, .btn-danger[disabled]:hover, fieldset[disabled] .btn-danger, fieldset[disabled] .btn-danger.active, fieldset[disabled] .btn-danger:active, fieldset[disabled] .btn-danger:focus, fieldset[disabled] .btn-danger:hover { - background: rgba(238, 241, 246, .3) !important; - box-shadow: inset 0 0 0 1px #CFD7E6 !important; - color: #CFD7E6 !important -} - -.btn-danger .badge { - color: #D64242; - background-color: #fff -} - -.btn-danger.btn-default { - color: #D64242 !important; - background: 0 0 !important; - box-shadow: inset 0 0 0 1px rgba(214, 66, 66, .6) -} - -.btn-danger.btn-default:hover { - background: rgba(214, 66, 66, .1) !important; - box-shadow: inset 0 0 0 1px rgba(214, 66, 66, .6) -} - -.actions-button .btn-danger.btn-default:focus, .btn-danger.btn-default.active, .btn-danger.btn-default:active { - background: rgba(214, 66, 66, .2) !important; - box-shadow: inset 0 0 0 1px rgba(214, 66, 66, .8) !important -} - -.actions-button .btn-danger.btn-default[disabled]:focus, .actions-button .btn-danger.disabled.btn-default:focus, .actions-button fieldset[disabled] .btn-danger.btn-default:focus, .btn-danger.btn-default.disabled, .btn-danger.btn-default.disabled.active, .btn-danger.btn-default.disabled:active, .btn-danger.btn-default.disabled:focus, .btn-danger.btn-default.disabled:hover, .btn-danger.btn-default[disabled], .btn-danger.btn-default[disabled].active, .btn-danger.btn-default[disabled]:active, .btn-danger.btn-default[disabled]:focus, .btn-danger.btn-default[disabled]:hover, fieldset[disabled] .actions-button .btn-danger.btn-default:focus, fieldset[disabled] .btn-danger.btn-default, fieldset[disabled] .btn-danger.btn-default.active, fieldset[disabled] .btn-danger.btn-default:active, fieldset[disabled] .btn-danger.btn-default:focus, fieldset[disabled] .btn-danger.btn-default:hover { - background: rgba(207, 215, 230, .1) !important; - box-shadow: inset 0 0 0 1px #CFD7E6 !important; - color: #CFD7E6 !important -} - -.btn-danger.btn-default .badge { - color: #fff; - background-color: #D64242 -} - -.btn-dropbox { - color: #fff !important; - background-color: #007EE5; - background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0, rgba(50, 151, 234, 0)), color-stop(1, #3297ea)); - background-image: -o-linear-gradient(left top, rgba(50, 151, 234, 0) 0, #3297ea 100%); - background-image: -moz-linear-gradient(left top, rgba(50, 151, 234, 0) 0, #3297ea 100%); - background-image: -webkit-linear-gradient(left top, rgba(50, 151, 234, 0) 0, #3297ea 100%); - background-image: -ms-linear-gradient(left top, rgba(50, 151, 234, 0) 0, #3297ea 100%); - background-image: linear-gradient(to left top, rgba(50, 151, 234, 0) 0, #3297ea 100%) -} - -.btn-dropbox.active, .btn-dropbox:active, .btn-dropbox:focus, .btn-dropbox:hover, .open > .btn-dropbox.drop-down__toggle, .open > .btn-dropbox.dropdown-toggle { - color: #fff; - background-color: #1a8be8 !important -} - -.btn-dropbox.active, .btn-dropbox:active, .open > .btn-dropbox.drop-down__toggle, .open > .btn-dropbox.dropdown-toggle { - background-color: #007de3 !important; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1) !important -} - -.btn-dropbox.disabled, .btn-dropbox.disabled.active, .btn-dropbox.disabled:active, .btn-dropbox.disabled:focus, .btn-dropbox.disabled:hover, .btn-dropbox[disabled], .btn-dropbox[disabled].active, .btn-dropbox[disabled]:active, .btn-dropbox[disabled]:focus, .btn-dropbox[disabled]:hover, fieldset[disabled] .btn-dropbox, fieldset[disabled] .btn-dropbox.active, fieldset[disabled] .btn-dropbox:active, fieldset[disabled] .btn-dropbox:focus, fieldset[disabled] .btn-dropbox:hover { - background: rgba(238, 241, 246, .3) !important; - box-shadow: inset 0 0 0 1px #CFD7E6 !important; - color: #CFD7E6 !important -} - -.btn-dropbox .badge { - color: #007EE5; - background-color: #fff -} - -.btn-dropbox.btn-default { - color: #007EE5 !important; - background: 0 0 !important; - box-shadow: inset 0 0 0 1px rgba(0, 126, 229, .6) -} - -.btn-dropbox.btn-default:hover { - background: rgba(0, 126, 229, .1) !important; - box-shadow: inset 0 0 0 1px rgba(0, 126, 229, .6) -} - -.actions-button .btn-dropbox.btn-default:focus, .btn-dropbox.btn-default.active, .btn-dropbox.btn-default:active { - background: rgba(0, 126, 229, .2) !important; - box-shadow: inset 0 0 0 1px rgba(0, 126, 229, .8) !important -} - -.actions-button .btn-dropbox.btn-default[disabled]:focus, .actions-button .btn-dropbox.disabled.btn-default:focus, .actions-button fieldset[disabled] .btn-dropbox.btn-default:focus, .btn-dropbox.btn-default.disabled, .btn-dropbox.btn-default.disabled.active, .btn-dropbox.btn-default.disabled:active, .btn-dropbox.btn-default.disabled:focus, .btn-dropbox.btn-default.disabled:hover, .btn-dropbox.btn-default[disabled], .btn-dropbox.btn-default[disabled].active, .btn-dropbox.btn-default[disabled]:active, .btn-dropbox.btn-default[disabled]:focus, .btn-dropbox.btn-default[disabled]:hover, fieldset[disabled] .actions-button .btn-dropbox.btn-default:focus, fieldset[disabled] .btn-dropbox.btn-default, fieldset[disabled] .btn-dropbox.btn-default.active, fieldset[disabled] .btn-dropbox.btn-default:active, fieldset[disabled] .btn-dropbox.btn-default:focus, fieldset[disabled] .btn-dropbox.btn-default:hover { - background: rgba(207, 215, 230, .1) !important; - box-shadow: inset 0 0 0 1px #CFD7E6 !important; - color: #CFD7E6 !important -} - -.btn-dropbox.btn-default .badge { - color: #fff; - background-color: #007EE5 -} - -.btn-github { - color: #fff !important; - background-color: #3F3F44; - background-image: -webkit-gradient(linear, left top, right bottom, color-stop(0, rgba(97, 97, 101, 0)), color-stop(1, #616165)); - background-image: -o-linear-gradient(left top, rgba(97, 97, 101, 0) 0, #616165 100%); - background-image: -moz-linear-gradient(left top, rgba(97, 97, 101, 0) 0, #616165 100%); - background-image: -webkit-linear-gradient(left top, rgba(97, 97, 101, 0) 0, #616165 100%); - background-image: -ms-linear-gradient(left top, rgba(97, 97, 101, 0) 0, #616165 100%); - background-image: linear-gradient(to left top, rgba(97, 97, 101, 0) 0, #616165 100%) -} - -.btn-github.active, .btn-github:active, .btn-github:focus, .btn-github:hover, .open > .btn-github.drop-down__toggle, .open > .btn-github.dropdown-toggle { - color: #fff; - background-color: #525257 !important -} - -.btn-github.active, .btn-github:active, .open > .btn-github.drop-down__toggle, .open > .btn-github.dropdown-toggle { - background-color: #3e3e43 !important; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1) !important -} - -.btn-github.disabled, .btn-github.disabled.active, .btn-github.disabled:active, .btn-github.disabled:focus, .btn-github.disabled:hover, .btn-github[disabled], .btn-github[disabled].active, .btn-github[disabled]:active, .btn-github[disabled]:focus, .btn-github[disabled]:hover, fieldset[disabled] .btn-github, fieldset[disabled] .btn-github.active, fieldset[disabled] .btn-github:active, fieldset[disabled] .btn-github:focus, fieldset[disabled] .btn-github:hover { - background: rgba(238, 241, 246, .3) !important; - box-shadow: inset 0 0 0 1px #CFD7E6 !important; - color: #CFD7E6 !important -} - -.btn-github .badge { - color: #3F3F44; - background-color: #fff -} - -.btn-github.btn-default { - color: #3F3F44 !important; - background: 0 0 !important; - box-shadow: inset 0 0 0 1px rgba(63, 63, 68, .6) -} - -.btn-github.btn-default:hover { - background: rgba(63, 63, 68, .1) !important; - box-shadow: inset 0 0 0 1px rgba(63, 63, 68, .6) -} - -.actions-button .btn-github.btn-default:focus, .btn-github.btn-default.active, .btn-github.btn-default:active { - background: rgba(63, 63, 68, .2) !important; - box-shadow: inset 0 0 0 1px rgba(63, 63, 68, .8) !important -} - -.actions-button .btn-github.btn-default[disabled]:focus, .actions-button .btn-github.disabled.btn-default:focus, .actions-button fieldset[disabled] .btn-github.btn-default:focus, .btn-github.btn-default.disabled, .btn-github.btn-default.disabled.active, .btn-github.btn-default.disabled:active, .btn-github.btn-default.disabled:focus, .btn-github.btn-default.disabled:hover, .btn-github.btn-default[disabled], .btn-github.btn-default[disabled].active, .btn-github.btn-default[disabled]:active, .btn-github.btn-default[disabled]:focus, .btn-github.btn-default[disabled]:hover, fieldset[disabled] .actions-button .btn-github.btn-default:focus, fieldset[disabled] .btn-github.btn-default, fieldset[disabled] .btn-github.btn-default.active, fieldset[disabled] .btn-github.btn-default:active, fieldset[disabled] .btn-github.btn-default:focus, fieldset[disabled] .btn-github.btn-default:hover { - background: rgba(207, 215, 230, .1) !important; - box-shadow: inset 0 0 0 1px #CFD7E6 !important; - color: #CFD7E6 !important -} - -.btn-github.btn-default .badge { - color: #fff; - background-color: #3F3F44 -} - -.btn-link { - font-weight: 400 -} - -.btn-link.disabled, .btn-link.disabled:hover, .btn-link[disabled], .btn-link[disabled]:hover, fieldset[disabled] .btn-link, fieldset[disabled] .btn-link:hover { - color: #CFD7E6; - background-color: transparent; - border-color: transparent; - box-shadow: none; - text-decoration: inherit -} - -.btn-group-lg > .btn, .btn-lg { - font-weight: 400; - padding-left: 20px; - padding-right: 20px; - border-radius: 6px -} - -.btn-group-sm > .btn, .btn-sm { - font-size: 13px -} - -.btn-group-xs > .btn, .btn-xs { - height: 24px; - line-height: 22px; - padding-left: 12px; - padding-right: 12px -} - -.btn-group-xs > .btn .icon, .btn-xs .icon { - margin-right: 0 -} - -.input-group-btn .btn { - line-height: 1.6; - z-index: 2 -} - -.gradient-primary, .purple-gradient { - background-image: -webkit-linear-gradient(bottom right, #79589F, #AB8ECD); - background-image: linear-gradient(to top left, #79589F, #AB8ECD); - background-color: #79589F -} - -.context-switcher__list, .drop-down__menu, .dropdown-menu { - font-size: 13px; - margin: 2px 0 0; - box-shadow: 0 3px 20px rgba(89, 105, 129, .3), 0 1px 2px rgba(0, 0, 0, .05), 0 0 0 1px rgba(89, 105, 129, .1); - border: none -} - -.context-switcher__list > li > a, .drop-down__menu > li > a, .dropdown-menu > li > a { - padding: 4px 12px 3px -} - -.context-switcher__list > li > a .icon, .drop-down__menu > li > a .icon, .dropdown-menu > li > a .icon { - position: relative; - margin: -2px 4px 0 2px -} - -.context-switcher__list .dropdown-menu-scroll, .drop-down__menu .dropdown-menu-scroll, .dropdown-menu .dropdown-menu-scroll { - overflow: auto; - max-height: 480px; - margin: -5px 0; - padding: 5px 0 -} - -.context-switcher__list .dropdown-menu-scroll::-webkit-scrollbar, .drop-down__menu .dropdown-menu-scroll::-webkit-scrollbar, .dropdown-menu .dropdown-menu-scroll::-webkit-scrollbar { - width: 12px; - height: 12px -} - -.context-switcher__list .dropdown-menu-scroll::-webkit-scrollbar-thumb, .drop-down__menu .dropdown-menu-scroll::-webkit-scrollbar-thumb, .dropdown-menu .dropdown-menu-scroll::-webkit-scrollbar-thumb { - width: 5px; - height: 5px; - border-radius: 10px; - background-clip: border-box; - box-shadow: inset 0 0 0 1px rgba(207, 215, 230, .5); - background: rgba(207, 215, 230, .5); - border: 3px solid #fff -} - -.context-switcher__list .dropdown-menu-scroll::-webkit-scrollbar-button, .drop-down__menu .dropdown-menu-scroll::-webkit-scrollbar-button, .dropdown-menu .dropdown-menu-scroll::-webkit-scrollbar-button { - width: 0; - height: 0; - display: none -} - -.context-switcher__list .dropdown-menu-scroll > li > a, .drop-down__menu .dropdown-menu-scroll > li > a, .dropdown-menu .dropdown-menu-scroll > li > a { - display: block; - padding: 3px 12px; - clear: both; - font-weight: 400; - font-size: 13px; - line-height: 1.42857; - color: #596981; - white-space: nowrap -} - -.context-switcher__list .dropdown-menu-scroll > li > a:focus, .context-switcher__list .dropdown-menu-scroll > li > a:hover, .drop-down__menu .dropdown-menu-scroll > li > a:focus, .drop-down__menu .dropdown-menu-scroll > li > a:hover, .dropdown-menu .dropdown-menu-scroll > li > a:focus, .dropdown-menu .dropdown-menu-scroll > li > a:hover { - text-decoration: none; - color: #3F3F44; - background-color: #f7f8fb -} - -.context-switcher__list .dropdown-menu-scroll > .active > a, .context-switcher__list .dropdown-menu-scroll > .active > a:focus, .context-switcher__list .dropdown-menu-scroll > .active > a:hover, .drop-down__menu .dropdown-menu-scroll > .active > a, .drop-down__menu .dropdown-menu-scroll > .active > a:focus, .drop-down__menu .dropdown-menu-scroll > .active > a:hover, .dropdown-menu .dropdown-menu-scroll > .active > a, .dropdown-menu .dropdown-menu-scroll > .active > a:focus, .dropdown-menu .dropdown-menu-scroll > .active > a:hover { - color: #fff; - text-decoration: none; - outline: 0; - background-color: #79589F -} - -.context-switcher__list .dropdown-menu-scroll > .disabled > a, .context-switcher__list .dropdown-menu-scroll > .disabled > a:focus, .context-switcher__list .dropdown-menu-scroll > .disabled > a:hover, .drop-down__menu .dropdown-menu-scroll > .disabled > a, .drop-down__menu .dropdown-menu-scroll > .disabled > a:focus, .drop-down__menu .dropdown-menu-scroll > .disabled > a:hover, .dropdown-menu .dropdown-menu-scroll > .disabled > a, .dropdown-menu .dropdown-menu-scroll > .disabled > a:focus, .dropdown-menu .dropdown-menu-scroll > .disabled > a:hover { - color: #CFD7E6 -} - -.context-switcher__list .dropdown-menu-scroll > .disabled > a:focus, .context-switcher__list .dropdown-menu-scroll > .disabled > a:hover, .drop-down__menu .dropdown-menu-scroll > .disabled > a:focus, .drop-down__menu .dropdown-menu-scroll > .disabled > a:hover, .dropdown-menu .dropdown-menu-scroll > .disabled > a:focus, .dropdown-menu .dropdown-menu-scroll > .disabled > a:hover { - text-decoration: none; - background-color: transparent; - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); - cursor: not-allowed -} - -.dropdown-menu.with-point, .with-point.context-switcher__list, .with-point.drop-down__menu { - margin: 8px 0 0 -} - -.dropdown-menu.with-point::after, .with-point.context-switcher__list::after, .with-point.drop-down__menu::after { - content: ''; - position: absolute; - top: -13px; - left: 0; - width: 30px; - height: 13px; - background: url(data:image/png; base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAANCAYAAAC+ct6XAAAAAXNSR0IArs4c6QAAAYhJREFUOBGVULtOAlEQFXxD6RdYam1HpDPREENhYYHUVITS2BA6bWjZzvgP2lmjrUZrbdZHAYEF15CsEeese26uI8tjksm8zpwz9ybmprfElNDhNLhJZJPmkzRij4gj1n1dzyr47wBNOK7WszhxW8TOgTe1JrNr5oxYtHPU2gyxDJgzAmtym2hUzh4jlpEnM5mdNRTN5nVbwre4IbVy9hhl9AcXkoEwJJWYFJ+PfEEifDHytONcFHq9/l2//3HfaJwfST9lzYnnPrjg5Ec0xiZBXLIFlwSdrtedgyD46gwjC4Kggx5m4sDwQOySh7zUkdGvsQEAwVo0Vaud7g4GgzeKMkrvvVo925NdvHycOHVCVRa8CsL8LlwPolS5fLLt+/4TxXSU2XOlcpwFNtrBLnnASX7qmb8f9VqIrhaLpa1ut/ugxXTted4jsNgR58v1l8cK80pcvJLLHW60Wu0bLRJXC/Y2ny9sYld81KvHCmNhOZvdX3fdl0sR+ZzFXff1CrvgsMT53aHwDzqEBw7ZOUAbAAAAAElFTkSuQmCC) no-repeat -} - -@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2 / 1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { - .dropdown-menu.with-point::after, .with-point.context-switcher__list::after, .with-point.drop-down__menu::after { - background: url(data:image/png; base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAAaCAYAAADrCT9ZAAAAAXNSR0IArs4c6QAABHNJREFUWAm9Vt1rm1UcXj6arNU2KowWP2DNRkqgYywpXWhs61y7mw4KK+IuhoIjV068mbDp1S7cBqIXA/0L9HIwKXi1XWwwLwqdKJbOybqWCl3b2K3E6j6M8/e83S97evKevCdp9cDp+X0+v+c5b/KmoW3/zwo5jnniWNdwmSsR1wFbjadzt+wiNktws/0qqN6z4QtolHC9fa719Qqpt36bKxF9Ai71LjWK53K6iHKp8Wa5kguqC8qrMFudK+GguqB84BO2EYSAWjmXvF6C7QwiXytvzTVK2tZni9tEucZtAuqN13xKNvJ+cb+YiqmV0xo+bSJQ45fzi9lqrYJtJP3irjEW5Wr7iXGN+Yquh6xZa/oY4BfjuOb1VPLmiR5emq8V86tB/Ya4DmYgl5hZY/rA4xjsUHt7e3TXrkxHJNL0HArK5cdrt2/fuLu4uPi3uCDG5NhGOZYZC/KreqIezLM/TFKjZqwRP9zZ2Z1IJtPJ8+dPjyaTO/MAn5mZvX7q1LlvW1qmZ+7c+XlVQv/IVhE6R320IFaP79eDWGUBkHdYfN4R8Xnjwng3ic87Ln6ziG0fG3tnqFj8/foTY0ns+7Gx94ZQg1rZ6GEM2DwDNnOAzRxhswbYvsssgs9A5hAmYRKMSa8ntqNj946DB48cWFhYvGporbiSu3bo0Ftvolb6VDQwTFyeafJhrn5aBG7jMosYADYP4MFMCiQrYtvaXn0pnx/pn52dG6+osxhzc/Pjg4Mj/egRDBZtCufZzMnka+rZqFY8s4ABGJgH2sS2JBKJF3O54fzU1M2vLRqrwtPTt75BD3qFT4tsfEr0EnkWc2BuzNnUI1DPlpnkRtgKyoOYgJLCiaeT2L9/KDcxMflllaqAwMTEja/QC4ynWIzNM5mL8jN5m7oEcn2ZCW5UMJw6hAczIYht7e0d7rl8+drZAG3W9JUrV88BA1iygckzeLbyYY7M3dQlUOuLE9wAW8EUHKcOZSIg9nxPz9C+ixfHT4uaslVRcKJ86dJ3HwMLmLJtopmT8jT5szZPDAK82Pez/WLesGx2oPPEicLA0aNHPg2FQriURleoq2t3fzwe+2V+fvn+wsIcfqOx+DcYPnOBj+UXW89IDkTNAvbV1pMBNeZ9CrLZN147duztvkLh3c/C4TBeOJtacmGRPXvSAw8fPppaXl4T0bOlp4AQrbN5hl+M855dr2AGhY0d7e7u6xgdPdx78uT7n0ej0ReqpjQYkIuLZbN7X19aWvmxWFy7v7Q0/6dAuTxl60RTsClIGzXOJ+xIOt23Y3j4QObMmY++iMfj+G9pS1ckEmnO5TI5+Z3+4d69x6vF4m9/yQBTtDlTeSLOtleHgG7+wnvfS8nh1JcDv6y2d3Xte/n48Q9GSqU/bgW/hzZXUSqt/VoofHg4ldr7ivDZLhsvTOWj/Jgza1F9Vd9hvg219RT8ym2FU6lsaybTm75w4ewnbW2tOyWHm//PdizW1Dw4mE9NTt786cGD8urKyt1HMs980sxV0tXrX5i0cpIDU/r5AAAAAElFTkSuQmCC); - background-size: 30px 13px - } -} - -.dropdown-menu.with-point.dropdown-menu-right::after, .with-point.dropdown-menu-right.context-switcher__list::after, .with-point.dropdown-menu-right.drop-down__menu::after { - left: auto; - right: 0 -} - -.dropdown-menu-center.context-switcher__list, .dropdown-menu-center.drop-down__menu, .dropdown-menu.dropdown-menu-center { - margin-left: 50%; - -webkit-transform: translateX(-50%); - -moz-transform: translateX(-50%); - -ms-transform: translateX(-50%); - -o-transform: translateX(-50%); - transform: translateX(-50%) -} - -.dropdown-menu-center.with-point.context-switcher__list::after, .dropdown-menu-center.with-point.drop-down__menu::after, .dropdown-menu.dropdown-menu-center.with-point::after { - left: 50%; - -webkit-transform: translateX(-50%); - -moz-transform: translateX(-50%); - -ms-transform: translateX(-50%); - -o-transform: translateX(-50%); - transform: translateX(-50%) -} - -.dropup .context-switcher__list, .dropup .drop-down__menu, .dropup .dropdown-menu { - margin: 0 0 2px -} - -.dropup .dropdown-menu.with-point, .dropup .with-point.context-switcher__list, .dropup .with-point.drop-down__menu { - margin: 0 0 8px -} - -.dropup .dropdown-menu.with-point::after, .dropup .with-point.context-switcher__list::after, .dropup .with-point.drop-down__menu::after { - -webkit-transform: rotate(180deg); - -ms-transform: rotate(180deg); - -o-transform: rotate(180deg); - transform: rotate(180deg); - top: auto; - bottom: -13px -} - -.list-group-item { - border-left: none; - border-right: none; - padding: 10px 0 -} - -.list-group-item:first-of-type { - border-top: none -} - -.list-group-item:last-of-type { - border-bottom: none -} - -.list-group-item-link { - color: #555 -} - -.list-group-item-link .list-group-item-heading { - color: #3F3F44 -} - -.list-group-item-link:focus, .list-group-item-link:hover { - text-decoration: none; - color: #555; - background-color: #f7f8fb -} - -.list-group-item-link.active:before, a.list-group-item.active:before { - background: #408FEC; - content: ''; - display: block; - height: 100%; - left: -15px; - position: absolute; - top: 0; - width: 3px -} - -.list-group-lg > .list-group-item { - padding-bottom: 40px; - padding-top: 40px -} - -.nav.sub-nav { - border: none; - padding-top: 9px; - box-shadow: inset 0 -1px 0 #E7E7EC -} - -.nav.sub-nav a { - display: inline-block; - margin-right: 26px; - padding: 10px 2px 12px; - color: #96A3B6; - position: relative -} - -.nav.sub-nav a.active::after, .nav.sub-nav a:hover::after { - position: absolute; - height: 1px; - width: 100%; - content: ''; - left: 0; - bottom: 0 -} - -.nav.sub-nav a.active, .nav.sub-nav a.active-override { - color: #79589F -} - -.nav.sub-nav a:last-child { - margin-right: 0 -} - -@media (max-width: 768px) { - .nav.sub-nav a { - margin-right: 10px - } - - .nav.sub-nav a i { - display: none - } -} - -@media (max-width: 420px) { - .nav.sub-nav a i { - display: inline-block; - margin-left: 4px; - margin-right: 4px - } - - .nav.sub-nav a span { - display: none - } -} - -.nav.sub-nav a:hover::after { - background: #CFD7E6 -} - -.nav.sub-nav a.active::after { - background: #A996C0 -} - -.nav.sub-nav a > a { - display: inline; - color: gray; - border: none; - padding: 0 -} - -.nav.sub-nav a > a:hover { - background: 0 0 -} - -.nav.sub-nav a i { - position: relative; - top: -1px; - margin-right: 4px; - display: inline-block -} - -.nav.sub-nav a.active { - border: none -} - -.nav.sub-nav a.active > a { - color: #408FEC -} - -.nav.nav-pills li a .panel-section .connected.panel-details, .nav.nav-pills li a small.connected, .panel-section .nav.nav-pills li a .connected.panel-details { - font-weight: 700 -} - -.nav.nav-pills li.deploy-tab.tab-dropbox a { - color: #007EE5 -} - -.nav.nav-pills li.deploy-tab .label-github { - background: #3F3F44 -} - -.nav.nav-pills li.deploy-tab .label-dropbox { - background: #007EE5 -} - -.nav.nav-pills li.deploy-tab .icon.icon-success-alt { - position: relative; - top: -1px; - margin-left: 4px -} - -@media (max-width: 520px) { - .nav.nav-pills li.deploy-tab { - margin-left: 0; - margin-right: 0; - text-align: center - } - - .nav.nav-pills li.deploy-tab .service { - display: block; - padding-top: 4px - } - - .nav.nav-pills li.deploy-tab .panel-section .panel-details, .nav.nav-pills li.deploy-tab small, .panel-section .nav.nav-pills li.deploy-tab .panel-details { - display: none - } - - .nav.nav-pills li.deploy-tab a { - padding: 8px 10px; - font-size: 13px - } - - .nav.nav-pills li.deploy-tab .icon.tab-icon { - position: relative; - top: 0; - left: 0; - margin: 0 auto - } - - .nav.nav-pills li.deploy-tab .icon.icon-success-alt { - position: absolute; - top: 8px; - right: 10px; - background-color: #fff; - border-radius: 50% - } -} - -.panel-section .panel-content > :first-child, .panel-section .panel-title { - margin-top: 0 -} - -.panel-section .panel-description { - line-height: 24px -} - -@media (max-width: 767px) { - .panel-section .panel-description { - padding-bottom: 20px - } -} - -.panel-section .panel-title .label { - position: relative; - top: -2px; - margin-left: 4px; - text-transform: uppercase; - font-size: 9px; - padding: 2px 4px 1px -} - -.panel-section .panel-title .icon { - position: relative; - top: -1px; - margin-right: 4px -} - -.panel-section .panel-details { - color: #596981; - margin-bottom: 0 -} - -.panel-section.danger .panel-title { - color: #D64242 -} - -#overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper, #overview-page .data-unavailable, .buildpack-installations-list .sortable-item.is-dragging, .content-box, .metrics__chart-sorting .sortable-item.is-dragging, .metrics__monitor-preview-chart__loading, .metrics__not-available, .purple-box { - position: relative; - border-radius: 4px -} - -.loading-spinner, .spinner { - display: inline-flex; - -webkit-box-pack: distribute; - -moz-box-pack: distribute; - box-pack: distribute; - -webkit-justify-content: space-around; - -moz-justify-content: space-around; - -ms-justify-content: space-around; - -o-justify-content: space-around; - justify-content: space-around; - -ms-flex-pack: distribute; - position: relative; - width: 30px; - height: 6px -} - -.loading-spinner i.spinner__dot, .spinner i.spinner__dot { - width: 6px; - height: 6px; - border-radius: 50%; - background: #96A3B6; - -webkit-animation: pulse .85s infinite ease-in-out; - -o-animation: pulse .85s infinite ease-in-out; - animation: pulse .85s infinite ease-in-out -} - -.loading-spinner i.spinner__dot.spinner__dot--one, .spinner i.spinner__dot.spinner__dot--one { - -webkit-animation-delay: -.2s; - animation-delay: -.2s -} - -.loading-spinner i.spinner__dot.spinner__dot--two, .spinner i.spinner__dot.spinner__dot--two { - -webkit-animation-delay: -.1s; - animation-delay: -.1s -} - -.spinner--inverted.loading-spinner i.spinner__dot, .spinner.spinner--inverted i.spinner__dot { - background: #fff -} - -.btn--saving .loading-spinner, .btn--saving .spinner { - width: 18px; - margin-right: 8px; - opacity: .6 -} - -.btn--saving .loading-spinner i.spinner__dot, .btn--saving .spinner i.spinner__dot { - width: 3px; - height: 3px -} - -@-webkit-keyframes pulse { - 0%, 100%, 80% { - opacity: 0; - transform: scale(.8) - } - 40% { - opacity: 1; - transform: scale(1) - } -} - -@-moz-keyframes pulse { - 0%, 100%, 80% { - opacity: 0; - transform: scale(.8) - } - 40% { - opacity: 1; - transform: scale(1) - } -} - -@keyframes pulse { - 0%, 100%, 80% { - opacity: 0; - transform: scale(.8) - } - 40% { - opacity: 1; - transform: scale(1) - } -} - -.well { - background-color: rgba(238, 241, 246, .5); - box-shadow: inset 0 0 0 1px rgba(89, 105, 129, .1), inset 0 1px 3px rgba(207, 215, 230, .6); - border: none -} - -.modal-dialog { - box-shadow: 0 3px 20px rgba(63, 63, 68, .5), 0 1px 2px rgba(0, 0, 0, .05), 0 0 0 1px rgba(63, 63, 68, .25) -} - -.modal-content { - border: none; - box-shadow: none -} - -.certRadio.checked, .checked.hk-message--danger.certRadio { - box-shadow: 0 3px 16px 0 rgba(89, 105, 169, .2), 0 1px 2px 0 rgba(0, 0, 0, .05) -} - -@media (min-width: 768px) { - .modal-dialog { - margin: 40px auto - } -} - -.u-padding-Axxl { - padding: 40px -} - -.u-padding-Axl { - padding: 33px -} - -.u-padding-Al { - padding: 27px -} - -.u-padding-Axm { - padding: 22px -} - -.u-padding-Am { - padding: 20px -} - -.u-padding-As { - padding: 12px -} - -.u-padding-Axs { - padding: 9px -} - -.u-padding-Axxs { - padding: 6px -} - -.u-padding-An { - padding: 0 -} - -.u-margin-Axxl { - margin: 40px -} - -.u-margin-Axl { - margin: 33px -} - -.u-margin-Al { - margin: 27px -} - -.u-margin-Axm { - margin: 22px -} - -.u-margin-Am { - margin: 20px -} - -.u-margin-As { - margin: 12px -} - -.u-margin-Axs { - margin: 9px -} - -.u-margin-Axxs { - margin: 6px -} - -.u-margin-An { - margin: 0 -} - -.u-margin-Vxxl { - margin-top: 40px; - margin-bottom: 40px -} - -.u-margin-Vxl { - margin-top: 33px; - margin-bottom: 33px -} - -.u-margin-Vl { - margin-top: 27px; - margin-bottom: 27px -} - -.u-margin-Vxm { - margin-top: 22px; - margin-bottom: 22px -} - -.u-margin-Vm { - margin-top: 20px; - margin-bottom: 20px -} - -.u-margin-Vs { - margin-top: 12px; - margin-bottom: 12px -} - -.u-margin-Vxs { - margin-top: 9px; - margin-bottom: 9px -} - -.u-margin-Vxxs { - margin-top: 6px; - margin-bottom: 6px -} - -.u-margin-Vn { - margin-top: 0; - margin-bottom: 0 -} - -.peerings-table, .u-margin-Txxl { - margin-top: 40px -} - -.u-padding-Vxxl { - padding-top: 40px; - padding-bottom: 40px -} - -.u-padding-Vxl { - padding-top: 33px; - padding-bottom: 33px -} - -.u-padding-Vl { - padding-top: 27px; - padding-bottom: 27px -} - -.u-padding-Vxm { - padding-top: 22px; - padding-bottom: 22px -} - -.u-padding-Vm { - padding-top: 20px; - padding-bottom: 20px -} - -.u-padding-Vs { - padding-top: 12px; - padding-bottom: 12px -} - -.u-padding-Vxs { - padding-top: 9px; - padding-bottom: 9px -} - -.u-padding-Vxxs { - padding-top: 6px; - padding-bottom: 6px -} - -.u-padding-Vn { - padding-top: 0; - padding-bottom: 0 -} - -.u-margin-Hxxl { - margin-left: 40px; - margin-right: 40px -} - -.u-margin-Hxl { - margin-left: 33px; - margin-right: 33px -} - -.u-margin-Hl { - margin-left: 27px; - margin-right: 27px -} - -.u-margin-Hxm { - margin-left: 22px; - margin-right: 22px -} - -.u-margin-Hm { - margin-left: 20px; - margin-right: 20px -} - -.u-margin-Hs { - margin-left: 12px; - margin-right: 12px -} - -.u-margin-Hxs { - margin-left: 9px; - margin-right: 9px -} - -.u-margin-Hxxs { - margin-left: 6px; - margin-right: 6px -} - -.u-margin-Hn { - margin-left: 0; - margin-right: 0 -} - -.u-padding-Hxxl { - padding-left: 40px; - padding-right: 40px -} - -.u-padding-Hxl { - padding-left: 33px; - padding-right: 33px -} - -.u-padding-Hl { - padding-left: 27px; - padding-right: 27px -} - -.u-padding-Hxm { - padding-left: 22px; - padding-right: 22px -} - -.u-padding-Hm { - padding-left: 20px; - padding-right: 20px -} - -.u-padding-Hs { - padding-left: 12px; - padding-right: 12px -} - -.u-padding-Hxs { - padding-left: 9px; - padding-right: 9px -} - -.u-padding-Hxxs { - padding-left: 6px; - padding-right: 6px -} - -.u-padding-Hn { - padding-left: 0; - padding-right: 0 -} - -.u-margin-Txl { - margin-top: 33px -} - -.u-margin-Tl { - margin-top: 27px -} - -.u-margin-Txm { - margin-top: 22px -} - -.u-margin-Tm { - margin-top: 20px -} - -.u-margin-Ts { - margin-top: 12px -} - -.u-margin-Txs { - margin-top: 9px -} - -.u-margin-Txxs { - margin-top: 6px -} - -.u-margin-Tn { - margin-top: 0 -} - -.u-padding-Txxl { - padding-top: 40px -} - -.u-padding-Txl { - padding-top: 33px -} - -.u-padding-Tl { - padding-top: 27px -} - -.u-padding-Txm { - padding-top: 22px -} - -.u-padding-Tm { - padding-top: 20px -} - -.u-padding-Ts { - padding-top: 12px -} - -.u-padding-Txs { - padding-top: 9px -} - -.u-padding-Txxs { - padding-top: 6px -} - -.u-padding-Tn { - padding-top: 0 -} - -.u-margin-Bxxl { - margin-bottom: 40px -} - -.u-margin-Bxl { - margin-bottom: 33px -} - -.u-margin-Bl { - margin-bottom: 27px -} - -.u-margin-Bxm { - margin-bottom: 22px -} - -.lock-status, .u-margin-Bm { - margin-bottom: 20px -} - -.u-margin-Bs { - margin-bottom: 12px -} - -.u-margin-Bxs { - margin-bottom: 9px -} - -.u-margin-Bxxs { - margin-bottom: 6px -} - -.u-margin-Bn { - margin-bottom: 0 -} - -.u-padding-Bxxl { - padding-bottom: 40px -} - -.u-padding-Bxl { - padding-bottom: 33px -} - -.u-padding-Bl { - padding-bottom: 27px -} - -.u-padding-Bxm { - padding-bottom: 22px -} - -.build-view, .u-padding-Bm { - padding-bottom: 20px -} - -.u-padding-Bs { - padding-bottom: 12px -} - -.u-padding-Bxs { - padding-bottom: 9px -} - -.u-padding-Bxxs { - padding-bottom: 6px -} - -.u-padding-Bn { - padding-bottom: 0 -} - -.u-margin-Rxxl { - margin-right: 40px -} - -.u-margin-Rxl { - margin-right: 33px -} - -.u-margin-Rl { - margin-right: 27px -} - -.u-margin-Rxm { - margin-right: 22px -} - -.u-margin-Rm { - margin-right: 20px -} - -.u-margin-Rs { - margin-right: 12px -} - -.u-margin-Rxs { - margin-right: 9px -} - -.u-margin-Rxxs { - margin-right: 6px -} - -.u-margin-Rn { - margin-right: 0 -} - -.u-padding-Rxxl { - padding-right: 40px -} - -.u-padding-Rxl { - padding-right: 33px -} - -.u-padding-Rl { - padding-right: 27px -} - -.u-padding-Rxm { - padding-right: 22px -} - -.u-padding-Rm { - padding-right: 20px -} - -.u-padding-Rs { - padding-right: 12px -} - -.u-padding-Rxs { - padding-right: 9px -} - -.u-padding-Rxxs { - padding-right: 6px -} - -.u-padding-Rn { - padding-right: 0 -} - -.u-margin-Lxxl { - margin-left: 40px -} - -.u-margin-Lxl { - margin-left: 33px -} - -.u-margin-Ll { - margin-left: 27px -} - -.u-margin-Lxm { - margin-left: 22px -} - -.u-margin-Lm { - margin-left: 20px -} - -.u-margin-Ls { - margin-left: 12px -} - -.u-margin-Lxs { - margin-left: 9px -} - -.u-margin-Lxxs { - margin-left: 6px -} - -.u-margin-Ln { - margin-left: 0 -} - -.u-padding-Lxxl { - padding-left: 40px -} - -.u-padding-Lxl { - padding-left: 33px -} - -.u-padding-Ll { - padding-left: 27px -} - -.u-padding-Lxm { - padding-left: 22px -} - -.u-padding-Lm { - padding-left: 20px -} - -.u-padding-Ls { - padding-left: 12px -} - -.u-padding-Lxs { - padding-left: 9px -} - -.u-padding-Lxxs { - padding-left: 6px -} - -.u-padding-Ln, table.editable-list td:first-of-type, table.static-list td:first-of-type { - padding-left: 0 -} - -.u-is-hidden { - visibility: hidden !important -} - -.u-is-visible { - display: block !important; - visibility: visible !important -} - -.metrics__magic-chart-context.is-empty, .u-is-invisible, range-slider-value-indicator.is-hidden, range-slider.disabled range-slider-handle { - visibility: hidden -} - -.u-is-hidden-visually { - position: absolute !important; - overflow: hidden; - width: 1px; - height: 1px; - padding: 0; - border: 0; - clip: rect(1px, 1px, 1px, 1px) -} - -.u-is-actionable { - cursor: pointer -} - -.u-is-draggable { - cursor: move -} - -.u-is-disabled { - cursor: default -} - -.u-text-start { - text-align: left -} - -.u-text-end, table.editable-list .new-item { - text-align: right -} - -.u-text-extra-small { - font-size: 12px; - color: #96A3B6 -} - -.u-border-circle { - border-radius: 50% -} - -.alert-primary, .text-primary { - color: #79589F -} - -.alert-success, .text-success { - color: #008700 -} - -.alert-info, .text-info { - color: #006DEB -} - -.alert-warning, .text-warning { - color: #C74C00 -} - -.alert-danger, .text-danger { - color: #DE0A0A -} - -.label-primary { - background-color: #79589F -} - -.label-success { - background-color: #008700 -} - -.label-info { - background-color: #006DEB -} - -.label-warning { - background-color: #C74C00 -} - -.assume-identity, .label-danger { - background-color: #DE0A0A -} - -.label-default { - background-color: #62738D -} - -code { - color: #475366; - background-color: #F7F8FB -} - -.form-control::-webkit-input-placeholder { - color: #62738D -} - -.form-control:-moz-placeholder { - color: #62738D -} - -.form-control::-moz-placeholder { - color: #62738D -} - -.form-control:-ms-input-placeholder { - color: #62738D -} - -.form-control::-ms-input-placeholder { - color: #62738D -} - -.active .sub-nav-item-name { - color: #79589F -} - -.hk-slide-panel-overlay { - z-index: 100; - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - overflow: hidden; - opacity: 0; - background: 0 0; - transition: .4s cubic-bezier(.3, 0, 0, 1) -} - -.hk-slide-panel-overlay.is-visible { - opacity: 1; - background: rgba(89, 105, 129, .2) -} - -.hk-slide-panel-container { - overflow-y: hidden; - min-height: 200px; - transition: transform .4s cubic-bezier(.3, 0, 0, 1) -} - -.hk-slide-panel-container.from-left, .hk-slide-panel-container.from-right { - top: 0; - height: calc(100% - 20px) -} - -@media only screen and (min-device-width: 768px) and (orientation: portrait) { - .hk-slide-panel-container.from-left, .hk-slide-panel-container.from-right { - max-height: 1050px - } -} - -.hk-slide-panel-container.from-left { - left: 0; - transform: translateX(-400px) -} - -.hk-slide-panel-container.from-left.large { - transform: translateX(-50vw) -} - -.is-visible .hk-slide-panel-container.from-left, .is-visible .hk-slide-panel-container.from-left .large { - transform: translateX(0) -} - -.hk-slide-panel-container.from-right { - right: 0; - transform: translateX(400px) -} - -.hk-slide-panel-container.from-right.large { - transform: translateX(50vw) -} - -.is-visible .hk-slide-panel-container.from-right, .is-visible .hk-slide-panel-container.from-right .large { - transform: translateX(0) -} - -.hk-slide-panel-container.from-bottom, .hk-slide-panel-container.from-top { - left: 0; - right: 0 -} - -@media only screen and (min-device-width: 320px) and (max-device-width: 480px) { - .hk-slide-panel-container, .hk-slide-panel-container.from-left, .hk-slide-panel-container.from-right { - width: calc(100% - 20px) - } - - .hk-slide-panel-container.from-bottom, .hk-slide-panel-container.from-top { - height: 100% - } -} - -@media only screen and (min-device-width: 768px) { - .hk-slide-panel-container { - min-width: 400px - } - - .hk-slide-panel-container.from-left, .hk-slide-panel-container.from-right { - width: 400px - } - - .hk-slide-panel-container.from-left.large, .hk-slide-panel-container.from-right.large { - width: 50vw - } - - .hk-slide-panel-container.from-bottom, .hk-slide-panel-container.from-top { - height: 400px - } - - .hk-slide-panel-container.from-bottom.large, .hk-slide-panel-container.from-top.large { - height: 50vh; - min-height: 400px - } -} - -.hk-slide-panel-container.from-bottom { - bottom: 0; - transform: translateY(400px) -} - -.hk-slide-panel-container.from-bottom.large { - transform: translateY(50vh) -} - -.is-visible .hk-slide-panel-container.from-bottom, .is-visible .hk-slide-panel-container.from-bottom .large { - transform: translateY(0) -} - -.hk-slide-panel-container.from-top { - top: 0; - transform: translateY(-400px) -} - -.hk-slide-panel-container.from-top.large { - transform: translateY(-50vh) -} - -.is-visible .hk-slide-panel-container.from-top, .is-visible .hk-slide-panel-container.from-top .large { - transform: translateY(0) -} - -.hk-slide-panel-footer, .hk-slide-panel-header { - overflow: hidden; - min-height: 51px; - flex: 0 0 auto -} - -.hk-slide-panel-content { - flex: 1; - background: linear-gradient(white 30%, rgba(255, 255, 255, 0)), linear-gradient(rgba(255, 255, 255, 0), #fff 70%) 0 100%, radial-gradient(50% 0, farthest-side, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0)), radial-gradient(50% 100%, farthest-side, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0)) 0 100%; - background: linear-gradient(white 30%, rgba(255, 255, 255, 0)), linear-gradient(rgba(255, 255, 255, 0), #fff 70%) 0 100%, radial-gradient(farthest-side at 50% 0, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0)), radial-gradient(farthest-side at 50% 100%, rgba(0, 0, 0, .1), rgba(0, 0, 0, 0)) 0 100%; - background-repeat: no-repeat; - background-color: #fff; - background-size: 100% 40px, 100% 40px, 100% 14px, 100% 14px; - background-attachment: local, local, scroll, scroll -} - -.slide-panel-shadow-cover-top { - flex-basis: 10px; - flex-shrink: 0; - flex-grow: 0; - height: 10px; - width: 100%; - background: linear-gradient(#FFF 30%, rgba(255, 255, 255, 0)) 100% 0; - background-size: 100% 12px; - background-repeat: no-repeat; - pointer-events: none -} - -.slide-panel-shadow-cover-bottom { - flex-basis: 10px; - flex-shrink: 0; - flex-grow: 0; - height: 10px; - width: 100%; - background: linear-gradient(rgba(255, 255, 255, 0), #FFF 70%) 0 100%; - background-size: 100% 12px; - background-repeat: no-repeat; - pointer-events: none -} - -body.panel-is-visible { - -webkit-overflow-scrolling: touch; - overflow: hidden -} - -.hk-slide-panel-container.from-bottom .hk-slide-panel-content, .hk-slide-panel-container.from-top .hk-slide-panel-content { - height: calc(100% - 40px) -} - -.hk-slide-panel-container.from-bottom .hk-slide-panel-footer, .hk-slide-panel-container.from-bottom .hk-slide-panel-header, .hk-slide-panel-container.from-top .hk-slide-panel-footer, .hk-slide-panel-container.from-top .hk-slide-panel-header { - min-height: 40px -} - -@keyframes hk-fade-in { - from { - opacity: 0 - } - to { - opacity: 1 - } -} - -@keyframes hk-fade-out { - from { - opacity: 1 - } - to { - opacity: 0 - } -} - -@keyframes hk-slide-up { - from { - transform: translateY(calc(100% + 8px)) - } - to { - transform: translateY(0) - } -} - -@keyframes hk-slide-down { - from { - transform: translateY(0) - } - to { - transform: translateY(calc(100% + 8px)) - } -} - -.hk-slide-panel-breakout-overlay { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 100; - background: rgba(89, 105, 129, .15); - animation: .3s cubic-bezier(.3, 0, 0, 1) both hk-fade-in -} - -.hk-slide-panel-breakout-content { - position: absolute; - left: 0; - right: 0; - bottom: 0; - z-index: 100; - background: #fff; - animation: .3s cubic-bezier(.3, 0, 0, 1) .1s both hk-slide-up -} - -.hk-slide-panel-breakout[hidden] { - display: block -} - -.hk-slide-panel-breakout[hidden] .hk-slide-panel-breakout-overlay { - animation: .3s cubic-bezier(.3, 0, 0, 1) both hk-fade-out -} - -.hk-slide-panel-breakout[hidden] .hk-slide-panel-breakout-content { - animation: .3s cubic-bezier(.3, 0, 0, 1) both hk-slide-down -} - -table.editable-list, table.static-list { - table-layout: fixed -} - -.buildpack-installations-list .editable-list, table.editable-list.ssh-keys, table.table-auto { - table-layout: auto -} - -table.editable-list .icon-cell, table.static-list .icon-cell { - width: 32px -} - -table.editable-list td:last-of-type, table.static-list td:last-of-type { - padding-right: 0 -} - -table.editable-list .action-cell, table.static-list .action-cell { - width: 24px -} - -table.editable-list .action-cell button.btn-link, table.static-list .action-cell button.btn-link { - padding: 8px 10px; - border: none -} - -table.editable-list .action-cell .context-switcher__list button, table.editable-list .action-cell .drop-down__menu button, table.static-list .action-cell .context-switcher__list button, table.static-list .action-cell .drop-down__menu button { - padding: 4px 12px 3px -} - -table.editable-list .item-removed td { - color: #CFD7E6 !important -} - -table.editable-list .item-removed td .form-control, table.editable-list .item-removed td a, table.editable-list .item-removed td span { - color: #CFD7E6 !important; - text-decoration: line-through -} - -table.editable-list .item-removed td img { - opacity: .4 -} - -table.editable-list .item-not-addable { - display: none -} - -table.editable-list .item-added:not(.item-new) td { - color: #62738D -} - -table.editable-list .item-added:not(.item-new) td .form-control { - color: #62738D !important -} - -table.editable-list .item-added:not(.item-new) td img { - opacity: .6 -} - -table.editable-list tbody.app-json-config-row { - border-top: 1px solid #e7ebf3 !important -} - -table.editable-list tbody.app-json-config-row td, table.editable-list tbody.app-json-config-row:first-of-type { - border: none !important -} - -.certRadio.checked, .certRadio:hover { - border: 1px solid #79589f -} - -.certRadio { - transition: all 150ms ease-in-out -} - -.checked.hk-message--danger.certRadio { - border: 1px solid #de0a0a -} - -.form-group { - position: relative -} - -.form-group .input-badge { - position: absolute; - top: 7px; - right: 10px -} - -.form-group .app-picker { - position: relative -} - -.form-group .app-picker .icon { - position: absolute; - top: 8px; - left: 10px -} - -.form-group .app-picker .form-control { - padding-left: 32px -} - -.edit-first .input-badge { - left: 100%; - right: auto; - margin-left: -26px -} - -.edit-first .team-name { - height: 131px -} - -textarea.form-control { - resize: none; - white-space: nowrap; - overflow-x: hidden !important; - padding-right: 1px -} - -input[type=range] { - display: inline-block; - width: auto -} - -.form-control:focus ~ .field-error-message-wrapper, .nav.nav-tabs.sub-nav svg, .nav.nav-tabs.sub-nav.pipeline-nav::after { - display: none -} - -.field-error-message { - font-size: 11px; - font-weight: 700; - color: #DE0A0A; - padding: 2px 0 -} - -td .field-error-message { - position: absolute; - top: 4px; - right: 1px; - padding: 6px 10px; - background: #fff; - pointer-events: none -} - -td .field-error-message::after { - content: ''; - position: absolute; - left: -10px; - top: 0; - bottom: 0; - width: 10px; - background-image: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0, #fff 100%); - background-image: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0, #fff 100%); - background-image: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0, #fff 100%); - background-image: linear-gradient(to right, rgba(255, 255, 255, 0) 0, #fff 100%) -} - -td .form-group { - position: relative; - margin: 0; - padding: 0 -} - -.form-control::-webkit-input-placeholder { - opacity: 1 -} - -.form-control:-moz-placeholder { - opacity: 1 -} - -.form-control::-moz-placeholder { - opacity: 1 -} - -.form-control:-ms-input-placeholder { - opacity: 1 -} - -input.placeholder-value::-webkit-input-placeholder { - color: #3F3F44 -} - -input.placeholder-value:-moz-placeholder { - color: #3F3F44 -} - -input.placeholder-value::-moz-placeholder { - color: #3F3F44 -} - -input.placeholder-value:-ms-input-placeholder { - color: #3F3F44 -} - -input.placeholder-value:focus::-webkit-input-placeholder { - color: #fff -} - -input.placeholder-value:focus:-moz-placeholder { - color: #fff -} - -input.placeholder-value:focus::-moz-placeholder { - color: #fff -} - -input.placeholder-value:focus:-ms-input-placeholder { - color: #fff -} - -.input-group .input-group-btn .btn { - line-height: 20px; - padding-bottom: 7px; - padding-top: 7px -} - -@media (min-width: 768px) { - .edit-first .compacted-item, .edit-first input[type=password], .edit-first input[type=text], .edit-first select, .edit-first textarea { - width: 65% - } - - .edit-first label { - text-overflow: ellipsis; - overflow: hidden - } - - .edit-first .input-badge { - left: 65%; - right: auto; - margin-left: -26px - } -} - -.nav.nav-tabs.sub-nav { - position: relative; - border: none; - text-align: left; - padding: 3px 20px 0; - margin: 0 -20px 20px; - background: #fff; - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0 -} - -.nav.nav-tabs.sub-nav.pipeline-nav { - margin: 0; - box-shadow: inset 0 -1px 0 #e7ebf3 -} - -.nav.nav-tabs.sub-nav a { - padding: 11px 10px; - height: 47px -} - -.nav.nav-tabs.sub-nav svg { - margin: 0 -} - -.nav.nav-pills .active { - background: #408FEC; - color: #fff -} - -.addons-quick-add > .twitter-typeahead, .tag-toggle.unchecked { - background-color: #fff -} - -@media (max-width: 767px) { - .nav.nav-tabs.sub-nav { - text-align: center - } - - .nav.nav-tabs.sub-nav a { - padding: 11px 2px; - height: 47px - } - - .nav.nav-tabs.sub-nav .sub-nav-item-name { - display: none - } - - .nav.nav-tabs.sub-nav svg { - display: inline-block; - vertical-align: middle - } -} - -table.collaborator-list tr.collaborator-item { - min-height: 56px -} - -table.collaborator-list tr.collaborator-item .role { - color: #62738D -} - -@media screen and (min-width: 768px) { - table.collaborator-list tr.collaborator-item td.collaborator-info { - padding-top: 0; - padding-bottom: 0 - } - - table.collaborator-list tr.collaborator-item .email, table.collaborator-list tr.collaborator-item .form-group, table.collaborator-list tr.collaborator-item .permissions, table.collaborator-list tr.collaborator-item .role { - display: inline-block - } - - table.collaborator-list tr.collaborator-item .permissions, table.collaborator-list tr.collaborator-item .role { - padding: 6px 8px - } - - table.collaborator-list tr.collaborator-item .email { - padding: 8px - } - - table.collaborator-list tr.collaborator-item .email, table.collaborator-list tr.collaborator-item .form-group { - width: 50% - } - - table.collaborator-list tr.collaborator-item .show-role.show-permissions .email { - width: 35% - } - - table.collaborator-list tr.collaborator-item .show-role.show-permissions .role { - width: 15% - } -} - -@media (max-width: 768px) { - table.editable-list, table.static-list { - table-layout: auto - } - - table.collaborator-list tr.collaborator-item td.avatar { - vertical-align: top - } - - table.collaborator-list tr.collaborator-item .email, table.collaborator-list tr.collaborator-item .permissions, table.collaborator-list tr.collaborator-item .role { - padding: 3px 0 - } -} - -div.collaborator-list h5 { - float: left -} - -div.collaborator-list div.tooltip-inner a { - color: #fff -} - -.addons-quick-add { - z-index: 1 -} - -.addons-quick-add, .addons-quick-add > .twitter-typeahead { - width: 100% -} - -.addons-quick-add .tt-hint { - width: auto -} - -.addons-quick-add > i { - position: absolute; - top: 6px; - left: 6px; - z-index: 3 -} - -.addons-quick-add .addon-typeahead-cell.disabled .addon-icon { - opacity: .3 -} - -.addons-quick-add .addon-typeahead-cell.disabled .addon-typeahead-title { - color: #62738D -} - -.addons-quick-add .addon-typeahead-cell.disabled .disabled { - font-size: 11px; - padding: 3px 7px; - border-radius: 4px; - text-transform: uppercase; - background: #CFD7E6; - font-weight: 700 -} - -.addons-table-container.unfocused { - opacity: .3 -} - -#modal-overlays .ember-modal-dialog.dyno-upgrade-modal { - width: 450px; - padding: 0 25px -} - -#modal-overlays .ember-modal-dialog.dyno-upgrade-modal .modal-body div, #modal-overlays .ember-modal-dialog.dyno-upgrade-modal .panel-section .panel-details, #modal-overlays .ember-modal-dialog.dyno-upgrade-modal p, .panel-section #modal-overlays .ember-modal-dialog.dyno-upgrade-modal .panel-details { - text-align: center; - font-weight: lighter -} - -#modal-overlays .ember-modal-dialog.dyno-upgrade-modal .modal-footer { - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -moz-box-orient: vertical; - box-orient: vertical; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: column; - -moz-flex-direction: column; - flex-direction: column; - -ms-flex-direction: column; - text-align: center -} - -.attachments-dropdown .tooltip-component, .external-link { - display: inline-block -} - -#modal-overlays .ember-modal-dialog.dyno-upgrade-modal .modal-footer .btn + .btn { - margin: 0 0 12px !important -} - -#modal-overlays .ember-modal-dialog.dyno-upgrade-modal .btn-primary { - -webkit-box-ordinal-group: 1; - -moz-box-ordinal-group: 1; - box-ordinal-group: 1; - -webkit-order: 1; - -moz-order: 1; - order: 1; - -ms-flex-order: 1 -} - -#modal-overlays .ember-modal-dialog.dyno-upgrade-modal .btn-default { - -webkit-box-ordinal-group: 2; - -moz-box-ordinal-group: 2; - box-ordinal-group: 2; - -webkit-order: 2; - -moz-order: 2; - order: 2; - -ms-flex-order: 2 -} - -#modal-overlays .ember-modal-dialog.dyno-upgrade-modal .dyno-upgrade-pricing { - font-weight: 400 -} - -a.deprecated:focus, a.deprecated:hover { - color: rgba(222, 10, 10, .8) -} - -.context-switcher__list > li > a.hk-dropdown-item--danger, .context-switcher__list > li > a.hk-dropdown-item--danger:hover, .drop-down__menu > li > a.hk-dropdown-item--danger, .drop-down__menu > li > a.hk-dropdown-item--danger:hover { - color: #de0a0a -} - -.attachments-dropdown .icon.icon-inline { - margin-right: 0 !important -} - -.attachments-dropdown .malibu-fill-gradient-purple { - fill: url(#gradient-purple) -} - -.add.adding .icon { - -webkit-transform: rotate(45deg); - -moz-transform: rotate(45deg); - -ms-transform: rotate(45deg); - -o-transform: rotate(45deg); - transform: rotate(45deg) -} - -.external-link { - vertical-align: middle; - position: relative; - top: -2px; - margin-left: 4px -} - -.monospace { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace -} - -.app-resource-total-line-item { - padding-bottom: 15px -} - -.app-resource-total-line-item:after, .app-resource-total-line-item:before { - content: " "; - display: table -} - -.app-resource-total-line-item:after { - clear: both -} - -.app-resource-total-line-item .line-item-label { - color: #62738D; - float: left; - font-weight: 600 -} - -.app-resource-total-line-item .line-item-values { - float: right -} - -.app-resource-total-line-item .line-item-new-value { - display: inline-block; - text-align: right; - width: 90px -} - -.app-resource-total-line-item .dirty { - color: #CFD7E6; - text-decoration: line-through -} - -.metrics__datastore-chart .metrics__chart-sorting__handle, .metrics__datastore-chart .metrics__chart__devcenter-link { - display: none -} - -.metrics__datastore-chart .metrics__chart__header > div, .metrics__datastore-chart .metrics__chart__wrapper { - padding-left: 0; - padding-right: 0 -} - -.formation-filter-drop-down > button, .formation-filter-drop-down > button:active, .formation-filter-drop-down > button:focus, .formation-filter-drop-down > button:hover { - padding: 0 !important; - border: none !important; - background: 0 0 !important; - font-weight: 700 !important; - text-transform: uppercase !important; - box-shadow: none !important; - color: #96A3B6 !important; - font-size: 11px !important -} - -.formation-filter-drop-down .context-switcher__list, .formation-filter-drop-down .drop-down__menu { - margin-top: -20px -} - -.label.label-hollow { - background: 0 0; - border: 1px solid -} - -.label.label-caps { - font-variant: small-caps; - padding-top: .03em; - padding-bottom: .06em -} - -.label.label-text { - background: 0 0; - font-weight: 700; - font-size: 1em -} - -.label.label-text.label-default { - color: #62738D -} - -.label.label-text.label-success { - color: #008700 -} - -.label.label-text.label-primary { - color: #79589F -} - -.label.label-text.label-info { - color: #006DEB -} - -.label.label-text.label-warning { - color: #C74C00 -} - -.label.label-text.label-danger { - color: #DE0A0A -} - -.panel-section label .panel-details, label .panel-section .panel-details, label small { - display: block; - font-weight: 400; - font-size: 12px; - padding-top: 4px; - padding-bottom: 2px -} - -label span.optional { - color: #62738D; - font-weight: 400 -} - -.new-app-view .config-vars .btn { - width: 100% -} - -.new-app-view .config-vars label { - font-family: "Bitstream Vera Sans Mono", Consolas, Courier, monospace -} - -.new-app-view .building-failed, .new-app-view .creating-failed, .new-app-view .scaling-failed { - color: #DE0A0A -} - -.new-app-view .is-built, .new-app-view .is-configured, .new-app-view .is-created, .new-app-view .is-deployed, .new-app-view .is-scaled { - color: #008700 -} - -.new-app-view .will-build, .new-app-view .will-configure, .new-app-view .will-deploy, .new-app-view .will-scale { - color: #E3E7EF -} - -.new-app-view .template-env label:not(:first-of-type) { - margin-top: 15px -} - -@media (min-width: 768px) { - .new-space-view input[type=password], .new-space-view input[type=text], .new-space-view select, .new-space-view textarea { - width: 65% - } -} - -.app-list, .first-run, .space-list, .team-list { - margin-left: -20px; - margin-right: -20px -} - -.app-list .stack-info { - text-align: right; - margin-left: auto; - margin-bottom: 0; - padding-left: 0; - position: relative; - top: 1px -} - -.app-list .stack-info li { - display: inline -} - -.app-list .stack-info li a { - display: inline-block -} - -.app-list.list-group { - margin-bottom: 0 -} - -.app-list #favorites-container .metrics__summary-row__item, .app-list .apps-list-favorite-item .metrics__summary-row__item { - border-right: 1px solid #E3E7EF; - border-image: linear-gradient(to top, #CFD7E6, rgba(227, 231, 239, 0)) 1 100%; - padding-left: 10px -} - -.app-list #favorites-container .metrics__summary-row__item:first-child, .app-list .apps-list-favorite-item .metrics__summary-row__item:first-child { - padding-left: 2px; - padding-right: 10px -} - -.app-list #favorites-container .metrics__summary-row__value, .app-list .apps-list-favorite-item .metrics__summary-row__value { - font-size: 14px -} - -.app-list #favorites-container .metrics__summary-row__unit, .app-list .apps-list-favorite-item .metrics__summary-row__unit { - font-size: 12px -} - -.app-list #favorites-container timeseries-chart::after, .app-list .apps-list-favorite-item timeseries-chart::after { - content: ''; - position: absolute; - top: 0; - bottom: -1px; - left: 0; - width: 50px; - background-color: transparent; - background-image: -webkit-linear-gradient(left, #fff, rgba(255, 255, 255, 0)); - background-image: linear-gradient(to right, #fff, rgba(255, 255, 255, 0)) -} - -@media (max-width: 767px) { - .app-list #favorites-container .metrics__summary-row__item, .app-list .apps-list-favorite-item .metrics__summary-row__item { - border-right: 0 - } - - .app-list #favorites-container timeseries-chart, .app-list .apps-list-favorite-item timeseries-chart { - display: none - } -} - -@media (max-width: 320px) { - .app-list #favorites-container .favorite-app .favorite-tray, .app-list .apps-list-favorite-item .favorite-app .favorite-tray { - display: none - } -} - -.app-list .app-count { - position: relative; - padding-left: 10px; - display: inline-block -} - -.app-list .app-count .btn { - font-size: 13px; - color: #62738D; - text-decoration: none -} - -#getting-started + #app-list #favorites-container, #has-no-apps + #app-list #favorites-container { - margin-top: 10px -} - -.org-header { - position: relative; - text-align: center; - width: 100% -} - -.org-header h2, .org-header h3 { - line-height: 1; - margin: 0 -} - -.org-header h2 { - color: inherit; - font-size: 16px; - margin-bottom: 4px -} - -.org-header h3 { - color: #CFD7E6; - font-size: 12px -} - -.apps-header .org-header { - position: absolute -} - -.org-collaborators-list tr td.org-member-details .member-email, .org-members-list tr td.org-member-details .member-email { - display: inline-block; - float: left; - width: 33% -} - -.org-collaborators-list tr td.org-member-details .member-access, .org-collaborators-list tr td.org-member-details .member-auth, .org-collaborators-list tr td.org-member-details .member-role, .org-collaborators-list tr td.org-member-details .member-status, .org-members-list tr td.org-member-details .member-access, .org-members-list tr td.org-member-details .member-auth, .org-members-list tr td.org-member-details .member-role, .org-members-list tr td.org-member-details .member-status { - float: left; - width: 22% -} - -.org-collaborators-list tr td.org-member-details .static, .org-members-list tr td.org-member-details .static { - min-height: 34px; - padding: 7px 9px 8px -} - -.org-collaborators-list tr td.org-member-details .action-button .icon, .org-members-list tr td.org-member-details .action-button .icon { - position: relative; - left: 5px; - top: -1px -} - -.org-collaborators-list tr td.org-member-details .member-auth, .org-members-list tr td.org-member-details .member-auth { - position: relative -} - -.org-collaborators-list tr td.org-member-details .member-auth .member-auth-message, .org-members-list tr td.org-member-details .member-auth .member-auth-message { - position: absolute; - left: 36px; - top: 50%; - -webkit-transform: translate(0, -50%); - -moz-transform: translate(0, -50%); - -ms-transform: translate(0, -50%); - -o-transform: translate(0, -50%); - transform: translate(0, -50%); - width: 111px -} - -.org-collaborators-list tr td.org-member-details .member-access, .org-members-list tr td.org-member-details .member-access { - text-align: right; - font-size: 12px -} - -.org-collaborators-list tr td.org-member-details .member-status, .org-members-list tr td.org-member-details .member-status { - text-align: center; - color: #62738D -} - -@media (max-width: 768px) { - .org-collaborators-list tr td.org-member-details .member-email, .org-collaborators-list tr td.org-member-details .member-tfa, .org-members-list tr td.org-member-details .member-email, .org-members-list tr td.org-member-details .member-tfa { - margin-bottom: 8px - } - - .org-collaborators-list tr td.org-member-details .member-email, .org-collaborators-list tr td.org-member-details .member-role, .org-members-list tr td.org-member-details .member-email, .org-members-list tr td.org-member-details .member-role { - width: 65% - } - - .org-collaborators-list tr td.org-member-details .member-access, .org-collaborators-list tr td.org-member-details .member-tfa, .org-members-list tr td.org-member-details .member-access, .org-members-list tr td.org-member-details .member-tfa { - width: 35%; - padding-left: 9px - } - - .org-collaborators-list tr td.org-member-details .member-access .dropdown, .org-members-list tr td.org-member-details .member-access .dropdown { - float: left - } -} - -.org-members hr { - height: 2px; - background: #EEF1F6; - border-top: 1px solid rgba(207, 215, 230, .5); - border-bottom: 1px solid rgba(207, 215, 230, .5); - margin: -10px 0 12px -} - -.member-email { - overflow: hidden; - text-overflow: ellipsis -} - -@media (min-width: 768px) { - .org-plan dt { - width: 190px - } -} - -.org-plan dd .panel-section .panel-details, .org-plan dd small, .panel-section .org-plan dd .panel-details { - display: block; - color: #CFD7E6 -} - -progress[value] { - width: 100%; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - border: none -} - -.progress-actual progress[value] { - color: #79589F; - background: rgba(121, 88, 159, .1); - border-radius: 2px; - box-shadow: inset 0 0 0 1px rgba(121, 88, 159, .2); - height: 6px -} - -.progress-actual.over-quota progress[value] { - color: #DE0A0A; - background: rgba(222, 10, 10, .1); - box-shadow: inset 0 0 0 1px rgba(222, 10, 10, .2) -} - -.progress-allowance progress[value] { - color: #E3E7EF; - background: #E3E7EF; - height: 1px -} - -progress::-webkit-progress-bar { - background: rgba(121, 88, 159, .1); - border-radius: 2px; - box-shadow: inset 0 0 0 1px rgba(121, 88, 159, .2) -} - -.progress-allowance progress::-webkit-progress-bar { - background: #E3E7EF; - box-shadow: none -} - -progress::-webkit-progress-value { - background: #79589F; - border-radius: 2px; - transition: width .8s ease-in-out -} - -.progress-actual.over-quota progress::-webkit-progress-value { - background: #DE0A0A -} - -.progress-allowance progress::-webkit-progress-value { - background: #CFD7E6; - height: 3px; - position: relative; - top: -1px -} - -.progress-allowance progress::-webkit-progress-value::after { - content: ''; - position: absolute; - width: 7px; - height: 7px; - background: #CFD7E6; - top: -2px; - right: 0; - border-radius: 50% -} - -progress::-moz-progress-bar { - background: #79589F; - border-radius: 2px; - transition: width .8s ease-in-out -} - -.progress-actual.over-quota progress::-moz-progress-bar { - background: #DE0A0A -} - -.progress-allowance progress::-moz-progress-bar { - height: 3px; - position: relative; - margin-top: -1px; - background: #CFD7E6 -} - -.enterprise-teams li:last-of-type { - border: none -} - -.org-identicon-mini { - position: relative; - width: 18px; - height: 18px; - font-size: 8px; - font-weight: 700; - line-height: 19px; - color: #fff; - text-align: center; - display: inline-block; - box-shadow: inset 0 0 0 1px #62738D, inset 0 0 0 2px rgba(255, 255, 255, .7); - background: #62738D; - border-radius: 50% -} - -.org-identicon-mini .info-tooltip-component { - position: absolute; - top: 1px; - left: 1px; - margin-left: 0; - opacity: 0 -} - -.metrics__legend, .metrics__not-available { - -webkit-box-orient: vertical; - -moz-box-direction: normal -} - -.panel-section .in-progress.panel-details, p.in-progress { - display: inline-block; - border: 1px solid #E3E7EF; - border-radius: 4px; - color: #62738D; - font-size: 13px; - padding: 1px 18px 0 -} - -.top-nav { - position: relative; - margin-left: 0; - margin-right: 0; - padding: 12px 20px 10px; - min-height: 63px; - margin-top: 18px; - /*border-bottom: 1px solid #e7ebf3;*/ - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0 -} - -.top-nav .actions { - -webkit-flex-grow: 0; - -moz-flex-grow: 0; - flex-grow: 0; - -ms-flex-positive: 0 -} - -.top-nav .loading-spinner-wrapper { - position: absolute; - width: 100%; - top: 50%; - margin-top: -10px; - left: 0; - text-align: center -} - -.top-nav .loading-spinner-wrapper .loading-spinner { - vertical-align: middle -} - -.top-nav a { - text-decoration: none -} - -.feedback-link-sub-nav { - padding: unset !important; - height: unset !important; - margin-left: 4px !important; - display: inline-block !important; - text-decoration: underline !important; - color: #006deb !important -} - -.lock-status, .tag-toggle-list > div:first-of-type { - margin-left: 0 -} - -.feedback-link-sub-nav:hover::after { - display: none -} - -.tag-toggle-list > div { - display: inline-block; - margin-right: 4px -} - -.lock-status, .tag-toggle-list > div:last-of-type { - margin-right: 0 -} - -.tag-toggle { - padding: 2px 16px; - border-radius: 4px; - border: 1px solid gray; - font-size: 11px -} - -.tag-toggle.unchecked { - color: #79589F; - border-color: #ad97c6 -} - -.tag-toggle.actionable.checked, .tag-toggle.checked { - background-color: #79589F -} - -.tag-toggle.checked { - color: #fff; - border-color: #79589F -} - -.metrics__color--purple-001--legend--border, .metrics__color--purple-002--legend--border, .metrics__color--purple-003--legend--border, .metrics__color--purple-004--legend--border { - border-color: rgba(121, 88, 159, .7); - border-style: none; - border-width: 1px -} - -.tag-toggle.show-icon { - padding-left: 8px; - padding-right: 8px -} - -.tag-toggle.actionable { - cursor: pointer -} - -.tag-toggle.actionable:hover { - background-color: #9377b3; - color: #fff -} - -.metrics__color--purple-001--background, .metrics__color--purple-001--legend { - background-color: rgba(121, 88, 159, .1) -} - -.tag-toggle.nonactionable { - cursor: not-allowed -} - -.loading-spinner .dots { - width: 100%; - display: flex; - -webkit-box-pack: distribute; - -moz-box-pack: distribute; - box-pack: distribute; - -webkit-justify-content: space-around; - -moz-justify-content: space-around; - -ms-justify-content: space-around; - -o-justify-content: space-around; - justify-content: space-around; - -ms-flex-pack: distribute -} - -.loading-spinner.small { - width: 18px -} - -.loading-spinner.small i.spinner__dot { - width: 4px; - height: 4px -} - -.icons .loading-spinner, .in-progress .loading-spinner { - width: 26px; - height: 32px; - padding-top: 14px -} - -.icons .loading-spinner i.spinner__dot, .in-progress .loading-spinner i.spinner__dot { - width: 6px; - height: 6px -} - -.lock-status { - position: relative; - padding: 0 140px 18px 44px; - box-shadow: 0 1px 0 #e7ebf3 -} - -.lock-status .panel-section .panel-details, .lock-status p, .panel-section .lock-status .panel-details { - margin-bottom: 2px; - font-size: 13px; - color: #62738D -} - -.lock-status .panel-section .panel-details strong, .lock-status p strong, .panel-section .lock-status .panel-details strong { - font-size: 14px; - color: #56667D -} - -.metrics__color--purple-001--text, .metrics__color--purple-002--text, .metrics__color--purple-003--text, .metrics__color--purple-004--text { - color: rgba(121, 88, 159, .7) -} - -.lock-status .icon { - position: absolute; - left: 0; - top: 4px -} - -.lock-status button { - position: absolute; - right: 0; - top: 3px -} - -@media (max-width: 480px) { - .lock-status { - padding: 0 0 18px 44px - } - - .lock-status button { - position: relative; - margin-top: 8px - } -} - -#overview-page .app-overview-metrics .metrics__chart--minimal.metrics__summary-row--favorite__link-wrapper, #overview-page .metrics__chart--minimal.data-unavailable, .buildpack-installations-list .metrics__chart--minimal.sortable-item.is-dragging, .metrics__chart--minimal.content-box, .metrics__chart--minimal.metrics__monitor-preview-chart__loading, .metrics__chart--minimal.metrics__not-available, .metrics__chart--minimal.purple-box, .metrics__chart-sorting .metrics__chart--minimal.sortable-item.is-dragging { - box-shadow: none -} - - -.invoice-graph g rect, .btn[disabled] svg * { - fill: #CFD7E6 -} - -@-webkit-keyframes rotate { - from { - -webkit-transform: rotateZ(0); - -moz-transform: rotateZ(0); - -ms-transform: rotateZ(0); - -o-transform: rotateZ(0); - transform: rotateZ(0) - } - to { - -webkit-transform: rotateZ(360deg); - -moz-transform: rotateZ(360deg); - -ms-transform: rotateZ(360deg); - -o-transform: rotateZ(360deg); - transform: rotateZ(360deg) - } -} - -@-moz-keyframes rotate { - from { - -webkit-transform: rotateZ(0); - -moz-transform: rotateZ(0); - -ms-transform: rotateZ(0); - -o-transform: rotateZ(0); - transform: rotateZ(0) - } - to { - -webkit-transform: rotateZ(360deg); - -moz-transform: rotateZ(360deg); - -ms-transform: rotateZ(360deg); - -o-transform: rotateZ(360deg); - transform: rotateZ(360deg) - } -} - -@-o-keyframes rotate { - from { - -webkit-transform: rotateZ(0); - -moz-transform: rotateZ(0); - -ms-transform: rotateZ(0); - -o-transform: rotateZ(0); - transform: rotateZ(0) - } - to { - -webkit-transform: rotateZ(360deg); - -moz-transform: rotateZ(360deg); - -ms-transform: rotateZ(360deg); - -o-transform: rotateZ(360deg); - transform: rotateZ(360deg) - } -} - -@keyframes rotate { - from { - -webkit-transform: rotateZ(0); - -moz-transform: rotateZ(0); - -ms-transform: rotateZ(0); - -o-transform: rotateZ(0); - transform: rotateZ(0) - } - to { - -webkit-transform: rotateZ(360deg); - -moz-transform: rotateZ(360deg); - -ms-transform: rotateZ(360deg); - -o-transform: rotateZ(360deg); - transform: rotateZ(360deg) - } -} - - -.app-item-favorite-tray { - min-height: 80px -} - -.formation-summary { - font-size: 13px; - color: #56667D -} - -.metrics__main__charts { - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-pack: justify; - -moz-box-pack: justify; - box-pack: justify; - -webkit-justify-content: space-between; - -moz-justify-content: space-between; - -ms-justify-content: space-between; - -o-justify-content: space-between; - justify-content: space-between; - -ms-flex-pack: justify; - -webkit-box-lines: multiple; - -moz-box-lines: multiple; - box-lines: multiple; - -webkit-flex-wrap: wrap; - -moz-flex-wrap: wrap; - -ms-flex-wrap: wrap; - flex-wrap: wrap -} - -.metrics__main__charts.is-compact > * { - -webkit-flex-grow: 1; - -moz-flex-grow: 1; - flex-grow: 1; - -ms-flex-positive: 1 -} - -.metrics__main__charts.is-compact .sortable-item { - min-width: 44%; - max-width: calc(50%) -} - -.metrics__main__charts.is-compact .is-left-chart { - border-right: 1px solid #E3E7EF -} - -.metrics__main__charts.is-vertical { - -webkit-box-orient: vertical; - -moz-box-orient: vertical; - box-orient: vertical; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: column; - -moz-flex-direction: column; - flex-direction: column; - -ms-flex-direction: column -} - -@media (max-width: 1200px) { - .metrics__main__charts { - -webkit-box-orient: vertical; - -moz-box-orient: vertical; - box-orient: vertical; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: column; - -moz-flex-direction: column; - flex-direction: column; - -ms-flex-direction: column - } - - .metrics__main__charts.is-compact .sortable-item { - max-width: 100% - } - - .metrics__main__charts.is-compact .has-bb-when-stacked { - border-bottom: 1px solid #E3E7EF - } - - .metrics__main__charts.is-compact .is-left-chart { - border-right: 0 - } -} - -.notification-list { - margin: 0 auto; - width: 100% -} - -.notification-item { - padding: 20px 15px -} - -.notification-item.read { - opacity: .6 -} - -.notification-item:before { - height: 7px; - width: 7px; - display: inline-block; - border-radius: 50%; - content: ''; - position: absolute; - top: 55px; - margin-top: -4px; - left: 6px; - background: #CFD7E6 -} - -.notification-item.unread:before { - background: #56CDFC -} - -.notification-item .notification-title { - font-size: 15px; - margin-top: 4px; - color: #475366 -} - -.notification-item .notification-message { - padding-top: 4px -} - -.notification-item .notification-message .panel-section .panel-details, .notification-item .notification-message p, .panel-section .notification-item .notification-message .panel-details { - color: #56667D; - font-size: 14px; - line-height: 21px -} - -.notification-item .notification-message .panel-section .panel-details:last-of-type, .notification-item .notification-message p:last-of-type, .panel-section .notification-item .notification-message .panel-details:last-of-type { - margin-bottom: 0 -} - -.notification-item .notification-message table { - margin-bottom: 20px -} - -.notification-item .notification-message table td, .notification-item .notification-message table th { - padding: 5px 15px 5px 0 -} - -.notification-item .notification-time { - color: #62738D; - font-size: 14px; - font-weight: 700 -} - -.notification-item:after { - content: ''; - clear: both; - display: block -} - -.dropdown-inline, .production-check-item .label, .text-center .flash-messages .flash-message { - display: inline-block -} - -.flash-notification { - margin: 15px; - background: #DE0A0A; - color: #fff; - text-align: center -} - -#modal-overlays .ember-modal-dialog.production-check .modal-box .check-message { - padding-top: 4px; - padding-left: 59px; - width: 90% -} - -#modal-overlays .ember-modal-dialog.production-check .modal-box .check-message .panel-section .panel-details, #modal-overlays .ember-modal-dialog.production-check .modal-box .check-message p, .panel-section #modal-overlays .ember-modal-dialog.production-check .modal-box .check-message .panel-details { - margin: 0 -} - -#modal-overlays .ember-modal-dialog.production-check .modal-body { - padding: 0 -} - -.production-check-loading { - height: 180px -} - -.production-check-item { - font-size: 13px; - padding: 10px 14px; - border-bottom: 1px solid #e7ebf3 -} - -.production-check-item:last-of-type { - border-bottom: none -} - -.production-check-item.skipped { - color: #62738D -} - -.production-check-item a.dev-center { - float: right -} - -.production-check-item .label { - position: relative; - top: -1px; - margin-right: 6px; - width: 50px; - padding: 2px 0 1px; - line-height: inherit -} - -.production-check-item .title { - font-weight: 700 -} - -.production-check-item .title-success { - color: #008700 -} - -.production-check-item .title-danger { - color: #DE0A0A -} - -.production-check-item .title-warning { - color: #C74C00 -} - -.flash-messages { - position: fixed; - z-index: 1100; - top: 62px; - right: 12px; - max-width: 100%; - -webkit-font-smoothing: subpixel-antialiased; - opacity: 0; - -webkit-transform: translateY(-16px); - -moz-transform: translateY(-16px); - -ms-transform: translateY(-16px); - -o-transform: translateY(-16px); - transform: translateY(-16px); - -webkit-transition: .5s; - -o-transition: .5s; - transition: .5s; - -webkit-transition-timing-function: cubic-bezier(.3, 0, 0, 2); - transition-timing-function: cubic-bezier(.3, 0, 0, 2) -} - -.flash-messages.rolled-down { - opacity: 1; - -webkit-transform: translateY(0); - -moz-transform: translateY(0); - -ms-transform: translateY(0); - -o-transform: translateY(0); - transform: translateY(0) -} - -.flash-messages .flash-message { - position: relative; - margin-bottom: 6px; - font-size: 12px; - padding: 6px 24px 6px 10px; - max-width: 400px; - overflow: hidden; - box-shadow: 0 1px 6px rgba(0, 0, 0, .1) -} - -@media (max-width: 440px) { - .flash-messages .flash-message { - max-width: 100% - } -} - -.flash-messages .flash-message.alert { - border: none; - color: #fff -} - -.flash-messages .flash-message.alert-danger { - background: #DE0A0A -} - -.flash-messages .flash-message.alert-success { - background: #008700 -} - -.flash-messages .flash-message .title { - font-weight: 700; - padding-right: 10px -} - -.flash-messages .flash-message .content li { - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .05); - padding: 4px 0 -} - -.flash-messages .flash-message .content li:last-of-type { - box-shadow: none; - padding-bottom: 0 -} - -.flash-messages .flash-message .flash-message-close { - -webkit-transition: .2s; - -o-transition: .2s; - transition: .2s -} - -.flash-messages .flash-message .flash-message-close:hover { - opacity: 1 -} - -.dropdown-right .context-switcher__list, .dropdown-right .drop-down__menu, .dropdown-right .dropdown-menu, .dropdown-right.context-switcher__list, .dropdown-right.drop-down__menu, .dropdown-right.dropdown-menu { - left: auto; - right: 0 -} - -.truncated-dropdown { - max-height: 220px; - overflow: auto -} - -.dropdown .dropdown-item-content { - padding: 3px 20px -} - -.context-switcher__list, .drop-down__menu, .dropdown-menu { - z-index: 48 -} - -.context-switcher__list .filter-menu, .drop-down__menu .filter-menu, .dropdown-menu .filter-menu { - padding: 2px 12px -} - -.context-switcher__list .dropdown-header, .drop-down__menu .dropdown-header, .dropdown-menu .dropdown-header { - position: relative; - z-index: 1; - margin: -5px 0 5px; - box-shadow: 0 1px 0 rgba(0, 0, 0, .1); - background-color: #FBFBFD; - border-top-right-radius: 3px; - border-top-left-radius: 3px -} - -.context-switcher__list .selected, .drop-down__menu .selected, .dropdown-menu .selected { - background: #EEF1F6 -} - -.context-switcher__list .selected .btn-link, .drop-down__menu .selected .btn-link, .dropdown-menu .selected .btn-link { - position: relative; - padding-right: 34px -} - -.context-switcher__list .selected .btn-link .selected-mark, .drop-down__menu .selected .btn-link .selected-mark, .dropdown-menu .selected .btn-link .selected-mark { - position: absolute; - top: 50%; - margin-top: -8px; - right: 8px -} - -.hk-dropdown a { - display: flex !important; - line-height: 1.5 !important; - padding: 4px 14px 4px 10px !important -} - -.hk-dropdown .icon { - margin: 0 10px 0 0 !important -} - -@media (max-width: 767px) { - .app-item-favorite-tray { - min-height: 0 - } - - .panel-section .section-description { - padding-bottom: 20px - } -} - -.panel-section .section-title .label { - position: relative; - top: -2px; - margin-left: 4px; - text-transform: uppercase; - font-size: 9px; - padding: 2px 5px 1px -} - -.panel-section .section-title .icon { - position: relative; - top: -1px; - margin-right: 4px -} - -.panel-section .panel-content .group-header { - margin-top: -5px -} - -.panel-section .panel-content .panel-details, .panel-section .panel-content p { - line-height: 22px -} - -.panel-section .panel-content .actions.panel-details .btn, .panel-section .panel-content p.actions .btn { - margin-right: 10px -} - -.panel-section.danger .section-title { - color: #DE0A0A -} - -ul.list-group-lg > li:first-of-type { - padding-top: 20px -} - -.form-intro { - padding-top: 20px !important; - padding-bottom: 20px !important -} - -.deploy-section .panel-content .dyno-tier-picker-item-size-name, .deploy-section .panel-content .panel-section .panel-title, .deploy-section .panel-content h4, .panel-section .deploy-section .panel-content .panel-title, .panel-section .pipeline-config .panel-content .panel-title, .pipeline-config .panel-content .dyno-tier-picker-item-size-name, .pipeline-config .panel-content .panel-section .panel-title, .pipeline-config .panel-content h4 { - color: #3F3F44; - font-size: 14px; - font-weight: 400; - margin-top: 20px -} - -.deploy-section .panel-content .dyno-tier-picker-item-size-name:first-child, .deploy-section .panel-content .panel-section .panel-title:first-child, .deploy-section .panel-content h4:first-child, .panel-section .deploy-section .panel-content .panel-title:first-child, .panel-section .pipeline-config .panel-content .panel-title:first-child, .pipeline-config .panel-content .dyno-tier-picker-item-size-name:first-child, .pipeline-config .panel-content .panel-section .panel-title:first-child, .pipeline-config .panel-content h4:first-child { - margin-top: 0 -} - -.deploy-section .panel-content .dyno-tier-picker-item-size-name .icon, .deploy-section .panel-content .panel-section .panel-title .icon, .deploy-section .panel-content h4 .icon, .panel-section .deploy-section .panel-content .panel-title .icon, .panel-section .pipeline-config .panel-content .panel-title .icon, .pipeline-config .panel-content .dyno-tier-picker-item-size-name .icon, .pipeline-config .panel-content .panel-section .panel-title .icon, .pipeline-config .panel-content h4 .icon { - margin-right: 4px -} - -.deploy-section .panel-content .dyno-tier-picker-item-size-name code, .deploy-section .panel-content .panel-section .panel-title code, .deploy-section .panel-content h4 code, .panel-section .deploy-section .panel-content .panel-title code, .panel-section .pipeline-config .panel-content .panel-title code, .pipeline-config .panel-content .dyno-tier-picker-item-size-name code, .pipeline-config .panel-content .panel-section .panel-title code, .pipeline-config .panel-content h4 code { - padding: 3px 6px; - margin: 0 4px -} - -.deploy-section .panel-content .dyno-tier-picker-item-size-name code .icon, .deploy-section .panel-content .panel-section .panel-title code .icon, .deploy-section .panel-content h4 code .icon, .panel-section .deploy-section .panel-content .panel-title code .icon, .panel-section .pipeline-config .panel-content .panel-title code .icon, .pipeline-config .panel-content .dyno-tier-picker-item-size-name code .icon, .pipeline-config .panel-content .panel-section .panel-title code .icon, .pipeline-config .panel-content h4 code .icon { - margin-right: -2px; - margin-top: -1px -} - -.deploy-section .panel-content .panel-section .panel-details:not(.help-block), .deploy-section .panel-content p:not(.help-block), .panel-section .deploy-section .panel-content .panel-details:not(.help-block), .panel-section .pipeline-config .panel-content .panel-details:not(.help-block), .pipeline-config .panel-content .panel-section .panel-details:not(.help-block), .pipeline-config .panel-content p:not(.help-block) { - color: #56667D; - font-size: 13px; - line-height: 22px -} - -.deploy-section .panel-content .deploy-nav, .pipeline-config .panel-content .deploy-nav { - text-align: left; - padding-bottom: 0; - margin-bottom: 0; - border-bottom: none -} - -.deploy-section .panel-content #auto-deploy-prs, .deploy-section .panel-content .enable-option, .pipeline-config .panel-content #auto-deploy-prs, .pipeline-config .panel-content .enable-option { - padding: 8px 0 0 -} - -.deploy-section .panel-content #auto-deploy-prs label, .deploy-section .panel-content .enable-option label, .pipeline-config .panel-content #auto-deploy-prs label, .pipeline-config .panel-content .enable-option label { - font-size: 13px; - font-weight: 400; - color: #56667D; - width: auto; - margin-bottom: 0 -} - -.deploy-section .panel-content #auto-deploy-prs label input, .deploy-section .panel-content .enable-option label input, .pipeline-config .panel-content #auto-deploy-prs label input, .pipeline-config .panel-content .enable-option label input { - margin-right: 4px -} - -.deploy-section .panel-content #auto-deploy-prs .loading-spinner, .deploy-section .panel-content .enable-option .loading-spinner, .pipeline-config .panel-content #auto-deploy-prs .loading-spinner, .pipeline-config .panel-content .enable-option .loading-spinner { - position: relative; - margin-left: 20px; - top: -1px; - vertical-align: middle -} - -.deploy-section .panel-content #auto-deploy-prs .help-block, .deploy-section .panel-content .enable-option .help-block, .pipeline-config .panel-content #auto-deploy-prs .help-block, .pipeline-config .panel-content .enable-option .help-block { - margin-bottom: 0 -} - -.deploy-section .panel-content .input-group .btn, .pipeline-config .panel-content .input-group .btn { - position: relative; - z-index: 2 -} - -.deploy-section .btn, .deploy-section .pipeline-status, .pipeline-config .btn, .pipeline-config .pipeline-status { - position: relative -} - -.deploy-section .pipeline-status::before, .pipeline-config .pipeline-status::before { - content: ''; - position: absolute; - top: 0; - left: -20px; - bottom: 0; - right: -20px; - background-color: #fff; - background-image: -webkit-linear-gradient(#fff, #F9F7FC); - background-image: linear-gradient(#fff, #F9F7FC); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .05) -} - -.deploy-section .pipeline-status .list-group-item, .pipeline-config .pipeline-status .list-group-item { - position: relative; - background: 0 0 -} - -.deploy-section .pipeline-status > ul > li.list-group-item, .pipeline-config .pipeline-status > ul > li.list-group-item { - position: relative; - margin: 0 -10px; - padding: 20px 10px 40px -} - -.deploy-section .pipeline-status .btn-default:not(:hover), .pipeline-config .pipeline-status .btn-default:not(:hover) { - background: 0 0 -} - -.deploy-section .pipeline-status .pipeline-actions, .pipeline-config .pipeline-status .pipeline-actions { - max-width: 600px -} - -.deploy-section .pipeline-status .pipeline-actions .alert, .pipeline-config .pipeline-status .pipeline-actions .alert { - margin-bottom: 0 -} - -.deploy-section .pipeline-status .pipeline-actions .hk-select, .pipeline-config .pipeline-status .pipeline-actions .hk-select { - max-width: 400px -} - -.deploy-section .ci-billing-options, .pipeline-config .ci-billing-options { - margin: 0 0 14px -} - -.deploy-section #ci-billing-target, .pipeline-config #ci-billing-target { - display: inline-block; - max-width: 340px -} - -.github-is-connected, .pipeline-is-connected { - margin-top: -14px !important; - margin-bottom: 0 -} - -.github-is-connected .list-group-item, .pipeline-is-connected .list-group-item { - display: block; - padding: 14px 0 -} - -.github-is-connected .list-group-item:last-child, .pipeline-is-connected .list-group-item:last-child { - padding-bottom: 0 -} - -.github-is-connected .connection .badge, .pipeline-is-connected .connection .badge { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; - background: #f3f5f8 !important; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1) !important; - border-radius: 3px; - color: #56667D; - font-size: 13px; - font-weight: 400; - position: relative; - top: -1px; - margin: 0 2px; - padding: 3px 5px -} - -.github-is-connected .panel-section .panel-details, .github-is-connected p, .panel-section .github-is-connected .panel-details, .panel-section .pipeline-is-connected .panel-details, .pipeline-is-connected .panel-section .panel-details, .pipeline-is-connected p { - margin-bottom: 0 -} - -.github-is-connected code, .pipeline-is-connected code { - margin: 0 10px 0 4px -} - -.github-is-connected code .icon, .pipeline-is-connected code .icon { - position: relative; - left: 2px; - top: -1px -} - -.github-is-connected code.pr-ref, .pipeline-is-connected code.pr-ref { - background: 0 0; - box-shadow: none; - margin-left: 0 -} - -.github-is-connected code.pr-ref a, .pipeline-is-connected code.pr-ref a { - font-family: benton-sans, "Helvetica Neue", helvetica, arial, sans-serif; - color: #62738D; - text-decoration: none -} - -.ci-menu .ci-meta .branch, .ci-menu .ci-status .test-time.pending, .ci-view .ci-view--meta .repo-info, .repo-link, table.editable-list.ssh-keys td { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace -} - -.github-is-connected code.pr-ref a .pr-id, .pipeline-is-connected code.pr-ref a .pr-id { - color: #79589F; - text-decoration: underline -} - -.repo-link { - margin: 0 4px; - font-size: 13px; - white-space: nowrap -} - -.repo-link .icon { - margin-right: -2px -} - -.app-json-config-row .alert { - margin: 0 -} - -.app-json-addons td.addon-icon { - width: 36px -} - -.app-json-addons td.addon-plan { - text-align: left -} - -.deploy-github .deploy-steps, .deploy-pipeline .deploy-steps { - margin-bottom: 0 -} - -.build-output-modal .modal-title { - color: #62738D; - font-size: 15px -} - -.build-output-modal .modal-title .icon, .build-output-modal .modal-title .loading-spinner { - position: relative; - margin-right: 6px; - top: -1px -} - -.build-output-modal .modal-title .icon { - margin-right: 4px -} - -.build-output-modal .modal-body { - padding: 15px 40px -} - -.build-output-modal .modal-body .deploy-steps { - margin: 0 -} - -.build-output-modal .modal-body .deploy-steps .panel-section .panel-details, .build-output-modal .modal-body .deploy-steps p, .panel-section .build-output-modal .modal-body .deploy-steps .panel-details { - font-size: 13px -} - -.build-output-modal .modal-body .deploy-steps .build-stream.post-deploy-script .build-stream-output { - max-height: 160px; - height: auto -} - -.app-github-disconnect { - text-align: center; - margin: 12px 28px -} - -.app-github-disconnect-warnings .alert { - margin-bottom: 16px -} - -.app-github-disconnect-warnings .alert:first-child { - margin-top: 22px -} - -#profile .avatar { - position: absolute; - left: 15px; - top: -2px -} - -#profile .profile { - padding-left: 68px -} - -#privacy label { - font-size: 14px; - font-weight: 400; - color: #56667D -} - -#privacy label input { - margin-right: 4px -} - -#two-factor .list-group { - margin-top: -14px -} - -#two-factor .list-group-item { - display: block; - overflow: hidden; - padding: 14px 0 -} - -#two-factor .list-group-item span { - padding: 2px 0 -} - -#two-factor .list-group-item .icon { - position: relative; - top: -1px; - margin-right: 4px -} - -#two-factor .list-group-item .actions .btn { - margin-left: 8px -} - -#two-factor .list-group-item .alert { - margin-bottom: 14px -} - -#two-factor .list-group-item .alert .panel-section .panel-details, #two-factor .list-group-item .alert p, .panel-section #two-factor .list-group-item .alert .panel-details { - margin: 0 -} - -.account-header { - text-align: center -} - -.account-header h2 { - color: inherit; - font-size: 16px; - margin-bottom: 4px -} - -.edit-password .current-password-field { - position: relative; - padding-bottom: 30px; - margin-bottom: 20px -} - -.edit-password .current-password-field::after { - content: ''; - position: absolute; - bottom: 0; - left: 0; - width: 65%; - height: 1px; - background-image: -webkit-linear-gradient(left, rgba(227, 231, 239, 0) 0, rgba(227, 231, 239, .7) 10%, #e3e7ef 50%, rgba(227, 231, 239, .7) 90%, rgba(227, 231, 239, 0) 100%); - background-image: -moz-linear-gradient(left, rgba(227, 231, 239, 0) 0, rgba(227, 231, 239, .7) 10%, #e3e7ef 50%, rgba(227, 231, 239, .7) 90%, rgba(227, 231, 239, 0) 100%); - background-image: -ms-linear-gradient(left, rgba(227, 231, 239, 0) 0, rgba(227, 231, 239, .7) 10%, #e3e7ef 50%, rgba(227, 231, 239, .7) 90%, rgba(227, 231, 239, 0) 100%); - background-image: linear-gradient(to right, rgba(227, 231, 239, 0) 0, rgba(227, 231, 239, .7) 10%, #e3e7ef 50%, rgba(227, 231, 239, .7) 90%, rgba(227, 231, 239, 0) 100%) -} - -@media (max-width: 768px) { - .edit-password .current-password-field::after { - width: 100% - } -} - -.panel-section .status.panel-details, p.status { - font-size: 14px; - color: #3F3F44; - padding-bottom: 10px -} - -.panel-section .status.panel-details code, p.status code { - margin-left: 8px; - font-size: 13px -} - -.panel-section .status.panel-details .icon, p.status .icon { - position: relative; - margin-right: 4px -} - -.panel-section .api-key.panel-details, p.api-key { - max-width: 320px -} - -.panel-section .api-key.success.panel-details input, p.api-key.success input { - background-color: #74C080; - color: #fff -} - -.third-party-auth { - margin-bottom: 0 -} - -.third-party-auth td.party-icon { - width: 42px -} - -.third-party-auth td a { - white-space: nowrap -} - -.panel-section .third-party-auth .panel-details, .third-party-auth .panel-section .panel-details, .third-party-auth p { - display: inline-block; - color: #56667D; - font-size: 13px; - margin-bottom: 0; - vertical-align: middle -} - -.panel-section .third-party-auth .panel-details b, .third-party-auth .panel-section .panel-details b, .third-party-auth p b { - font-weight: 400; - color: #3F3F44; - font-size: 14px; - display: block -} - -#app-links-table { - list-style: none; - width: 480px; - max-width: 100%; - padding-bottom: 12px; - padding-left: 0 -} - -#app-links-table li { - overflow: hidden; - border-bottom: 1px solid #E3E7EF; - padding: 8px 10px -} - -#app-links-table li:last-child { - border-bottom: none -} - -#app-links-table .app-repo-name { - float: left; - font-size: 13px -} - -#app-links-table .app-repo-name .icon { - margin-right: 6px -} - -#app-links-table .app-syncing-status { - float: right; - color: #62738D; - font-size: 12px; - padding-top: 1px -} - -#update-credit-card { - padding-bottom: 20px -} - -table td.application, table td.client, table td.invoice-title, table td.title { - width: 40% -} - -table td.domain, table td.no-charge, table td.pending, table td.permissions, table td.title, table td.void { - color: #62738D -} - -table td.paid { - color: #008700 -} - -table td.declined, table td.unpaid { - font-weight: 700; - color: #DE0A0A -} - -.invoice-graph { - margin-bottom: 30px -} - -.current-usage .table > tbody > tr > td:first-of-type, .invoices .table > tbody > tr > td:first-of-type { - padding-left: 0 -} - -.current-usage .table > tbody > tr > td:last-of-type, .invoices .table > tbody > tr > td:last-of-type { - padding-right: 0 -} - -.current-usage .invoice-row .over-quota, .invoices .invoice-row .over-quota { - color: #DE0A0A -} - -.current-usage .invoice-row .panel-section .panel-details, .current-usage .invoice-row small, .invoices .invoice-row .panel-section .panel-details, .invoices .invoice-row small, .panel-section .current-usage .invoice-row .panel-details, .panel-section .invoices .invoice-row .panel-details, .steps-2fa li { - color: #62738D -} - -.pay-now table { - position: relative; - max-width: 60%; - margin-right: auto -} - -.panel-section .pay-now .panel-details b, .pay-now .panel-section .panel-details b, .pay-now p b { - display: block; - font-size: 16px; - padding: 8px 0 14px -} - -.steps-2fa { - padding-left: 0; - padding-top: 30px; - padding-bottom: 10px -} - -.steps-2fa li { - position: relative; - font-size: 13px; - line-height: 18px; - vertical-align: top; - width: 190px; - display: inline-block; - margin-left: 0; - margin-right: 40px -} - -.steps-2fa li img { - margin-bottom: 20px -} - -.steps-2fa li.step-2 { - width: 220px -} - -.steps-2fa li:last-of-type { - margin-right: 0 -} - -@media (max-width: 767px) { - .pay-now table { - max-width: 100% - } - - .steps-2fa li { - display: block; - width: 100%; - max-width: 500px; - min-height: 58px; - padding-left: 120px; - margin-bottom: 20px - } - - .steps-2fa li.step-2 { - width: auto - } - - .steps-2fa li img { - position: absolute; - top: 0; - left: 0; - width: 92px; - height: 57px - } - - .panel-section .steps-2fa li .panel-details, .steps-2fa li .panel-section .panel-details, .steps-2fa li p { - margin-bottom: 0 - } -} - -.instructions-2fa { - padding-top: 10px -} - -.instructions-2fa .alert-warning { - margin: 20px 0 10px; - display: inline-block -} - -#overview-page .app-overview-metrics .instructions-2fa .metrics__summary-row--favorite__link-wrapper, #overview-page .instructions-2fa .data-unavailable, .buildpack-installations-list .instructions-2fa .sortable-item.is-dragging, .instructions-2fa #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper, .instructions-2fa #overview-page .data-unavailable, .instructions-2fa .buildpack-installations-list .sortable-item.is-dragging, .instructions-2fa .content-box, .instructions-2fa .metrics__chart-sorting .sortable-item.is-dragging, .instructions-2fa .metrics__monitor-preview-chart__loading, .instructions-2fa .metrics__not-available, .instructions-2fa .purple-box, .metrics__chart-sorting .instructions-2fa .sortable-item.is-dragging { - display: inline-block; - margin-right: 16px; - padding: 18px 18px 8px -} - -@media (max-width: 1199px) { - #overview-page .app-overview-metrics .instructions-2fa .metrics__summary-row--favorite__link-wrapper, #overview-page .instructions-2fa .data-unavailable, .buildpack-installations-list .instructions-2fa .sortable-item.is-dragging, .instructions-2fa #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper, .instructions-2fa #overview-page .data-unavailable, .instructions-2fa .buildpack-installations-list .sortable-item.is-dragging, .instructions-2fa .content-box, .instructions-2fa .metrics__chart-sorting .sortable-item.is-dragging, .instructions-2fa .metrics__monitor-preview-chart__loading, .instructions-2fa .metrics__not-available, .instructions-2fa .purple-box, .metrics__chart-sorting .instructions-2fa .sortable-item.is-dragging { - margin-bottom: 16px - } -} - -#overview-page .app-overview-metrics .instructions-2fa .metrics__summary-row--favorite__link-wrapper:last-child, #overview-page .instructions-2fa .data-unavailable:last-child, .buildpack-installations-list .instructions-2fa .sortable-item.is-dragging:last-child, .instructions-2fa #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper:last-child, .instructions-2fa #overview-page .data-unavailable:last-child, .instructions-2fa .buildpack-installations-list .sortable-item.is-dragging:last-child, .instructions-2fa .content-box:last-child, .instructions-2fa .metrics__chart-sorting .sortable-item.is-dragging:last-child, .instructions-2fa .metrics__monitor-preview-chart__loading:last-child, .instructions-2fa .metrics__not-available:last-child, .instructions-2fa .purple-box:last-child, .metrics__chart-sorting .instructions-2fa .sortable-item.is-dragging:last-child { - margin-bottom: 0 -} - -#overview-page .app-overview-metrics .instructions-2fa .qr-code.metrics__summary-row--favorite__link-wrapper, #overview-page .instructions-2fa .qr-code.data-unavailable, .buildpack-installations-list .instructions-2fa .qr-code.sortable-item.is-dragging, .instructions-2fa #overview-page .app-overview-metrics .qr-code.metrics__summary-row--favorite__link-wrapper, .instructions-2fa #overview-page .qr-code.data-unavailable, .instructions-2fa .buildpack-installations-list .qr-code.sortable-item.is-dragging, .instructions-2fa .metrics__chart-sorting .qr-code.sortable-item.is-dragging, .instructions-2fa .purple-box.qr-code, .instructions-2fa .qr-code.content-box, .instructions-2fa .qr-code.metrics__monitor-preview-chart__loading, .instructions-2fa .qr-code.metrics__not-available, .metrics__chart-sorting .instructions-2fa .qr-code.sortable-item.is-dragging { - padding: 8px; - width: 216px -} - -#overview-page .app-overview-metrics .instructions-2fa .qr-code.metrics__summary-row--favorite__link-wrapper .panel-section .panel-details, #overview-page .app-overview-metrics .instructions-2fa .qr-code.metrics__summary-row--favorite__link-wrapper p, #overview-page .instructions-2fa .qr-code.data-unavailable .panel-section .panel-details, #overview-page .instructions-2fa .qr-code.data-unavailable p, .buildpack-installations-list .instructions-2fa .qr-code.sortable-item.is-dragging .panel-section .panel-details, .buildpack-installations-list .instructions-2fa .qr-code.sortable-item.is-dragging p, .instructions-2fa #overview-page .app-overview-metrics .qr-code.metrics__summary-row--favorite__link-wrapper .panel-section .panel-details, .instructions-2fa #overview-page .app-overview-metrics .qr-code.metrics__summary-row--favorite__link-wrapper p, .instructions-2fa #overview-page .qr-code.data-unavailable .panel-section .panel-details, .instructions-2fa #overview-page .qr-code.data-unavailable p, .instructions-2fa .buildpack-installations-list .qr-code.sortable-item.is-dragging .panel-section .panel-details, .instructions-2fa .buildpack-installations-list .qr-code.sortable-item.is-dragging p, .instructions-2fa .metrics__chart-sorting .qr-code.sortable-item.is-dragging .panel-section .panel-details, .instructions-2fa .metrics__chart-sorting .qr-code.sortable-item.is-dragging p, .instructions-2fa .purple-box.qr-code .panel-section .panel-details, .instructions-2fa .purple-box.qr-code p, .instructions-2fa .qr-code.content-box .panel-section .panel-details, .instructions-2fa .qr-code.content-box p, .instructions-2fa .qr-code.metrics__monitor-preview-chart__loading .panel-section .panel-details, .instructions-2fa .qr-code.metrics__monitor-preview-chart__loading p, .instructions-2fa .qr-code.metrics__not-available .panel-section .panel-details, .instructions-2fa .qr-code.metrics__not-available p, .metrics__chart-sorting .instructions-2fa .qr-code.sortable-item.is-dragging .panel-section .panel-details, .metrics__chart-sorting .instructions-2fa .qr-code.sortable-item.is-dragging p, .panel-section #overview-page .app-overview-metrics .instructions-2fa .qr-code.metrics__summary-row--favorite__link-wrapper .panel-details, .panel-section #overview-page .instructions-2fa .qr-code.data-unavailable .panel-details, .panel-section .buildpack-installations-list .instructions-2fa .qr-code.sortable-item.is-dragging .panel-details, .panel-section .instructions-2fa #overview-page .app-overview-metrics .qr-code.metrics__summary-row--favorite__link-wrapper .panel-details, .panel-section .instructions-2fa #overview-page .qr-code.data-unavailable .panel-details, .panel-section .instructions-2fa .buildpack-installations-list .qr-code.sortable-item.is-dragging .panel-details, .panel-section .instructions-2fa .metrics__chart-sorting .qr-code.sortable-item.is-dragging .panel-details, .panel-section .instructions-2fa .purple-box.qr-code .panel-details, .panel-section .instructions-2fa .qr-code.content-box .panel-details, .panel-section .instructions-2fa .qr-code.metrics__monitor-preview-chart__loading .panel-details, .panel-section .instructions-2fa .qr-code.metrics__not-available .panel-details, .panel-section .metrics__chart-sorting .instructions-2fa .qr-code.sortable-item.is-dragging .panel-details { - margin-top: 8px; - margin-bottom: -2px; - font-size: 12px; - line-height: 18px; - padding: 0 4px -} - -#overview-page .app-overview-metrics .instructions-2fa .metrics__summary-row--favorite__link-wrapper .meta, #overview-page .instructions-2fa .data-unavailable .meta, .buildpack-installations-list .instructions-2fa .sortable-item.is-dragging .meta, .instructions-2fa #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper .meta, .instructions-2fa #overview-page .data-unavailable .meta, .instructions-2fa .buildpack-installations-list .sortable-item.is-dragging .meta, .instructions-2fa .content-box .meta, .instructions-2fa .metrics__chart-sorting .sortable-item.is-dragging .meta, .instructions-2fa .metrics__monitor-preview-chart__loading .meta, .instructions-2fa .metrics__not-available .meta, .instructions-2fa .purple-box .meta, .metrics__chart-sorting .instructions-2fa .sortable-item.is-dragging .meta { - position: relative; - padding-left: 44px; - padding-bottom: 16px -} - -#overview-page .app-overview-metrics .instructions-2fa .metrics__summary-row--favorite__link-wrapper .meta h5, #overview-page .instructions-2fa .data-unavailable .meta h5, .buildpack-installations-list .instructions-2fa .sortable-item.is-dragging .meta h5, .instructions-2fa #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper .meta h5, .instructions-2fa #overview-page .data-unavailable .meta h5, .instructions-2fa .buildpack-installations-list .sortable-item.is-dragging .meta h5, .instructions-2fa .content-box .meta h5, .instructions-2fa .metrics__chart-sorting .sortable-item.is-dragging .meta h5, .instructions-2fa .metrics__monitor-preview-chart__loading .meta h5, .instructions-2fa .metrics__not-available .meta h5, .instructions-2fa .purple-box .meta h5, .metrics__chart-sorting .instructions-2fa .sortable-item.is-dragging .meta h5 { - color: #3F3F44; - font-size: 13px; - font-weight: 700; - margin-top: 0; - margin-bottom: 2px -} - -#overview-page .app-overview-metrics .instructions-2fa .metrics__summary-row--favorite__link-wrapper .meta a, #overview-page .instructions-2fa .data-unavailable .meta a, .buildpack-installations-list .instructions-2fa .sortable-item.is-dragging .meta a, .instructions-2fa #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper .meta a, .instructions-2fa #overview-page .data-unavailable .meta a, .instructions-2fa .buildpack-installations-list .sortable-item.is-dragging .meta a, .instructions-2fa .content-box .meta a, .instructions-2fa .metrics__chart-sorting .sortable-item.is-dragging .meta a, .instructions-2fa .metrics__monitor-preview-chart__loading .meta a, .instructions-2fa .metrics__not-available .meta a, .instructions-2fa .purple-box .meta a, .metrics__chart-sorting .instructions-2fa .sortable-item.is-dragging .meta a { - color: #62738D; - text-decoration: none; - font-size: 12px -} - -#overview-page .app-overview-metrics .instructions-2fa .metrics__summary-row--favorite__link-wrapper .meta a:hover, #overview-page .instructions-2fa .data-unavailable .meta a:hover, .buildpack-installations-list .instructions-2fa .sortable-item.is-dragging .meta a:hover, .instructions-2fa #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper .meta a:hover, .instructions-2fa #overview-page .data-unavailable .meta a:hover, .instructions-2fa .buildpack-installations-list .sortable-item.is-dragging .meta a:hover, .instructions-2fa .content-box .meta a:hover, .instructions-2fa .metrics__chart-sorting .sortable-item.is-dragging .meta a:hover, .instructions-2fa .metrics__monitor-preview-chart__loading .meta a:hover, .instructions-2fa .metrics__not-available .meta a:hover, .instructions-2fa .purple-box .meta a:hover, .metrics__chart-sorting .instructions-2fa .sortable-item.is-dragging .meta a:hover { - color: #3F3F44 -} - -#overview-page .app-overview-metrics .instructions-2fa .metrics__summary-row--favorite__link-wrapper .meta img, #overview-page .instructions-2fa .data-unavailable .meta img, .buildpack-installations-list .instructions-2fa .sortable-item.is-dragging .meta img, .instructions-2fa #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper .meta img, .instructions-2fa #overview-page .data-unavailable .meta img, .instructions-2fa .buildpack-installations-list .sortable-item.is-dragging .meta img, .instructions-2fa .content-box .meta img, .instructions-2fa .metrics__chart-sorting .sortable-item.is-dragging .meta img, .instructions-2fa .metrics__monitor-preview-chart__loading .meta img, .instructions-2fa .metrics__not-available .meta img, .instructions-2fa .purple-box .meta img, .metrics__chart-sorting .instructions-2fa .sortable-item.is-dragging .meta img { - position: absolute; - left: 0; - top: 0; - width: 32px; - height: 32px -} - -.instructions-2fa .steps { - counter-reset: purple-numbers; - list-style: none; - padding-left: 0 -} - -.instructions-2fa .steps .dyno-tier-picker-item-size-name, .instructions-2fa .steps .panel-section .panel-title, .instructions-2fa .steps h4, .panel-section .instructions-2fa .steps .panel-title { - color: #3F3F44; - font-size: 14px; - font-weight: 400; - margin-top: 0; - margin-bottom: 2px -} - -.instructions-2fa .steps .panel-section .panel-details, .instructions-2fa .steps p, .panel-section .instructions-2fa .steps .panel-details { - font-size: 13px; - color: #62738D; - line-height: 24px; - margin-bottom: 16px -} - -.instructions-2fa .steps > li { - position: relative; - padding: 26px 0 30px 44px; - border-bottom: 1px solid #e7ebf3 -} - -.instructions-2fa .steps > li:last-of-type { - border-bottom: none -} - -.instructions-2fa .steps > li::before { - content: counter(purple-numbers); - counter-increment: purple-numbers; - position: absolute; - top: 29px; - left: 0; - border-radius: 50%; - width: 28px; - height: 28px; - background: rgba(121, 88, 159, .1); - border: 1px solid rgba(121, 88, 159, .4); - color: #79589F; - text-align: center; - font-size: 16px; - font-weight: 200; - line-height: 28px -} - -.instructions-2fa .steps > li #qr-code { - padding-bottom: 12px; - background: #E3E7EF; - width: 200px; - height: 200px -} - -.instructions-2fa .steps > li .download-badge { - display: inline-block; - margin-right: 6px; - margin-bottom: 8px -} - -.invoice-graph g .quota-limit-marker.is-interpolated, .tt-menu, .x-axis path { - display: none -} - -.instructions-2fa .steps > li .download-badge:last-child { - margin-right: 0 -} - -.instructions-2fa .steps > li .download-badge img { - text-indent: 100%; - white-space: nowrap; - overflow: hidden; - height: 42px -} - -input#two-factor-code { - max-width: 160px -} - -.two-factor-confirmation hr { - margin-bottom: 36px -} - -.two-factor-confirmation hr:last-of-type { - margin-bottom: 20px -} - -.recovery-method { - max-width: 540px; - padding-top: 4px; - padding-bottom: 16px -} - -.recovery-method h5 { - color: #3F3F44; - font-size: 14px -} - -.panel-section .recovery-method .panel-details, .recovery-method .panel-section .panel-details, .recovery-method p { - font-size: 13px; - color: #62738D; - line-height: 24px; - padding-bottom: 4px -} - -.two-factor-required #two-factor-token { - width: 240px -} - -table.editable-list.ssh-keys td { - font-size: 13px; - white-space: nowrap -} - -table.editable-list.ssh-keys td.ssh-key-local { - max-width: 150px -} - -table.editable-list.ssh-keys td .local { - overflow: hidden; - text-overflow: ellipsis; - color: #62738D -} - -.invoice-graph g .quota-limit-marker { - shape-rendering: crispEdges; - stroke: #E3E7EF -} - -.invoice-graph g rect.quota-limit { - fill: #f52626 -} - -.invoice-graph g:hover rect { - fill: #006DEB -} - -.invoice-graph g:hover rect.quota-limit { - fill: #DE0A0A -} - -.invoice-graph g:hover .quota-limit-marker { - stroke: #1f87ff -} - -.x-axis text { - fill: #CFD7E6; - font-size: 11px; - text-anchor: start -} - -.x-axis.x-axis-year text { - fill: #62738D -} - -.x-axis line, .x-axis path { - fill: none; - stroke: none; - shape-rendering: crispEdges -} - -.invoice-graph-tip { - padding: 1px 4px; - background-color: #62738D; - border-radius: 2px; - color: #fff; - font-size: 11px -} - -.tt-menu, .typeahead { - background-color: #fff -} - -.is-delinquent a, .is-delinquent button { - opacity: .3; - cursor: not-allowed; - pointer-events: none -} - -.is-delinquent .allow-if-delinquent a, .is-delinquent .allow-if-delinquent button, .is-delinquent .nav-tabs a.active { - cursor: inherit; - opacity: inherit; - pointer-events: inherit -} - -.modal-prompt .modal-title .icon, .two-factor .modal-title .icon { - position: relative; - margin-top: -3px; - margin-right: 3px -} - -.modal-prompt .modal-body h5, .two-factor .modal-body h5 { - font-weight: 700; - color: #475366 -} - -.modal-prompt .modal-body .panel-section h5 + .panel-details, .modal-prompt .modal-body h5 + p, .panel-section .modal-prompt .modal-body h5 + .panel-details, .panel-section .two-factor .modal-body h5 + .panel-details, .two-factor .modal-body .panel-section h5 + .panel-details, .two-factor .modal-body h5 + p { - font-size: 13px; - margin-bottom: 20px; - padding: 0 20px -} - -.modal-prompt .modal-body .form-control, .two-factor .modal-body .form-control { - max-width: 340px -} - -.modal-prompt .modal-body .form-control.center-block, .two-factor .modal-body .form-control.center-block { - text-align: center -} - -.modal-prompt .modal-body .form-control#sms-phone-number, .two-factor .modal-body .form-control#sms-phone-number { - max-width: 240px -} - -.modal-prompt .modal-body .form-control#sms-confirmation-code, .two-factor .modal-body .form-control#sms-confirmation-code { - max-width: 160px -} - -.modal-prompt .modal-body .panel-section .help-block.panel-details, .modal-prompt .modal-body p.help-block, .panel-section .modal-prompt .modal-body .help-block.panel-details, .panel-section .two-factor .modal-body .help-block.panel-details, .two-factor .modal-body .panel-section .help-block.panel-details, .two-factor .modal-body p.help-block { - position: relative; - margin: 8px auto; - max-width: 380px; - font-size: 13px -} - -.modal-prompt .modal-body .ghe-hostname, .modal-prompt .modal-body .password-prompt-form, .two-factor .modal-body .ghe-hostname, .two-factor .modal-body .password-prompt-form { - padding-top: 10px -} - -.modal-prompt .modal-body .alert, .two-factor .modal-body .alert { - margin: 0 30px 10px -} - -#overview-page .app-overview-metrics .modal-prompt .modal-body .metrics__summary-row--favorite__link-wrapper, #overview-page .app-overview-metrics .two-factor .modal-body .metrics__summary-row--favorite__link-wrapper, #overview-page .modal-prompt .modal-body .data-unavailable, #overview-page .two-factor .modal-body .data-unavailable, .buildpack-installations-list .modal-prompt .modal-body .sortable-item.is-dragging, .buildpack-installations-list .two-factor .modal-body .sortable-item.is-dragging, .metrics__chart-sorting .modal-prompt .modal-body .sortable-item.is-dragging, .metrics__chart-sorting .two-factor .modal-body .sortable-item.is-dragging, .modal-prompt .modal-body #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper, .modal-prompt .modal-body #overview-page .data-unavailable, .modal-prompt .modal-body .buildpack-installations-list .sortable-item.is-dragging, .modal-prompt .modal-body .content-box, .modal-prompt .modal-body .metrics__chart-sorting .sortable-item.is-dragging, .modal-prompt .modal-body .metrics__monitor-preview-chart__loading, .modal-prompt .modal-body .metrics__not-available, .modal-prompt .modal-body .purple-box, .two-factor .modal-body #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper, .two-factor .modal-body #overview-page .data-unavailable, .two-factor .modal-body .buildpack-installations-list .sortable-item.is-dragging, .two-factor .modal-body .content-box, .two-factor .modal-body .metrics__chart-sorting .sortable-item.is-dragging, .two-factor .modal-body .metrics__monitor-preview-chart__loading, .two-factor .modal-body .metrics__not-available, .two-factor .modal-body .purple-box { - position: relative; - margin: 16px auto 14px; - text-align: left; - max-width: 320px; - padding: 12px -} - -#overview-page .app-overview-metrics .modal-prompt .modal-body .metrics__summary-row--favorite__link-wrapper h5, #overview-page .app-overview-metrics .two-factor .modal-body .metrics__summary-row--favorite__link-wrapper h5, #overview-page .modal-prompt .modal-body .data-unavailable h5, #overview-page .two-factor .modal-body .data-unavailable h5, .buildpack-installations-list .modal-prompt .modal-body .sortable-item.is-dragging h5, .buildpack-installations-list .two-factor .modal-body .sortable-item.is-dragging h5, .metrics__chart-sorting .modal-prompt .modal-body .sortable-item.is-dragging h5, .metrics__chart-sorting .two-factor .modal-body .sortable-item.is-dragging h5, .modal-prompt .modal-body #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper h5, .modal-prompt .modal-body #overview-page .data-unavailable h5, .modal-prompt .modal-body .buildpack-installations-list .sortable-item.is-dragging h5, .modal-prompt .modal-body .content-box h5, .modal-prompt .modal-body .metrics__chart-sorting .sortable-item.is-dragging h5, .modal-prompt .modal-body .metrics__monitor-preview-chart__loading h5, .modal-prompt .modal-body .metrics__not-available h5, .modal-prompt .modal-body .purple-box h5, .two-factor .modal-body #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper h5, .two-factor .modal-body #overview-page .data-unavailable h5, .two-factor .modal-body .buildpack-installations-list .sortable-item.is-dragging h5, .two-factor .modal-body .content-box h5, .two-factor .modal-body .metrics__chart-sorting .sortable-item.is-dragging h5, .two-factor .modal-body .metrics__monitor-preview-chart__loading h5, .two-factor .modal-body .metrics__not-available h5, .two-factor .modal-body .purple-box h5 { - font-size: 13px; - color: #62738D; - margin-top: 0 -} - -#overview-page .app-overview-metrics .modal-prompt .modal-body .metrics__summary-row--favorite__link-wrapper .actions, #overview-page .app-overview-metrics .two-factor .modal-body .metrics__summary-row--favorite__link-wrapper .actions, #overview-page .modal-prompt .modal-body .data-unavailable .actions, #overview-page .two-factor .modal-body .data-unavailable .actions, .buildpack-installations-list .modal-prompt .modal-body .sortable-item.is-dragging .actions, .buildpack-installations-list .two-factor .modal-body .sortable-item.is-dragging .actions, .metrics__chart-sorting .modal-prompt .modal-body .sortable-item.is-dragging .actions, .metrics__chart-sorting .two-factor .modal-body .sortable-item.is-dragging .actions, .modal-prompt .modal-body #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper .actions, .modal-prompt .modal-body #overview-page .data-unavailable .actions, .modal-prompt .modal-body .buildpack-installations-list .sortable-item.is-dragging .actions, .modal-prompt .modal-body .content-box .actions, .modal-prompt .modal-body .metrics__chart-sorting .sortable-item.is-dragging .actions, .modal-prompt .modal-body .metrics__monitor-preview-chart__loading .actions, .modal-prompt .modal-body .metrics__not-available .actions, .modal-prompt .modal-body .purple-box .actions, .two-factor .modal-body #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper .actions, .two-factor .modal-body #overview-page .data-unavailable .actions, .two-factor .modal-body .buildpack-installations-list .sortable-item.is-dragging .actions, .two-factor .modal-body .content-box .actions, .two-factor .modal-body .metrics__chart-sorting .sortable-item.is-dragging .actions, .two-factor .modal-body .metrics__monitor-preview-chart__loading .actions, .two-factor .modal-body .metrics__not-available .actions, .two-factor .modal-body .purple-box .actions { - overflow: hidden; - width: 100% -} - -#overview-page .app-overview-metrics .modal-prompt .modal-body .metrics__summary-row--favorite__link-wrapper .actions .btn-primary, #overview-page .app-overview-metrics .two-factor .modal-body .metrics__summary-row--favorite__link-wrapper .actions .btn-primary, #overview-page .modal-prompt .modal-body .data-unavailable .actions .btn-primary, #overview-page .two-factor .modal-body .data-unavailable .actions .btn-primary, .buildpack-installations-list .modal-prompt .modal-body .sortable-item.is-dragging .actions .btn-primary, .buildpack-installations-list .two-factor .modal-body .sortable-item.is-dragging .actions .btn-primary, .metrics__chart-sorting .modal-prompt .modal-body .sortable-item.is-dragging .actions .btn-primary, .metrics__chart-sorting .two-factor .modal-body .sortable-item.is-dragging .actions .btn-primary, .modal-prompt .modal-body #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper .actions .btn-primary, .modal-prompt .modal-body #overview-page .data-unavailable .actions .btn-primary, .modal-prompt .modal-body .buildpack-installations-list .sortable-item.is-dragging .actions .btn-primary, .modal-prompt .modal-body .content-box .actions .btn-primary, .modal-prompt .modal-body .metrics__chart-sorting .sortable-item.is-dragging .actions .btn-primary, .modal-prompt .modal-body .metrics__monitor-preview-chart__loading .actions .btn-primary, .modal-prompt .modal-body .metrics__not-available .actions .btn-primary, .modal-prompt .modal-body .purple-box .actions .btn-primary, .two-factor .modal-body #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper .actions .btn-primary, .two-factor .modal-body #overview-page .data-unavailable .actions .btn-primary, .two-factor .modal-body .buildpack-installations-list .sortable-item.is-dragging .actions .btn-primary, .two-factor .modal-body .content-box .actions .btn-primary, .two-factor .modal-body .metrics__chart-sorting .sortable-item.is-dragging .actions .btn-primary, .two-factor .modal-body .metrics__monitor-preview-chart__loading .actions .btn-primary, .two-factor .modal-body .metrics__not-available .actions .btn-primary, .two-factor .modal-body .purple-box .actions .btn-primary { - float: left -} - -#overview-page .app-overview-metrics .modal-prompt .modal-body .metrics__summary-row--favorite__link-wrapper .actions .btn-default, #overview-page .app-overview-metrics .two-factor .modal-body .metrics__summary-row--favorite__link-wrapper .actions .btn-default, #overview-page .modal-prompt .modal-body .data-unavailable .actions .btn-default, #overview-page .two-factor .modal-body .data-unavailable .actions .btn-default, .buildpack-installations-list .modal-prompt .modal-body .sortable-item.is-dragging .actions .btn-default, .buildpack-installations-list .two-factor .modal-body .sortable-item.is-dragging .actions .btn-default, .metrics__chart-sorting .modal-prompt .modal-body .sortable-item.is-dragging .actions .btn-default, .metrics__chart-sorting .two-factor .modal-body .sortable-item.is-dragging .actions .btn-default, .modal-prompt .modal-body #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper .actions .btn-default, .modal-prompt .modal-body #overview-page .data-unavailable .actions .btn-default, .modal-prompt .modal-body .buildpack-installations-list .sortable-item.is-dragging .actions .btn-default, .modal-prompt .modal-body .content-box .actions .btn-default, .modal-prompt .modal-body .metrics__chart-sorting .sortable-item.is-dragging .actions .btn-default, .modal-prompt .modal-body .metrics__monitor-preview-chart__loading .actions .btn-default, .modal-prompt .modal-body .metrics__not-available .actions .btn-default, .modal-prompt .modal-body .purple-box .actions .btn-default, .two-factor .modal-body #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper .actions .btn-default, .two-factor .modal-body #overview-page .data-unavailable .actions .btn-default, .two-factor .modal-body .buildpack-installations-list .sortable-item.is-dragging .actions .btn-default, .two-factor .modal-body .content-box .actions .btn-default, .two-factor .modal-body .metrics__chart-sorting .sortable-item.is-dragging .actions .btn-default, .two-factor .modal-body .metrics__monitor-preview-chart__loading .actions .btn-default, .two-factor .modal-body .metrics__not-available .actions .btn-default, .two-factor .modal-body .purple-box .actions .btn-default { - float: right -} - -.modal-prompt .modal-body pre, .two-factor .modal-body pre { - width: 100%; - margin: 0 -} - -.modal-prompt .modal-body pre code, .two-factor .modal-body pre code { - float: left -} - -.modal-prompt .modal-body pre code:first-child, .two-factor .modal-body pre code:first-child { - margin-right: 20px -} - -.modal-prompt .modal-body .resend-link, .two-factor .modal-body .resend-link { - text-decoration: underline !important; - border: none -} - -.modal-prompt .modal-footer .btn-link, .two-factor .modal-footer .btn-link { - margin-right: 14px -} - -.modal-prompt .modal-footer .btn-default, .two-factor .modal-footer .btn-default { - margin-right: 6px -} - -.tt-hint, .tt-query, .typeahead { - width: 396px; - border: 2px solid #ccc; - border-radius: 8px; - outline: 0 -} - -.typeahead:focus { - border: 2px solid #0097cf -} - -.tt-query { - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - line-height: 30px -} - -.tt-hint { - color: #CFD7E6; - margin-left: -1px; - line-height: 30px -} - -.tt-menu { - width: 100%; - margin-top: 4px; - border-radius: 4px; - box-shadow: 0 0 0 1px rgba(0, 0, 0, .05), 0 2px 6px rgba(0, 0, 0, .2); - max-height: 400px; - overflow-y: auto -} - -.panel-section .tt-suggestion .panel-details, .tt-suggestion .panel-section .panel-details, .tt-suggestion p, hr.no-margin { - margin: 0 -} - -.tt-menu.visible { - display: block; - position: absolute; - top: 100%; - left: 0; - z-index: 100 -} - -.tt-suggestion { - padding: 6px 10px; - border-bottom: 1px solid rgba(0, 0, 0, .1); - cursor: pointer -} - -.tt-suggestion:last-child { - border-bottom: none -} - -.tt-suggestion.tt-cursor, .tt-suggestion:hover { - background: #fafafb -} - -.tt-suggestion.typeahead-empty-state-suggestion { - display: block; - padding: 10px; - text-align: center -} - -.addon-typeahead-title { - color: #79589F; - padding: 0 12px; - flex: none -} - -.addon-typeahead-description { - color: #62738D; - flex: 1 -} - -.addon-typeahead-cell { - display: flex; - align-items: center; - position: relative -} - -.typeahead-component { - position: relative -} - -.typeahead-component > .icon { - position: absolute; - left: 9px; - top: 9px; - z-index: 1 -} - -.typeahead-component .loading-spinner { - position: absolute; - top: 15px; - left: 8px -} - -.typeahead-component .form-control { - padding-left: 30px -} - -.alert .alert-title { - font-weight: 700; - display: block; - font-size: 14px -} - -.alert .alert-title:not(:only-child) { - padding-bottom: 4px -} - -.alert .alert-body { - font-size: 13px -} - -.alert a { - text-decoration: underline -} - -.alert--full-width { - margin: 0 -20px 40px; - border-radius: 0; - border-width: 1px 0; - padding: 24px 45px -} - -.alert--above-footer { - border-bottom: 0; - margin: 0; - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0 -} - -.actions-button { - position: relative; - margin-left: auto -} - -.actions-button.btn-group:not(:first-child):not(:last-child) > .btn { - border-bottom-right-radius: 4px; - border-top-right-radius: 4px -} - -.actions-button .context-switcher__list, .actions-button .drop-down__menu, .actions-button .dropdown-menu { - position: absolute; - left: auto; - right: 0; - font-size: 12px -} - -.actions-button .context-switcher__list li.divider, .actions-button .drop-down__menu li.divider, .actions-button .dropdown-menu li.divider { - margin: 5px 0 -} - -.actions-button .btn-link { - padding-left: 10px; - padding-right: 10px; - margin-right: -10px -} - -.actions-button .btn-link i { - position: relative; - margin: 0 -} - -.actions-button .btn-link i.icon-add-button { - margin-right: 2px -} - -[class*=protected-pipelines-pipeline-] .main-content { - display: flex; - -webkit-box-orient: vertical; - -moz-box-orient: vertical; - box-orient: vertical; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: column; - -moz-flex-direction: column; - flex-direction: column; - -ms-flex-direction: column; - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0; - min-height: 380px; - padding: 0; - background: #F7F8FB -} - -#pipeline-overview, .pipeline-app.app-suggestion .box, .switch-mode { - display: -webkit-box; - display: -moz-box -} - -[class*=protected-pipelines-pipeline-] .generic-banner, [class*=protected-pipelines-pipeline-] .message-banner { - margin: 0 0 1px; - z-index: 2 -} - -.protected-pipelines-pipeline-access .main-content, .protected-pipelines-pipeline-settings .main-content { - background: #fff -} - -.pipeline-config { - padding: 20px 20px 0 -} - -.pipeline-config hr { - margin: 30px 0 -} - -.pipeline-config .alert { - margin: 20px 0 10px -} - -.pipeline-config .alert hr { - margin: 10px 0 -} - -#pipeline-overview { - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-grow: 1; - -moz-flex-grow: 1; - flex-grow: 1; - -ms-flex-positive: 1; - -webkit-box-align: stretch; - -moz-box-align: stretch; - box-align: stretch; - -webkit-align-items: stretch; - -moz-align-items: stretch; - -ms-align-items: stretch; - -o-align-items: stretch; - align-items: stretch; - -ms-flex-align: stretch; - position: relative; - overflow-x: auto; - min-height: 320px; - margin-bottom: 10px -} - -#pipeline-overview.has-overflow { - cursor: -webkit-grab -} - -#pipeline-overview.has-overflow:active { - cursor: -webkit-grabbing -} - -#pipeline-overview::-webkit-scrollbar { - width: 6px; - height: 6px -} - -#pipeline-overview::-webkit-scrollbar-track { - border-radius: 10px; - box-shadow: inset 0 0 0 1px rgba(207, 215, 230, .2); - background: rgba(207, 215, 230, .2) -} - -#pipeline-overview::-webkit-scrollbar-thumb { - border-radius: 10px; - box-shadow: inset 0 0 0 1px rgba(207, 215, 230, .5); - background: rgba(207, 215, 230, .5) -} - -#pipeline-overview::-webkit-scrollbar-button { - display: block; - width: 10px; - height: 10px -} - -#pipeline-overview .pipeline-stages { - padding: 0 5px -} - -#pipeline-overview .stage { - -webkit-box-flex: 1; - -moz-box-flex: 1; - box-flex: 1; - -webkit-flex: 1; - -moz-flex: 1; - -ms-flex: 1; - flex: 1; - position: relative; - overflow: visible; - min-width: 350px; - max-width: 410px -} - -#pipeline-overview .stage::after { - content: ''; - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 10px; - background: linear-gradient(rgba(247, 248, 251, 0), #f7f8fb) -} - -#pipeline-overview .stage .app-list { - margin-left: 0; - margin-right: 0; - padding-bottom: 10px -} - -#pipeline-overview .stage.review-apps .dyno-tier-picker-item-size-name, #pipeline-overview .stage.review-apps .panel-section .panel-title, #pipeline-overview .stage.review-apps h4, .panel-section #pipeline-overview .stage.review-apps .panel-title { - margin-right: 8px -} - -#pipeline-overview .stage:first-child { - margin-left: auto -} - -#pipeline-overview .stage:last-child { - margin-right: auto -} - -#pipeline-overview .stage:last-child .pipeline-arrow { - display: none -} - -#pipeline-overview .pipeline-arrow { - position: relative; - margin-left: auto -} - -#pipeline-overview .pipeline-arrow::after { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 1; - background: linear-gradient(to right, #f7f8fb, rgba(247, 248, 251, 0)) -} - -#pipeline-overview .typeahead-component .tt-hint { - margin-left: 0 -} - -#pipeline-overview .typeahead-component .tt-suggestion.empty { - padding-left: 36px -} - -#pipeline-overview .twitter-typeahead { - width: 100% -} - -#pipeline-overview .twitter-typeahead::after { - content: ''; - position: absolute; - bottom: -12px; - left: 0; - right: 0; - height: 12px -} - -#pipeline-overview input.pipeline-app-search { - width: 100% -} - -#pipeline-overview .stage-header { - min-height: 24px; - padding: 0 5px -} - -#pipeline-overview .stage-header .dyno-tier-picker-item-size-name, #pipeline-overview .stage-header .panel-section .panel-title, #pipeline-overview .stage-header .review-stage-btn, #pipeline-overview .stage-header h4, .panel-section #pipeline-overview .stage-header .panel-title { - font-size: 11px; - font-weight: 700; - text-transform: uppercase; - color: #62738D -} - -#pipeline-overview .stage-header .review-stage-btn { - background: 0 0; - padding: 0; - border: none -} - -#pipeline-overview .stage-header .add-app { - background: 0 0 !important -} - -#pipeline-overview .stage-header .add-app .icon { - -webkit-transition: all .1s ease; - -o-transition: all .1s ease; - transition: all .1s ease -} - -#pipeline-overview .stage-header .add-app.adding .icon { - -webkit-transform: rotate(45deg); - -moz-transform: rotate(45deg); - -ms-transform: rotate(45deg); - -o-transform: rotate(45deg); - transform: rotate(45deg) -} - -#pipeline-overview .stage-header .gravatar-icon, #pipeline-overview .stage-header .org-identicon-mini { - cursor: default -} - -#pipeline-overview .stage-header .review-meta-info .loading { - display: block; - width: 100%; - text-align: center; - margin: 4px 0 -} - -#pipeline-overview .stage-header .review-meta-info.context-switcher__list, #pipeline-overview .stage-header .review-meta-info.drop-down__menu { - font-size: 12px; - white-space: nowrap -} - -#pipeline-overview .stage-header .review-meta-info.context-switcher__list .divider, #pipeline-overview .stage-header .review-meta-info.drop-down__menu .divider { - margin: 5px 0 -} - -#pipeline-overview .stage-header .review-meta-info.context-switcher__list label, #pipeline-overview .stage-header .review-meta-info.drop-down__menu label { - display: block; - padding: 3px 16px 3px 10px -} - -#pipeline-overview .stage-header .review-meta-info.context-switcher__list .toggle-auto-destroy-set-stale, #pipeline-overview .stage-header .review-meta-info.drop-down__menu .toggle-auto-destroy-set-stale { - padding: 0 16px 3px 36px -} - -#pipeline-overview .stage-header .review-meta-info.context-switcher__list .toggle-auto-destroy-set-stale .panel-section .panel-details, #pipeline-overview .stage-header .review-meta-info.context-switcher__list .toggle-auto-destroy-set-stale small, #pipeline-overview .stage-header .review-meta-info.drop-down__menu .toggle-auto-destroy-set-stale .panel-section .panel-details, #pipeline-overview .stage-header .review-meta-info.drop-down__menu .toggle-auto-destroy-set-stale small, .panel-section #pipeline-overview .stage-header .review-meta-info.context-switcher__list .toggle-auto-destroy-set-stale .panel-details, .panel-section #pipeline-overview .stage-header .review-meta-info.drop-down__menu .toggle-auto-destroy-set-stale .panel-details { - color: #62738D; - font-size: 11px; - padding-top: 5px -} - -#pipeline-overview .stage-header .review-meta-info.context-switcher__list .toggle-auto-destroy-set-stale .hk-select, #pipeline-overview .stage-header .review-meta-info.drop-down__menu .toggle-auto-destroy-set-stale .hk-select { - height: 28px -} - -#pipeline-overview .stage-header .review-meta-info.context-switcher__list .btn, #pipeline-overview .stage-header .review-meta-info.context-switcher__list a, #pipeline-overview .stage-header .review-meta-info.drop-down__menu .btn, #pipeline-overview .stage-header .review-meta-info.drop-down__menu a { - font-size: 12px; - border-radius: 0; - padding-left: 12px; - padding-right: 16px -} - -#pipeline-overview .stage-header .review-meta-info.context-switcher__list .btn:hover code, #pipeline-overview .stage-header .review-meta-info.context-switcher__list a:hover code, #pipeline-overview .stage-header .review-meta-info.drop-down__menu .btn:hover code, #pipeline-overview .stage-header .review-meta-info.drop-down__menu a:hover code { - text-decoration: underline -} - -#pipeline-overview .stage-header .review-meta-info.context-switcher__list .icon, #pipeline-overview .stage-header .review-meta-info.drop-down__menu .icon { - position: relative; - margin: -1px 4px 0 2px -} - -#pipeline-overview .stage-header .review-meta-info.context-switcher__list .form-control, #pipeline-overview .stage-header .review-meta-info.drop-down__menu .form-control { - position: relative; - display: inline; - width: 12px; - height: 12px; - margin: -1px 5px 0 6px -} - -#pipeline-overview .app-list { - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - overflow: auto -} - -#pipeline-overview .app-list::-webkit-scrollbar { - width: 12px; - height: 12px -} - -#pipeline-overview .app-list::-webkit-scrollbar-thumb { - width: 6px; - height: 6px; - border: 3px solid #F7F8FB; - border-radius: 10px; - background-clip: border-box; - box-shadow: inset 0 0 0 1px rgba(207, 215, 230, .5); - background: rgba(207, 215, 230, .5) -} - -#pipeline-overview .app-list::-webkit-scrollbar-button { - width: 0; - height: 0; - display: none -} - -#pipeline-overview .app-list .add-app-coupling { - margin: 4px 4px 0 -} - -#pipeline-overview ul { - list-style: none -} - -#pipeline-overview ul li.empty { - margin: 5px 5px 0 -} - -#pipeline-overview ul li.empty.initial-state .panel-section .panel-details:last-child, #pipeline-overview ul li.empty.initial-state p:last-child, .panel-section #pipeline-overview ul li.empty.initial-state .panel-details:last-child { - margin-bottom: 0 -} - -#pipeline-overview ul li.empty.initial-state .icon { - margin: 4px auto 10px -} - -#pipeline-overview ul.links, #pipeline-overview ul.links li { - margin: 0 -} - -#pipeline-overview .context-switcher__list .divider, #pipeline-overview .drop-down__menu .divider { - margin: 5px 0 -} - -#pipeline-overview .context-switcher__list .btn, #pipeline-overview .context-switcher__list a, #pipeline-overview .drop-down__menu .btn, #pipeline-overview .drop-down__menu a { - font-size: 13px; - border-radius: 0 -} - -#pipeline-overview .context-switcher__list .btn.disabled, #pipeline-overview .context-switcher__list a.disabled, #pipeline-overview .drop-down__menu .btn.disabled, #pipeline-overview .drop-down__menu a.disabled { - box-shadow: none !important -} - -#pipeline-overview .context-switcher__list .btn.disabled .icon, #pipeline-overview .context-switcher__list a.disabled .icon, #pipeline-overview .drop-down__menu .btn.disabled .icon, #pipeline-overview .drop-down__menu a.disabled .icon { - opacity: .3 -} - -.modal-body .parent-app-picker { - padding: 10px 30px 8px -} - -.modal-body .parent-app-picker label { - line-height: 16px -} - -.modal-body .parent-app-picker label .panel-section .panel-details, .modal-body .parent-app-picker label small, .panel-section .modal-body .parent-app-picker label .panel-details { - padding: 2px 0 6px -} - -.modal-body .disconnection-warnings .alert { - margin-bottom: 16px -} - -.modal-body .github-features { - text-align: left; - padding: 18px 0 10px; - border-top: 1px solid #E3E7EF; - margin: 0 50px -} - -.modal-body .github-features .dyno-tier-picker-item-size-name, .modal-body .github-features .panel-section .panel-title, .modal-body .github-features h4, .panel-section .modal-body .github-features .panel-title { - font-size: 14px; - font-weight: 400; - color: #56667D; - margin: 0; - padding-top: 10px -} - -.modal-body .github-features .panel-section .panel-details, .modal-body .github-features p, .panel-section .modal-body .github-features .panel-details { - font-size: 13px; - color: #62738D -} - -#review-app-setup { - padding: 0 50px -} - -#review-app-setup form { - padding-bottom: 8px -} - -#review-app-setup #auto-deploy-prs, #review-app-setup #auto-destroy-prs, #review-app-setup #review-app-space, #review-app-setup .enable-option { - padding: 0 0 12px -} - -#review-app-setup #auto-deploy-prs .help-block, #review-app-setup #auto-destroy-prs .help-block, #review-app-setup #review-app-space .help-block, #review-app-setup .enable-option .help-block { - margin-top: 5px; - margin-bottom: 0 -} - -#review-app-setup #auto-deploy-prs label, #review-app-setup #auto-destroy-prs label, #review-app-setup #review-app-space label, #review-app-setup .enable-option label { - font-size: 13px; - font-weight: 400; - color: #56667D; - width: auto; - margin-bottom: 0 -} - -#review-app-setup #auto-deploy-prs .help-block .panel-section .panel-details, #review-app-setup #auto-deploy-prs .help-block small, #review-app-setup #auto-destroy-prs .help-block .panel-section .panel-details, #review-app-setup #auto-destroy-prs .help-block small, #review-app-setup #review-app-space .help-block .panel-section .panel-details, #review-app-setup #review-app-space .help-block small, #review-app-setup .enable-option .help-block .panel-section .panel-details, #review-app-setup .enable-option .help-block small, .panel-section #review-app-setup #auto-deploy-prs .help-block .panel-details, .panel-section #review-app-setup #auto-destroy-prs .help-block .panel-details, .panel-section #review-app-setup #review-app-space .help-block .panel-details, .panel-section #review-app-setup .enable-option .help-block .panel-details, .pipeline-app .pr-info .pr-meta { - font-size: 12px -} - -#review-app-setup #auto-deploy-prs label input, #review-app-setup #auto-destroy-prs label input, #review-app-setup #review-app-space label input, #review-app-setup .enable-option label input { - margin-right: 4px -} - -#review-app-setup #auto-destroy-prs, #review-app-setup #review-app-space { - border-top: 1px solid #E3E7EF; - padding-top: 12px -} - -#review-app-setup #auto-destroy-prs .icon, #review-app-setup #review-app-space .icon { - margin-left: 2px; - margin-right: 2px; - margin-top: -1px -} - -#review-app-setup .alert .icon { - margin-left: 2px; - margin-right: 2px; - margin-top: -2px -} - -.review-apps .app-list { - padding-bottom: 0 -} - -.review-apps .load-more { - margin: 10px 5px 0 -} - -.pipeline-app { - position: relative; - border: none; - min-width: 290px; - background: 0 0 !important; - -webkit-transition: opacity ease .7s; - -o-transition: opacity ease .7s; - transition: opacity ease .7s -} - -.pipeline-app:not(.app-suggestion):last-child { - margin-bottom: 0; - padding-bottom: 0 -} - -.pipeline-app.is-saving, .pipeline-app.is-updated { - opacity: .4 -} - -.pipeline-app .mismatched-pipeline-app { - border-color: #FA9F47 -} - -.pipeline-app .mismatched-pipeline-app .mismatched-ownership-warning { - margin: 10px -10px -10px -} - -.pipeline-app .pipeline-app-header { - position: relative; - display: flex; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center -} - -.pipeline-app .app-info, .pipeline-app .pr-info { - padding-right: 6px; - width: 1px; - -webkit-flex-grow: 1; - -moz-flex-grow: 1; - flex-grow: 1; - -ms-flex-positive: 1 -} - -.pipeline-app .app-name { - display: block; - padding: 0 2px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis -} - -.pipeline-app .app-name a { - display: inline -} - -.pipeline-app .app-name a:hover { - color: #79589F -} - -.pipeline-app .pr-info { - display: block -} - -.pipeline-app .badge { - color: #fff; - font-size: 10px; - padding: 3px 4px 2px; - margin: 0 2px; - transition: background ease .2s -} - -.pipeline-app .badge.badge-failed { - background: #DE0A0A -} - -.pipeline-app .badge.badge-success { - background: #008700 -} - -.pipeline-app .build-info, .pipeline-app .promotion-info, .pipeline-app .release-info { - position: relative; - display: flex; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center; - margin: 0 -10px -1px; - padding: 8px 10px 9px; - box-shadow: inset 0 1px 0 #E3E7EF, inset 0 -1px 0 #E3E7EF -} - -.pipeline-app .build-info:last-child, .pipeline-app .promotion-info:last-child, .pipeline-app .release-info:last-child { - margin-bottom: -10px; - padding-bottom: 10px; - border-bottom-right-radius: 6px; - border-bottom-left-radius: 6px; - box-shadow: inset 0 1px 0 #E3E7EF -} - -.pipeline-app .build-info .loading-spinner, .pipeline-app .promotion-info .loading-spinner, .pipeline-app .release-info .loading-spinner { - margin-top: 6px -} - -.pipeline-app .build-info .loading-spinner + span, .pipeline-app .promotion-info .loading-spinner + span, .pipeline-app .release-info .loading-spinner + span { - padding-left: 4px -} - -.pipeline-app .build-info span, .pipeline-app .promotion-info span, .pipeline-app .release-info span { - font-size: 12px; - color: #56667D -} - -.pipeline-app .build-info span.build-status, .pipeline-app .build-info span.promotion-status, .pipeline-app .build-info span.release-status, .pipeline-app .promotion-info span.build-status, .pipeline-app .promotion-info span.promotion-status, .pipeline-app .promotion-info span.release-status, .pipeline-app .release-info span.build-status, .pipeline-app .release-info span.promotion-status, .pipeline-app .release-info span.release-status { - position: relative; - top: 2px; - display: inline-block -} - -.pipeline-app .build-info span:first-letter, .pipeline-app .promotion-info span:first-letter, .pipeline-app .release-info span:first-letter { - text-transform: uppercase -} - -#overview-page .formation-tier .panel-section .panel-details b, #overview-page .formation-tier p b, .panel-section #overview-page .formation-tier .panel-details b, .pipeline-app .build-info .promotion-failures:first-letter, .pipeline-app .build-info span .badge:first-letter, .pipeline-app .promotion-info .promotion-failures:first-letter, .pipeline-app .promotion-info span .badge:first-letter, .pipeline-app .release-info .promotion-failures:first-letter, .pipeline-app .release-info span .badge:first-letter { - text-transform: lowercase -} - -.pipeline-app .build-info span .btn-link, .pipeline-app .promotion-info span .btn-link, .pipeline-app .release-info span .btn-link { - color: #79589F; - display: inline; - font-size: 12px; - text-decoration: underline -} - -.pipeline-app .build-info span .badge, .pipeline-app .promotion-info span .badge, .pipeline-app .release-info span .badge { - font-size: 10px; - color: #fff -} - -.pipeline-app .build-info code, .pipeline-app .promotion-info code, .pipeline-app .release-info code { - padding-bottom: 1px -} - -.pipeline-app .build-info .promotion-failures, .pipeline-app .build-info .release-detail, .pipeline-app .promotion-info .promotion-failures, .pipeline-app .promotion-info .release-detail, .pipeline-app .release-info .promotion-failures, .pipeline-app .release-info .release-detail { - font-size: 11px; - display: block; - position: relative -} - -.pipeline-app .build-info .promotion-failures code, .pipeline-app .build-info .release-detail code, .pipeline-app .promotion-info .promotion-failures code, .pipeline-app .promotion-info .release-detail code, .pipeline-app .release-info .promotion-failures code, .pipeline-app .release-info .release-detail code { - display: inline-block; - margin: 3px 2px 2px 0 -} - -.pipeline-app .build-info .release-detail-button, .pipeline-app .promotion-info .release-detail-button, .pipeline-app .release-info .release-detail-button { - position: relative; - margin-top: -1px; - padding: 0 6px 6px; - font-size: 13px; - line-height: 8px; - margin-left: 4px -} - -.pipeline-app .build-info.build-failed, .pipeline-app .build-info.promotion-failed, .pipeline-app .build-info.release-failed, .pipeline-app .promotion-info.build-failed, .pipeline-app .promotion-info.promotion-failed, .pipeline-app .promotion-info.release-failed, .pipeline-app .release-info.build-failed, .pipeline-app .release-info.promotion-failed, .pipeline-app .release-info.release-failed { - background: #fdf6f6; - box-shadow: inset 0 1px 0 rgba(239, 179, 179, .6), inset 0 -1px 0 rgba(239, 179, 179, .6) -} - -.pipeline-app .build-info.build-failed:last-child, .pipeline-app .build-info.promotion-failed:last-child, .pipeline-app .build-info.release-failed:last-child, .pipeline-app .promotion-info.build-failed:last-child, .pipeline-app .promotion-info.promotion-failed:last-child, .pipeline-app .promotion-info.release-failed:last-child, .pipeline-app .release-info.build-failed:last-child, .pipeline-app .release-info.promotion-failed:last-child, .pipeline-app .release-info.release-failed:last-child { - box-shadow: inset 0 1px 0 rgba(239, 179, 179, .6) -} - -.panel-section .pipeline-app .build-info.build-failed .panel-details, .panel-section .pipeline-app .build-info.build-failed .panel-details .btn-link, .panel-section .pipeline-app .build-info.promotion-failed .panel-details, .panel-section .pipeline-app .build-info.promotion-failed .panel-details .btn-link, .panel-section .pipeline-app .build-info.release-failed .panel-details, .panel-section .pipeline-app .build-info.release-failed .panel-details .btn-link, .panel-section .pipeline-app .promotion-info.build-failed .panel-details, .panel-section .pipeline-app .promotion-info.build-failed .panel-details .btn-link, .panel-section .pipeline-app .promotion-info.promotion-failed .panel-details, .panel-section .pipeline-app .promotion-info.promotion-failed .panel-details .btn-link, .panel-section .pipeline-app .promotion-info.release-failed .panel-details, .panel-section .pipeline-app .promotion-info.release-failed .panel-details .btn-link, .panel-section .pipeline-app .release-info.build-failed .panel-details, .panel-section .pipeline-app .release-info.build-failed .panel-details .btn-link, .panel-section .pipeline-app .release-info.promotion-failed .panel-details, .panel-section .pipeline-app .release-info.promotion-failed .panel-details .btn-link, .panel-section .pipeline-app .release-info.release-failed .panel-details, .panel-section .pipeline-app .release-info.release-failed .panel-details .btn-link, .pipeline-app .build-info.build-failed .panel-section .panel-details, .pipeline-app .build-info.build-failed .panel-section .panel-details .btn-link, .pipeline-app .build-info.build-failed small, .pipeline-app .build-info.build-failed small .btn-link, .pipeline-app .build-info.build-failed span, .pipeline-app .build-info.build-failed span .btn-link, .pipeline-app .build-info.promotion-failed .panel-section .panel-details, .pipeline-app .build-info.promotion-failed .panel-section .panel-details .btn-link, .pipeline-app .build-info.promotion-failed small, .pipeline-app .build-info.promotion-failed small .btn-link, .pipeline-app .build-info.promotion-failed span, .pipeline-app .build-info.promotion-failed span .btn-link, .pipeline-app .build-info.release-failed .panel-section .panel-details, .pipeline-app .build-info.release-failed .panel-section .panel-details .btn-link, .pipeline-app .build-info.release-failed small, .pipeline-app .build-info.release-failed small .btn-link, .pipeline-app .build-info.release-failed span, .pipeline-app .build-info.release-failed span .btn-link, .pipeline-app .promotion-info.build-failed .panel-section .panel-details, .pipeline-app .promotion-info.build-failed .panel-section .panel-details .btn-link, .pipeline-app .promotion-info.build-failed small, .pipeline-app .promotion-info.build-failed small .btn-link, .pipeline-app .promotion-info.build-failed span, .pipeline-app .promotion-info.build-failed span .btn-link, .pipeline-app .promotion-info.promotion-failed .panel-section .panel-details, .pipeline-app .promotion-info.promotion-failed .panel-section .panel-details .btn-link, .pipeline-app .promotion-info.promotion-failed small, .pipeline-app .promotion-info.promotion-failed small .btn-link, .pipeline-app .promotion-info.promotion-failed span, .pipeline-app .promotion-info.promotion-failed span .btn-link, .pipeline-app .promotion-info.release-failed .panel-section .panel-details, .pipeline-app .promotion-info.release-failed .panel-section .panel-details .btn-link, .pipeline-app .promotion-info.release-failed small, .pipeline-app .promotion-info.release-failed small .btn-link, .pipeline-app .promotion-info.release-failed span, .pipeline-app .promotion-info.release-failed span .btn-link, .pipeline-app .release-info.build-failed .panel-section .panel-details, .pipeline-app .release-info.build-failed .panel-section .panel-details .btn-link, .pipeline-app .release-info.build-failed small, .pipeline-app .release-info.build-failed small .btn-link, .pipeline-app .release-info.build-failed span, .pipeline-app .release-info.build-failed span .btn-link, .pipeline-app .release-info.promotion-failed .panel-section .panel-details, .pipeline-app .release-info.promotion-failed .panel-section .panel-details .btn-link, .pipeline-app .release-info.promotion-failed small, .pipeline-app .release-info.promotion-failed small .btn-link, .pipeline-app .release-info.promotion-failed span, .pipeline-app .release-info.promotion-failed span .btn-link, .pipeline-app .release-info.release-failed .panel-section .panel-details, .pipeline-app .release-info.release-failed .panel-section .panel-details .btn-link, .pipeline-app .release-info.release-failed small, .pipeline-app .release-info.release-failed small .btn-link, .pipeline-app .release-info.release-failed span, .pipeline-app .release-info.release-failed span .btn-link { - color: #DE0A0A -} - -.panel-section .pipeline-app .build-info.build-failed .panel-details code, .panel-section .pipeline-app .build-info.promotion-failed .panel-details code, .panel-section .pipeline-app .build-info.release-failed .panel-details code, .panel-section .pipeline-app .promotion-info.build-failed .panel-details code, .panel-section .pipeline-app .promotion-info.promotion-failed .panel-details code, .panel-section .pipeline-app .promotion-info.release-failed .panel-details code, .panel-section .pipeline-app .release-info.build-failed .panel-details code, .panel-section .pipeline-app .release-info.promotion-failed .panel-details code, .panel-section .pipeline-app .release-info.release-failed .panel-details code, .pipeline-app .build-info.build-failed .panel-section .panel-details code, .pipeline-app .build-info.build-failed small code, .pipeline-app .build-info.build-failed span code, .pipeline-app .build-info.promotion-failed .panel-section .panel-details code, .pipeline-app .build-info.promotion-failed small code, .pipeline-app .build-info.promotion-failed span code, .pipeline-app .build-info.release-failed .panel-section .panel-details code, .pipeline-app .build-info.release-failed small code, .pipeline-app .build-info.release-failed span code, .pipeline-app .promotion-info.build-failed .panel-section .panel-details code, .pipeline-app .promotion-info.build-failed small code, .pipeline-app .promotion-info.build-failed span code, .pipeline-app .promotion-info.promotion-failed .panel-section .panel-details code, .pipeline-app .promotion-info.promotion-failed small code, .pipeline-app .promotion-info.promotion-failed span code, .pipeline-app .promotion-info.release-failed .panel-section .panel-details code, .pipeline-app .promotion-info.release-failed small code, .pipeline-app .promotion-info.release-failed span code, .pipeline-app .release-info.build-failed .panel-section .panel-details code, .pipeline-app .release-info.build-failed small code, .pipeline-app .release-info.build-failed span code, .pipeline-app .release-info.promotion-failed .panel-section .panel-details code, .pipeline-app .release-info.promotion-failed small code, .pipeline-app .release-info.promotion-failed span code, .pipeline-app .release-info.release-failed .panel-section .panel-details code, .pipeline-app .release-info.release-failed small code, .pipeline-app .release-info.release-failed span code { - color: #DE0A0A; - background: rgba(222, 10, 10, .1); - box-shadow: inset 0 0 0 1px rgba(222, 10, 10, .4) -} - -.panel-section .pipeline-app .build-info.build-failed .panel-details .badge, .panel-section .pipeline-app .build-info.promotion-failed .panel-details .badge, .panel-section .pipeline-app .build-info.release-failed .panel-details .badge, .panel-section .pipeline-app .promotion-info.build-failed .panel-details .badge, .panel-section .pipeline-app .promotion-info.promotion-failed .panel-details .badge, .panel-section .pipeline-app .promotion-info.release-failed .panel-details .badge, .panel-section .pipeline-app .release-info.build-failed .panel-details .badge, .panel-section .pipeline-app .release-info.promotion-failed .panel-details .badge, .panel-section .pipeline-app .release-info.release-failed .panel-details .badge, .pipeline-app .build-info.build-failed .panel-section .panel-details .badge, .pipeline-app .build-info.build-failed small .badge, .pipeline-app .build-info.build-failed span .badge, .pipeline-app .build-info.promotion-failed .panel-section .panel-details .badge, .pipeline-app .build-info.promotion-failed small .badge, .pipeline-app .build-info.promotion-failed span .badge, .pipeline-app .build-info.release-failed .panel-section .panel-details .badge, .pipeline-app .build-info.release-failed small .badge, .pipeline-app .build-info.release-failed span .badge, .pipeline-app .promotion-info.build-failed .panel-section .panel-details .badge, .pipeline-app .promotion-info.build-failed small .badge, .pipeline-app .promotion-info.build-failed span .badge, .pipeline-app .promotion-info.promotion-failed .panel-section .panel-details .badge, .pipeline-app .promotion-info.promotion-failed small .badge, .pipeline-app .promotion-info.promotion-failed span .badge, .pipeline-app .promotion-info.release-failed .panel-section .panel-details .badge, .pipeline-app .promotion-info.release-failed small .badge, .pipeline-app .promotion-info.release-failed span .badge, .pipeline-app .release-info.build-failed .panel-section .panel-details .badge, .pipeline-app .release-info.build-failed small .badge, .pipeline-app .release-info.build-failed span .badge, .pipeline-app .release-info.promotion-failed .panel-section .panel-details .badge, .pipeline-app .release-info.promotion-failed small .badge, .pipeline-app .release-info.promotion-failed span .badge, .pipeline-app .release-info.release-failed .panel-section .panel-details .badge, .pipeline-app .release-info.release-failed small .badge, .pipeline-app .release-info.release-failed span .badge { - color: #fff -} - -.pipeline-app .build-info.promotion-succeeded, .pipeline-app .build-info.release-succeeded, .pipeline-app .promotion-info.promotion-succeeded, .pipeline-app .promotion-info.release-succeeded, .pipeline-app .release-info.promotion-succeeded, .pipeline-app .release-info.release-succeeded { - background: #f8fcf9; - box-shadow: inset 0 1px 0 rgba(199, 230, 204, .6), inset 0 -1px 0 rgba(199, 230, 204, .6) -} - -.pipeline-app .build-info.promotion-succeeded:last-child, .pipeline-app .build-info.release-succeeded:last-child, .pipeline-app .promotion-info.promotion-succeeded:last-child, .pipeline-app .promotion-info.release-succeeded:last-child, .pipeline-app .release-info.promotion-succeeded:last-child, .pipeline-app .release-info.release-succeeded:last-child { - box-shadow: inset 0 1px 0 rgba(199, 230, 204, .6) -} - -.panel-section .pipeline-app .build-info.promotion-succeeded .panel-details, .panel-section .pipeline-app .build-info.promotion-succeeded .panel-details .btn-link, .panel-section .pipeline-app .build-info.release-succeeded .panel-details, .panel-section .pipeline-app .build-info.release-succeeded .panel-details .btn-link, .panel-section .pipeline-app .promotion-info.promotion-succeeded .panel-details, .panel-section .pipeline-app .promotion-info.promotion-succeeded .panel-details .btn-link, .panel-section .pipeline-app .promotion-info.release-succeeded .panel-details, .panel-section .pipeline-app .promotion-info.release-succeeded .panel-details .btn-link, .panel-section .pipeline-app .release-info.promotion-succeeded .panel-details, .panel-section .pipeline-app .release-info.promotion-succeeded .panel-details .btn-link, .panel-section .pipeline-app .release-info.release-succeeded .panel-details, .panel-section .pipeline-app .release-info.release-succeeded .panel-details .btn-link, .pipeline-app .build-info.promotion-succeeded .panel-section .panel-details, .pipeline-app .build-info.promotion-succeeded .panel-section .panel-details .btn-link, .pipeline-app .build-info.promotion-succeeded small, .pipeline-app .build-info.promotion-succeeded small .btn-link, .pipeline-app .build-info.promotion-succeeded span, .pipeline-app .build-info.promotion-succeeded span .btn-link, .pipeline-app .build-info.release-succeeded .panel-section .panel-details, .pipeline-app .build-info.release-succeeded .panel-section .panel-details .btn-link, .pipeline-app .build-info.release-succeeded small, .pipeline-app .build-info.release-succeeded small .btn-link, .pipeline-app .build-info.release-succeeded span, .pipeline-app .build-info.release-succeeded span .btn-link, .pipeline-app .promotion-info.promotion-succeeded .panel-section .panel-details, .pipeline-app .promotion-info.promotion-succeeded .panel-section .panel-details .btn-link, .pipeline-app .promotion-info.promotion-succeeded small, .pipeline-app .promotion-info.promotion-succeeded small .btn-link, .pipeline-app .promotion-info.promotion-succeeded span, .pipeline-app .promotion-info.promotion-succeeded span .btn-link, .pipeline-app .promotion-info.release-succeeded .panel-section .panel-details, .pipeline-app .promotion-info.release-succeeded .panel-section .panel-details .btn-link, .pipeline-app .promotion-info.release-succeeded small, .pipeline-app .promotion-info.release-succeeded small .btn-link, .pipeline-app .promotion-info.release-succeeded span, .pipeline-app .promotion-info.release-succeeded span .btn-link, .pipeline-app .release-info.promotion-succeeded .panel-section .panel-details, .pipeline-app .release-info.promotion-succeeded .panel-section .panel-details .btn-link, .pipeline-app .release-info.promotion-succeeded small, .pipeline-app .release-info.promotion-succeeded small .btn-link, .pipeline-app .release-info.promotion-succeeded span, .pipeline-app .release-info.promotion-succeeded span .btn-link, .pipeline-app .release-info.release-succeeded .panel-section .panel-details, .pipeline-app .release-info.release-succeeded .panel-section .panel-details .btn-link, .pipeline-app .release-info.release-succeeded small, .pipeline-app .release-info.release-succeeded small .btn-link, .pipeline-app .release-info.release-succeeded span, .pipeline-app .release-info.release-succeeded span .btn-link { - color: #008700 -} - -.panel-section .pipeline-app .build-info.promotion-succeeded .panel-details code, .panel-section .pipeline-app .build-info.release-succeeded .panel-details code, .panel-section .pipeline-app .promotion-info.promotion-succeeded .panel-details code, .panel-section .pipeline-app .promotion-info.release-succeeded .panel-details code, .panel-section .pipeline-app .release-info.promotion-succeeded .panel-details code, .panel-section .pipeline-app .release-info.release-succeeded .panel-details code, .pipeline-app .build-info.promotion-succeeded .panel-section .panel-details code, .pipeline-app .build-info.promotion-succeeded small code, .pipeline-app .build-info.promotion-succeeded span code, .pipeline-app .build-info.release-succeeded .panel-section .panel-details code, .pipeline-app .build-info.release-succeeded small code, .pipeline-app .build-info.release-succeeded span code, .pipeline-app .promotion-info.promotion-succeeded .panel-section .panel-details code, .pipeline-app .promotion-info.promotion-succeeded small code, .pipeline-app .promotion-info.promotion-succeeded span code, .pipeline-app .promotion-info.release-succeeded .panel-section .panel-details code, .pipeline-app .promotion-info.release-succeeded small code, .pipeline-app .promotion-info.release-succeeded span code, .pipeline-app .release-info.promotion-succeeded .panel-section .panel-details code, .pipeline-app .release-info.promotion-succeeded small code, .pipeline-app .release-info.promotion-succeeded span code, .pipeline-app .release-info.release-succeeded .panel-section .panel-details code, .pipeline-app .release-info.release-succeeded small code, .pipeline-app .release-info.release-succeeded span code { - color: #008700; - background: rgba(0, 135, 0, .1); - box-shadow: inset 0 0 0 1px rgba(0, 135, 0, .4) -} - -.panel-section .pipeline-app .build-info.promotion-succeeded .panel-details .badge, .panel-section .pipeline-app .build-info.release-succeeded .panel-details .badge, .panel-section .pipeline-app .promotion-info.promotion-succeeded .panel-details .badge, .panel-section .pipeline-app .promotion-info.release-succeeded .panel-details .badge, .panel-section .pipeline-app .release-info.promotion-succeeded .panel-details .badge, .panel-section .pipeline-app .release-info.release-succeeded .panel-details .badge, .pipeline-app .build-info.promotion-succeeded .panel-section .panel-details .badge, .pipeline-app .build-info.promotion-succeeded small .badge, .pipeline-app .build-info.promotion-succeeded span .badge, .pipeline-app .build-info.release-succeeded .panel-section .panel-details .badge, .pipeline-app .build-info.release-succeeded small .badge, .pipeline-app .build-info.release-succeeded span .badge, .pipeline-app .promotion-info.promotion-succeeded .panel-section .panel-details .badge, .pipeline-app .promotion-info.promotion-succeeded small .badge, .pipeline-app .promotion-info.promotion-succeeded span .badge, .pipeline-app .promotion-info.release-succeeded .panel-section .panel-details .badge, .pipeline-app .promotion-info.release-succeeded small .badge, .pipeline-app .promotion-info.release-succeeded span .badge, .pipeline-app .release-info.promotion-succeeded .panel-section .panel-details .badge, .pipeline-app .release-info.promotion-succeeded small .badge, .pipeline-app .release-info.promotion-succeeded span .badge, .pipeline-app .release-info.release-succeeded .panel-section .panel-details .badge, .pipeline-app .release-info.release-succeeded small .badge, .pipeline-app .release-info.release-succeeded span .badge { - color: #fff -} - -.pipeline-app .auto-deploy, .pipeline-app .commit-sha { - height: 18px; - line-height: 11px -} - -.pipeline-app .auto-deploy .ci-status-component, .pipeline-app .commit-sha .ci-status-component { - height: 18px -} - -.pipeline-app .auto-deploy .ci-status-component .btn-group, .pipeline-app .commit-sha .ci-status-component .btn-group { - line-height: 0; - height: 18px; - display: block -} - -.pipeline-app .auto-deploy .ci-status-component .drop-down__toggle, .pipeline-app .commit-sha .ci-status-component .drop-down__toggle { - position: relative; - padding: 2px 2px 2px 0; - border: 1px solid transparent; - border-radius: 4px -} - -.pipeline-app .auto-deploy .ci-status-component .drop-down__toggle:hover, .pipeline-app .commit-sha .ci-status-component .drop-down__toggle:hover { - background-color: #E3E7EF; - border-color: #CFD7E6; - padding-left: 2px -} - -.pipeline-app .commit-sha { - max-width: 80px -} - -.pipeline-app .btn-remove { - border-radius: 50%; - border: none; - right: -7px; - top: -7px; - width: 22px; - height: 22px; - padding: 0; - box-shadow: 0 0 0 1px #CFD7E6, 0 2px 1px rgba(207, 215, 230, .4) -} - -.pipeline-app .btn-remove:active { - background: #f1f3f7 -} - -.pipeline-app.pr-app .app-icon, .pipeline-app.pr-app-pending .app-icon { - width: 21px -} - -.pipeline-app.pr-app .app-name, .pipeline-app.pr-app-pending .app-name { - font-size: 13px -} - -.pipeline-app.pr-app .app-pr-meta, .pipeline-app.pr-app-pending .app-pr-meta { - color: #56667D -} - -.pipeline-app.pr-app .github-avatar, .pipeline-app.pr-app-pending .github-avatar { - position: absolute; - top: 1px; - right: 0; - opacity: .8 -} - -.pipeline-app.app-suggestion .box, .pipeline-app.pr-app-pending .box { - background: rgba(255, 255, 255, .4); - border: 1px dashed rgba(86, 102, 125, .2); - box-shadow: none -} - -.pipeline-app.app-suggestion .box .btn:not(:hover), .pipeline-app.pr-app-pending .box .btn:not(:hover), .pipeline-dropdown .dropdown-menu-scroll > li .btn-link:hover, .pipeline-dropdown .dropdown-menu-scroll > li > a.active:hover, .pipeline-dropdown > li .btn-link:hover, .pipeline-dropdown > li > a.active:hover { - background: 0 0 -} - -.pipeline-app.app-suggestion .box .build-info, .pipeline-app.pr-app-pending .box .build-info { - margin-top: 20px -} - -.pipeline-app.app-suggestion .box { - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: horizontal; - -moz-box-orient: horizontal; - box-orient: horizontal; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: row; - -moz-flex-direction: row; - flex-direction: row; - -ms-flex-direction: row; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center; - width: 100% -} - -.pipeline-app.app-suggestion .app-info { - -webkit-box-flex: 1; - -moz-box-flex: 1; - box-flex: 1; - -webkit-flex: 1; - -moz-flex: 1; - -ms-flex: 1; - flex: 1 -} - -.manage-pipeline-app { - position: relative; - right: 0; - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0 -} - -.manage-pipeline-app .btn-group { - margin-left: 0 -} - -.manage-pipeline-app .drop-down__toggle { - display: flex; - align-items: center; - padding: 0 4px; - height: 20px -} - -.manage-pipeline-app .drop-down__toggle .icon { - margin: 0 !important -} - -.pipeline-dropdown { - top: 100%; - margin-top: 1px; - max-width: 300px; - transform: translate3d(0, 0, 0) -} - -.pipeline-dropdown .dropdown-menu-scroll { - max-height: 320px -} - -.pipeline-dropdown .dropdown-menu-scroll > li, .pipeline-dropdown > li { - font-size: 13px -} - -.pipeline-dropdown .dropdown-menu-scroll > li .icon, .pipeline-dropdown > li .icon { - position: relative; - margin-top: -2px; - margin-left: 0; - margin-right: 4px -} - -.pipeline-dropdown .dropdown-menu-scroll > li .icon.icon-space-mini, .pipeline-dropdown > li .icon.icon-space-mini { - margin-top: 1px; - top: -1px -} - -.pipeline-dropdown .dropdown-menu-scroll > li.dropdown-heading, .pipeline-dropdown > li.dropdown-heading { - color: #62738D; - padding: 8px 16px 0; - margin: 6px 0 2px; - border-top: 1px solid #E3E7EF -} - -.pipeline-dropdown .dropdown-menu-scroll > li.dropdown-heading:first-of-type, .pipeline-dropdown > li.dropdown-heading:first-of-type { - margin-top: 0; - padding-top: 2px; - border: none -} - -.pipeline-dropdown .dropdown-menu-scroll > li.dropdown-heading.loading, .pipeline-dropdown > li.dropdown-heading.loading { - padding-top: 10px -} - -.pipeline-dropdown .dropdown-menu-scroll > li .btn-link, .pipeline-dropdown .dropdown-menu-scroll > li h6, .pipeline-dropdown > li .btn-link, .pipeline-dropdown > li .dropdown-menu-scroll > li .btn-link, .pipeline-dropdown > li h6 { - font-size: 11px; - font-weight: 700; - color: #62738D; - margin: 0; - padding: 2px 0; - pointer-events: none -} - -.pipeline-dropdown .dropdown-menu-scroll > li .btn-link, .pipeline-dropdown > li .btn-link { - padding: 2px 0; - border: none; - pointer-events: auto -} - -.pipeline-dropdown .dropdown-menu-scroll > li .btn-link .icon, .pipeline-dropdown > li .btn-link .icon { - position: relative; - margin-left: 4px; - margin-top: -2px; - transition: ease .1s -} - -.pipeline-dropdown .dropdown-menu-scroll > li .btn-link .icon.icon-space-mini, .pipeline-dropdown > li .btn-link .icon.icon-space-mini { - margin-top: 1px -} - -.pipeline-dropdown .dropdown-menu-scroll > li .btn-link .icon.icon-toggle, .pipeline-dropdown > li .btn-link .icon.icon-toggle { - margin-left: 0; - margin-right: 2px; - transform: rotate(-90deg) -} - -.pipeline-dropdown .dropdown-menu-scroll > li .btn-link .icon.icon-toggle.opened, .pipeline-dropdown > li .btn-link .icon.icon-toggle.opened { - transform: rotate(0) -} - -.pipeline-dropdown .dropdown-menu-scroll > li > a, .pipeline-dropdown > li > a { - padding: 3px 16px; - color: #56667D !important -} - -.pipeline-dropdown .dropdown-menu-scroll > li > a:hover, .pipeline-dropdown > li > a:hover { - color: #475366 !important -} - -.pipeline-dropdown .dropdown-menu-scroll > li > a.active, .pipeline-dropdown > li > a.active { - color: #79589F !important -} - -.pipeline-dropdown .dropdown-menu-scroll > li.dropdown-header, .pipeline-dropdown > li.dropdown-header { - position: relative; - z-index: 1; - margin: -5px 0 5px; - padding: 0; - box-shadow: 0 1px 0 rgba(0, 0, 0, .1); - background-color: rgba(227, 231, 239, 0); - background-image: -webkit-linear-gradient(rgba(227, 231, 239, 0), rgba(227, 231, 239, .3)); - background-image: linear-gradient(rgba(227, 231, 239, 0), rgba(227, 231, 239, .3)); - border-top-right-radius: 3px; - border-top-left-radius: 3px -} - -.pipeline-dropdown .dropdown-menu-scroll > li.dropdown-header > a, .pipeline-dropdown > li.dropdown-header > a { - background: 0 0; - color: #79589F; - padding-top: 10px; - padding-bottom: 10px -} - -.pipeline-dropdown .dropdown-menu-scroll > li.dropdown-header > a .icon, .pipeline-dropdown > li.dropdown-header > a .icon { - margin-left: 0 -} - -.pipeline-dropdown-button, .pipeline-dropdown-button:focus { - text-decoration: none -} - -.deploy-ui, .promotion-ui { - position: relative; - margin: -16px -15px; - text-align: center -} - -.deploy-ui .well, .promotion-ui .well { - border-radius: 0; - margin: 0; - padding: 20px 40px; - text-align: left -} - -.deploy-ui .well .dyno-tier-picker-item-size-name, .deploy-ui .well .panel-section .panel-title, .deploy-ui .well h4, .panel-section .deploy-ui .well .panel-title, .panel-section .promotion-ui .well .panel-title, .promotion-ui .well .dyno-tier-picker-item-size-name, .promotion-ui .well .panel-section .panel-title, .promotion-ui .well h4 { - font-size: 11px; - font-weight: 700; - text-transform: uppercase; - color: #62738D -} - -.deploy-ui .well ul, .promotion-ui .well ul { - list-style: none -} - -.deploy-ui .well .form-control, .promotion-ui .well .form-control { - background-color: #fff; - margin-top: 20px -} - -.deploy-ui .branch-selection { - margin: 0 !important -} - -.deploy-ui .branch-selection .form-control { - margin-top: 0; - width: 100% -} - -.auto-deploy-modal .modal-title .icon { - margin: -2px 1px 0 3px -} - -.auto-deploy-modal .modal-intro .title .icon { - position: relative; - margin-bottom: 0; - margin-right: 2px; - top: -1px -} - -.auto-deploy-modal .form-group { - padding: 10px 10px 0; - margin-bottom: 10px; - text-align: left -} - -.auto-deploy-modal .form-group label { - font-size: 12px; - color: #62738D; - font-weight: 700; - padding-bottom: 4px -} - -.auto-deploy-modal .branch-selection select { - display: block; - width: 100% -} - -.auto-deploy-modal .disable-auto-deploys { - border-top: 1px solid #E3E7EF; - text-align: center; - margin: 5px auto 0; - width: 95%; - padding-top: 24px -} - -.ra-enable-header { - background: linear-gradient(0deg, rgba(255, 255, 255, 0), #fff), linear-gradient(90deg, rgba(66, 174, 203, .15), rgba(157, 113, 208, .15)) -} - -.ra-enable-banner-header { - background: linear-gradient(rgba(157, 113, 208, .15), rgba(66, 174, 203, .15)) -} - -.ra-confirmation-gradient { - background: linear-gradient(135deg, rgba(157, 113, 208, .15), rgba(66, 174, 203, .15)) -} - -.review-app-errored .review-app-error { - border: 1px dashed #E3E7EF -} - -.pipeline-access-table.pipeline-collaborator-access-table tr td:last-child, .pipeline-access-table.pipeline-collaborator-access-table tr th:last-child { - width: 138px -} - -.pipeline-access-table.team-admin-access-table tr td:last-child, .pipeline-access-table.team-admin-access-table tr th:last-child { - padding-right: calc(138px + 28px) -} - -.ci-panel { - position: relative; - display: flex; - -webkit-box-flex: 1; - -moz-box-flex: 1; - box-flex: 1; - -webkit-flex: 1; - -moz-flex: 1; - -ms-flex: 1; - flex: 1; - -webkit-box-align: stretch; - -moz-box-align: stretch; - box-align: stretch; - -webkit-align-items: stretch; - -moz-align-items: stretch; - -ms-align-items: stretch; - -o-align-items: stretch; - align-items: stretch; - -ms-flex-align: stretch; - background: #fff -} - -@media (max-width: 767px) { - .ci-panel { - -webkit-box-orient: vertical; - -moz-box-orient: vertical; - box-orient: vertical; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: column; - -moz-flex-direction: column; - flex-direction: column; - -ms-flex-direction: column - } -} - -.ci-panel .pipeline-dropdown .dropdown-menu-scroll > li .btn-link, .ci-panel .pipeline-dropdown > li .btn-link, .ci-panel h6, .pipeline-dropdown .dropdown-menu-scroll > li .ci-panel .btn-link, .pipeline-dropdown > li .ci-panel .btn-link { - font-size: 10px; - font-weight: 700; - margin: 0; - padding: 0 -} - -.ci-placeholder, .ci-setup { - display: flex; - -webkit-box-flex: 1; - -moz-box-flex: 1; - box-flex: 1; - -webkit-flex: 1; - -moz-flex: 1; - -ms-flex: 1; - flex: 1; - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center; - padding: 40px 0; - background: #EEF1F6 -} - -.ci-menu, .ci-menu .empty-state { - -webkit-flex-direction: column; - -moz-box-orient: vertical; - -moz-box-direction: normal -} - -.ci-placeholder { - background: #fff -} - -.ci-index #tests-setup { - position: relative; - margin: 30px auto; - max-width: 680px; - z-index: 1 -} - -.ci-index #tests-setup .dyno-tier-picker-item-size-name, .ci-index #tests-setup .panel-section .panel-title, .ci-index #tests-setup .title, .ci-index #tests-setup h4, .panel-section .ci-index #tests-setup .panel-title { - font-size: 15px; - font-weight: 400; - color: #475366 -} - -.ci-index #tests-setup .dyno-tier-picker-item-size-name .icon, .ci-index #tests-setup .panel-section .panel-title .icon, .ci-index #tests-setup .title .icon, .ci-index #tests-setup h4 .icon, .panel-section .ci-index #tests-setup .panel-title .icon { - position: relative; - margin: -1px 4px 0 2px -} - -.ci-index #tests-setup .dyno-tier-picker-item-size-name .panel-section .panel-details, .ci-index #tests-setup .dyno-tier-picker-item-size-name small, .ci-index #tests-setup .panel-section .panel-title .panel-details, .ci-index #tests-setup .panel-section .panel-title small, .ci-index #tests-setup .title .panel-section .panel-details, .ci-index #tests-setup .title small, .ci-index #tests-setup h4 .panel-section .panel-details, .ci-index #tests-setup h4 small, .panel-section .ci-index #tests-setup .dyno-tier-picker-item-size-name .panel-details, .panel-section .ci-index #tests-setup .panel-title .panel-details, .panel-section .ci-index #tests-setup .panel-title small, .panel-section .ci-index #tests-setup .title .panel-details, .panel-section .ci-index #tests-setup h4 .panel-details { - font-size: 12px; - padding-left: 6px -} - -.ci-index #tests-setup .panel-section .panel-details, .ci-index #tests-setup p, .panel-section .ci-index #tests-setup .panel-details { - color: #56667D; - font-size: 13px -} - -.ci-index #tests-setup .setup-step { - position: relative; - margin-top: 20px; - padding: 20px 30px 10px 120px; - border-top: 1px solid #E3E7EF; - text-align: left -} - -.ci-index #tests-setup .setup-step > .icon { - position: absolute; - top: 30px; - left: 66px -} - -.ci-index #tests-setup .setup-step .pipeline-ci-toggle .ci-billing-options, .ci-index #tests-setup .setup-step .pipeline-ci-toggle .panel-section .panel-details, .ci-index #tests-setup .setup-step .pipeline-ci-toggle p, .panel-section .ci-index #tests-setup .setup-step .pipeline-ci-toggle .panel-details { - margin-bottom: 14px -} - -.ci-index #tests-setup .setup-step .alert { - margin: 20px 0 10px -} - -.ci-index #tests-setup .setup-step .alert hr { - margin: 10px 0 -} - -.ci-menu { - position: relative; - display: flex; - -webkit-box-orient: vertical; - box-orient: vertical; - -webkit-box-direction: normal; - box-direction: normal; - -moz-flex-direction: column; - flex-direction: column; - -ms-flex-direction: column; - width: 33%; - background: #F7F8FB; - border-right: 1px solid #e7ebf3 -} - -@media (max-width: 767px) { - .ci-menu { - display: block; - width: 100%; - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 1 auto; - -moz-flex: 0 1 auto; - -ms-flex: 0 1 auto; - flex: 0 1 auto; - padding-right: 0; - box-shadow: inset 0 -1px 0 #E3E7EF; - border-right: none - } - - .ci-menu .ci-menu--context { - margin: 8px 20px 12px - } -} - -.ci-menu .ci-menu--context { - display: flex; - position: relative; - z-index: 2; - padding: 8px 10px 8px 15px; - background: #fff; - min-height: 42px; - box-shadow: 0 1px 0 rgba(98, 115, 141, .1), 0 2px 0 rgba(0, 0, 0, .02); - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center -} - -@media (max-width: 767px) { - .ci-menu .ci-menu--context { - background: 0 0; - box-shadow: none; - padding: 0; - min-height: 24px - } - - .ci-menu .ci-menu--context.has-tests { - padding: 0 0 34px - } -} - -.ci-menu .ci-menu--context .btn-group { - margin-left: 12px -} - -.ci-menu .ci-menu--context .btn-group.filter-branches { - display: flex; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center; - margin-left: 0; - margin-right: 15px; - min-width: 0 -} - -.ci-menu .ci-menu--context .branch-selector-btn { - padding: 0; - border: none; - background: 0 0; - white-space: nowrap; - width: 100% -} - -.ci-menu .ci-menu--context .branch-selector-btn code, .ci-menu .ci-menu--context .branch-selector-btn span { - position: relative; - font-size: 12px; - line-height: 13px; - padding: 3px 4px 2px; - margin: 0; - text-overflow: ellipsis; - overflow: hidden; - display: inline-block; - vertical-align: middle; - width: calc(100% - 44px) -} - -.ci-menu .ci-menu--context .branch-selector-btn .pipeline-dropdown .dropdown-menu-scroll > li .btn-link, .ci-menu .ci-menu--context .branch-selector-btn .pipeline-dropdown > li .btn-link, .ci-menu .ci-menu--context .branch-selector-btn h6, .pipeline-dropdown .dropdown-menu-scroll > li .ci-menu .ci-menu--context .branch-selector-btn .btn-link, .pipeline-dropdown > li .ci-menu .ci-menu--context .branch-selector-btn .btn-link { - color: #62738D; - font-size: 11px; - font-weight: 700; - padding: 3px 0 2px; - text-transform: uppercase -} - -.ci-menu .ci-menu--context .branch-selector-btn .icon { - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0; - position: relative; - top: 0; - margin-left: 2px -} - -.ci-menu .ci-menu--context .info-tooltip-component { - position: relative; - left: -4px; - margin-right: 4px -} - -.ci-menu .ci-menu--context .new-btn { - margin-right: 5px; - margin-left: auto -} - -@media (max-width: 767px) { - .ci-menu .ci-menu--context .new-btn { - margin-right: 0 - } -} - -.ci-menu .ci-menu--context .new-btn .icon { - margin: -2px 2px 0; - -webkit-transition: all .1s ease; - -o-transition: all .1s ease; - transition: all .1s ease -} - -.ci-menu .ci-menu--context .new-btn .icon.rotate { - -webkit-transform: rotate(45deg); - -moz-transform: rotate(45deg); - -ms-transform: rotate(45deg); - -o-transform: rotate(45deg); - transform: rotate(45deg) -} - -.ci-menu .ci-menu--context .mobile-menu { - position: absolute; - bottom: 0; - left: 0; - right: 0; - width: 100%; - padding-top: 6px; - margin-top: 8px; - border-top: 1px solid rgba(207, 215, 230, .5) -} - -.ci-menu .ci-menu--context .mobile-menu .btn-group { - margin-left: 0 -} - -.ci-menu .context-switcher__list, .ci-menu .drop-down__menu, .ci-menu .dropdown-menu { - font-size: 12px -} - -.ci-menu .context-switcher__list .divider, .ci-menu .drop-down__menu .divider, .ci-menu .dropdown-menu .divider { - margin: 5px 0 -} - -.ci-menu .branch-dropdown.context-switcher__list, .ci-menu .branch-dropdown.drop-down__menu, .ci-menu .dropdown-menu.branch-dropdown, .ci-menu .dropdown-menu.tests-dropdown, .ci-menu .tests-dropdown.context-switcher__list, .ci-menu .tests-dropdown.drop-down__menu { - width: 240px; - max-width: calc(33vw - 42px); - max-height: 350px; - overflow: auto -} - -.ci-menu .branch-dropdown.context-switcher__list .btn-link, .ci-menu .branch-dropdown.drop-down__menu .btn-link, .ci-menu .dropdown-menu.branch-dropdown .btn-link, .ci-menu .dropdown-menu.tests-dropdown .btn-link, .ci-menu .tests-dropdown.context-switcher__list .btn-link, .ci-menu .tests-dropdown.drop-down__menu .btn-link { - max-width: 100%; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap -} - -.ci-menu .dropdown-menu.tests-dropdown, .ci-menu .tests-dropdown.context-switcher__list, .ci-menu .tests-dropdown.drop-down__menu { - width: auto; - background: #EEF1F6; - padding: 0 -} - -.ci-menu .dropdown-menu.tests-dropdown .ci-menu--header:first-child, .ci-menu .tests-dropdown.context-switcher__list .ci-menu--header:first-child, .ci-menu .tests-dropdown.drop-down__menu .ci-menu--header:first-child { - padding-top: 10px -} - -.ci-menu .ci-menu--scroll { - position: absolute; - top: 42px; - left: 0; - right: 0; - bottom: 0; - z-index: 1; - overflow: auto -} - -.ci-menu .test-run-btn { - color: #62738D; - font-size: 11px; - font-weight: 700; - text-transform: uppercase; - padding: 0; - margin: -1px 6px 0 0; - border: none; - background: 0 0 -} - -.ci-menu .test-run-btn .icon { - position: relative; - top: -1px; - margin-left: 2px -} - -.ci-menu .ci-menu--header { - padding: 8px 15px; - border-bottom: 1px solid #E3E7EF; - background: rgba(255, 255, 255, .7) -} - -.ci-menu .ci-menu--header .pipeline-dropdown .dropdown-menu-scroll > li .btn-link, .ci-menu .ci-menu--header .pipeline-dropdown > li .btn-link, .ci-menu .ci-menu--header h6, .pipeline-dropdown .dropdown-menu-scroll > li .ci-menu .ci-menu--header .btn-link, .pipeline-dropdown > li .ci-menu .ci-menu--header .btn-link { - color: #62738D -} - -.ci-menu .ci-menu--new { - border-bottom: 1px solid #E3E7EF; - padding: 11px 10px 9px; - margin-top: -93px; - transition: ease .2s; - opacity: 0; - pointer-events: none -} - -.ci-menu .ci-menu--new.reveal { - margin-top: 0; - opacity: 1; - pointer-events: auto -} - -@media (max-width: 767px) { - .ci-menu .branch-dropdown.context-switcher__list, .ci-menu .branch-dropdown.drop-down__menu, .ci-menu .dropdown-menu.branch-dropdown, .ci-menu .dropdown-menu.tests-dropdown, .ci-menu .tests-dropdown.context-switcher__list, .ci-menu .tests-dropdown.drop-down__menu { - max-height: 300px; - max-width: calc(100vw - 42px) - } - - .ci-menu .ci-menu--new { - border-top: 1px solid rgba(207, 215, 230, .5); - box-shadow: inset 0 1px 0 #E3E7EF; - transition: none; - display: none; - margin-top: 0 - } - - .ci-menu .ci-menu--new.reveal { - display: block - } -} - -.ci-menu .ci-menu--new .ci-menu--item { - background: rgba(255, 255, 255, .4); - border-radius: 5px; - padding: 10px; - border: 1px dashed rgba(86, 102, 125, .2) -} - -.ci-menu .ci-menu--new .ci-menu--item .ci-meta .commit { - color: #62738D -} - -.ci-menu .ci-menu--new .ci-menu--item .ci-meta .branch { - color: #56667D -} - -.ci-menu .ci-menu--item .ci-menu--item--link { - position: relative; - color: #475366; - text-decoration: none; - display: block; - padding: 12px 15px; - border-bottom: 1px solid #E3E7EF -} - -.ci-menu .ci-menu--item .ci-menu--item--link:hover { - background: rgba(255, 255, 255, .5) -} - -.ci-menu .ci-menu--item .ci-menu--item--link.active { - background: #fff; - border-bottom: 1px solid rgba(207, 215, 230, .8); - box-shadow: 0 1px 0 rgba(207, 215, 230, .3), 0 -1px 0 rgba(207, 215, 230, .3); - z-index: 2 -} - -.ci-menu .ci-menu--item .ci-menu--item--link.active .ci-meta .commit { - font-weight: 700; - position: relative; - top: -1px -} - -.ci-menu .ci-menu--item.succeeded .ci-menu--item--link .commit { - color: #008700 -} - -.ci-menu .ci-menu--item.errored .ci-menu--item--link .commit, .ci-menu .ci-menu--item.errored .ci-menu--item--link .test-status, .ci-menu .ci-menu--item.failed .ci-menu--item--link .commit, .ci-menu .ci-menu--item.failed .ci-menu--item--link .test-status { - color: #DE0A0A -} - -.ci-menu .ci-meta, .ci-menu .ci-status { - display: flex; - font-size: 12px; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center; - -webkit-box-pack: justify; - -moz-box-pack: justify; - box-pack: justify; - -webkit-justify-content: space-between; - -moz-justify-content: space-between; - -ms-justify-content: space-between; - -o-justify-content: space-between; - justify-content: space-between; - -ms-flex-pack: justify -} - -.ci-menu .ci-meta { - padding-bottom: 6px -} - -.ci-menu .ci-meta .branch, .ci-menu .ci-meta .commit { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis -} - -.ci-menu .ci-meta .commit { - color: #79589F -} - -.ci-menu .ci-meta .commit .icon { - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0; - margin-top: -2px; - margin-left: 1px; - margin-right: 4px -} - -.ci-menu .ci-meta .branch { - font-size: 11px; - text-align: right; - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0; - margin-left: 20px; - max-width: 50% -} - -.ci-menu .ci-meta .branch .icon { - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0; - margin-top: -1px -} - -.ci-menu .ci-status { - line-height: 18px -} - -.ci-menu .ci-status .test-status, .ci-menu .ci-status .test-time { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis -} - -.ci-menu .ci-status .test-status .icon { - margin-top: -2px; - margin-right: 2px -} - -.ci-menu .ci-status .test-time { - padding-left: 10px -} - -.ci-menu .empty-state { - position: relative; - display: flex; - -webkit-box-orient: vertical; - box-orient: vertical; - -webkit-box-direction: normal; - box-direction: normal; - -moz-flex-direction: column; - flex-direction: column; - -ms-flex-direction: column; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center; - -webkit-box-pack: center; - -moz-box-pack: center; - box-pack: center; - -webkit-justify-content: center; - -moz-justify-content: center; - -ms-justify-content: center; - -o-justify-content: center; - justify-content: center; - -ms-flex-pack: center; - height: 100%; - padding: 40px 0 -} - -.ci-menu .empty-state .panel-section .panel-details, .ci-menu .empty-state p, .panel-section .ci-menu .empty-state .panel-details { - color: #62738D; - text-align: center; - padding-top: 16px; - max-width: 200px -} - -.ci-view { - -webkit-box-flex: 2; - -moz-box-flex: 2; - box-flex: 2; - -webkit-flex: 2; - -moz-flex: 2; - -ms-flex: 2; - flex: 2; - position: relative; - padding: 15px 40px; - background: #fff; - overflow: auto -} - -@media (max-width: 767px) { - .ci-view { - padding: 10px 20px - } -} - -.ci-view .ci-view--header, .ci-view .ci-view--meta { - display: flex; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center; - padding: 14px 0 -} - -.ci-view .ci-view--header { - padding: 14px 10px; - margin: 0 -10px; - border-bottom: 1px solid #E3E7EF -} - -.ci-view .ci-view--header h3 { - font-size: 16px; - line-height: 24px; - color: #56667D; - margin: 0 auto 0 0 -} - -.ci-view .ci-view--header h3 span { - color: #62738D -} - -.ci-view .ci-view--header h3 span.is-passed { - color: #008700 -} - -.ci-view .ci-view--header h3 span.is-failed { - color: #DE0A0A -} - -.ci-view .ci-view--header h3 span.display-duration { - display: inline-block -} - -.ci-view .ci-view--header h3 .icon { - margin-top: -2px; - margin-right: 4px -} - -.ci-view .ci-view--header .ci-actions { - margin-left: 20px; - flex-shrink: 0 -} - -.ci-view .ci-view--header .ci-actions .run-again { - min-width: 83px -} - -.ci-view .ci-view--header .ci-actions .btn .icon { - margin-left: 0; - margin-top: -2px -} - -.ci-view .ci-view--header .ci-actions .context-switcher__list, .ci-view .ci-view--header .ci-actions .drop-down__menu { - font-size: 12px; - min-width: 170px -} - -.ci-view .ci-view--header .ci-actions .context-switcher__list .divider, .ci-view .ci-view--header .ci-actions .drop-down__menu .divider { - margin: 5px 0 -} - -.ci-view .ci-view--header .ci-actions .context-switcher__list .async-button, .ci-view .ci-view--header .ci-actions .drop-down__menu .async-button { - width: 100% -} - -.ci-view .ci-view--header .ci-actions .context-switcher__list .async-button.pending, .ci-view .ci-view--header .ci-actions .drop-down__menu .async-button.pending { - text-align: center -} - -.ci-view .ci-view--meta { - font-size: 12px; - display: flex -} - -.ci-view .ci-view--meta .author-info, .ci-view .ci-view--meta .repo-info { - display: inline-flex; - max-width: 50% -} - -.ci-view .ci-view--meta .author-info .author, .ci-view .ci-view--meta .author-info .branch, .ci-view .ci-view--meta .author-info .repo, .ci-view .ci-view--meta .author-info .time, .ci-view .ci-view--meta .repo-info .author, .ci-view .ci-view--meta .repo-info .branch, .ci-view .ci-view--meta .repo-info .repo, .ci-view .ci-view--meta .repo-info .time { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis -} - -.ci-view .ci-view--meta .repo-info { - color: #56667D; - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 1 auto; - -moz-flex: 0 1 auto; - -ms-flex: 0 1 auto; - flex: 0 1 auto -} - -.ci-view .ci-view--meta .repo-info .branch, .ci-view .ci-view--meta .repo-info .repo { - margin-right: 14px -} - -.ci-view .ci-view--meta .repo-info a { - color: inherit; - text-decoration: none -} - -.ci-view .ci-view--meta .repo-info a:hover { - text-decoration: underline -} - -.ci-view .ci-view--meta .author-info { - color: #62738D; - margin-left: auto -} - -.ci-view .ci-view--pr { - margin-left: auto -} - -.ci-view .ci-view--commit { - border: none; - padding-bottom: 10px -} - -.ci-view .ci-view--commit .icon { - margin-top: -1px -} - -.ci-view .ci-view--commit code { - margin: 0 6px -} - -.ci-view .ci-view--commit .panel-section .panel-details, .ci-view .ci-view--commit p, .panel-section .ci-view .ci-view--commit .panel-details { - font-size: 12px; - color: #56667D; - display: flex; - width: 100%; - -webkit-box-align: top; - -moz-box-align: top; - box-align: top; - -webkit-align-items: top; - -moz-align-items: top; - -ms-align-items: top; - -o-align-items: top; - align-items: top; - -ms-flex-align: top -} - -.ci-view .ci-view--commit .panel-section .panel-details .commit-meta, .ci-view .ci-view--commit p .commit-meta, .panel-section .ci-view .ci-view--commit .panel-details .commit-meta { - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0 -} - -.ci-view .ci-view--commit .panel-section .panel-details .commit-meta a, .ci-view .ci-view--commit p .commit-meta a, .panel-section .ci-view .ci-view--commit .panel-details .commit-meta a { - text-decoration: none -} - -.ci-view .ci-view--commit .panel-section .panel-details .commit-meta a:hover, .ci-view .ci-view--commit p .commit-meta a:hover, .deploy-steps > li .toggle-output, .dyno-size-help > a, .panel-section .ci-view .ci-view--commit .panel-details .commit-meta a:hover { - text-decoration: underline -} - -.ci-view .ci-view--commit .panel-section .panel-details .commit-message, .ci-view .ci-view--commit p .commit-message, .panel-section .ci-view .ci-view--commit .panel-details .commit-message { - display: inline-block; - vertical-align: top; - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 1 auto; - -moz-flex: 0 1 auto; - -ms-flex: 0 1 auto; - flex: 0 1 auto -} - -.ci-view .ci-view--commit .panel-section .panel-details .commit-message .panel-details, .ci-view .ci-view--commit .panel-section .panel-details .commit-message small, .ci-view .ci-view--commit p .commit-message .panel-section .panel-details, .ci-view .ci-view--commit p .commit-message small, .panel-section .ci-view .ci-view--commit .panel-details .commit-message .panel-details, .panel-section .ci-view .ci-view--commit .panel-details .commit-message small, .panel-section .ci-view .ci-view--commit p .commit-message .panel-details { - font-size: 12px; - display: block; - color: #62738D; - padding-top: 4px; - word-wrap: break-word -} - -.ci-view .ci-view--commit .panel-section .panel-details .btn, .ci-view .ci-view--commit p .btn, .panel-section .ci-view .ci-view--commit .panel-details .btn { - position: relative; - margin-top: -1px; - padding: 0 6px 6px; - font-size: 13px; - line-height: 8px; - margin-left: 4px -} - -.ci-view .ci-view--module { - font-size: 13px; - padding: 14px 0; - border-bottom: 1px solid #E3E7EF -} - -.ci-view .ci-view--module:last-child { - border-bottom: none -} - -.ci-view .ci-view--module h5 { - font-size: 13px; - margin: 0; - padding-bottom: 14px -} - -.ci-view .ci-view--module h5 .icon { - margin: -2px 4px 0 -} - -.ci-view .ci-view--module .pipeline-dropdown .dropdown-menu-scroll > li .btn-link, .ci-view .ci-view--module .pipeline-dropdown .dropdown-menu-scroll > li .btn-link .btn-link, .ci-view .ci-view--module .pipeline-dropdown > li .btn-link, .ci-view .ci-view--module .pipeline-dropdown > li .btn-link .btn-link, .ci-view .ci-view--module h6, .ci-view .ci-view--module h6 .btn-link, .pipeline-dropdown .dropdown-menu-scroll > li .ci-view .ci-view--module .btn-link, .pipeline-dropdown .dropdown-menu-scroll > li .ci-view .ci-view--module .btn-link .btn-link, .pipeline-dropdown > li .ci-view .ci-view--module .btn-link, .pipeline-dropdown > li .ci-view .ci-view--module .btn-link .btn-link { - color: #62738D; - font-size: 11px; - font-weight: 700; - text-transform: uppercase; - margin: 0 0 10px -} - -.ci-view .ci-view--module .pipeline-dropdown .dropdown-menu-scroll > li .btn-link .btn-link, .ci-view .ci-view--module .pipeline-dropdown > li .btn-link .btn-link, .ci-view .ci-view--module h6 .btn-link, .ci-view .ci-view--module.test-output-module .pipeline-dropdown .dropdown-menu-scroll > li .btn-link, .ci-view .ci-view--module.test-output-module .pipeline-dropdown > li .btn-link, .ci-view .ci-view--module.test-output-module h6, .pipeline-dropdown .dropdown-menu-scroll > li .ci-view .ci-view--module .btn-link .btn-link, .pipeline-dropdown .dropdown-menu-scroll > li .ci-view .ci-view--module.test-output-module .btn-link, .pipeline-dropdown > li .ci-view .ci-view--module .btn-link .btn-link, .pipeline-dropdown > li .ci-view .ci-view--module.test-output-module .btn-link { - margin-bottom: 0 -} - -.ci-view .ci-view--module .pipeline-dropdown .dropdown-menu-scroll > li .btn-link .btn-link:disabled, .ci-view .ci-view--module .pipeline-dropdown .dropdown-menu-scroll > li .btn-link:disabled, .ci-view .ci-view--module .pipeline-dropdown > li .btn-link .btn-link:disabled, .ci-view .ci-view--module .pipeline-dropdown > li .btn-link:disabled, .ci-view .ci-view--module h6 .btn-link:disabled, .ci-view .ci-view--module h6:disabled, .pipeline-dropdown .dropdown-menu-scroll > li .ci-view .ci-view--module .btn-link .btn-link:disabled, .pipeline-dropdown .dropdown-menu-scroll > li .ci-view .ci-view--module .btn-link:disabled, .pipeline-dropdown > li .ci-view .ci-view--module .btn-link .btn-link:disabled, .pipeline-dropdown > li .ci-view .ci-view--module .btn-link:disabled { - opacity: .5 -} - -.ci-view .ci-view--module .build-stream .build-stream-output { - min-height: 340px -} - -.ci-view .ci-view--module .build-stream-full { - margin-top: 11px; - min-height: 60px; - max-height: calc(100vh - 200px); - padding-bottom: 32px; - height: auto -} - -.ci-view .ci-view--module .build-stream-full .build-stream-output { - max-height: calc(100vh - 200px - 32px) -} - -.ci-view .ci-view--module .build-stream-full .build-stream-line { - font-size: 11px -} - -.ci-view .ci-view--module.test-output-module .icon-toggle { - position: relative; - top: -2px; - margin-right: 4px; - transform: rotate(-90deg); - transition: ease .1s -} - -.ci-view .ci-view--module.test-output-module .icon-toggle.opened { - top: -1px; - transform: rotate(0) -} - -.ci-view .ci-view--messages { - position: relative; - margin: -10px 0 0; - border-top: 0 solid #fff; - border-bottom: 1px solid #fff -} - -.ci-view .ci-view--messages .test-message { - color: #62738D; - font-size: 13px; - position: relative; - padding: 16px 20px; - margin-bottom: 20px; - border-radius: 4px; - box-shadow: inset 0 0 0 1px #E3E7EF; - background: #EEF1F6 -} - -.ci-view .ci-view--messages .test-message:last-child { - margin-bottom: 0 -} - -.ci-view .ci-view--messages .test-message .pipeline-dropdown .dropdown-menu-scroll > li .btn-link, .ci-view .ci-view--messages .test-message .pipeline-dropdown > li .btn-link, .ci-view .ci-view--messages .test-message h6, .pipeline-dropdown .dropdown-menu-scroll > li .ci-view .ci-view--messages .test-message .btn-link, .pipeline-dropdown > li .ci-view .ci-view--messages .test-message .btn-link { - position: relative; - color: #62738D -} - -.ci-view .ci-view--messages .test-message .icon { - margin-right: 12px -} - -.ci-view .ci-view--messages .test-warning { - color: #C74C00; - box-shadow: inset 0 0 0 1px rgba(199, 76, 0, .2); - background: rgba(199, 76, 0, .04) -} - -.ci-view .ci-view--messages .test-warning a { - color: inherit -} - -.ci-view .ci-view--messages .test-fail { - color: #DE0A0A; - box-shadow: inset 0 0 0 1px rgba(222, 10, 10, .4); - background: rgba(222, 10, 10, .04) -} - -.ci-view .ci-view--messages .test-fail .panel-section .panel-details, .ci-view .ci-view--messages .test-fail p, .panel-section .ci-view .ci-view--messages .test-fail .panel-details { - padding-bottom: 10px; - border-bottom: 1px solid rgba(222, 10, 10, .3) -} - -.ci-view .ci-view--messages .test-fail a { - color: inherit -} - -.ci-view .ci-view--messages .test-case-fail { - padding: 4px 0 18px; - margin-bottom: 10px; - border-bottom: 1px solid rgba(222, 10, 10, .3) -} - -.ci-view .ci-view--messages .test-case-fail:last-child { - padding-bottom: 0; - margin-bottom: 0; - border: none -} - -.ci-view .ci-view--messages .test-case-fail pre { - font-size: 12px; - margin: 6px 0 0 28px; - border: 1px solid rgba(222, 10, 10, .3); - background: rgba(255, 255, 255, .8) -} - -.ci-view--output .build-stream, .ci-view--output .build-stream-full { - min-height: 160px -} - -.test-run-status-message { - padding-left: 6px; - font-size: 16px -} - -.test-run-status-message.creating, .test-run-status-message.pending, .test-run-status-message.running { - color: #62738D -} - -.test-run-status-message.succeeded { - color: #008700 -} - -.test-run-status-message.errored, .test-run-status-message.failed { - color: #DE0A0A -} - -.ci-status-component { - display: inline-block -} - -.ci-status-component .btn-group { - position: static -} - -.ci-status-component .drop-down__toggle { - border: none; - width: 18px -} - -.ci-status-component .context-switcher__list, .ci-status-component .drop-down__menu { - margin-top: 5px; - right: 0 -} - -.ci-status-component .context-switcher__list li.dropdown-header, .ci-status-component .drop-down__menu li.dropdown-header { - padding: 8px 12px 6px -} - -.ci-status-component .context-switcher__list li .ci-check-summary, .ci-status-component .drop-down__menu li .ci-check-summary { - color: #62738D; - font-size: 11px; - margin: 0 !important -} - -.ci-status-component .context-switcher__list li .ci-check-summary b, .ci-status-component .drop-down__menu li .ci-check-summary b { - font-weight: 400; - font-size: 13px; - display: block -} - -.addons-provision-error .addons-provision-error__header, .assume-identity, .is-current .dyno-tier-picker-item-size-name { - font-weight: 700 -} - -.ci-status-component .context-switcher__list li .icon, .ci-status-component .drop-down__menu li .icon { - margin-left: 0 !important; - margin-right: 5px !important -} - -.ci-status-component .context-switcher__list li a, .ci-status-component .drop-down__menu li a { - font-size: 12px !important; - color: #56667D !important; - display: block !important; - text-overflow: ellipsis; - overflow: hidden -} - -.ci-status-component .context-switcher__list li a .panel-section .panel-details, .ci-status-component .context-switcher__list li a small, .ci-status-component .drop-down__menu li a .panel-section .panel-details, .ci-status-component .drop-down__menu li a small, .panel-section .ci-status-component .context-switcher__list li a .panel-details, .panel-section .ci-status-component .drop-down__menu li a .panel-details { - font-size: 11px; - color: #62738D -} - -.test-nodes--nav li { - min-width: 60px -} - -.test-nodes--nav li:last-child { - border-right: none -} - -.test-nodes--nav .btn-group { - display: flex -} - -.test-nodes--nav .btn-group .overflow-tab { - min-width: 60px -} - -.test-nodes--nav .btn-group .active { - border-left: 1px solid #e3e7ef -} - -.test-nodes--nav .context-switcher__list, .test-nodes--nav .drop-down__menu { - min-width: 100px -} - -.table-action-button { - padding: 0 22px 0 10px; - width: 38px; - text-align: center; - border: 0; - background-color: transparent; - border-radius: 3px -} - -.table-action-button:hover i { - color: #62738D -} - -.table-action-button i { - position: relative; - top: -2px -} - -.addons-provision .addons-provision__header { - text-align: center -} - -.addons-provision .addons-provision__header .item { - vertical-align: top; - display: inline-block; - text-align: center; - width: calc(46% - 22px) -} - -.addons-provision .addons-provision__header .item .description { - padding-top: 10px; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden -} - -.addons-provision .addon-details { - display: inline-block; - width: 100%; - font-size: 12px; - margin-top: 10px; - margin-bottom: 10px; - text-align: center -} - -.addons-provision .addons-provision__addon-icon-container { - height: 48px; - width: 48px; - overflow: hidden; - display: inline-block; - border-radius: 5px; - background-color: #fff -} - -.addons-provision .addons-provision__body { - padding: 20px 20px 5px -} - -.addons-provision .addons-provision__provision-errors { - font-size: 12px; - line-height: 1.5em; - padding-left: 40px; - padding-right: 10px -} - -.addons-provision .addons-provision__provision-errors li { - position: relative; - display: inline-block; - padding: 0 -} - -.addons-provision .addons-provision__provision-errors li .icon { - position: absolute; - top: -3px; - left: -31px -} - -.addons-provision .addons-provision__provision-errors li + li { - margin-top: 20px -} - -.addons-provision-error { - text-align: center -} - -.addons-provision-error img { - height: 80px; - width: 80px -} - -#modal-overlays .ember-modal-dialog.addon-provision-modal { - width: 100%; - max-width: 460px -} - -#modal-overlays .ember-modal-dialog.addon-provision-modal .modal-header { - border-bottom: none -} - -#modal-overlays .ember-modal-dialog.addon-provision-modal .modal-header .modal-title { - display: none -} - -#modal-overlays .ember-modal-dialog.addon-provision-modal .modal-body { - margin-top: -10px; - padding: 0 -} - -#modal-overlays .ember-modal-dialog.addon-provision-modal .modal-footer { - padding: 20px -} - -#modal-overlays .ember-modal-dialog.addon-provision-modal .modal-footer button { - width: 100% -} - -#modal-overlays .ember-modal-dialog.addon-provision-modal .separator { - border-bottom: 1px solid #e7ebf3 -} - -#modal-overlays .ember-modal-dialog.addon-confirm-delete-modal .modal-body { - padding: 20px 20px 5px -} - -.log-color { - color: gray -} - -.log-color--blue { - color: #437BD7 -} - -.log-color--orange { - color: #F38900 -} - -.log-color--purple { - color: #8854B3 -} - -.log-color--green { - color: #728E40 -} - -.log-color--red { - color: #C62919 -} - -.log-color--yellow { - color: #EEC800 -} - -.assume-identity { - position: fixed; - bottom: 20px; - color: #fff; - cursor: pointer; - z-index: 999; - text-transform: uppercase; - font-size: 12px; - padding: 6px 20px 7px; - border-radius: 20px; - left: 50%; - width: 220px; - margin-left: -110px; - box-shadow: 0 1px 6px rgba(0, 0, 0, .1) -} - -.switch-mode { - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex -} - -.switch-mode__toggle { - padding-right: 10px -} - -.switch__status__text { - position: relative; - top: 2px; - font-size: 11px; - text-transform: uppercase -} - -.new-org { - overflow: visible -} - -.new-org .org-owner div { - float: left -} - -.new-org .org-owner div .panel-section .panel-details, .new-org .org-owner div p, .panel-section .new-org .org-owner div .panel-details { - margin-bottom: 0 -} - -.new-org .org-owner div.owner-details { - padding-left: 20px -} - -.new-org .panel-content .btn-link { - padding: 0 25px -} - -.new-org .list-group-item { - border-bottom: none -} - -.new-org .list-group-item:last-child { - border-top: none -} - -.new-org .alert { - margin-top: 1px -} - -.btn { - outline: 0 !important -} - -@media (max-width: 767px) { - #overview-page { - display: block - } - - #overview-page .overview-activity, #overview-page .overview-content, #overview-page .overview-team { - width: 100% - } - - #overview-page .overview-content { - padding-right: 20px - } - - #overview-page .overview-activity { - padding-left: 20px; - box-shadow: inset 0 1px 0 #E3E7EF - } -} - -#overview-page .collaborator-list, #overview-page .member-list { - max-height: 312px; - margin: 0 5px; - padding: 5px 0; - border-top: 5px solid transparent; - border-bottom: 5px solid transparent -} - -#overview-page .collaborator-list::-webkit-scrollbar, #overview-page .member-list::-webkit-scrollbar { - width: 6px; - height: 6px -} - -#overview-page .collaborator-list::-webkit-scrollbar-track, #overview-page .member-list::-webkit-scrollbar-track { - border-radius: 10px; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .05); - background: rgba(0, 0, 0, .05) -} - -#overview-page .collaborator-list::-webkit-scrollbar-thumb, #overview-page .member-list::-webkit-scrollbar-thumb { - border-radius: 10px; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .05); - background: rgba(0, 0, 0, .1) -} - -#overview-page .collaborator-list::-webkit-scrollbar-button, #overview-page .member-list::-webkit-scrollbar-button { - display: block; - width: 0; - height: 0 -} - -#overview-page .collaborator-list h5, #overview-page .member-list h5 { - float: none -} - -#overview-page .collaborator, #overview-page .member { - position: relative; - -webkit-box-lines: multiple; - -moz-box-lines: multiple; - box-lines: multiple; - -webkit-flex-wrap: wrap; - -moz-flex-wrap: wrap; - -ms-flex-wrap: wrap; - flex-wrap: wrap -} - -#overview-page .collaborator .avatar, #overview-page .member .avatar { - position: relative -} - -#overview-page .collaborator .user-info, #overview-page .member .user-info { - max-width: 75%; - text-overflow: ellipsis; - overflow: hidden; - display: inline-block -} - -#overview-page .header { - padding: 0 0 14px -} - -#overview-page .header h5 { - font-size: 13px; - margin: 0 -} - -#overview-page .header h5 .icon { - margin: -2px 4px 0 -} - -#overview-page .header h5 .badge { - border-radius: 12px; - margin: -1px 5px 0; - cursor: default; - background: #62738D -} - -#overview-page .header h5 .badge.badge--light { - background: #CFD7E6 -} - -#overview-page .header .btn-link { - font-size: 12px; - margin-top: -1px -} - -#overview-page .header .btn-link .icon { - margin: -2px 0 0 1px -} - -#overview-page .header .btn-default { - margin: -4px 0 -} - -.bar-chart { - height: 100px -} - -.bar-chart__col { - max-width: 90px; - flex-basis: 0 -} - -.bar-chart__col__chart { - background: #CFD7E6; - min-height: 1px -} - -.bar-chart__col__quota { - height: 1px; - background: #CFD7E6; - bottom: 0; - margin-bottom: 20px; - width: 100%; - z-index: 5; - box-shadow: 0 0 0 1px #fff -} - -.bar-chart__col__quota--over-limit { - background: #D64242 -} - -.bar-chart__col:hover .bar-chart__col__chart { - background: #62738D -} - -.bar-chart__col:hover .bar-chart__col__chart.bar-chart__col__quota--over-limit { - background: #A70404 -} - -.context-switcher--container { - z-index: 5 -} - -.context-switcher__list { - position: absolute; - z-index: 48; - top: 36px; - left: 0; - width: 320px; - max-width: calc(100vw - 40px); - max-height: calc(100vh - 160px); - padding: 0 -} - -.limit-width, .list-group-lg { - position: relative; - width: 100%; - max-width: 1200px; - margin-left: auto !important; - margin-right: auto !important -} - -.top-nav .limit-width, .top-nav .list-group-lg { - display: flex; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center -} - -#overview-page .limit-width, #overview-page .list-group-lg { - max-width: 578px -} - -.overview-content .limit-width, .overview-content .list-group-lg { - margin-right: 0 !important -} - -.overview-activity .limit-width, .overview-activity .list-group-lg, .overview-team .limit-width, .overview-team .list-group-lg { - margin-left: 0 !important -} - -.message-banner .limit-width, .message-banner .list-group-lg { - display: flex; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center; - -webkit-align-content: space-around; - -moz-align-content: space-around; - align-content: space-around; - -ms-flex-line-pack: distribute -} - -@media (max-width: 767px) { - .overview-content .limit-width, .overview-content .list-group-lg { - max-width: 100% !important; - margin-left: 0 !important - } - - .overview-activity .limit-width, .overview-activity .list-group-lg, .overview-team .limit-width, .overview-team .list-group-lg { - max-width: 100% !important; - margin-right: 0 !important - } - - .message-banner .limit-width, .message-banner .list-group-lg { - -webkit-box-lines: multiple; - -moz-box-lines: multiple; - box-lines: multiple; - -webkit-flex-wrap: wrap; - -moz-flex-wrap: wrap; - -ms-flex-wrap: wrap; - flex-wrap: wrap - } -} - -.app-wrapper { - display: flex; - min-height: calc(100vh - 50px); - -webkit-box-orient: vertical; - -moz-box-orient: vertical; - box-orient: vertical; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: column; - -moz-flex-direction: column; - flex-direction: column; - -ms-flex-direction: column; - -webkit-box-align: stretch; - -moz-box-align: stretch; - box-align: stretch; - -webkit-align-items: stretch; - -moz-align-items: stretch; - -ms-align-items: stretch; - -o-align-items: stretch; - align-items: stretch; - -ms-flex-align: stretch -} - -.modal-buildpacks { - width: 100%; - font-size: 0; - margin: 15px 0 -} - -.modal-buildpacks a.supported-buildpack { - text-decoration: none; - display: inline-block; - text-align: center; - font-size: 14px; - line-height: 16px; - color: #62738D; - width: 19.6%; - margin-right: .5%; - margin-bottom: .5%; - padding: 7px 10px; - border-radius: 4px; - box-shadow: inset 0 0 0 1px #E3E7EF; - -webkit-transition: ease .2s; - -o-transition: ease .2s; - transition: ease .2s -} - -.modal-buildpacks a.supported-buildpack.selected, .modal-buildpacks a.supported-buildpack:hover { - color: #79589F; - background: #f8f7fa; - box-shadow: inset 0 0 0 1px #c9bcd9 -} - -.modal-buildpacks a.supported-buildpack .language-icon { - height: 40px; - padding: 5px 0; - display: block; - text-align: center -} - -.modal-buildpacks a.supported-buildpack .language-icon .icon { - display: inline-block; - vertical-align: middle -} - -@media (min-width: 480px) { - .modal-buildpacks a.supported-buildpack:nth-child(5n) { - margin-right: 0 - } -} - -@media (max-width: 480px) { - .modal-buildpacks a.supported-buildpack { - width: 33% - } - - .modal-buildpacks a.supported-buildpack:nth-child(3n) { - margin-right: 0 - } -} - - -#modal-overlays .ember-modal-dialog.formation-tier-picker { - width: 900px -} - -.dyno-size-icon { - position: relative; - width: 38px; - height: 40px -} - -.dyno-size-options button { - display: flex; - align-items: center; - font-weight: 400; - padding: 5px -} - -.cmn-toggle:hover, .context-switcher__list label, .drop-down__menu label, .ember-power-select-clear-btn, .ember-power-select-multiple-remove-btn, .ember-power-select-option, .nps-modal-content label, range-slider { - cursor: pointer -} - -.dyno-size-option.disabled:active .dyno-size-option__description, .dyno-size-option.disabled:active .dyno-size-option__title, .dyno-size-option.disabled:focus .dyno-size-option__description, .dyno-size-option.disabled:focus .dyno-size-option__title, .dyno-size-option.disabled:hover .dyno-size-option__description, .dyno-size-option.disabled:hover .dyno-size-option__title { - color: #62738D -} - -.dyno-size-option__note { - color: #006DEB; - white-space: normal -} - -.dyno-size-option__content { - padding: 0 12px; - -webkit-box-flex: 1; - -moz-box-flex: 1; - box-flex: 1; - -webkit-flex: 1; - -moz-flex: 1; - -ms-flex: 1; - flex: 1 -} - -.toggle-switch { - display: flex -} - -input[type=checkbox].cmn-toggle { - opacity: 0; - z-index: 9; - width: 60px; - height: 30px; - margin: 0 -} - -.cmn-toggle + label { - display: block; - position: relative; - outline: 0; - user-select: none; - font-size: 12px; - margin-bottom: 0; - margin-left: -60px -} - -.disabled .cmn-toggle:hover { - cursor: default -} - -input.cmn-toggle-round-flat + label { - padding: 2px; - width: 60px; - height: 30px; - background-color: #fff; - border: 1px solid #006DEB; - border-radius: 30px; - -webkit-transition: background .4s; - transition: background .4s -} - -.disabled input.cmn-toggle-round-flat + label { - border: 1px solid #CFD7E6 -} - -input.cmn-toggle-round-flat + label:after, input.cmn-toggle-round-flat + label:before { - display: block; - position: absolute; - content: "" -} - -input.cmn-toggle-round-flat:focus + label { - outline: 0; - border-color: #408fec; - box-shadow: 0 0 0 2px rgba(142, 189, 241, .4) -} - -input.cmn-toggle-round-flat + label:before { - top: 6px; - left: 8px; - border-radius: 30px; - -webkit-transition: background .4s; - transition: background .4s; - content: ""; - color: #fff -} - -input.cmn-toggle-round-flat + label:after { - top: -1px; - left: -1px; - bottom: -1px; - width: 30px; - background-color: #fff; - border: 1px solid #006DEB; - border-radius: 30px; - -webkit-transition: margin .3s, background .3s; - transition: margin .3s, background .3s -} - -.disabled input.cmn-toggle-round-flat + label:after { - border: 1px solid #CFD7E6 -} - -input.cmn-toggle-round-flat + label .off-label { - position: absolute; - right: 8px; - top: 6px; - color: #62738D -} - -.disabled input.cmn-toggle-round-flat + label .off-label { - color: #62738D -} - -input.cmn-toggle-round-flat:checked + label { - background-color: #006DEB; - border: 1px solid #0055b8 -} - -.disabled input.cmn-toggle-round-flat:checked + label { - background-color: #CFD7E6; - border: 1px solid #adbbd5 -} - -input.cmn-toggle-round-flat:checked + label:after { - margin-left: 30px; - background-color: #fff; - border: 1px solid #006DEB -} - -.disabled input.cmn-toggle-round-flat:checked + label:after { - border: 1px solid #adbbd5 -} - -.build-stream { - margin: 11px 0 4px; - background-color: #F7F8FB; - border: 1px solid #E3E7EF; - border-radius: 4px -} - -.build-stream.build-stream-expanded .build-stream-output { - height: 460px -} - -.build-stream .build-stream-output { - position: relative; - height: 160px; - margin: 0 5px 0 9px; - padding: 9px 5px 9px 0; - overflow: auto; - -webkit-transition: height ease .3s; - -o-transition: height ease .3s; - transition: height ease .3s -} - -.build-stream .build-stream-output::-webkit-scrollbar { - width: 7px; - height: 7px -} - -.build-stream .build-stream-output::-webkit-scrollbar-track { - border-radius: 10px; - box-shadow: inset 0 0 0 1px rgba(207, 215, 230, .2); - background: rgba(207, 215, 230, .2) -} - -.build-stream .build-stream-output::-webkit-scrollbar-thumb { - border-radius: 10px; - box-shadow: inset 0 0 0 1px rgba(98, 115, 141, .3); - background: rgba(98, 115, 141, .4) -} - -.build-stream .build-stream-output::-webkit-scrollbar-button { - display: block; - width: 2px; - height: 2px -} - -.build-stream .build-stream-output .loading-spinner { - position: absolute; - top: 50%; - left: 50%; - margin-left: -15px -} - -.build-stream .build-stream-output .build-stream-line { - margin: 0; - padding: 0; - background: 0 0; - border: none; - border-radius: 0; - color: #323B49; - font-size: 11px; - line-height: 18px -} - -.build-stream .build-stream-footer { - height: 30px; - padding: 6px 10px; - overflow: hidden; - font-size: 12px; - border-top: 1px solid #E3E7EF; - background-color: #fff; - border-bottom-left-radius: 4px; - border-bottom-right-radius: 4px -} - -.build-stream .build-stream-footer label { - float: left; - margin-bottom: 0 -} - -.build-stream .build-stream-footer label input { - margin-top: 2px; - margin-right: 3px -} - -.build-stream .build-stream-footer a { - float: right; - margin-left: 10px -} - -.build-stream .build-stream-footer .btn-link.expand-output { - font-size: 12px; - color: #62738D -} - -.build-stream .build-stream-footer .btn-link.expand-output .icon { - left: 0; - margin-top: -2px; - margin-left: 0 -} - -.build-stream-full { - position: relative; - margin-top: 0; - height: calc(100% - 80px) -} - -.build-stream-full .build-stream-output { - height: calc(100% - 32px) -} - -.build-stream-full .build-stream-output .build-stream-line { - font-size: 12px -} - -.build-stream-full .build-stream-footer { - position: absolute; - bottom: 0; - left: 0; - right: 0 -} - -.deploy-steps { - margin-top: 15px -} - -.deploy-steps > li > .icon, .deploy-steps > li > .loading-spinner, .deploy-steps > li > i, .deploy-steps > li > img { - float: right -} - -.deploy-steps > li > .loading-spinner { - margin: 7px 0 6px -} - -.deploy-steps > li a, .deploy-steps > li button, .deploy-steps > li span { - -webkit-transition-duration: .4s; - transition-duration: .4s; - -webkit-transition-property: opacity, color; - transition-property: opacity, color; - -webkit-transition-timing-function: ease-out; - transition-timing-function: ease-out -} - -.deploy-steps > li span { - color: #62738D; - float: left; - padding-bottom: 1px -} - -.deploy-steps > li span.dots, .deploy-steps > li span.loading-spinner { - float: none -} - -.deploy-steps > li .toggle-output { - margin-left: 8px; - padding: 0; - font-size: 13px; - border: none -} - -#overview-page .addons-grid .addon .panel-section .panel-details a, #overview-page .addons-grid .addon p a, #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper, .account-quota-usage table tbody a, .btn-link, .btn-link:hover, .context-switcher__list .btn-link, .deploy-steps > li.stage-done span, .deploy-steps > li.stage-failed span, .drop-down__menu .btn-link, .drop-down__toggle a, .page-breadcrumb a, .panel-section #overview-page .addons-grid .addon .panel-details a { - text-decoration: none -} - -.deploy-steps > li .build-stream { - float: left; - width: 100% -} - -.deploy-steps > li .deploy-message { - clear: both; - font-size: 13px; - font-weight: 400; - margin: 0; - color: #62738D; - padding-top: 2px; - padding-right: 20px -} - -.deploy-steps > li .deploy-message:first-letter { - text-transform: uppercase -} - -.deploy-steps > li .deployed-message { - text-align: center; - clear: both; - width: 100%; - padding-top: 10px -} - -.deploy-steps > li .deployed-message strong { - font-size: 14px; - color: #62738D; - display: block; - text-align: center; - padding-bottom: 10px -} - -.deploy-steps > li .deployed-message .btn { - margin: 0 4px; - width: auto -} - -.deploy-steps > li.stage-current span { - color: #3F3F44 -} - -.deploy-steps > li.stage-failed a, .deploy-steps > li.stage-failed button, .deploy-steps > li.stage-failed span { - color: #DE0A0A -} - -.deploy-steps > li.stage-done a, .deploy-steps > li.stage-done button, .deploy-steps > li.stage-done span { - color: #62738D -} - -.deploy-steps > li.success span { - color: #008700 -} - -.enterprise-no-account-banner { - box-shadow: 0 8px 16px -8px rgba(0, 0, 0, .3), 0 13px 27px -5px rgba(50, 59, 73, .25); - transition: box-shadow .3s ease-in-out 0s -} - -.nav.nav-tabs.sub-nav .sub-nav-item { - display: inline-block; - margin-left: 4px; - margin-right: 4px; - transform: translateX(-10px) -} - -@media (max-width: 767px) { - .nav.nav-tabs.sub-nav .sub-nav-item { - margin-left: 8px; - margin-right: 8px - } -} - -.nav.nav-tabs.sub-nav .sub-nav-item:first-child { - margin-left: 0 -} - -.nav.nav-tabs.sub-nav .sub-nav-item:last-child { - margin-right: 0 -} - -.nav.nav-tabs.sub-nav .sub-nav-item a { - padding-bottom: 15px -} - -.protected-team-space-apps .nav.nav-tabs.sub-nav, .protected-team-space-apps_loading .nav.nav-tabs.sub-nav, .protected-team-switchable-apps .nav.nav-tabs.sub-nav, .protected-team-switchable-apps_loading .nav.nav-tabs.sub-nav { - margin-bottom: 0 -} - -.ember-modal-dialog { - z-index: 51; - position: fixed; - border-radius: 8px; - background-color: #fff; - box-shadow: 0 0 10px #222; - padding: 10px -} - -.ember-modal-dialog.emd-in-place { - position: static -} - -.ember-modal-wrapper.emd-static.emd-wrapper-target-attachment-center .ember-modal-dialog { - top: 50%; - left: 50%; - transform: translate(-50%, -50%) -} - -.ember-modal-wrapper.emd-animatable.emd-wrapper-target-attachment-center { - width: 100vw; - height: 100vh; - position: fixed; - top: 0; - left: 0; - z-index: 50; - display: flex; - align-items: center; - justify-content: center -} - -.ember-modal-wrapper.emd-animatable.emd-wrapper-target-attachment-center .ember-modal-overlay { - display: flex; - align-items: center; - justify-content: center -} - -.ember-modal-wrapper.emd-animatable .ember-modal-dialog { - position: relative -} - -.ember-modal-overlay { - width: 100vw; - height: 100vh; - position: fixed; - top: 0; - left: 0; - z-index: 50 -} - -.ember-modal-overlay.translucent { - background-color: rgba(128, 128, 128, .77) -} - -@-webkit-keyframes fadeIn { - 0% { - opacity: 0 - } - 100% { - opacity: 1 - } -} - -@-moz-keyframes fadeIn { - 0% { - opacity: 0 - } - 100% { - opacity: 1 - } -} - -@-o-keyframes fadeIn { - 0% { - opacity: 0 - } - 100% { - opacity: 1 - } -} - -@keyframes fadeIn { - 0% { - opacity: 0 - } - 100% { - opacity: 1 - } -} - -@-webkit-keyframes fadeOut { - 0% { - opacity: 1 - } - 100% { - opacity: 0 - } -} - -@-moz-keyframes fadeOut { - 0% { - opacity: 1 - } - 100% { - opacity: 0 - } -} - -@-o-keyframes fadeOut { - 0% { - opacity: 1 - } - 100% { - opacity: 0 - } -} - -@keyframes fadeOut { - 0% { - opacity: 1 - } - 100% { - opacity: 0 - } -} - -@-webkit-keyframes zoomIn { - 0% { - -webkit-transform: scale(1.1); - -moz-transform: scale(1.1); - -ms-transform: scale(1.1); - -o-transform: scale(1.1); - transform: scale(1.1); - opacity: 0 - } - 100% { - -webkit-transform: scale(1); - -moz-transform: scale(1); - -ms-transform: scale(1); - -o-transform: scale(1); - transform: scale(1); - opacity: 1 - } -} - -@-moz-keyframes zoomIn { - 0% { - -webkit-transform: scale(1.1); - -moz-transform: scale(1.1); - -ms-transform: scale(1.1); - -o-transform: scale(1.1); - transform: scale(1.1); - opacity: 0 - } - 100% { - -webkit-transform: scale(1); - -moz-transform: scale(1); - -ms-transform: scale(1); - -o-transform: scale(1); - transform: scale(1); - opacity: 1 - } -} - -@-o-keyframes zoomIn { - 0% { - -webkit-transform: scale(1.1); - -moz-transform: scale(1.1); - -ms-transform: scale(1.1); - -o-transform: scale(1.1); - transform: scale(1.1); - opacity: 0 - } - 100% { - -webkit-transform: scale(1); - -moz-transform: scale(1); - -ms-transform: scale(1); - -o-transform: scale(1); - transform: scale(1); - opacity: 1 - } -} - -@keyframes zoomIn { - 0% { - -webkit-transform: scale(1.1); - -moz-transform: scale(1.1); - -ms-transform: scale(1.1); - -o-transform: scale(1.1); - transform: scale(1.1); - opacity: 0 - } - 100% { - -webkit-transform: scale(1); - -moz-transform: scale(1); - -ms-transform: scale(1); - -o-transform: scale(1); - transform: scale(1); - opacity: 1 - } -} - -@-webkit-keyframes zoomOut { - 0% { - -webkit-transform: scale(1); - -moz-transform: scale(1); - -ms-transform: scale(1); - -o-transform: scale(1); - transform: scale(1); - opacity: 1 - } - 100% { - -webkit-transform: scale(1.1); - -moz-transform: scale(1.1); - -ms-transform: scale(1.1); - -o-transform: scale(1.1); - transform: scale(1.1); - opacity: 0 - } -} - -@-moz-keyframes zoomOut { - 0% { - -webkit-transform: scale(1); - -moz-transform: scale(1); - -ms-transform: scale(1); - -o-transform: scale(1); - transform: scale(1); - opacity: 1 - } - 100% { - -webkit-transform: scale(1.1); - -moz-transform: scale(1.1); - -ms-transform: scale(1.1); - -o-transform: scale(1.1); - transform: scale(1.1); - opacity: 0 - } -} - -@-o-keyframes zoomOut { - 0% { - -webkit-transform: scale(1); - -moz-transform: scale(1); - -ms-transform: scale(1); - -o-transform: scale(1); - transform: scale(1); - opacity: 1 - } - 100% { - -webkit-transform: scale(1.1); - -moz-transform: scale(1.1); - -ms-transform: scale(1.1); - -o-transform: scale(1.1); - transform: scale(1.1); - opacity: 0 - } -} - -@keyframes zoomOut { - 0% { - -webkit-transform: scale(1); - -moz-transform: scale(1); - -ms-transform: scale(1); - -o-transform: scale(1); - transform: scale(1); - opacity: 1 - } - 100% { - -webkit-transform: scale(1.1); - -moz-transform: scale(1.1); - -ms-transform: scale(1.1); - -o-transform: scale(1.1); - transform: scale(1.1); - opacity: 0 - } -} - -#modal-overlays .modal-backdrop { - z-index: 50; - background: rgba(89, 105, 129, .6); - -webkit-animation: fadeIn .2s ease-out; - -moz-animation: fadeIn .2s ease-out; - -o-animation: fadeIn .2s ease-out; - animation: fadeIn .2s ease-out -} - -#modal-overlays .modal-backdrop.is-closing { - -webkit-animation: fadeOut .1s ease-out; - -moz-animation: fadeOut .1s ease-out; - -o-animation: fadeOut .1s ease-out; - animation: fadeOut .1s ease-out -} - -#modal-overlays .ember-modal-overlay { - position: fixed; - overflow-x: hidden; - overflow-y: auto; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: 0 0; - z-index: 51; - padding: 0 5px; - -webkit-overflow-scrolling: touch; - -webkit-animation: fadeIn .2s ease-out; - -moz-animation: fadeIn .2s ease-out; - -o-animation: fadeIn .2s ease-out; - animation: fadeIn .2s ease-out -} - -#modal-overlays .ember-modal-overlay.is-closing { - -webkit-animation: fadeOut .1s ease-out; - -moz-animation: fadeOut .1s ease-out; - -o-animation: fadeOut .1s ease-out; - animation: fadeOut .1s ease-out -} - -#modal-overlays .ember-modal-dialog { - position: relative; - margin: 40px auto; - max-width: 100%; - width: 600px; - padding: 0; - z-index: 51; - -webkit-animation: zoomIn .2s ease-out; - -moz-animation: zoomIn .2s ease-out; - -o-animation: zoomIn .2s ease-out; - animation: zoomIn .2s ease-out; - border-radius: 6px; - box-shadow: 0 0 0 1px rgba(0, 0, 0, .1), 0 3px 20px 0 rgba(0, 0, 0, .3), 0 1px 2px 0 rgba(0, 0, 0, .1); - background: #fff -} - -@media (max-width: 767px) { - #modal-overlays .ember-modal-dialog { - margin: 10px auto - } -} - -#modal-overlays .ember-modal-dialog.is-closing { - -webkit-animation: zoomOut .1s ease-out; - -moz-animation: zoomOut .1s ease-out; - -o-animation: zoomOut .1s ease-out; - animation: zoomOut .1s ease-out -} - -#modal-overlays .ember-modal-dialog.is-expanded { - width: 80% -} - -#modal-overlays .ember-modal-dialog.is-fullscreen { - width: 100% -} - -#modal-overlays .ember-modal-dialog .modal-box { - position: relative; - display: flex; - flex-direction: column; - align-items: stretch; - max-height: 100%; - -webkit-transition: width ease .3s; - -o-transition: width ease .3s; - transition: width ease .3s -} - -#modal-overlays .ember-modal-dialog .modal-box .modal-content { - background: 0 0 -} - -#modal-overlays .ember-modal-dialog .modal-box .modal-footer.custom-footer { - margin: 15px -15px -15px -} - -#modal-overlays .ember-modal-dialog .modal-box .modal-footer .btn-link { - margin-right: 14px -} - -#modal-overlays .ember-modal-dialog .modal-box .modal-footer .btn + .btn { - margin-left: 10px -} - -body.modal-is-open { - overflow: hidden -} - -#modal-overlays .ember-modal-dialog.purple-list-modal .modal-box, .drop-down { - overflow: visible -} - -@media only screen and (max-device-width: 812px) { - .ember-modal-dialog { - margin-bottom: 124px !important - } -} - -.crumb-trail--context-switcher-toggle { - padding: 1px 2px; - line-height: 1; - height: auto; - position: relative; - margin: 0 -} - -.postgres-config .hk-button--secondary { - margin-left: auto -} - -.drop-down { - position: relative -} - -.context-switcher__list, .drop-down__menu { - display: block -} - -.context-switcher__list .btn-link, .drop-down__menu .btn-link { - display: block; - text-align: left; - min-width: 100%; - white-space: nowrap; - padding: 4px 12px 3px; - color: #56667D; - border: none -} - -.context-switcher__list .btn-link .icon, .drop-down__menu .btn-link .icon { - position: relative; - margin: -2px 4px 0 2px -} - -.context-switcher__list .btn-link:hover, .drop-down__menu .btn-link:hover { - color: #475366; - background-color: #f7f8fb -} - -.context-switcher__list .btn-link:disabled, .drop-down__menu .btn-link:disabled { - color: #62738D; - pointer-events: none -} - -.drop-down__toggle li { - list-style: none -} - -table.purple-list .action-cell { - width: 108px; - text-align: right -} - -@-webkit-keyframes fadeIt { - 0% { - background-color: #fef1e3 - } - 100% { - background-color: #fff - } -} - -@-moz-keyframes fadeIt { - 0% { - background-color: #fef1e3 - } - 100% { - background-color: #fff - } -} - -@-o-keyframes fadeIt { - 0% { - background-color: #fef1e3 - } - 100% { - background-color: #fff - } -} - -@keyframes fadeIt { - 0% { - background-color: #fef1e3 - } - 100% { - background-color: #fff - } -} - -table.purple-list .new-list-item { - -webkit-animation: fadeIt 1.5s ease-in; - -moz-animation: fadeIt 1.5s ease-in; - -o-animation: fadeIt 1.5s ease-in; - animation: fadeIt 1.5s ease-in -} - -#modal-overlays .ember-modal-dialog.purple-list-modal .panel-section, #modal-overlays .ember-modal-dialog.purple-list-modal .row { - padding: 0 10px -} - -#modal-overlays .ember-modal-dialog.purple-list-modal .col-sm-12 { - padding-left: 5px; - padding-right: 5px; - padding-bottom: 18px -} - -#modal-overlays .ember-modal-dialog.purple-list-modal .btn-primary, #modal-overlays .ember-modal-dialog.purple-list-modal .hk-button--primary, #modal-overlays .ember-modal-dialog.purple-list-modal .twitter-typeahead { - width: 100% -} - -.buildpack-installations-list input, .domain-item input { - background-color: #fff !important; - border: 0; - box-shadow: none; - padding-left: 0; - text-overflow: ellipsis -} - -.buildpack-installations-list input:active, .buildpack-installations-list input:focus, .domain-item input:active, .domain-item input:focus { - border: 0 !important; - box-shadow: none !important -} - -.buildpack-installations-list .buildpacks-list-table tr th, .buildpack-installations-list .domains-list-table tr th, .domain-item .buildpacks-list-table tr th, .domain-item .domains-list-table tr th { - padding-left: 0 -} - -.buildpack-installations-list .buildpacks-list-table tr td, .buildpack-installations-list .domains-list-table tr td, .domain-item .buildpacks-list-table tr td, .domain-item .domains-list-table tr td { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - padding-left: 0 -} - -.buildpack-installations-list .domains-list-table__content-column, .domain-item .domains-list-table__content-column { - width: 45% -} - -.config-vars-list .config-var-add { - width: 85px -} - -.config-vars-list .config-var-add button { - width: 100% -} - -.config-vars-list .config-var-value { - white-space: pre -} - -.formations-list-item { - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - box-orient: vertical; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -moz-flex-direction: column; - flex-direction: column; - -ms-flex-direction: column; - padding: 10px 12px; - background-color: transparent -} - -@media (min-width: 36rem) { - .formations-list-item { - -webkit-box-orient: horizontal; - -moz-box-orient: horizontal; - box-orient: horizontal; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: row; - -moz-flex-direction: row; - flex-direction: row; - -ms-flex-direction: row; - -webkit-box-lines: multiple; - -moz-box-lines: multiple; - box-lines: multiple; - -webkit-flex-wrap: wrap; - -moz-flex-wrap: wrap; - -ms-flex-wrap: wrap; - flex-wrap: wrap - } -} - -.formations-list-item:last-child { - border-bottom: none !important -} - -.formations-list-item .value--dirty { - color: #006DEB -} - -.formations-list-item .value--original { - text-decoration: line-through; - color: #62738D -} - -.formations-list-item .suffix { - color: #62738D -} - -@media (min-width: 24rem) { - .formations-list-item .input--scale { - max-width: 80px - } -} - -.formations-list-item .process { - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: horizontal; - -moz-box-orient: horizontal; - box-orient: horizontal; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: row; - -moz-flex-direction: row; - flex-direction: row; - -ms-flex-direction: row; - -webkit-box-lines: single; - -moz-box-lines: single; - box-lines: single; - -webkit-flex-wrap: nowrap; - -moz-flex-wrap: nowrap; - -ms-flex-wrap: nowrap; - flex-wrap: nowrap; - -webkit-flex-grow: 1; - -moz-flex-grow: 1; - flex-grow: 1; - -ms-flex-positive: 1; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center; - -webkit-box-ordinal-group: 1; - -moz-box-ordinal-group: 1; - box-ordinal-group: 1; - -webkit-order: 1; - -moz-order: 1; - order: 1; - -ms-flex-order: 1; - white-space: nowrap; - text-overflow: ellipsis; - min-width: 0 -} - -@media (min-width: 36rem) { - .formations-list-item .process { - -webkit-flex-basis: 0; - -moz-flex-basis: 0; - flex-basis: 0; - -ms-flex-preferred-size: 0 - } -} - -.formations-list-item .icon--process { - width: 68px; - -webkit-flex-basis: 68px; - -moz-flex-basis: 68px; - flex-basis: 68px; - -ms-flex-preferred-size: 68px; - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0 -} - -.formations-list-item .icon--process button { - padding: 0 -} - -.formations-list-item .process-details { - white-space: nowrap; - text-overflow: ellipsis; - min-width: 0; - -webkit-flex-grow: 1; - -moz-flex-grow: 1; - flex-grow: 1; - -ms-flex-positive: 1 -} - -@media (min-width: 36rem) { - .formations-list-item .process-details { - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-lines: single; - -moz-box-lines: single; - box-lines: single; - -webkit-flex-wrap: nowrap; - -moz-flex-wrap: nowrap; - -ms-flex-wrap: nowrap; - flex-wrap: nowrap; - -webkit-box-orient: horizontal; - -moz-box-orient: horizontal; - box-orient: horizontal; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: row; - -moz-flex-direction: row; - flex-direction: row; - -ms-flex-direction: row; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center - } -} - -.formations-list-item .process-description { - -webkit-flex-grow: 1; - -moz-flex-grow: 1; - flex-grow: 1; - -ms-flex-positive: 1; - white-space: nowrap; - text-overflow: ellipsis; - min-width: 0; - overflow: hidden; - margin: 0 0 3px -} - -.formations-list-item .command, .formations-list-item .name { - -webkit-flex-basis: 0; - -moz-flex-basis: 0; - flex-basis: 0; - -ms-flex-preferred-size: 0; - white-space: nowrap; - text-overflow: ellipsis; - min-width: 0; - overflow: hidden -} - -.formations-list-item .command { - padding: 0; - background: 0 0; - box-shadow: none; - color: #62738D; - font-size: 13px -} - -.formations-list-item .process-usage { - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0; - color: #56667D; - font-size: 13px -} - -.formations-list-item .process-usage.process--off, .formations-list-item .process-usage.process--off .suffix { - color: #CFD7E6 -} - -@media (min-width: 36rem) { - .formations-list-item .process-description { - margin: 0 20px 0 0 - } - - .formations-list-item .process-usage { - -webkit-box-orient: vertical; - -moz-box-orient: vertical; - box-orient: vertical; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: column; - -moz-flex-direction: column; - flex-direction: column; - -ms-flex-direction: column; - -webkit-flex-basis: 120px; - -moz-flex-basis: 120px; - flex-basis: 120px; - -ms-flex-preferred-size: 120px; - margin-left: auto - } -} - -.formations-list-item .actions, .formations-list-item .actions__edit { - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center -} - -.formations-list-item .actions__edit svg { - width: 12px; - height: 12px -} - -.formations-list-item .actions__edit svg path { - fill: #79589F -} - -.formations-list-item .process-actions { - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center; - -webkit-box-ordinal-group: 2; - -moz-box-ordinal-group: 2; - box-ordinal-group: 2; - -webkit-order: 2; - -moz-order: 2; - order: 2; - -ms-flex-order: 2; - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0; - margin-left: 20px -} - -@media (max-width: 36rem) { - .formations-list-item .process-actions { - -webkit-align-self: flex-start; - -moz-align-self: flex-start; - align-self: flex-start; - -ms-flex-item-align: start; - -webkit-flex-basis: 100%; - -moz-flex-basis: 100%; - flex-basis: 100%; - -ms-flex-preferred-size: 100%; - -webkit-box-flex: 1; - -moz-box-flex: 1; - box-flex: 1; - -webkit-flex: 1 100%; - -moz-flex: 1 100%; - -ms-flex: 1 100%; - flex: 1 100%; - -webkit-box-ordinal-group: 3; - -moz-box-ordinal-group: 3; - box-ordinal-group: 3; - -webkit-order: 3; - -moz-order: 3; - order: 3; - -ms-flex-order: 3; - margin: 10px 0 0 - } - - .formations-list-item .process-actions .btn { - -webkit-flex-grow: 1; - -moz-flex-grow: 1; - flex-grow: 1; - -ms-flex-positive: 1 - } -} - -.formations-list-item .editor { - -webkit-box-flex: 1; - -moz-box-flex: 1; - box-flex: 1; - -webkit-flex: 1 100%; - -moz-flex: 1 100%; - -ms-flex: 1 100%; - flex: 1 100%; - -webkit-box-ordinal-group: 2; - -moz-box-ordinal-group: 2; - box-ordinal-group: 2; - -webkit-order: 2; - -moz-order: 2; - order: 2; - -ms-flex-order: 2 -} - -.formations-list-item .editor-row { - -webkit-box-lines: multiple; - -moz-box-lines: multiple; - box-lines: multiple; - -webkit-flex-wrap: wrap; - -moz-flex-wrap: wrap; - -ms-flex-wrap: wrap; - flex-wrap: wrap -} - -.formations-list-item .editor-item { - -webkit-box-lines: multiple; - -moz-box-lines: multiple; - box-lines: multiple; - -webkit-flex-wrap: wrap; - -moz-flex-wrap: wrap; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - color: #56667D -} - -.formations-list-item .editor-item-label { - min-width: 200px; - max-width: 200px -} - -.formations-list-item .editor-item .description, .formations-list-item .editor-item .unit { - font-size: 13px; - color: #62738D -} - -.formations-list-item .editor .input-group { - max-width: 140px -} - -.formations-list-item .editor .input-group-addon { - background: #fff -} - -.formations-list-item .editor .label--budget { - font-size: 13px; - color: #62738D; - margin: 4px 0 0 -} - -.formations-list-item .editor .label--budget.dirty { - color: #006DEB -} - -.formations-list-item .dyno-size-options .drop-down__toggle, .formations-list-item .dyno-size-options .dropdown-toggle { - border: 0; - background-color: transparent; - box-shadow: none; - padding: 0; - text-align: left; - min-height: 48px; - min-width: 66px -} - -.formations-list-item.use-toggle { - -webkit-box-orient: horizontal; - -moz-box-orient: horizontal; - box-orient: horizontal; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: row; - -moz-flex-direction: row; - flex-direction: row; - -ms-flex-direction: row; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center; - -webkit-box-lines: multiple; - -moz-box-lines: multiple; - box-lines: multiple; - -webkit-flex-wrap: wrap; - -moz-flex-wrap: wrap; - -ms-flex-wrap: wrap; - flex-wrap: wrap -} - -@media (max-width: 24rem) { - .formations-list-item range-slider { - display: none - } - - .formations-list-item.use-toggle { - -webkit-box-orient: vertical; - -moz-box-orient: vertical; - box-orient: vertical; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: column; - -moz-flex-direction: column; - flex-direction: column; - -ms-flex-direction: column; - white-space: nowrap; - text-overflow: ellipsis; - min-width: 0; - overflow: hidden - } - - .formations-list-item.use-toggle .process { - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -moz-box-orient: vertical; - box-orient: vertical; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: column; - -moz-flex-direction: column; - flex-direction: column; - -ms-flex-direction: column; - -webkit-box-align: start; - -moz-box-align: start; - box-align: start; - -webkit-align-items: flex-start; - -moz-align-items: flex-start; - -ms-align-items: flex-start; - -o-align-items: flex-start; - align-items: flex-start; - -ms-flex-align: start; - white-space: nowrap; - text-overflow: ellipsis; - min-width: 0; - overflow: hidden; - width: 100% - } - - .formations-list-item.use-toggle .process-details { - margin-bottom: 12px - } -} - -.formations-list-item.use-toggle .process { - -webkit-flex-grow: 1; - -moz-flex-grow: 1; - flex-grow: 1; - -ms-flex-positive: 1 -} - -.formations-list-item.use-toggle .process-details { - display: inline-block; - white-space: nowrap; - text-overflow: ellipsis; - min-width: 0; - overflow: hidden -} - -.formations-list-item.use-toggle .command { - white-space: nowrap; - text-overflow: ellipsis; - min-width: 0 -} - -.formations-list-item.use-toggle .usage { - -webkit-flex-basis: 0; - -moz-flex-basis: 0; - flex-basis: 0; - -ms-flex-preferred-size: 0; - padding: 0 -} - -.formations-list-item.use-toggle .actions { - -webkit-box-ordinal-group: 3; - -moz-box-ordinal-group: 3; - box-ordinal-group: 3; - -webkit-order: 3; - -moz-order: 3; - order: 3; - -ms-flex-order: 3 -} - -.formation-range-slider { - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center -} - -.formation-range-slider range-slider { - -webkit-flex-grow: 1; - -moz-flex-grow: 1; - flex-grow: 1; - -ms-flex-positive: 1; - -webkit-box-align: center; - -moz-box-align: center; - box-align: center; - -webkit-align-items: center; - -moz-align-items: center; - -ms-align-items: center; - -o-align-items: center; - align-items: center; - -ms-flex-align: center -} - -.buildpack-installations-list .sortable-item.is-dragging { - position: relative; - left: -4px; - z-index: 100; - cursor: move; - opacity: .6 -} - -.buildpack-installations-list .handle { - cursor: move; - transition: fill 120ms ease -} - -.buildpack-installations-list .handle:hover { - fill: #006DEB -} - -#overview-page .app-overview-stream .header { - padding-bottom: 4px -} - -#overview-page .event, #overview-page .formation { - display: block; - padding: 15px 0; - border-bottom: 1px solid #E3E7EF -} - -#overview-page .event:last-child, #overview-page .formation:last-child { - border-bottom: none -} - -#overview-page .formation-tier { - display: flex; - padding: 6px 15px; - font-size: 13px; - color: #62738D; - box-shadow: inset 0 -1px 0 #E3E7EF; - -webkit-box-lines: multiple; - -moz-box-lines: multiple; - box-lines: multiple; - -webkit-flex-wrap: wrap; - -moz-flex-wrap: wrap; - -ms-flex-wrap: wrap; - flex-wrap: wrap -} - -#overview-page .formation-tier .panel-section .panel-details, #overview-page .formation-tier p, .panel-section #overview-page .formation-tier .panel-details { - margin: 0; - padding: 6px 0 -} - -#overview-page .formation-tier .quota-badge { - float: none; - margin: 3px -10px 3px auto -} - -#overview-page .formation-tier .quota-badge__chart .panel-section .panel-details, #overview-page .formation-tier .quota-badge__chart p, .panel-section #overview-page .formation-tier .quota-badge__chart .panel-details { - margin: 0; - padding: 0 -} - -#overview-page .formation-tier .quota-badge__chart .panel-section .panel-details b, #overview-page .formation-tier .quota-badge__chart p b, .panel-section #overview-page .formation-tier .quota-badge__chart .panel-details b { - text-transform: none -} - -#overview-page .collaborator-list { - overflow: auto -} - -#overview-page .collaborator:nth-child(1) .avatar::after { - content: ''; - background: url(data:image/png; base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAQCAYAAAAS7Y8mAAAAAXNSR0IArs4c6QAAAP1JREFUOBHFUUEKwkAMbFU8eOkn+pL2VOqDhD7D9wj6DA89FfUHIkKpM2VT05SlKygGhmQnk2m6G0X/jK7rCqBxKL62izNE6qMJMV5QBPncRg9lpuue9s6jwd+UmGyERg60Drn6iBhP5ldOFCvxWtVSdij6v0NmbUPPvL2wSQbUgESlJ0EepMHa9CrVo0em+7znUglY7ihA3hqex9L1dqbX89Y4NSIerwDv1ga5iyVxTsV0uA+QS5B3QN+X6ELyE6JNHMctxfIgkSPqEAePphbTkbETnz1DIfRodtj418bHkNU8Gv8sHxA4AZ8GZ/j4/oAgAfbADZgLaqhNrOMLYYKjk9arOOYAAAAASUVORK5CYII=) center center no-repeat #E4C991; - background-size: 10px 8px; - width: 12px; - height: 12px; - border-radius: 50%; - position: absolute; - top: -4px; - right: -4px; - box-shadow: 0 0 0 2px #fff -} - -#overview-page .collaborator .stat { - color: #62738D; - text-align: right; - line-height: 12px; - padding-top: 4px -} - -#overview-page .collaborator .stat b { - font-weight: 400; - color: #56667D -} - -#overview-page .collaborator .stat .icon { - position: relative; - top: -2px; - margin-right: 2px -} - -#overview-page .app-overview-metrics { - min-height: 230px -} - -#overview-page .app-overview-metrics .metrics__summary-container { - min-height: 190px -} - -#overview-page .app-overview-metrics .metrics__chart__wrapper { - padding: 0 -} - -#overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper { - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-grow: 1; - -moz-flex-grow: 1; - flex-grow: 1; - -ms-flex-positive: 1; - -webkit-box-orient: vertical; - -moz-box-orient: vertical; - box-orient: vertical; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: column; - -moz-flex-direction: column; - flex-direction: column; - -ms-flex-direction: column; - background: #fff; - border-radius: 4px; - padding-bottom: 0; - margin-bottom: 32px; - overflow: hidden -} - -@media (max-width: 767px) { - #overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper { - -webkit-box-lines: multiple; - -moz-box-lines: multiple; - box-lines: multiple; - -webkit-flex-wrap: wrap; - -moz-flex-wrap: wrap; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - -webkit-box-orient: horizontal; - -moz-box-orient: horizontal; - box-orient: horizontal; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: row; - -moz-flex-direction: row; - flex-direction: row; - -ms-flex-direction: row - } -} - -#overview-page .app-overview-metrics .metrics__summary-row__item { - margin-bottom: 0; - padding: 10px 0 0 10px; - -webkit-flex-grow: 1; - -moz-flex-grow: 1; - flex-grow: 1; - -ms-flex-positive: 1; - border-image: none; - border-bottom: 1px solid #E3E7EF; - border-right: 0 -} - -#overview-page .app-overview-metrics .metrics__summary-row__item:after, #overview-page .app-overview-metrics .metrics__summary-row__item:before { - display: none -} - -#overview-page .app-overview-metrics .metrics__summary-row__item:last-child { - border-bottom: 0 -} - -#overview-page .app-overview-metrics .metrics__summary-row__item.metric-active-alerts, #overview-page .app-overview-metrics .metrics__summary-row__item.metric-error-count { - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: horizontal; - -moz-box-orient: horizontal; - box-orient: horizontal; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: row; - -moz-flex-direction: row; - flex-direction: row; - -ms-flex-direction: row; - -webkit-box-lines: single; - -moz-box-lines: single; - box-lines: single; - -webkit-flex-wrap: nowrap; - -moz-flex-wrap: nowrap; - -ms-flex-wrap: nowrap; - flex-wrap: nowrap; - padding: 12px 20px 10px 10px; - font-size: 13px; - color: #56667D -} - -@media (max-width: 767px) { - #overview-page .app-overview-metrics .metrics__summary-row__item { - border-bottom: 0; - border-right: 1px solid #E3E7EF; - border-image: none; - width: 33% - } - - #overview-page .app-overview-metrics .metrics__summary-row__item:last-child { - border-right: 0 - } - - #overview-page .app-overview-metrics .metrics__summary-row__item.metric-active-alerts, #overview-page .app-overview-metrics .metrics__summary-row__item.metric-error-count { - width: 100%; - border-bottom: 1px solid #E3E7EF; - border-right: 0 - } - - #overview-page .app-overview-metrics timeseries-chart { - display: none - } -} - -#overview-page .app-overview-metrics .metrics__summary-row__label { - font-size: 12px; - color: #62738D; - text-transform: capitalize -} - -#overview-page .app-overview-metrics .metrics__summary-row__value { - font-size: 18px; - min-width: 60px; - color: #56667D; - margin: 0 10px 30px 0 -} - -#overview-page .app-overview-metrics .metrics__summary-row__unit { - font-size: 12px; - letter-spacing: 1px; - color: #62738D; - margin: 0 0 0 2px -} - -#overview-page .app-overview-metrics timeseries-chart { - position: relative; - overflow: hidden; - border-radius: 0; - margin-bottom: 0 -} - -#overview-page .app-overview-metrics timeseries-chart::after { - content: ''; - position: absolute; - top: 0; - bottom: -1px; - left: 0; - width: 50px; - background-color: transparent; - background-image: -webkit-linear-gradient(left, #fff, rgba(255, 255, 255, 0)); - background-image: linear-gradient(to right, #fff, rgba(255, 255, 255, 0)) -} - -#overview-page .app-overview-metrics .has-no-errors { - display: none -} - -#overview-page .addons-grid { - flex-wrap: wrap; - justify-content: space-between -} - -#overview-page .addons-grid .addon { - flex: 0 50%; - border-bottom-width: 1px; - border-bottom-style: solid; - -webkit-box-align: start; - -moz-box-align: start; - box-align: start; - -webkit-align-items: flex-start; - -moz-align-items: flex-start; - -ms-align-items: flex-start; - -o-align-items: flex-start; - align-items: flex-start; - -ms-flex-align: start -} - -#overview-page .addons-grid .addon:nth-last-child(1) { - border-bottom: none -} - -@media (min-width: 500px) { - #overview-page .addons-grid .addon:nth-last-child(2):nth-child(odd) { - border-bottom: none - } - - #overview-page .addons-grid .addon:nth-child(odd) { - border-right-width: 1px; - border-right-style: solid - } -} - -@media (max-width: 500px) { - #overview-page .addons-grid .addon { - flex: 0 100% - } -} - -#overview-page .addons-grid .addon .isDeprecated { - position: relative -} - -#overview-page .addons-grid .addon .isDeprecated .icon { - position: absolute; - bottom: -2px; - right: -4px -} - -#overview-page .addons-grid .addon .panel-section .panel-details, #overview-page .addons-grid .addon p, .panel-section #overview-page .addons-grid .addon .panel-details { - max-width: calc(100% - 32px); - -webkit-flex-grow: 1; - -moz-flex-grow: 1; - flex-grow: 1; - -ms-flex-positive: 1 -} - -#overview-page .addons-grid .addon a { - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0 -} - -#overview-page .addons-grid .addon .panel-section .panel-details, #overview-page .addons-grid .addon small, #overview-page .addons-grid .addon strong, .panel-section #overview-page .addons-grid .addon .panel-details { - display: block; - width: 100%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap -} - -#overview-page .addons-grid .addon strong { - font-size: 13px -} - -#overview-page .addons-grid .addon .panel-section .panel-details, #overview-page .addons-grid .addon small, .panel-section #overview-page .addons-grid .addon .panel-details { - color: #62738D -} - -#overview-page .data-unavailable { - color: rgba(98, 115, 141, .5); - font-size: 13px; - margin-top: -2px; - margin-bottom: 22px; - padding-top: 14px; - padding-bottom: 14px; - text-align: center; - background: rgba(227, 231, 239, .3) !important -} - -.github-linker .panel-section .panel-details, .github-linker p, .panel-section .github-linker .panel-details { - font-size: 13px; - color: #56667D; - line-height: 24px -} - -.github-linker .panel-section .help-block.panel-details, .github-linker p.help-block, .panel-section .github-linker .help-block.panel-details { - padding-top: 4px -} - -.github-linker .org-selection { - position: relative; - display: inline-block; - vertical-align: top; - width: calc(35% - 14px); - margin-right: 10px -} - -.remote-terminal-did-exit, .terminal-container { - position: absolute; - left: 0; - right: 0; - bottom: 0 -} - -.github-linker .org-selection select { - width: 100% -} - -@media (max-width: 767px) { - .github-linker .org-selection { - display: block; - width: 100%; - margin-bottom: 12px; - margin-right: 0 - } -} - -.github-linker .repo-selection { - display: inline-block; - vertical-align: top; - width: 65% -} - -@media (max-width: 767px) { - .github-linker .repo-selection { - display: block; - width: 100% - } -} - -#terminal-place-holder .terminal { - margin-left: 7px; - margin-bottom: 0 -} - -.terminal-container { - top: 40px -} - -.ssl-slide-panel .hk-slide-panel-container form label { - font-size: 14px; - font-weight: 400 -} - -.ssl-slide-panel .hk-slide-panel-container .hk-slide-panel-content { - display: flex; - flex-direction: column -} - -.ssl-slide-panel .hk-slide-panel-container .hk-slide-panel-content .file-drop { - padding: 15px; - border-radius: 4px; - box-shadow: none; - border: 2px dashed #CFD7E6; - background-color: #f7f8fb; - display: flex; - flex-direction: column -} - -.ssl-slide-panel .hk-slide-panel-container .hk-slide-panel-content .file-drop.is-dragged-over { - background-color: #cce2fb; - border: 2px solid #006DEB -} - -.ssl-slide-panel .hk-slide-panel-container .hk-slide-panel-content .file-drop .file-drop__header { - flex: 1; - align-items: center; - align-self: stretch; - position: relative; - top: 8px -} - -.ssl-slide-panel .hk-slide-panel-container .hk-slide-panel-content .file-drop .file-drop__header__description { - font-size: 13px; - color: #62738D; - position: relative; - top: -6px -} - -.ssl-slide-panel .hk-slide-panel-container .hk-slide-panel-content .file-drop .file-drop__footer { - font-size: 13px; - padding-bottom: 15px; - color: #62738D -} - -.ssl-slide-panel .hk-slide-panel-container .hk-slide-panel-content .body { - flex: 1; - display: flex; - align-items: center; - text-align: center; - justify-content: center; - width: 100%; - flex-direction: column; - min-height: 200px -} - -.ssl-slide-panel .hk-slide-panel-container .hk-slide-panel-content .body textarea { - flex: 1; - font-family: monospace -} - -.ssl-slide-panel .hk-slide-panel-container .hk-slide-panel-content .body .ltr-dns-update { - display: flex; - justify-content: center -} - -.ssl-slide-panel .hk-slide-panel-container .hk-slide-panel-content .body .ltr-dns-update .ltr-dns-update__from, .ssl-slide-panel .hk-slide-panel-container .hk-slide-panel-content .body .ltr-dns-update .ltr-dns-update__to { - width: 228px; - overflow-wrap: break-word; - word-wrap: break-word; - -ms-word-break: break-all; - word-break: break-all; - word-break: break-word -} - -.ssl-slide-panel .hk-slide-panel-container .hk-slide-panel-content .footer button { - width: 100% -} - -.process-stepper { - display: flex; - margin: -15px -15px 15px; - height: 32px; - line-height: 30px; - font-size: 12px; - box-shadow: inset 0 -1px 0 #E3E7EF -} - -.process-stepper__step { - flex: 1; - font-weight: 700; - text-align: center; - color: #62738D; - border-right: 1px solid #E3E7EF -} - -.process-stepper__step:last-child { - border-right: 0 -} - -.process-stepper__step:after { - content: " "; - display: block; - width: 0; - height: 0; - border-top: 16px solid transparent; - border-bottom: 16px solid transparent; - border-left: 8px solid transparent; - position: relative; - left: 100%; - top: -30px; - z-index: 200 -} - -.process-stepper__step--active { - background-color: #8669a9; - color: #fff -} - -.process-stepper__step--active:after { - border-left-color: #8669a9 -} - -.process-stepper__step--done { - background-color: #E3E7EF; - color: #62738D; - box-shadow: inset 0 -1px 0 rgba(207, 215, 230, .5) -} - -.process-stepper__step--done:after { - border-left-color: #E3E7EF -} - -.account-quota-usage table .pie-chart { - position: absolute; - left: 2px; - top: 4px -} - -svg.pie-chart { - width: 27px; - height: 27px; - transform: rotate(-90deg); - background: #008700; - border-radius: 100%; - border: 2px solid #62738D -} - -svg.pie-chart circle { - fill: #fff; - stroke: #62738D; - stroke-width: 32 -} - -.confirmable-action > div { - display: inline -} - -.content-box { - text-align: center; - width: 420px -} - -.content-box .content-box--header { - padding: 25px 50px 15px -} - -.content-box .content-box--body { - padding: 0 50px -} - -.content-box .content-box--footer { - padding: 0 50px 15px -} - -.content-box .content-box--header [class*=icon-hex-] { - margin-bottom: 15px -} - -.content-box .content-box--header h2 { - color: #56667D; - font-size: 16px; - margin: 0 0 5px -} - -.content-box .content-box--header .panel-section .panel-details, .content-box .content-box--header p, .panel-section .content-box .content-box--header .panel-details { - color: #62738D; - margin: 0 -} - -.content-box .content-box--body .panel-section .panel-details, .content-box .content-box--body p, .panel-section .content-box .content-box--body .panel-details { - font-size: 13px; - color: #62738D; - margin-bottom: 20px -} - -.content-box .content-box--footer .btn { - margin-bottom: 10px -} - -.content-box .message-banner { - margin: 0 -50px -} - -range-slider { - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - height: 14px; - position: relative; - border-radius: 5px; - background: rgba(227, 231, 239, .1); - box-shadow: inset 0 2px 6px 0 rgba(227, 231, 239, .2) -} - -range-slider.disabled { - cursor: default -} - -range-slider.disabled range-slider-fill { - background-color: rgba(0, 0, 0, 0); - background-image: -webkit-linear-gradient(left, rgba(121, 88, 159, .48), rgba(121, 88, 159, .92)); - background-image: linear-gradient(to right, rgba(121, 88, 159, .48), rgba(121, 88, 159, .92)); - border-color: #79589F -} - -range-slider.disabled range-slider-fill.pre-min { - background: rgba(121, 88, 159, .48) -} - -range-slider.disabled range-slider-fill.used { - background: rgba(121, 88, 159, .95) -} - -range-slider.disabled range-slider-fill.headroom { - background: rgba(121, 88, 159, .14) -} - -range-slider.disabled range-slider-value-indicator svg path { - fill: #79589F -} - -range-slider .dyno-marker { - position: absolute; - width: 0; - height: 0; - left: 0; - top: 8px; - border-style: solid; - border-width: 5px 4px 0; - border-color: #006DEB transparent transparent -} - -range-slider .tooltip { - opacity: 0 -} - -range-slider.is-down .tooltip, range-slider:hover .tooltip { - opacity: 1 -} - -range-slider .range-slider-ticks { - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-grow: 1; - -moz-flex-grow: 1; - flex-grow: 1; - -ms-flex-positive: 1; - border-radius: 5px; - border: 1px solid #CFD7E6; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - pointer-events: none -} - -range-slider .range-slider-tick { - width: 1px; - -webkit-flex-grow: 1; - -moz-flex-grow: 1; - flex-grow: 1; - -ms-flex-positive: 1; - border-right: 1px solid rgba(227, 231, 239, .8) -} - -range-slider .range-slider-tick:last-child { - border: none -} - -range-slider-fill { - pointer-events: none; - width: 50%; - height: 100%; - position: absolute; - top: 0; - left: 0; - opacity: .7; - border: 1px solid #006DEB; - max-width: 100%; - background-color: rgba(0, 0, 0, 0); - background-image: -webkit-linear-gradient(left, rgba(0, 109, 235, .48), rgba(0, 109, 235, .92)); - background-image: linear-gradient(to right, rgba(0, 109, 235, .48), rgba(0, 109, 235, .92)) -} - -range-slider-fill.starts-at-min { - border-top-left-radius: 5px; - border-bottom-left-radius: 5px -} - -range-slider-fill.ends-at-max { - border-top-right-radius: 5px; - border-bottom-right-radius: 5px -} - -range-slider-fill.is-empty { - display: none -} - -range-slider-fill.pre-min { - background: rgba(0, 109, 235, .36); - border-right: none -} - -range-slider-fill.headroom { - background: rgba(0, 109, 235, .9) -} - -range-slider-handle { - height: 25px; - width: 8px; - border-radius: 3px; - border: 1px solid #006DEB; - background: #fff; - position: relative; - margin-left: -4px; - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-pack: center; - -moz-box-pack: center; - box-pack: center; - -webkit-justify-content: center; - -moz-justify-content: center; - -ms-justify-content: center; - -o-justify-content: center; - justify-content: center; - -ms-flex-pack: center; - -webkit-align-self: center; - -moz-align-self: center; - align-self: center; - -ms-flex-item-align: center -} - -range-slider-handle .tooltip { - bottom: 26px -} - -range-slider-handle.min { - -webkit-box-pack: end; - -moz-box-pack: end; - box-pack: end; - -webkit-justify-content: flex-end; - -moz-justify-content: flex-end; - -ms-justify-content: flex-end; - -o-justify-content: flex-end; - justify-content: flex-end; - -ms-flex-pack: end -} - -range-slider-handle.min .tooltip { - -webkit-transform: translateX(-4px); - -moz-transform: translateX(-4px); - -ms-transform: translateX(-4px); - -o-transform: translateX(-4px); - transform: translateX(-4px) -} - -range-slider-handle.min .tooltip .tooltip-inner { - border-bottom-right-radius: 0 -} - -range-slider-handle.min .tooltip .tooltip-arrow { - border-width: 0 5px 5px 0; - border-color: transparent #56667D transparent transparent; - left: auto; - right: 0 -} - -range-slider-handle.max { - -webkit-box-pack: start; - -moz-box-pack: start; - box-pack: start; - -webkit-justify-content: flex-start; - -moz-justify-content: flex-start; - -ms-justify-content: flex-start; - -o-justify-content: flex-start; - justify-content: flex-start; - -ms-flex-pack: start; - right: 4px -} - -range-slider-handle.max .tooltip { - -webkit-transform: translateX(4px); - -moz-transform: translateX(4px); - -ms-transform: translateX(4px); - -o-transform: translateX(4px); - transform: translateX(4px) -} - -range-slider-handle.max .tooltip .tooltip-inner { - border-bottom-left-radius: 0 -} - -range-slider-handle.max .tooltip .tooltip-arrow { - left: 5px; - border-width: 5px 5px 0 0 -} - -range-slider-value-indicator { - pointer-events: none; - position: absolute; - top: -15px; - left: -4.5px -} - -.x-identicon.x-identicon--account-small, .x-identicon.x-identicon--small { - width: 20px; - height: 20px -} - -.x-identicon.x-identicon--account-small span, .x-identicon.x-identicon--small span { - font-size: 11px -} - -.x-identicon.x-identicon--large { - width: 48px; - height: 48px -} - -.x-identicon.x-identicon--large span { - font-size: 22px -} - -.hk-braintree-hosted-fields { - line-height: 20px; - transition: background ease .1s, border-color ease .1s; - -webkit-appearance: none; - -moz-appearance: none; - outline: 0; - border-radius: 4px; - border-style: solid; - border-width: 1px; - font-size: 13px; - background-color: #fff; - border-color: #cfd7e6; - box-shadow: inset 0 1px 2px 0 rgba(207, 215, 230, .4) -} - -.stencil, .stencil-box { - background-color: rgba(86, 102, 125, .1) !important; - color: transparent !important -} - -.hk-braintree-hosted-fields-focused { - outline: 0; - border-color: #79589f; - box-shadow: 0 0 0 2px rgba(157, 112, 208, .4) -} - -.hk-braintree-hosted-fields.hk-braintree-hosted-fields-invalid { - border-color: #de7575 -} - -.hk-braintree-hosted-fields-focused.hk-braintree-hosted-fields-invalid { - outline: 0; - border-color: #de0a0a; - box-shadow: 0 0 0 2px rgba(229, 143, 143, .4) -} - -.hk-braintree-hosted-fields.hk-braintree-hosted-fields-valid { - border-color: #86cf95 -} - -.hk-braintree-hosted-fields-focused.hk-braintree-hosted-fields-valid { - outline: 0; - border-color: #059e1c; - box-shadow: 0 0 0 2px rgba(171, 215, 180, .4) -} - -.ember-power-select-trigger, .ember-power-select-trigger--active, .ember-power-select-trigger:focus { - border-top: 1px solid #cfd7e6; - border-bottom: 1px solid #cfd7e6; - border-right: 1px solid #cfd7e6; - border-left: 1px solid #cfd7e6 -} - -.stencil { - border-radius: 30px; - padding: 0 !important; - font-size: 9px !important -} - -.stencil-box { - box-shadow: none -} - -@-webkit-keyframes fadeIn { - from { - opacity: 0 - } - to { - opacity: 1 - } -} - -@-moz-keyframes fadeIn { - from { - opacity: 0 - } - to { - opacity: 1 - } -} - -@-o-keyframes fadeIn { - from { - opacity: 0 - } - to { - opacity: 1 - } -} - -@keyframes fadeIn { - from { - opacity: 0 - } - to { - opacity: 1 - } -} - -.anim-fade-in { - -webkit-animation-duration: .6s; - animation-duration: .6s; - -webkit-animation-fill-mode: both; - animation-fill-mode: both; - -webkit-animation-name: fadeIn; - animation-name: fadeIn -} - -@-webkit-keyframes pulse { - 0%, 100% { - opacity: .2 - } - 50% { - opacity: 1 - } -} - -@-moz-keyframes pulse { - 0%, 100% { - opacity: .2 - } - 50% { - opacity: 1 - } -} - -@-o-keyframes pulse { - 0%, 100% { - opacity: .2 - } - 50% { - opacity: 1 - } -} - -@keyframes pulse { - 0%, 100% { - opacity: .2 - } - 50% { - opacity: 1 - } -} - -.anim-pulse { - -webkit-animation-duration: 3s; - animation-duration: 3s; - -webkit-animation-fill-mode: both; - animation-fill-mode: both; - -webkit-animation-name: pulse; - animation-name: pulse; - -webkit-animation-iteration-count: infinite; - animation-iteration-count: infinite -} - -.stencil-apps-list-item > div, .stencil-spaces-list-item > div { - max-width: 1240px -} - -.stencil-process-switcher { - box-shadow: inset 0 0 0 1px #cfd7e6; - border-radius: 4px; - height: 52px; - align-items: center; - padding-top: 4px -} - -.stencil-process-switcher div.bg-light-silver { - width: 16px; - height: 16px -} - -.bulk-app-transfer .apps-list-container, .pipeline-transfer-list .apps-list-container { - -webkit-transition: flex-shrink .4s cubic-bezier(.3, 0, 0, 1); - -o-transition: flex-shrink .4s cubic-bezier(.3, 0, 0, 1); - transition: flex-shrink .4s cubic-bezier(.3, 0, 0, 1); - flex-basis: 100% -} - -.bottom-slide-panel .app-container { - -webkit-transition: left .25s ease-out, opacity .25s ease-out; - -o-transition: left .25s ease-out, opacity .25s ease-out; - transition: left .25s ease-out, opacity .25s ease-out; - position: relative; - left: 0 -} - -.bottom-slide-panel.transfers-complete .app-container { - opacity: 0; - left: -50px -} - -.bottom-slide-panel .icon-arrow { - -webkit-transition: left .25s ease-out, opacity .25s ease-out; - -o-transition: left .25s ease-out, opacity .25s ease-out; - transition: left .25s ease-out, opacity .25s ease-out; - position: relative; - left: -3px; - top: 0 -} - -.bottom-slide-panel.transfers-complete .icon-arrow { - opacity: 0; - left: -40px -} - -.bottom-slide-panel .summary { - -webkit-transition: transform 1s ease-out .2s, opacity .25s ease-out .3s; - -o-transition: transform 1s ease-out .2s, opacity .25s ease-out .3s; - transition: transform 1s ease-out .2s, opacity .25s ease-out .3s -} - -.bottom-slide-panel.transfers-complete .summary { - opacity: 0; - transform: translate3d(-100%, 0, 0) -} - -.bottom-slide-panel .conclusion { - -webkit-transition: transform .25s ease-out .2s, opacity .5s ease-out .5s; - -o-transition: transform .25s ease-out .2s, opacity .5s ease-out .5s; - transition: transform .25s ease-out .2s, opacity .5s ease-out .5s; - opacity: 0 -} - -.bottom-slide-panel.transfers-complete .conclusion { - opacity: 1; - transform: translate3d(-100%, 0, 0) -} - -.bottom-slide-panel .identicon-container { - -webkit-transition: left .25s ease-out .15s; - -o-transition: left .25s ease-out .15s; - transition: left .25s ease-out .15s; - position: relative; - left: 0 -} - -.bottom-slide-panel .identicon-container .check { - -webkit-transition: transform .2s cubic-bezier(.175, .885, .32, 1.275) .7s; - -o-transition: transform .2s cubic-bezier(.175, .885, .32, 1.275) .7s; - transition: transform .2s cubic-bezier(.175, .885, .32, 1.275) .7s; - transform: scale(0) -} - -.bottom-slide-panel.transfers-complete .identicon-container { - left: -50px -} - -.pipeline-transfer-list.transfer-with-apps .bottom-slide-panel.transfers-complete .identicon-container { - left: -62px -} - -.bottom-slide-panel.transfers-complete .identicon-container .check { - transform: scale(1.25) -} - -.bottom-slide-panel .message-container { - position: relative; - overflow: hidden -} - -.cp-validating-gravatar-input .gravatar-icon { - position: absolute; - top: 1px; - left: 1px; - border-radius: unset -} - -.cp-validating-gravatar-input .gravatar-icon img { - border-radius: 3px 0 0 3px -} - -.pipeline-selector .pipeline-selection { - max-height: 250px; - overflow: auto; - width: 100% -} - -.display-formation-list progress { - height: 4px -} - -.display-formation-list progress::-webkit-progress-bar { - background: rgba(227, 231, 239, .8); - border-radius: 2px; - box-shadow: none -} - -.display-formation-list progress::-webkit-progress-value { - background: #79589f -} - -.web-hook-deliveries-list .expanded { - transform: rotate(90deg); - transform-origin: 45% 53% -} - -.web-hook-deliveries-list pre { - max-height: 350px; - min-height: 75px -} - -.nps-modal { - width: 600px -} - -.nps-modal-content .w-49 { - width: 49% -} - -.nps-modal-content .selected { - background-color: #F7F8FB -} - -.two-factor-catch-all--full-screen { - z-index: 200; - height: calc(100vh - 50px) -} - -.two-factor-catch-all--full-screen .two-factor-catch-all { - margin-top: 0; - top: 53px; - left: 0; - position: fixed -} - -body.two-factor-catch-all-is-open #hk-slide-panels, body.two-factor-catch-all-is-open #modal-overlays { - display: none; - visibility: hidden !important; - height: 0; - width: 0 -} - -.app-function .c3-tooltip-container, .function-app .c3-tooltip-container { - background-color: #323B49; - color: #fff; - text-align: center; - padding: 5px; - border-radius: 6px; - transition: opacity .6s -} - -.app-function .c3-tooltip-container tr, .function-app .c3-tooltip-container tr { - float: left -} - -.app-function .c3-tooltip-container td, .function-app .c3-tooltip-container td { - padding-right: 5px; - padding-left: 5px -} - -.app-function .c3-chart-bar ._expanded_, .function-app .c3-chart-bar ._expanded_ { - stroke: #9370db !important; - fill: #9370db !important -} - -.c3 line, .c3 path { - fill: none -} - -table.functions th:first-child { - border-top-left-radius: 3px -} - -table.functions th:last-child { - border-top-right-radius: 3px -} - -.ember-basic-dropdown { - position: relative -} - -.ember-basic-dropdown, .ember-basic-dropdown-content, .ember-basic-dropdown-content * { - box-sizing: border-box -} - -.ember-basic-dropdown-content { - position: absolute; - width: auto; - z-index: 1000; - background-color: #fff -} - -.ember-basic-dropdown-content--left { - left: 0 -} - -.ember-basic-dropdown-content--right { - right: 0 -} - -.ember-basic-dropdown-overlay { - position: fixed; - background: rgba(0, 0, 0, .5); - width: 100%; - height: 100%; - z-index: 10; - top: 0; - left: 0; - pointer-events: none -} - -.ember-basic-dropdown-content-wormhole-origin { - display: inline -} - -.ember-power-select-dropdown * { - box-sizing: border-box -} - -.ember-power-select-trigger { - position: relative; - border-radius: 4px; - background-color: #fff; - line-height: 1.75; - overflow-x: hidden; - text-overflow: ellipsis; - min-height: 1.75em; - user-select: none; - -webkit-user-select: none; - color: inherit -} - -.ember-power-select-trigger:after { - content: ""; - display: table; - clear: both -} - -.ember-power-select-trigger--active, .ember-power-select-trigger:focus { - outline: 0 -} - -.ember-basic-dropdown-trigger--below.ember-power-select-trigger[aria-expanded=true], .ember-basic-dropdown-trigger--in-place.ember-power-select-trigger[aria-expanded=true] { - border-bottom-left-radius: 4px; - border-bottom-right-radius: 4px -} - -.ember-basic-dropdown-trigger--above.ember-power-select-trigger[aria-expanded=true] { - border-top-left-radius: 4px; - border-top-right-radius: 4px -} - -.ember-power-select-placeholder { - color: #999; - display: block; - overflow-x: hidden; - white-space: nowrap; - text-overflow: ellipsis -} - -.ember-power-select-status-icon { - position: absolute; - width: 0; - height: 0; - top: 0; - bottom: 0; - margin: auto; - border-style: solid; - border-width: 7px 4px 0; - border-color: #cfd7e6 transparent transparent -} - -.ember-basic-dropdown-trigger[aria-expanded=true] .ember-power-select-status-icon { - transform: rotate(180deg) -} - -.ember-power-select-clear-btn { - position: absolute -} - -.ember-power-select-trigger-multiple-input { - font-family: inherit; - font-size: inherit; - border: none; - display: inline-block; - line-height: inherit; - -webkit-appearance: none; - outline: 0; - padding: 0; - float: left; - background-color: transparent; - text-indent: 2px -} - -.ember-power-select-trigger-multiple-input:disabled { - background-color: #eee -} - -.ember-power-select-trigger-multiple-input::placeholder { - opacity: 1; - color: #999 -} - -.ember-power-select-trigger-multiple-input::-webkit-input-placeholder { - opacity: 1; - color: #999 -} - -.ember-power-select-trigger-multiple-input::-moz-placeholder { - opacity: 1; - color: #999 -} - -.ember-power-select-trigger-multiple-input::-ms-input-placeholder { - opacity: 1; - color: #999 -} - -.ember-power-select-multiple-options { - padding: 0; - margin: 0 -} - -.ember-power-select-multiple-option { - border: 1px solid gray; - border-radius: 4px; - color: #333; - background-color: #e4e4e4; - padding: 0 4px; - display: inline-block; - line-height: 1.45; - float: left; - margin: 2px 0 2px 3px -} - -.ember-power-select-multiple-remove-btn:not(:hover) { - opacity: .5 -} - -.ember-power-select-search-input { - border: 1px solid #cfd7e6; - border-radius: 4px; - width: 100%; - font-size: inherit; - line-height: inherit; - padding: 0 5px -} - -.ember-power-select-search-input:focus { - border: 1px solid #79589f; - box-shadow: 0 0 0 2px rgba(157, 112, 208, .4); - outline: 0 -} - -.ember-power-select-dropdown { - border-left: none; - border-right: none; - line-height: 1.75; - border-radius: 4px; - box-shadow: 0 0 0 1px rgba(89, 105, 129, .1), 0 3px 20px 0 rgba(89, 105, 129, .3), 0 1px 2px 0 rgba(0, 0, 0, .05); - overflow: hidden; - color: inherit -} - -.ember-power-select-dropdown.ember-basic-dropdown-content--above { - transform: translateY(calc(-1 * 3px)); - border-top: none; - border-bottom: none; - border-bottom-left-radius: 4px; - border-bottom-right-radius: 4px -} - -.ember-power-select-dropdown.ember-basic-dropdown-content--below, .ember-power-select-dropdown.ember-basic-dropdown-content--in-place { - transform: translateY(3px); - border-top: none; - border-bottom: none; - border-top-left-radius: 4px; - border-top-right-radius: 4px -} - -.ember-power-select-dropdown.ember-basic-dropdown-content--in-place { - width: 100% -} - -.ember-power-select-options { - list-style: none; - margin: 0; - padding: 0; - user-select: none; - -webkit-user-select: none -} - -.ember-power-select-option { - padding: 0 8px -} - -.ember-power-select-group[aria-disabled=true] { - color: #999; - cursor: not-allowed -} - -.ember-power-select-group[aria-disabled=true] .ember-power-select-option, .ember-power-select-option[aria-disabled=true] { - color: #999; - pointer-events: none; - cursor: not-allowed -} - -.ember-power-select-option[aria-selected=true] { - background-color: #f7f8fb -} - -.ember-power-select-option[aria-current=true] { - background-color: #f7f8fb; - color: inherit -} - -.ember-power-select-group-name { - cursor: default; - font-weight: 700 -} - -.ember-power-select-trigger[aria-disabled=true] { - background-color: #eee -} - -.ember-power-select-trigger { - padding: 0 16px 0 0; - -ms-flex-align: center; - align-items: center -} - -.ember-power-select-placeholder, .ember-power-select-selected-item { - margin-left: 8px -} - -.ember-power-select-status-icon { - right: 5px; - display: none -} - -.ember-power-select-clear-btn { - right: 25px -} - -.ember-power-select-group .ember-power-select-group .ember-power-select-group-name { - padding-left: 24px -} - -.ember-power-select-group .ember-power-select-group .ember-power-select-option { - padding-left: 40px -} - -.ember-power-select-trigger[dir=rtl] { - padding: 0 0 0 16px -} - -.ember-power-select-trigger[dir=rtl] .ember-power-select-placeholder, .ember-power-select-trigger[dir=rtl] .ember-power-select-selected-item { - margin-right: 8px -} - -.ember-power-select-trigger[dir=rtl] .ember-power-select-multiple-option, .ember-power-select-trigger[dir=rtl] .ember-power-select-trigger-multiple-input { - float: right -} - -.ember-power-select-trigger[dir=rtl] .ember-power-select-status-icon { - left: 5px; - right: initial -} - -.ember-power-select-trigger[dir=rtl] .ember-power-select-clear-btn { - left: 25px; - right: initial -} - -.ember-power-select-dropdown[dir=rtl] .ember-power-select-group .ember-power-select-group .ember-power-select-group-name { - padding-right: 24px -} - -.ember-power-select-dropdown[dir=rtl] .ember-power-select-group .ember-power-select-group .ember-power-select-option { - padding-right: 40px -} - -.ember-power-select-dropdown[dir=rtl] .ember-power-select-group .ember-power-select-option { - padding-right: 24px -} - -.ember-power-select-dropdown[dir=rtl] .ember-power-select-group .ember-power-select-group-name { - padding-right: 8px -} - -.ember-power-select-trigger--active, .ember-power-select-trigger:focus { - box-shadow: 0 1px 3px 0 rgba(89, 105, 129, .05), 0 1px 1px 0 rgba(0, 0, 0, .025) -} - -.ember-power-select-options[role=listbox] { - overflow-y: auto; - -webkit-overflow-scrolling: touch; - padding: 5px 0; - max-height: 300px -} - -.ember-power-select-search { - padding: 10px; - border-bottom: 1px solid #e3e7ef -} - -.ember-power-select-search .ember-power-select-search-input { - padding: 5px 10px; - box-shadow: inset 0 1px 2px 0 rgba(207, 215, 230, .4); - line-height: 20px -} - -.ember-power-select-search .ember-power-select-search-input:focus { - box-shadow: 0 0 0 2px rgba(157, 112, 208, .4) -} - -.nav.nav-tabs, .nav.nav-tabs li a { - box-shadow: inset 0 -1px 0 #e7ebf3 -} - -.ember-power-select-search .ember-power-select-search-input::placeholder { - color: #62738D -} - -.ember-power-select-group .ember-power-select-group-name { - font-size: 13px; - color: #56667D; - line-height: 24px; - padding-left: 10px -} - -.ember-power-select-group .ember-power-select-option { - font-size: 13px; - line-height: 24px; - padding-left: 20px -} - -.ember-basic-dropdown-trigger--below.br--right.ember-power-select-trigger[aria-expanded=true], .ember-basic-dropdown-trigger--in-place.br--right.ember-power-select-trigger[aria-expanded=true], .ember-power-select-trigger.br--right { - border-top-left-radius: 0; - border-bottom-left-radius: 0 -} - -* { - -webkit-font-smoothing: subpixel-antialiased !important; - text-decoration-skip: ink !important; - -webkit-text-decoration-skip: ink !important -} - -@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2 / 1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { - * { - -webkit-font-smoothing: antialiased !important; - -moz-osx-font-smoothing: grayscale - } -} - -.nav.nav-pills li a, .nav.nav-tabs li a { - -webkit-font-smoothing: subpixel-antialiased; - -webkit-transition: opacity ease .3s -} - -html { - position: relative; - height: 100vH; - background-color: #fff -} - -body { - font-family: salesforce-sans, "Helvetica Neue", helvetica, arial, sans-serif; - min-width: 320px; - min-height: 100vH; - padding-top: 50px; - background: 0 0 -} - -nav.glostick { - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 49; - font-family: salesforce-sans, "Helvetica Neue", helvetica, arial, sans-serif !important -} - -nav.glostick .glostick__menu { - max-height: calc(100vH - 64px); - overflow: auto -} - -@media screen and (max-width: 600px) { - nav.glostick .glostick__menu { - max-height: calc(100vH - 20px - 46px); - top: 56px - } -} - -.icon { - vertical-align: middle -} - -h2 { - margin-top: 0 -} - -.main-panel { - display: flex; - box-orient: vertical; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -moz-flex-direction: column; - flex-direction: column; - -ms-flex-direction: column; - -webkit-flex-grow: 1; - -moz-flex-grow: 1; - flex-grow: 1; - -ms-flex-positive: 1 -} - -@media (max-width: 767px) { - .main-panel { - padding-left: 0 - } -} - -.main-content, .section-content, .top-nav .section-content { - padding: 0 20px -} - -.main-content { - display: flex; - position: relative; - background: #fff; - -webkit-box-orient: vertical; - -moz-box-orient: vertical; - box-orient: vertical; - -webkit-box-direction: normal; - -moz-box-direction: normal; - box-direction: normal; - -webkit-flex-direction: column; - -moz-flex-direction: column; - flex-direction: column; - -ms-flex-direction: column; - -webkit-flex-grow: 1; - -moz-flex-grow: 1; - flex-grow: 1; - -ms-flex-positive: 1; - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0 -} - -.scrollable-container { - overflow: auto; - max-height: 100%; - height: 100%; - -webkit-overflow-scrolling: touch -} - -.gravatar-icon { - position: relative; - display: inline-block; - vertical-align: middle; - overflow: hidden; - -webkit-flex-shrink: 0; - -moz-flex-shrink: 0; - flex-shrink: 0; - -ms-flex-negative: 0 -} - -.gravatar-icon img { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100% -} - -.section-header .action-buttons { - margin-bottom: 10px; - text-align: right -} - -.item-changed-value { - color: #006DEB -} - -.container-fluid { - padding: 0 -} - -.page-breadcrumb { - color: #62738D; - font-weight: 700; - font-size: 12px; - padding-bottom: 20px -} - -.page-breadcrumb i { - position: relative; - top: -2px; - margin: 0 10px -} - -.list-group-item.active { - z-index: 0 -} - -.list-group-item:first-of-type { - border-top-right-radius: none; - border-top-left-radius: none -} - -.list-group-item:last-of-type { - margin-bottom: 0; - border-bottom-right-radius: none; - border-bottom-left-radius: none -} - -.huge-text { - text-align: center; - font-size: 180px; - font-weight: 200; - color: #CFD7E6 -} - -@media (max-width: 991px) { - .main-panel { - width: 100% - } - - .huge-text { - font-size: 140px - } -} - -.huge-text img { - width: 140px; - margin: 0 auto -} - -.error-text { - width: 420px; - margin: 0 auto; - text-align: center; - color: #62738D -} - -@media (max-width: 991px) { - .error-text { - width: 100% - } -} - -.error-text .panel-section .panel-details, .error-text p, .panel-section .error-text .panel-details { - font-size: 13px -} - -.error-text .panel-section .panel-details:first-of-type, .error-text p:first-of-type, .panel-section .error-text .panel-details:first-of-type { - font-weight: 400; - font-size: 16px -} - -.message-banner.warning .message-banner-text, .nav.nav-tabs li a .panel-section .connected.panel-details, .nav.nav-tabs li a small.connected, .panel-section .nav.nav-tabs li a .connected.panel-details { - font-weight: 700 -} - -.error-text .panel-section .panel-details:first-of-type.text-danger, .error-text p:first-of-type.text-danger, .panel-section .error-text .panel-details:first-of-type.text-danger { - color: #DE0A0A -} - -.error-text .panel-section .alert-warning.panel-details, .error-text p.alert-warning, .panel-section .error-text .alert-warning.panel-details { - padding: 4px 6px; - position: relative; - margin-top: -4px; - margin-left: auto; - margin-right: auto; - display: inline-block -} - -.error-text span.repo-name { - white-space: nowrap -} - -.error-text .icon { - position: relative; - margin-left: 4px; - margin-right: 2px; - top: -1px; - opacity: .7 -} - -.error-text ul { - text-align: left -} - -.modal-body .modal-intro { - padding: 10px 30px -} - -.modal-body .modal-intro .icon { - margin-bottom: 12px -} - -.modal-body .modal-intro .panel-section .panel-details, .modal-body .modal-intro p, .panel-section .modal-body .modal-intro .panel-details { - font-size: 13px; - color: #56667D -} - -.modal-body .modal-intro .panel-section .title.panel-details, .modal-body .modal-intro p.title, .panel-section .modal-body .modal-intro .title.panel-details { - font-size: 14px; - color: #56667D; - margin-bottom: 6px -} - -.nav.nav-tabs { - position: relative; - text-align: center; - padding-bottom: 0; - margin: 0 -20px 20px; - overflow: hidden; - border: none -} - -.nav.nav-tabs + .nav-tabs { - margin-top: -10px -} - -.nav.nav-tabs li { - position: relative; - float: none; - display: inline-block; - vertical-align: top; - text-align: left; - margin: 0 4px; - padding-top: 2px -} - -.nav.nav-tabs li a { - position: relative; - color: #79589F; - display: inline-block; - opacity: .7; - background: #fff; - border: none; - -o-transition: opacity ease .3s; - transition: opacity ease .3s -} - -.nav.nav-tabs li a.active, .nav.nav-tabs li a:hover { - opacity: 1; - background: #fff -} - -.nav.nav-tabs li a.active { - outline: 0; - color: #56667D; - box-shadow: inset 0 -1px 0 #fff, 0 0 0 1px rgba(71, 83, 102, .1), 0 1px 2px rgba(0, 0, 0, .05); - border-radius: 3px 3px none none -} - -.nav.nav-tabs li a .panel-section .panel-details, .nav.nav-tabs li a small, .panel-section .nav.nav-tabs li a .panel-details { - color: #62738D; - display: block; - padding-top: 2px -} - -.nav.nav-tabs li.deploy-tab a { - color: #79589F -} - -.nav.nav-tabs li.deploy-tab.tab-github a { - color: #3F3F44 -} - -.nav.nav-tabs li.deploy-tab a { - padding: 16px 18px 14px 62px -} - -.nav.nav-tabs li.deploy-tab .label { - position: relative; - top: -2px; - margin-left: 4px; - text-transform: uppercase; - font-size: 9px; - padding: 2px 4px 1px -} - -.nav.nav-tabs li.deploy-tab .icon.tab-icon { - position: absolute; - left: 16px; - top: 50%; - margin-top: -16px -} - -@media (max-width: 767px) { - .nav.nav-tabs li.deploy-tab { - margin: 0 - } - - .nav.nav-tabs li.deploy-tab a { - padding: 14px 12px 14px 52px - } - - .nav.nav-tabs li.deploy-tab .icon.tab-icon { - left: 10px - } - - .nav.nav-tabs li.deploy-tab .panel-section .panel-details, .nav.nav-tabs li.deploy-tab small, .panel-section .nav.nav-tabs li.deploy-tab .panel-details { - display: none - } -} - -@media (max-width: 520px) { - .nav.nav-tabs li.deploy-tab { - text-align: center - } - - .nav.nav-tabs li.deploy-tab .service { - display: block; - padding-top: 4px - } - - .nav.nav-tabs li.deploy-tab a { - padding: 8px 10px; - font-size: 13px - } - - .nav.nav-tabs li.deploy-tab .icon.tab-icon { - position: relative; - top: 0; - left: 0; - margin: 0 auto - } -} - -.nav.nav-pills { - position: relative; - text-align: center; - padding-bottom: 20px; - margin-bottom: 30px; - border-bottom: 1px solid #e7ebf3 -} - -.nav.nav-pills li { - float: none; - display: inline-block; - vertical-align: top; - text-align: left; - margin: 0 2px 2px 0 -} - -.nav.nav-pills li a { - position: relative; - color: #79589F; - display: inline-block; - opacity: .7; - background: #fff; - -o-transition: opacity ease .3s; - transition: opacity ease .3s -} - -.nav.nav-pills li a:hover { - opacity: 1; - background: #fff -} - -.nav.nav-pills li a.active, .nav.nav-pills li a:active, .nav.nav-pills li a:focus { - outline: 0; - opacity: 1; - color: #56667D; - box-shadow: 0 0 0 1px rgba(71, 83, 102, .1), 0 1px 2px rgba(0, 0, 0, .05); - border-radius: 3px; - background: #fff -} - -.nav.nav-pills li a .panel-section .panel-details, .nav.nav-pills li a small, .panel-section .nav.nav-pills li a .panel-details { - color: #62738D; - display: block; - padding-top: 2px -} - -.nav.nav-pills li a .panel-section .connected.panel-details, .nav.nav-pills li a small.connected, .panel-section .nav.nav-pills li a .connected.panel-details { - color: #008700 -} - -.nav.nav-pills li.deploy-tab a { - color: #79589F -} - -.nav.nav-pills li.deploy-tab.tab-github a { - color: #3F3F44 -} - -.nav.nav-pills li.deploy-tab.tab-containers a { - color: #56667D; - padding-left: 52px -} - -.nav.nav-pills li.deploy-tab.tab-containers a .icon { - margin-top: -15px -} - -.nav.nav-pills li.deploy-tab a { - padding: 10px 14px 10px 54px -} - -.nav.nav-pills li.deploy-tab.connected a { - padding-right: 40px -} - -.nav.nav-pills li.deploy-tab .label { - position: relative; - top: -2px; - margin-left: 4px; - text-transform: uppercase; - font-size: 9px; - padding: 2px 4px 1px -} - -.nav.nav-pills li.deploy-tab .icon.tab-icon { - position: absolute; - left: 12px; - top: 50%; - margin-top: -17px -} - -.nav.nav-pills li.deploy-tab .icon.icon-success-badge { - position: absolute; - top: 16px; - right: 12px -} - -@media (max-width: 520px) { - .nav.nav-pills li.deploy-tab { - margin-left: 0; - margin-right: 0; - text-align: center - } - - .nav.nav-pills li.deploy-tab .service { - display: block; - padding-top: 4px - } - - .nav.nav-pills li.deploy-tab .service .success-badge-bg { - width: 20px; - height: 20px; - position: absolute; - top: 8px; - right: 10px; - background-color: #fff; - border-radius: 50%; - box-shadow: 0 0 0 2px #fff - } - - .nav.nav-pills li.deploy-tab .panel-section .panel-details, .nav.nav-pills li.deploy-tab small, .panel-section .nav.nav-pills li.deploy-tab .panel-details { - display: none - } - - .nav.nav-pills li.deploy-tab a { - padding: 8px 10px; - font-size: 13px - } - - .nav.nav-pills li.deploy-tab.connected a { - padding-right: 10px - } - - .nav.nav-pills li.deploy-tab.tab-containers a { - color: #56667D; - padding-left: 10px - } - - .nav.nav-pills li.deploy-tab.tab-containers a .icon { - margin: 2px auto - } - - .nav.nav-pills li.deploy-tab .icon.tab-icon { - position: relative; - top: 0; - left: 0; - margin: 0 auto - } - - .nav.nav-pills li.deploy-tab .icon.icon-success-badge { - position: absolute; - top: 6px; - right: 8px - } -} - -.extra-small, .show-more .btn { - font-size: 12px -} - -.sub-nav + .nav-pills { - margin-top: -10px; - padding-bottom: 16px -} - -.subnav-toolbar { - margin-top: -10px -} - -.subnav-toolbar header { - margin: 0 -20px -} - -.extra-small { - color: #62738D -} - -.show-more { - text-align: left -} - -.show-more .btn .icon { - margin-left: 0 -} - -.darken-on-hover:hover { - fill: #475366 -} - -.btn-link { - padding: 0 -} - -.btn .icon.caret-icon { - margin-right: -6px; - margin-left: 2px -} - -.btn-default:focus { - background: inherit -} - -#overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper, #overview-page .data-unavailable, .buildpack-installations-list .sortable-item.is-dragging, .content-box, .metrics__chart-sorting .sortable-item.is-dragging, .metrics__monitor-preview-chart__loading, .metrics__not-available, .purple-box { - background-color: #fff; - box-shadow: 0 0 0 1px rgba(89, 105, 128, .1), 0 1px 3px 0 rgba(89, 105, 128, .1), 0 1px 2px 0 rgba(0, 0, 0, .05) -} - -#overview-page .app-overview-metrics .metrics__summary-row--favorite__link-wrapper .close-purple-box, #overview-page .data-unavailable .close-purple-box, .buildpack-installations-list .sortable-item.is-dragging .close-purple-box, .content-box .close-purple-box, .metrics__chart-sorting .sortable-item.is-dragging .close-purple-box, .metrics__monitor-preview-chart__loading .close-purple-box, .metrics__not-available .close-purple-box, .purple-box .close-purple-box { - position: absolute; - top: 20px; - right: 20px -} - -.purple-box__header { - background-color: transparent; - margin: 0; - padding: 10px; - box-shadow: none; - border-radius: 0; - border-bottom: 1px solid #E3E7EF; - color: #56667D -} - -.panel-section .purple-box__header .panel-details, .purple-box__header .panel-section .panel-details, .purple-box__header p { - color: #56667D -} - -.generic-banner { - margin-left: -20px; - margin-right: -20px -} - -.nav-tabs + .generic-banner { - margin-top: -20px -} - -.message-banner .message-banner-text .panel-section .panel-details, .message-banner .message-banner-text small, .panel-section .message-banner .message-banner-text .panel-details { - font-size: 13px; - display: block -} - -.message-banner.warning .message-banner-text .panel-section .panel-details, .message-banner.warning .message-banner-text small, .panel-section .message-banner.warning .message-banner-text .panel-details { - font-weight: 400 -} - -.modal-title { - font-size: 15px -} - -.btn.fulfilled, .btn.pending { - pointer-events: none -} - -@media (max-width: 767px) { - .form-control { - font-size: 16px - } -} - -.u-display-inline-block { - display: inline-block -} - -.u-display-block { - display: block -} - -.mimic-select, select.form-control:not([multiple]) { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - padding-right: 22px; - -moz-appearance: none; - background: url(data:image/png; base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAANCAYAAABlyXS1AAAABGdBTUEAALGPC/xhBQAAALJJREFUGBm9UCEOwkAQ3L3Cf2pwpKkhoQkej0GRUE/bpSdwbR3BYXlAwwOQmP4Eh7xlh4BFsuJmZzK7N3dMnxJp4xD05ByvRfIBssMh0i1CoJsqP4Hg0KOybDcmnIn44H2+SpJsrKrHNJ0/MDljpr332xpuIDh08H8XF0XTM/O9rnP5Xm4vEEs8sbSuV6VdVTVISEBw6AzBnJk5L7ZhMIwNl7bp+v4hNFHkpuYbAcEx9LNeG4xMYRDZ28cAAAAASUVORK5CYII=) right 8 px center no-repeat -} - -@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2 / 1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { - .mimic-select, select.form-control:not([multiple]) { - background: url(data:image/png; base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAaCAYAAACHD21cAAAABGdBTUEAALGPC/xhBQAAAf5JREFUOBHtVL1rU1EUv/dcTItIJwch0r8gQwfXmrzF2jYWXAKFbhVEROwbdGjzcXgvdehg2kFKB2cxS4em0C6at4pCwUwODkLAWRw0+O7t77zktWkiriJ4Ifec+/u4796Xc55WvxnNZtN0Ot2GULlc1i+VSvGoTI8CzC+uxPHPV8CLA65lzMQy88Pvw9oLxnp9N9vr/Wg552YuiLQ+yWQmi+Xyg26KnxmZGzNx7FogskJqrVkiNkki0q4xusjsnwhuZGLeLlqrDpFelbVSVAtDP4ii4yifn3ewewCnsN2K581/bLePPulqtfHIOYUX4ZJNYKqE4Vo98Q+mSmW7rJQN+0sda618wlGepCYcrzxqErFgwvWNzoiHjFH3AH4GuBEE/mafHJ8H3IZotabVccV/5F98A5p5Z8Fau4fDv8SfzH+6BMpT+FUium9mZ2+9xeI6fgXPmyMUdhv52IApQKlVQUwhFgjlE6Jof4kSHVKt1Z4PivncKxjEFUFEKx4TRUcf0DrvACwBn0Cn3CwUbl/Ck9+IEE+qA0sKHHX6Dd1zNwjWXg818k4Odz3EztNiwD2eSQS2LhGmL8AWmR93krVM6cD35pq1vQOYb6SYRJjeE2Xu4LvzNcUpTSQKQXQ5j2Pvp7jkgg2bhDs7aiqUyOzI2saW5ET+U2ZtJf+74xRlgcKObZd2ywAAAABJRU5ErkJggg==) right 8 px center no-repeat; - background-size: 7px 13px - } -} - -pre { - word-wrap: normal; - word-break: normal -} - -pre.build-stream-line { - word-wrap: break-word; - overflow-wrap: break-word -} - -a.no-hover-underline:active, a.no-hover-underline:hover { - text-decoration: inherit !important -} - -.hk-no-link-style:active, .hk-no-link-style:focus, .hk-no-link-style:hover, .link:active, .link:hover { - text-decoration: none !important; - outline: 0 -} - -.malibu-icon { - background: 0 0 !important; - -moz-transform: scale(1) -} - -.rot90 { - transform: rotate(90deg) -} - -.rot270 { - transform: rotate(270deg) -} - -.word-wrap { - word-break: break-all -} - -.hk-button-xs { - display: flex; - align-items: center; - justify-content: center; - flex-shrink: none; - height: 22px; - padding-top: 0; - padding-bottom: 0 -} - -.collapse { - display: table -} - -.top--glostick { - top: 53px -} - -.fade-to-white--up { - background-image: linear-gradient(white, rgba(255, 255, 255, 0)) -} - -.fade-to-white--down { - background-image: linear-gradient(rgba(255, 255, 255, 0), #fff) -} - -.focus-z-1:focus { - z-index: 1 -} - -.hk-button--primary { - background-clip: border-box!important; - background-origin: border-box!important; - background: #79589f; - color: #fff; -} \ No newline at end of file diff --git a/rootfs/web/src/assets/home.css b/rootfs/web/src/assets/home.css deleted file mode 100644 index ed32021..0000000 --- a/rootfs/web/src/assets/home.css +++ /dev/null @@ -1,616 +0,0 @@ -.glostick { - box-sizing: border-box; - background: white; - font-family: sans-serif; - display: flex; - display: -webkit-box; - display: -ms-flexbox; - display: -webkit-flex; - padding: 0 15px; - height: 50px; - -webkit-user-select: none; - font-family: benton-sans, 'Helvetica Neue', sans-serif; - box-shadow: 0px 4px 4px rgba(0,0,0,0.1); -} - -.glostick::after { - background: linear-gradient(to right, #9E7CC1, #8ECDEA); - content:''; - width:100%; - position: absolute; - top: 50px; - height: 3px; - left: 0; -} - -.glostick.glostick--sfdc { - box-shadow: 0px 2px 4px rgba(0,0,0,0.1); -} - -.glostick.glostick--sfdc::after { - background: none; - height: 0px; - display: none; -} - -.glostick a { - cursor: pointer; -} - -.glostick.glostick--sfdc .glostick__property__name svg { - display:none; -} - -.glostick__modal-bg { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0,0,0,0.2); - z-index: 999; - opacity: 0; - pointer-events: none; - transition: .4s cubic-bezier(.3, 0, 0, 1.3); -} - -.glostick__modal-bg--active { - opacity: 0; - pointer-events: auto; -} - -.glostick__link--search { - cursor: pointer; -} - -.glostick__icon--search { - background: url('data:image/svg+xml;utf8,search'); - background-size: 22px 22px; - background-repeat: no-repeat; - background-position: center center; - width: 32px; - height: 50px; -} - -.glostick__property { - flex: 1; - -webkit-box-flex: 1; - -webkit-flex: 1; - -ms-flex: 1; -} - -.glostick__property__name { - display: inline-block; - height: 50px; - width: auto; - text-decoration: none; - color: #9E7CC1!important; - padding-left: 0px; - font-size: 18px; -} - -.glostick__property__name svg { - fill: currentColor; - position: relative; - top: 2px; -} - -.glostick--sfdc .glostick__property__name { - font-size: inherit; -} - -.glostick.glostick--sfdc .glostick__property__name span { - display: none; -} - -.glostick__property__name:hover { - color: #9E7CC1!important; -} - -.glostick__property__name:active { - color: #9E7CC1!important; -} - -.glostick__property__name:focus { - color: #9E7CC1!important; -} - -.glostick__property__name span { - position: absolute; - left: 52px; - top: 1px; - line-height: 48px; -} - -.glostick__property .icon-logo { - background: url('data:image/svg+xml;utf8,drycc-logo'); - background-size: 27px 30px; - width: 27px; - height: 30px; - display: inline-block; - position: relative; - opacity: 1; - top: 10px; - margin-right: 7px; -} - -.glostick.glostick--sfdc .glostick__property .icon-logo { - background: url('data:image/svg+xml;utf8,'); - width: 103px; - height: 24px; - background-repeat: no-repeat; - top: 13px; -} - -.glostick__user .icon-navigator-toggle { - background: url('data:image/svg+xml;utf8,Combined Shape Copy 2'); - background-size: 18px 18px; - background-repeat: no-repeat; - background-position: center center; - width: 32px; - height: 50px; - display: inline-block; - cursor: pointer; -} - -.glostick__user { - display: flex; - margin-left: 5px; -} - -.glostick__user__avatar--container { - position: relative; - width: 30px; - height: 30px; - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1); - border-radius: 50%; - overflow: hidden; -} - -.glostick__user__avatar--container::after { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-image: url('/src/assets/style/avatar.png'); - background-size: cover; - border-radius: 50%; - z-index: 1; -} - -.glostick__menu__item--account-details .glostick__user__avatar--container { - width: 48px; - height: 48px; - margin: 0 auto 10px; - box-shadow: none; -} - -.glostick__user__avatar, .glostick__account-details__avatar { - position: relative; - width: 30px; - height: 30px; - z-index: 2; -} - -.glostick__account-details__avatar { - width: 48px; - height: 48px; - box-shadow: none; -} - -.glostick__menu { - width: 240px; - box-shadow: 0 3px 20px rgba(89, 105, 129, .3), 0 1px 2px rgba(0, 0, 0, .05), 0 0 0 1px rgba(89, 105, 129, .1); - position: absolute; - background-color: #fff; - opacity: 0; - pointer-events: none; - border-radius: 3px; - background-clip: content-box; - z-index: 9991; - transform: translateY(-4px); - transition: transform ease 0.1s, opacity ease 0.1s; - padding: 0; - list-style: none outside; -} - -.glostick__menu--open { - transform: translateY(0px); -} - -.glostick__menu-icon { - display: inline-block; - z-index: 1000; -} - -.glostick__menu-icon--account { - position: relative; - display: inline-block; - width: 32px; - height: 40px; - padding-top: 10px; - margin-left: 12px; -} - -.glostick__user__notification { - opacity: 0; - position: absolute; - top: 8px; - right: 0; - width: 10px; - height: 10px; - border-radius: 50%; - background: #fff; - box-shadow: 0 1px 1px 0 rgba(0, 0, 0, .2); - transition: opacity ease .3s; - z-index: 3; -} - -.glostick__user__notification.visible { - opacity: 1; -} - -.glostick__user__notification::after { - content: ''; - position: absolute; - top: 2px; - left: 2px; - width: 6px; - height: 6px; - transform: scale(1.2); - border-radius: 50%; - background-image: linear-gradient(-180deg, #8FE8FE 0%, #00B7FF 100%); -} - -.glostick__menu--navigator { - position: absolute; - right: 56px; - top: 56px; -} - -.glostick__menu--account { - position: absolute; - right: 8px; - top: 56px; -} - -.glostick__menu__listitem { - margin: 0; - padding: 0; - border-bottom: 1px solid #EEF1F6; -} - -.glostick__menu__item { - position: relative; - display: block; - height: 40px; - text-decoration: none; - font-size: 14px; - line-height: 40px; - color: #79589F; - padding: 0 46px; - background-size: 21px 23px; - background-repeat: no-repeat; - background-position: 15px 48%; -} - -.glostick__menu__listitem:first-child { - border-top-right-radius: 3px; - border-top-left-radius: 3px; -} - -.glostick__menu__listitem:last-child { - border-bottom: 0; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} - -.glostick__menu__item:hover { - text-decoration: none; - background-color: #F7F8FB; - color: #61467f; -} - -.glostick__menu__item:focus { - outline: none; -} - -.glostick__menu__item--notifications__indicator { - position: absolute; - top: 50%; - right: 12px; - width: 8px; - height: 8px; - margin-top: -5px; - border-radius: 50%; - background-image: linear-gradient(-180deg, #8FE8FE 0%, #00B7FF 100%); -} - -.glostick__menu__item--account-details { - height: auto; - display: block; - line-height: normal; - text-align: center; - color: #3F3F44; - padding: 20px 10px 20px; -} - -.glostick__account-details__name { - display: block; - margin-bottom: 5px; -} - -.glostick__account-details__email { - font-size: 13px; - display: block; - color: #96A3B6; - width: 100%; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; -} - -.glostick__menu__item--assume-identity { - background-image: url('data:image/svg+xml;utf8,assume-identity'); -} - -.glostick__menu__item--dashboard { - background-image: url('data:image/svg+xml;utf8,dashboard'); -} - -.glostick__menu__item--databases { - background-image: url('data:image/svg+xml;utf8,databases'); -} - -.glostick__menu__item--dataclips { - background-image: url('data:image/svg+xml;utf8,dataclips'); -} - -.glostick__menu__item--elements { - background-image: url('data:image/svg+xml;utf8,elements'); -} - -.glostick__menu__item--health { - background-image: url('data:image/svg+xml;utf8,health'); -} - -.glostick__menu__item--support { - background-image: url('data:image/svg+xml;utf8,support'); -} - -.glostick__menu__item--docs { - background-image: url('data:image/svg+xml;utf8,docs'); -} - -.glostick__menu__item--settings { - background-image: url('data:image/svg+xml;utf8,settings'); -} - -.glostick__menu__item--notifications { - background-image: url('data:image/svg+xml;utf8,notifications'); -} - -.glostick__menu__item--signout { - background-image: url('data:image/svg+xml;utf8,signout'); -} - -.glostick__menu--open { - opacity: 1; - pointer-events: auto; -} - -.glostick__link--right { - display: inline-block; - padding-top: 18px; - margin-right: 10px; -} - -.glostick__link--right a { - color: #8DCAE9; - text-decoration: none; -} - -@media (max-width: 600px) { - /* Mobile device styles */ - .glostick { - padding: 0 10px; - } - - .glostick__property__name span { - left: 45px; - } - - .glostick__menu { - position: fixed; - left: 10px; - right: 10px; - top: 10px; - width: auto; - } -} -.quick-jump__filter.form-control { - box-sizing: border-box; - outline: none; - width: 100%; - height: 34px; - padding: 6px 12px; - background-color: #fff; - background-image: none; - border: 1px solid #CFD7E6; - border-radius: 4px; - box-shadow: none; - -webkit-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s; - -o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s; - transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s; } - -.quick-jump { - display: none; - box-sizing: border-box; - position: fixed; - top: 8px; - left: calc(50% - 195px); - z-index: 49; - width: 390px; - pointer-events: none; } -@media (max-width: 767px) { - .quick-jump { - width: 310px; - left: calc(50% - 155px); } } - -.quick-jump__filter__wrap { - box-sizing: border-box; - position: relative; - z-index: 2; - transition: transform ease 0.1s; - width: 100%; } -@media (max-width: 767px) { - .quick-jump__filter__wrap { - width: 150px; - margin: 0 auto; } - .quick-jump--focused .quick-jump__filter__wrap { - width: calc(100% - 20px); } - .quick-jump--focused .quick-jump__filter__wrap .quick-jump__filter { - width: 100%; } } -@media (max-width: 480px) { - .quick-jump__filter__wrap { - width: 80px; } } - -.quick-jump__filter__wrap--tt { - width: 100%; } - -.quick-jump__filter { - position: relative; - border: none; - background-color: white; - transform: translateY(0px); - transition: transform ease .1s; - pointer-events: auto; - -webkit-appearance: none; } -.quick-jump__filter::-webkit-input-placeholder { - /* Chrome/Opera/Safari */ - opacity: 1; } -.quick-jump__filter::-moz-placeholder { - /* Firefox 19+ */ - opacity: 1; } -.quick-jump__filter:-ms-input-placeholder { - /* IE 10+ */ - opacity: 1; } -.quick-jump__filter:-moz-placeholder { - /* Firefox 18- */ - opacity: 1; } -.quick-jump__filter:focus { - background-color: white; } - -.quick-jump__results { - background-color: #fff; - border-radius: 3px; - position: absolute; - top: 53px; - left: 0; - right: 0; - overflow: hidden; - box-shadow: 0 3px 20px rgba(89, 105, 129, 0.3), 0 1px 2px rgba(0, 0, 0, 0.05), 0 0 0 1px rgba(89, 105, 129, 0.1); - pointer-events: none; - opacity: 0; - transform: translateY(-4px); - transition: transform ease 0.1s, opacity ease 0.1s; } -.quick-jump__results.quick-jump--focused { - pointer-events: auto; - opacity: 1; - transform: translateY(5px); } -@media (max-width: 767px) { - .quick-jump__results { - top: 0px; - z-index: 1; } } - -.quick-jump__list { - border-radius: 4px; } - -.quick-jump__list { - max-height: 410px; - overflow-y: scroll; - margin-bottom: 0; } -@media screen and (max-width: 600px) { - .quick-jump__list { - max-height: calc(100vH - 20px - 46px); } } - -.quick-jump-result__icon-container { - display: flex; - width: 26px; } - -.quick-jump-result__icon { - display: inline-block; - width: 18px; - height: 18px; - background-size: cover; - background-repeat: no-repeat; } - -.quick-jump-result__icon--pipeline { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8ZGVmcz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iYSIgeDE9IjAlIiB5MT0iMCUiIHkyPSIxMDAlIj4KICAgICAgPHN0b3Agc3RvcC1jb2xvcj0iI0FDOEVDRSIgb2Zmc2V0PSIwJSIvPgogICAgICA8c3RvcCBzdG9wLWNvbG9yPSIjNzk1ODlGIiBvZmZzZXQ9IjEwMCUiLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgPC9kZWZzPgogIDxwYXRoIGZpbGw9InVybCgjYSkiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTkuMDMzODA2MTYsMi44NDU4NTI4MiBDOS42MzIxOTM5NiwyLjUxODA1NzIgMTAuMzY4NTU1OSwyLjUxODA1NzIgMTAuOTY2OTQzNywyLjg0NTg1MjgyIEwxNS4wMzQxODExLDUuMDc3NzEzNDIgQzE1LjYzMTgxOSw1LjQwNjIyMTY0IDE2LDYuMDExOTMwOTMgMTYsNi42NjgyMzQ3NyBMMTYsMTEuMTMxOTU2IEMxNiwxMS43ODc1NDcyIDE1LjYzMTgxOSwxMi4zOTM5NjkxIDE1LjAzNDE4MTEsMTIuNzIyNDc3MyBMMTAuOTY2OTQzNywxNC45NTM2MjUzIEMxMC4zNjg1NTU5LDE1LjI4MjEzMzUgOS42MzIxOTM5NiwxNS4yODIxMzM1IDkuMDMzODA2MTYsMTQuOTUzNjI1MyBMNC45NjY1Njg3NywxMi43MjI0NzczIEM0LjM2ODE4MDk3LDEyLjM5Mzk2OTEgNCwxMS43ODc1NDcyIDQsMTEuMTMxOTU2IEw0LDYuNjY4MjM0NzcgQzQsNi4wMTE5MzA5MyA0LjM2ODE4MDk3LDUuNDA2MjIxNjQgNC45NjY1Njg3Nyw1LjA3NzcxMzQyIEw5LjAzMzgwNjE2LDIuODQ1ODUyODIgWiBNOS45ODAzMDMyMywxLjQ3OTgyNzI1IEw5Ljk4MDMwMzIzLDEuNDc5ODI3MjUgQzkuNTk3NzI0NDQsMS40ODI5MTI2MyA5LjIxNTgxNTcxLDEuNTczOTM5OTEgOC44NzI3NzM4NSwxLjc1MjkwOTA3IEw0LjEyNzY2MzU2LDQuMjMyNzU0MTEgQzMuNDI5NTQ0NDYsNC41OTc3NjMyMyAzLDUuMjcwNzczNTQgMyw2IEwzLDExLjQxODQzODQgQzIuMzc5NTkwMTUsMTEuMDc0MjQ1NyAyLDEwLjQ2MjY2NSAyLDkuODAyODA1MTUgTDIsNS4xOTczNzg2NSBDMiw0LjUyMDIzOTggMi4zOTg4NjI3MSwzLjg5NTMwMTY1IDMuMDQ3MTE2MTcsMy41NTYzNjQ2MSBMNy40NTMyOTAwMSwxLjI1MzY1MTM2IEM4LjEwMTU0MzQ2LDAuOTE1NDQ5NTQ1IDguODk5MjY4ODksMC45MTU0NDk1NDUgOS41NDc1MjIzNCwxLjI1MzY1MTM2IEw5Ljk4MDMwMzIzLDEuNDc5ODI3MjUgWiBNNy45ODAzMDMyMywwLjQ3OTgyNzI1MiBMNy45ODAzMDMyMywwLjQ3OTgyNzI1MiBDNy41OTc3MjQ0NCwwLjQ4MjkxMjYzNCA3LjIxNTgxNTcxLDAuNTczOTM5OTA4IDYuODcyNzczODUsMC43NTI5MDkwNzMgTDIuMTI3NjYzNTYsMy4yMzI3NTQxMSBDMS40Mjk1NDQ0NiwzLjU5Nzc2MzIzIDEsNC4yNzA3NzM1NCAxLDUgTDEsMTAuNDE4NDM4NCBDMC4zNzk1OTAxNTIsMTAuMDc0MjQ1NyAwLDkuNDYyNjY0OTcgMCw4LjgwMjgwNTE1IEwwLDQuMTk3Mzc4NjUgQzAsMy41MjAyMzk4IDAuMzk4ODYyNzEzLDIuODk1MzAxNjUgMS4wNDcxMTYxNywyLjU1NjM2NDYxIEw1LjQ1MzI5MDAxLDAuMjUzNjUxMzY0IEM2LjEwMTU0MzQ2LC0wLjA4NDU1MDQ1NDYgNi44OTkyNjg4OSwtMC4wODQ1NTA0NTQ2IDcuNTQ3NTIyMzQsMC4yNTM2NTEzNjQgTDcuOTgwMzAzMjMsMC40Nzk4MjcyNTIgWiIvPgo8L3N2Zz4K"); } - -.quick-jump-result__icon--app { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2IiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgPGRlZnM+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImIiIHgxPSIwJSIgeTE9IjAlIiB5Mj0iMTAwJSI+CiAgICAgIDxzdG9wIHN0b3AtY29sb3I9IiNBQzhFQ0UiIG9mZnNldD0iMCUiLz4KICAgICAgPHN0b3Agc3RvcC1jb2xvcj0iIzc5NTg5RiIgb2Zmc2V0PSIxMDAlIi8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHBhdGggaWQ9ImEiIGQ9Ik02Ljg3Mjc3Mzg1LDAuOTg0ODY5ODEgQzcuNTcwODkyOTYsMC42MDUwNDMxNDIgOC40Mjk5ODE4OCwwLjYwNTA0MzE0MiA5LjEyODEwMDk4LDAuOTg0ODY5ODEgTDEzLjg3MzIxMTMsMy41NzA5OTM5OSBDMTQuNTcwNDU1NSwzLjk1MTY0NjM3IDE1LDQuNjUzNDk5OTkgMTUsNS40MTM5NzkwNCBMMTUsMTAuNTg2MjI3NCBDMTUsMTEuMzQ1ODgwNyAxNC41NzA0NTU1LDEyLjA0ODU2MDEgMTMuODczMjExMywxMi40MjkyMTI0IEw5LjEyODEwMDk4LDE1LjAxNDUxMDkgQzguNDI5OTgxODgsMTUuMzk1MTYzMyA3LjU3MDg5Mjk2LDE1LjM5NTE2MzMgNi44NzI3NzM4NSwxNS4wMTQ1MTA5IEwyLjEyNzY2MzU2LDEyLjQyOTIxMjQgQzEuNDI5NTQ0NDYsMTIuMDQ4NTYwMSAxLDExLjM0NTg4MDcgMSwxMC41ODYyMjc0IEwxLDUuNDEzOTc5MDQgQzEsNC42NTM0OTk5OSAxLjQyOTU0NDQ2LDMuOTUxNjQ2MzcgMi4xMjc2NjM1NiwzLjU3MDk5Mzk5IEw2Ljg3Mjc3Mzg1LDAuOTg0ODY5ODEgWiIvPgogIDwvZGVmcz4KICA8ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgPHVzZSBmaWxsPSJ1cmwoI2IpIiB4bGluazpocmVmPSIjYSIvPgogIDwvZz4KPC9zdmc+Cg=="); } - -.quick-jump-result__icon--space { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8ZGVmcz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iYSIgeDE9IjAlIiB5MT0iMCUiIHkyPSIxMDAlIj4KICAgICAgPHN0b3Agc3RvcC1jb2xvcj0iI0FDOEVDRSIgb2Zmc2V0PSIwJSIvPgogICAgICA8c3RvcCBzdG9wLWNvbG9yPSIjNzk1ODlGIiBvZmZzZXQ9IjEwMCUiLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgPC9kZWZzPgogIDxwYXRoIGZpbGw9InVybCgjYSkiIGQ9Ik0xLjI4ODc1ODM2LDMuMTQ2Mjk0OTEgTDYuNzExNzQxNTUsMC4zMTIxODYyOTQgQzcuNTA5NTkxOTUsLTAuMTA0MDYyMDk4IDguNDkxNDA3ODYsLTAuMTA0MDYyMDk4IDkuMjg5MjU4MjYsMC4zMTIxODYyOTQgTDE0LjcxMjI0MTUsMy4xNDYyOTQ5MSBDMTUuNTA5MDkyLDMuNTYzNDQ4MTkgMTYsNC4zMzI2MDI4MiAxNiw1LjE2NjAwNDUgTDE2LDEwLjgzNDIyMTcgQzE2LDExLjY2NjcxODUgMTUuNTA5MDkyLDEyLjQzNjc3OCAxNC43MTIyNDE1LDEyLjg1MzkzMTMgTDkuMjg5MjU4MjYsMTUuNjg3MTM1IEM4LjQ5MTQwNzg2LDE2LjEwNDI4ODMgNy41MDk1OTE5NSwxNi4xMDQyODgzIDYuNzExNzQxNTUsMTUuNjg3MTM1IEwxLjI4ODc1ODM2LDEyLjg1MzkzMTMgQzAuNDkwOTA3OTU1LDEyLjQzNjc3OCAwLDExLjY2NjcxODUgMCwxMC44MzQyMjE3IEwwLDUuMTY2MDA0NSBDMCw0LjMzMjYwMjgyIDAuNDkwOTA3OTU1LDMuNTYzNDQ4MTkgMS4yODg3NTgzNiwzLjE0NjI5NDkxIFogTTEuMSw1LjE2NjAwNDUgTDEuMSwxMC44MzQyMjE3IEMxLjEsMTEuMjQ3MjM2NCAxLjM1NTMwMjc4LDExLjY0NzQ0MzkgMS43OTgxMjA4OCwxMS44Nzg5Njk5IEw3LjIyMTQxMjQ1LDE0LjcxMjMzNDggQzcuNjk5OTg1NjQsMTQuOTYyNTU1MSA4LjMwMTAxNDE3LDE0Ljk2MjU1NTEgOC43Nzk4OTU3NCwxNC43MTIxNzM2IEwxNC4yMDIwNjg2LDExLjg3OTM5MzcgQzE0LjY0NDY3NzcsMTEuNjQ3Njg2NyAxNC45LDExLjI0NzIyMzYgMTQuOSwxMC44MzQyMjE3IEwxNC45LDUuMTY2MDA0NSBDMTQuOSw0Ljc1MjQ5MjMgMTQuNjQ1MDQxOSw0LjM1MjczMDIzIDE0LjIwMjc1MTEsNC4xMjExODk1OCBMOC43ODA0NTYyLDEuMjg3NDQwMzQgQzguMzAxNDE3MzgsMS4wMzc1MTk4OSA3LjY5OTU4MjQzLDEuMDM3NTE5ODkgNy4yMjEyMzE4NiwxLjI4NzA4MDk3IEwxLjc5ODM1MDc2LDQuMTIxMTM2MjMgQzEuMzU0OTA4NDEsNC4zNTMwMTk5MSAxLjEsNC43NTI1MDQgMS4xLDUuMTY2MDA0NSBaIE0xMS4yODMwNDMxLDYuOTk2NjQxOTIgTDEzLjI4MzA0MzEsNy44ODA4NDIzNiBDMTMuNTM2NTA3Myw3Ljk5Mjg5ODkyIDEzLjcsOC4yNDM5MzY3MyAxMy43LDguNTIxMDY2MjIgTDEzLjcsMTAuODc4OTMzOSBDMTMuNywxMS4xNTYwNjM0IDEzLjUzNjUwNzMsMTEuNDA3MTAxMiAxMy4yODMwNDMxLDExLjUxOTE1NzggTDExLjI4MzA0MzEsMTIuNDAzMzU4MiBDMTEuMTAyNzYzOCwxMi40ODMwNTk3IDEwLjg5NzIzNjIsMTIuNDgzMDU5NyAxMC43MTY5NTY5LDEyLjQwMzM1ODIgTDguNzE2OTU2OSwxMS41MTkxNTc4IEM4LjQ2MzQ5MjczLDExLjQwNzEwMTIgOC4zLDExLjE1NjA2MzQgOC4zLDEwLjg3ODkzMzkgTDguMyw4LjUyMTA2NjIyIEM4LjMsOC4yNDM5MzY3MyA4LjQ2MzQ5MjcyLDcuOTkyODk4OTIgOC43MTY5NTY4OSw3Ljg4MDg0MjM2IEwxMC43MTY5NTY5LDYuOTk2NjQxOTIgQzEwLjg5NzIzNjIsNi45MTY5NDA0MSAxMS4xMDI3NjM4LDYuOTE2OTQwNDEgMTEuMjgzMDQzMSw2Ljk5NjY0MTkyIFogTTUuMjgzMDQzMTEsNi45OTY2NDE5MiBMNy4yODMwNDMxMSw3Ljg4MDg0MjM2IEM3LjUzNjUwNzI4LDcuOTkyODk4OTIgNy43LDguMjQzOTM2NzMgNy43LDguNTIxMDY2MjIgTDcuNywxMC44Nzg5MzM5IEM3LjcsMTEuMTU2MDYzNCA3LjUzNjUwNzI3LDExLjQwNzEwMTIgNy4yODMwNDMxLDExLjUxOTE1NzggTDUuMjgzMDQzMSwxMi40MDMzNTgyIEM1LjEwMjc2MzgyLDEyLjQ4MzA1OTcgNC44OTcyMzYxOCwxMi40ODMwNTk3IDQuNzE2OTU2OSwxMi40MDMzNTgyIEwyLjcxNjk1NjksMTEuNTE5MTU3OCBDMi40NjM0OTI3MywxMS40MDcxMDEyIDIuMywxMS4xNTYwNjM0IDIuMywxMC44Nzg5MzM5IEwyLjMsOC41MjEwNjYyMiBDMi4zLDguMjQzOTM2NzMgMi40NjM0OTI3Miw3Ljk5Mjg5ODkyIDIuNzE2OTU2ODksNy44ODA4NDIzNiBMNC43MTY5NTY4OSw2Ljk5NjY0MTkyIEM0Ljg5NzIzNjE4LDYuOTE2OTQwNDEgNS4xMDI3NjM4Miw2LjkxNjk0MDQxIDUuMjgzMDQzMTEsNi45OTY2NDE5MiBaIE04LjI4MzA0MzExLDIuMzU5Nzc2MTMgTDEwLjI4MzA0MzEsMy4yNDM5NzY1NyBDMTAuNTM2NTA3MywzLjM1NjAzMzEzIDEwLjcsMy42MDcwNzA5NCAxMC43LDMuODg0MjAwNDQgTDEwLjcsNi4yNDIwNjgxMyBDMTAuNyw2LjUxOTE5NzYzIDEwLjUzNjUwNzMsNi43NzAyMzU0NCAxMC4yODMwNDMxLDYuODgyMjkyIEw4LjI4MzA0MzEsNy43NjY0OTIzOSBDOC4xMDI3NjM4Miw3Ljg0NjE5Mzg5IDcuODk3MjM2MTgsNy44NDYxOTM4OSA3LjcxNjk1NjksNy43NjY0OTIzOSBMNS43MTY5NTY5LDYuODgyMjkyIEM1LjQ2MzQ5MjczLDYuNzcwMjM1NDQgNS4zLDYuNTE5MTk3NjMgNS4zLDYuMjQyMDY4MTMgTDUuMywzLjg4NDIwMDQ0IEM1LjMsMy42MDcwNzA5NCA1LjQ2MzQ5MjcyLDMuMzU2MDMzMTMgNS43MTY5NTY4OSwzLjI0Mzk3NjU3IEw3LjcxNjk1Njg5LDIuMzU5Nzc2MTMgQzcuODk3MjM2MTgsMi4yODAwNzQ2MiA4LjEwMjc2MzgyLDIuMjgwMDc0NjIgOC4yODMwNDMxMSwyLjM1OTc3NjEzIFogTTExLDcuNjM2ODY1NzkgTDksOC41MjEwNjYyMiBMOSwxMC44Nzg5MzM5IEwxMSwxMS43NjMxMzQzIEwxMywxMC44Nzg5MzM5IEwxMyw4LjUyMTA2NjIyIEwxMSw3LjYzNjg2NTc5IFogTTUsNy42MzY4NjU3OSBMMyw4LjUyMTA2NjIyIEwzLDEwLjg3ODkzMzkgTDUsMTEuNzYzMTM0MyBMNywxMC44Nzg5MzM5IEw3LDguNTIxMDY2MjIgTDUsNy42MzY4NjU3OSBaIE04LDMgTDYsMy44ODQyMDA0NCBMNiw2LjI0MjA2ODEzIEw4LDcuMTI2MjY4NTIgTDEwLDYuMjQyMDY4MTMgTDEwLDMuODg0MjAwNDQgTDgsMyBaIi8+Cjwvc3ZnPgo="); } - -.quick-jump-result__icon--personal-apps { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8ZGVmcz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iYSIgeDE9IjAlIiB5MT0iMCUiIHkyPSIxMDAlIj4KICAgICAgPHN0b3Agc3RvcC1jb2xvcj0iIzlBN0NCQyIgb2Zmc2V0PSIwJSIvPgogICAgICA8c3RvcCBzdG9wLWNvbG9yPSIjNzk1ODlGIiBvZmZzZXQ9IjEwMCUiLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgPC9kZWZzPgogIDxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICA8cGF0aCBmaWxsPSIjNzk1ODlGIiBmaWxsLW9wYWNpdHk9Ii42MDEiIGZpbGwtcnVsZT0ibm9uemVybyIgZD0iTTEsMi42NjAwMzUzNCBMMSwxMy4zMzk5NjQ3IEMxLDE0LjI1NzYxNzYgMS43NDI2NTQyMSwxNSAyLjY2MDAzNTM0LDE1IEwxMy4zMzk5NjQ3LDE1IEMxNC4yNTc2MTc2LDE1IDE1LDE0LjI1NzM0NTggMTUsMTMuMzM5OTY0NyBMMTUsMi42NjAwMzUzNCBDMTUsMS43NDIzODIzOCAxNC4yNTczNDU4LDEgMTMuMzM5OTY0NywxIEwyLjY2MDAzNTM0LDEgQzEuNzQyMzgyMzgsMSAxLDEuNzQyNjU0MjEgMSwyLjY2MDAzNTM0IFogTTAsMi42NjAwMzUzNCBDMCwxLjE5MDkzODM5IDEuMTg5NTI4ODUsMCAyLjY2MDAzNTM0LDAgTDEzLjMzOTk2NDcsMCBDMTQuODA5MDYxNiwwIDE2LDEuMTg5NTI4ODUgMTYsMi42NjAwMzUzNCBMMTYsMTMuMzM5OTY0NyBDMTYsMTQuODA5MDYxNiAxNC44MTA0NzExLDE2IDEzLjMzOTk2NDcsMTYgTDIuNjYwMDM1MzQsMTYgQzEuMTkwOTM4MzksMTYgMCwxNC44MTA0NzExIDAsMTMuMzM5OTY0NyBMMCwyLjY2MDAzNTM0IFoiLz4KICAgIDxwYXRoIGZpbGw9InVybCgjYSkiIGQ9Ik0xMi4yMTA1MjYzLDEzIEwzLjgzMTk2MzI2LDEzIEMzLjM0ODEzNzA1LDEzIDMsMTIuNzExMjk3NyAzLDEyLjIyMDA1NTYgQzMsMTEuNzI4ODEzNiAzLjUyNjMxNTc5LDEwLjk3OTQ4MjYgNC4wNTI2MzE1OCwxMC43MTE4NjQ0IEM0LjU3ODk0NzM3LDEwLjQ0NDI0NjIgNC44NDIxMDUyNiwxMC4zMjM4MTggNS42MTU1NDU2NywxMC4yMjg3MDk1IEM1LjYxNTU0NTY3LDEwLjIyODcwOTUgNi45MzEzMzUxNSw5Ljk0OTE1MjU0IDYuOTMxMzM1MTUsOS40NzA3MzQ5NyBDNi45MzEzMzUxNSw5LjI3MTE4NjQ0IDYuOTY0Mjg5NDgsOS4xOTMzODYzOSA2LjcwNDc4NTgsOC45ODU3MjcwMyBDNi4yMTQyODU3MSw4LjU5MzIyMDM0IDUuNjE1NTQ1NjcsNy41MDQ5MDYyOCA1LjYxNTU0NTY3LDYuMDE1MTY1MDEgQzUuNjE1NTQ1NjcsNC41MjU0MjM3MyA2LjMwMjExMDE5LDMuNzY0MDk4OCA2LjU3MTQyODU3LDMuNTA4NDc0NTggQzcuMjg1NzE0MjksMi44MzA1MDg0NyA4LjcxNDI4NTcxLDIuODMwNTA4NDcgOS40Mjg1NzE0MywzLjUwODQ3NDU4IEM5Ljk0NTM4OTUsMy45OTkwMTM3NiAxMC4zNTIzODc4LDQuNTI1NDIzNzMgMTAuMzUyMzg3OCw2LjAxNTE2NTAzIEMxMC4zNTIzODc4LDcuNTA0OTA2MzMgOS43ODU3MTQyOSw4LjU5MzIyMDM0IDkuMjk5NzU2Miw4Ljk4NTcyNzAzIEM5LjAxNTczOTM2LDkuMjE1MTI2NDcgOS4wNTI2MzE1OCw5LjI3MTE4NjQ0IDkuMDUyNjMxNTgsOS40NzA3MzQ5NyBDOS4wNTI2MzE1OCwxMC4wMDkyNjY2IDEwLjI0NzcxNDQsMTAuMjE0NTc1NiAxMC4zNTIzODc4LDEwLjIyODcwOTUgQzExLjE1Nzg5NDcsMTAuMzIzODE4IDExLjQyMTA1MjYsMTAuMzMxNTc2NiAxMS45NDczNjg0LDEwLjcxMTg2NDQgQzEyLjU1MTE0OTYsMTEuMTQ4MTI0NiAxMywxMS42OTQzNDc5IDEzLDEyLjIyMDA1NTMgQzEzLDEyLjc0NTc2MjcgMTIuNzM2ODQyMSwxMyAxMi4yMTA1MjYzLDEzIFoiLz4KICA8L2c+Cjwvc3ZnPgo="); } - -.quick-jump__list .identicon { - position: relative; - background-color: #fff; - border-radius: 3px; - display: inline-block; - height: 18px; - width: 18px; - line-height: 18px; - vertical-align: middle; - text-align: center; - font-size: 11px; - font-weight: 600; - color: #AB8ECD; - box-shadow: 0 0 0 1px #AB8ECD; - border: none; - text-transform: capitalize; - border-radius: 50%; } - -.quick-jump__item--highlighted { - background-color: #f7f8fb !important; - background-image: none !important; } - -.quick-jump__hint { - text-align: center; - font-size: 12px; - padding: 10px 0; } -.quick-jump__hint .quick-jump__hint__title { - font-weight: bold; - font-size: 11px; - text-transform: uppercase; } -.quick-jump__hint .quick-jump__hint__key { - border: 1px solid #CFD7E6; - border-radius: 4px; - padding: 0px 5px; - background-color: #fff; - font-family: monospace; - margin: 0 2px; } - -.quick-jump__title { - font-size: 11px; - text-transform: uppercase; - font-weight: 600; - padding: 10px; } - -.quick-jump-result { - display: flex; - flex-wrap: wrap; - align-items: center; - font-size: 14px; - padding: 5px 10px; - cursor: pointer; - min-height: 32px; } -.quick-jump-result:hover { - background-color: #f7f8fb; -} diff --git a/rootfs/web/src/assets/icons/drycc.svg b/rootfs/web/src/assets/icons/drycc.svg new file mode 100644 index 0000000..5a7cdca --- /dev/null +++ b/rootfs/web/src/assets/icons/drycc.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/rootfs/web/src/assets/icons/github.svg b/rootfs/web/src/assets/icons/github.svg new file mode 100644 index 0000000..dc2f59a --- /dev/null +++ b/rootfs/web/src/assets/icons/github.svg @@ -0,0 +1,8 @@ + + + + + GitHub icon + + + \ No newline at end of file diff --git a/rootfs/web/src/assets/icons/google.svg b/rootfs/web/src/assets/icons/google.svg new file mode 100644 index 0000000..e9f9e65 --- /dev/null +++ b/rootfs/web/src/assets/icons/google.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/rootfs/web/src/assets/style/SalesforceSans-Bold.ttf b/rootfs/web/src/assets/style/SalesforceSans-Bold.ttf deleted file mode 100644 index 12e439f..0000000 Binary files a/rootfs/web/src/assets/style/SalesforceSans-Bold.ttf and /dev/null differ diff --git a/rootfs/web/src/assets/style/SalesforceSans-Regular.ttf b/rootfs/web/src/assets/style/SalesforceSans-Regular.ttf deleted file mode 100644 index f486935..0000000 Binary files a/rootfs/web/src/assets/style/SalesforceSans-Regular.ttf and /dev/null differ diff --git a/rootfs/web/src/assets/style/avatar.png b/rootfs/web/src/assets/style/avatar.png deleted file mode 100644 index a09db42..0000000 Binary files a/rootfs/web/src/assets/style/avatar.png and /dev/null differ diff --git a/rootfs/web/src/assets/style/bentonsans-book.eot b/rootfs/web/src/assets/style/bentonsans-book.eot deleted file mode 100644 index 2976398..0000000 Binary files a/rootfs/web/src/assets/style/bentonsans-book.eot and /dev/null differ diff --git a/rootfs/web/src/assets/style/bentonsans-book.svg b/rootfs/web/src/assets/style/bentonsans-book.svg deleted file mode 100644 index 5fc530e..0000000 --- a/rootfs/web/src/assets/style/bentonsans-book.svg +++ /dev/null @@ -1,400 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/web/src/assets/style/bentonsans-book.ttf b/rootfs/web/src/assets/style/bentonsans-book.ttf deleted file mode 100644 index b08631f..0000000 Binary files a/rootfs/web/src/assets/style/bentonsans-book.ttf and /dev/null differ diff --git a/rootfs/web/src/assets/style/bentonsans-book.woff b/rootfs/web/src/assets/style/bentonsans-book.woff deleted file mode 100644 index b9fddca..0000000 Binary files a/rootfs/web/src/assets/style/bentonsans-book.woff and /dev/null differ diff --git a/rootfs/web/src/assets/style/bentonsans-medium.eot b/rootfs/web/src/assets/style/bentonsans-medium.eot deleted file mode 100644 index c092af1..0000000 Binary files a/rootfs/web/src/assets/style/bentonsans-medium.eot and /dev/null differ diff --git a/rootfs/web/src/assets/style/bentonsans-medium.svg b/rootfs/web/src/assets/style/bentonsans-medium.svg deleted file mode 100644 index 9091ce4..0000000 --- a/rootfs/web/src/assets/style/bentonsans-medium.svg +++ /dev/null @@ -1,416 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/web/src/assets/style/bentonsans-medium.ttf b/rootfs/web/src/assets/style/bentonsans-medium.ttf deleted file mode 100644 index fefc155..0000000 Binary files a/rootfs/web/src/assets/style/bentonsans-medium.ttf and /dev/null differ diff --git a/rootfs/web/src/assets/style/bentonsans-medium.woff b/rootfs/web/src/assets/style/bentonsans-medium.woff deleted file mode 100644 index c558fc9..0000000 Binary files a/rootfs/web/src/assets/style/bentonsans-medium.woff and /dev/null differ diff --git a/rootfs/web/src/assets/style/bentonsans-regular.eot b/rootfs/web/src/assets/style/bentonsans-regular.eot deleted file mode 100644 index 8b05068..0000000 Binary files a/rootfs/web/src/assets/style/bentonsans-regular.eot and /dev/null differ diff --git a/rootfs/web/src/assets/style/bentonsans-regular.svg b/rootfs/web/src/assets/style/bentonsans-regular.svg deleted file mode 100644 index fb635da..0000000 --- a/rootfs/web/src/assets/style/bentonsans-regular.svg +++ /dev/null @@ -1,416 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/web/src/assets/style/bentonsans-regular.ttf b/rootfs/web/src/assets/style/bentonsans-regular.ttf deleted file mode 100644 index a57c247..0000000 Binary files a/rootfs/web/src/assets/style/bentonsans-regular.ttf and /dev/null differ diff --git a/rootfs/web/src/assets/style/bentonsans-regular.woff b/rootfs/web/src/assets/style/bentonsans-regular.woff deleted file mode 100644 index 548a9fd..0000000 Binary files a/rootfs/web/src/assets/style/bentonsans-regular.woff and /dev/null differ diff --git a/rootfs/web/src/assets/style/purple3.min.css b/rootfs/web/src/assets/style/purple3.min.css deleted file mode 100644 index b06a2f1..0000000 --- a/rootfs/web/src/assets/style/purple3.min.css +++ /dev/null @@ -1 +0,0 @@ -html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}progress{vertical-align:baseline}[hidden],template{display:none}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit;font-weight:bolder}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background-color:gold;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}button,input,optgroup,select,textarea{font:inherit;margin:0}optgroup{font-weight:700}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}body,html{font-family:Salesforce Sans,-apple-system,BlinkMacSystemFont,avenir next,avenir,helvetica,helvetica neue,ubuntu,roboto,noto,segoe ui,arial,sans-serif;line-height:1}.hk-badge,.hk-badge--square{font-weight:600;background:#62738d;color:#fff;border-radius:9999px;background-clip:border-box!important;background-origin:border-box!important;padding-left:5px;padding-right:5px;font-size:12px;line-height:1.5;border:1px solid transparent;text-align:center}.hk-badge--square{border-radius:4px;font-size:11px}.hk-badge--outline{color:#fff;border-radius:9999px;border:1px solid #62738d;color:#62738d}.hk-badge--alpha,.hk-badge--outline{font-weight:600;background:#62738d;background-clip:border-box!important;background-origin:border-box!important;padding-left:5px;padding-right:5px;font-size:12px;line-height:1.5;text-align:center;background-color:transparent}.hk-badge--alpha{color:#fff;border-radius:9999px;border:1px solid #c74c00;color:#c74c00}.hk-badge--beta{background:#62738d;color:#fff;border-radius:9999px;background-clip:border-box!important;background-origin:border-box!important;background-color:transparent;border:1px solid #006deb;color:#006deb}.hk-badge--beta,.hk-badge--new{font-weight:600;padding-left:5px;padding-right:5px;font-size:12px;line-height:1.5;text-align:center}.hk-badge--new{background:#62738d;color:#fff;border-radius:9999px;background-clip:border-box!important;background-origin:border-box!important;border:1px solid transparent;background:linear-gradient(135deg,#036fec,#0056ba)}.hk-badge--code{background:#f7f8fb;color:#475366;border-radius:4px;border:1px solid #cfd7e6;font-family:consolas,monaco,monospace;padding-left:5px;padding-right:5px;line-height:1.5;font-size:13px}.hk-banner{border-bottom-style:solid;border-bottom-width:1px}.hk-banner,.hk-banner--generic{line-height:1.5;font-size:13px;padding:5px 10px}.hk-banner--generic{color:#475366;border-left-color:#cfd7e6;border-bottom:1px solid #cfd7e6;border-right-color:#cfd7e6;border-top-color:#cfd7e6}.hk-banner--info{color:#006deb;background:#f6faff;border-left-color:#8ebdf1;border-bottom:1px solid #8ebdf1;border-right-color:#8ebdf1;border-top-color:#8ebdf1}.hk-banner--info,.hk-banner--success{line-height:1.5;font-size:13px;padding:5px 10px}.hk-banner--success{color:#008700;background:#f8fcf9;border-left-color:#86cf95;border-bottom:1px solid #86cf95;border-right-color:#86cf95;border-top-color:#86cf95}.hk-banner--warning{color:#c74c00;background:#fffaf6;border-left-color:#fa9f47;border-bottom:1px solid #fa9f47;border-right-color:#fa9f47;border-top-color:#fa9f47}.hk-banner--danger,.hk-banner--warning{line-height:1.5;font-size:13px;padding:5px 10px}.hk-banner--danger{color:#de0a0a;background:#fdf6f6;border-left-color:#de7575;border-bottom:1px solid #de7575;border-right-color:#de7575;border-top-color:#de7575}.hk-button-base{font-size:13px;line-height:22px;height:32px}.hk-button-base,.hk-button-base-sm{-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale}.hk-button-base-sm{font-size:12px;line-height:16px;height:26px}.hk-button-secondary-border{border:1px solid #79589f}.hk-button-disabled-border{border:1px solid #cfd7e6}.hk-button-danger-border{border:1px solid #de0a0a}.hk-button-warning-border{border:1px solid #c74c00}.hk-button-info-border{border:1px solid #006deb}.hk-button-success-border{border:1px solid #008700}.hk-button-secondary-border--white{border:1px solid #fff}.hk-button{background-clip:border-box!important;background-origin:border-box!important}.hk-button,.hk-button--primary{font-size:13px;line-height:22px;height:32px;-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;text-align:center;border-radius:4px;padding:4px 15px;font-weight:600;white-space:nowrap;cursor:pointer;text-decoration:none;box-sizing:border-box;border:1px solid transparent}.hk-button--primary{background-clip:border-box!important;background-origin:border-box!important;background:#79589f;color:#fff}.hk-button--secondary{border-radius:4px;border:1px solid #79589f}.hk-button--secondary,.hk-button--tertiary{font-size:13px;line-height:22px;height:32px;-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;text-align:center;padding:4px 15px;font-weight:600;white-space:nowrap;cursor:pointer;text-decoration:none;box-sizing:border-box;background-clip:border-box!important;background-origin:border-box!important;color:#79589f;background:#fff}.hk-button--tertiary{border-radius:4px;border:1px solid transparent}.hk-button--danger-primary{border-radius:4px;border:1px solid transparent;background-clip:border-box!important;background-origin:border-box!important;background:#de0a0a;color:#fff}.hk-button--danger,.hk-button--danger-primary{font-size:13px;line-height:22px;height:32px;-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;text-align:center;padding:4px 15px;font-weight:600;white-space:nowrap;cursor:pointer;text-decoration:none;box-sizing:border-box}.hk-button--danger{border-radius:4px;background-clip:border-box!important;background-origin:border-box!important;color:#de0a0a;border:1px solid #de0a0a;background:#fff}.hk-button--warning{border-radius:4px;color:#c74c00;border:1px solid #c74c00}.hk-button--info,.hk-button--warning{font-size:13px;line-height:22px;height:32px;-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;text-align:center;padding:4px 15px;font-weight:600;white-space:nowrap;cursor:pointer;text-decoration:none;box-sizing:border-box;background-clip:border-box!important;background-origin:border-box!important;background:#fff}.hk-button--info{border-radius:4px;color:#006deb;border:1px solid #006deb}.hk-button--success{border-radius:4px;cursor:pointer;background-clip:border-box!important;background-origin:border-box!important;color:#008700;background:#fff;border:1px solid #008700}.hk-button--disabled-primary,.hk-button--success{font-size:13px;line-height:22px;height:32px;-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;text-align:center;padding:4px 15px;font-weight:600;white-space:nowrap;text-decoration:none;box-sizing:border-box}.hk-button--disabled-primary{border-radius:4px;cursor:pointer;background-clip:border-box!important;background-origin:border-box!important;background:none;background:#eef1f6;color:#56667d;border:1px solid #cfd7e6;cursor:not-allowed;outline:0}.hk-button--disabled-danger,.hk-button--disabled-danger-primary,.hk-button--disabled-info,.hk-button--disabled-secondary,.hk-button--disabled-success,.hk-button--disabled-warning{font-size:13px;line-height:22px;height:32px;-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;text-align:center;border-radius:4px;padding:4px 15px;font-weight:600;white-space:nowrap;cursor:pointer;text-decoration:none;box-sizing:border-box;background-clip:border-box!important;background-origin:border-box!important;background:none;background:#eef1f6;color:#56667d;border:1px solid #cfd7e6;cursor:not-allowed;outline:0}.hk-button--danger-primary:disabled,.hk-button--danger:disabled,.hk-button--info:disabled,.hk-button--primary:disabled,.hk-button--secondary:disabled,.hk-button--success:disabled,.hk-button--warning:disabled{background:none;background:#eef1f6;color:#56667d;border:1px solid #cfd7e6;cursor:not-allowed;outline:0}.hk-button--disabled-tertiary{font-size:13px;line-height:22px;height:32px;-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;text-align:center;border-radius:4px;padding:4px 15px;font-weight:600;white-space:nowrap;cursor:pointer;text-decoration:none;box-sizing:border-box;border:1px solid transparent;background-clip:border-box!important;background-origin:border-box!important;color:#62738d;cursor:not-allowed;outline:0}.hk-button--tertiary:disabled{color:#62738d;cursor:not-allowed;outline:0}.hk-button--async{font-size:13px;line-height:22px;height:32px;border-radius:4px;cursor:pointer;background-clip:border-box!important;background-origin:border-box!important;background:#eef1f6;color:#56667d;border:1px solid #cfd7e6;cursor:wait;outline:0}.hk-button--async,.hk-button-sm{-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;text-align:center;padding:4px 15px;font-weight:600;white-space:nowrap;text-decoration:none;box-sizing:border-box}.hk-button-sm{font-size:12px;line-height:16px;height:26px;border-radius:4px;cursor:pointer;border:1px solid transparent;background-clip:border-box!important;background-origin:border-box!important}.hk-button-sm--primary{border-radius:4px;border:1px solid transparent;background-clip:border-box!important;background-origin:border-box!important;background:#79589f;color:#fff}.hk-button-sm--primary,.hk-button-sm--secondary{font-size:12px;line-height:16px;height:26px;-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;text-align:center;font-weight:600;padding:4px 15px;white-space:nowrap;cursor:pointer;text-decoration:none;box-sizing:border-box}.hk-button-sm--secondary{border-radius:4px;background-clip:border-box!important;background-origin:border-box!important;color:#79589f;background:#fff;border:1px solid #79589f}.hk-button-sm--tertiary{background-clip:border-box!important;background-origin:border-box!important;color:#79589f;background:#fff}.hk-button-sm--danger-primary,.hk-button-sm--tertiary{font-size:12px;line-height:16px;height:26px;-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;text-align:center;border-radius:4px;font-weight:600;padding:4px 15px;white-space:nowrap;cursor:pointer;text-decoration:none;box-sizing:border-box;border:1px solid transparent}.hk-button-sm--danger-primary{background-clip:border-box!important;background-origin:border-box!important;background:#de0a0a;color:#fff}.hk-button-sm--danger{border-radius:4px;color:#de0a0a;border:1px solid #de0a0a}.hk-button-sm--danger,.hk-button-sm--warning{font-size:12px;line-height:16px;height:26px;-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;text-align:center;font-weight:600;padding:4px 15px;white-space:nowrap;cursor:pointer;text-decoration:none;box-sizing:border-box;background-clip:border-box!important;background-origin:border-box!important;background:#fff}.hk-button-sm--warning{border-radius:4px;color:#c74c00;border:1px solid #c74c00}.hk-button-sm--info{border-radius:4px;color:#006deb;border:1px solid #006deb}.hk-button-sm--info,.hk-button-sm--success{font-size:12px;line-height:16px;height:26px;-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;text-align:center;font-weight:600;padding:4px 15px;white-space:nowrap;cursor:pointer;text-decoration:none;box-sizing:border-box;background-clip:border-box!important;background-origin:border-box!important;background:#fff}.hk-button-sm--success{border-radius:4px;color:#008700;border:1px solid #008700}.hk-button-sm--disabled-danger,.hk-button-sm--disabled-danger-primary,.hk-button-sm--disabled-info,.hk-button-sm--disabled-primary,.hk-button-sm--disabled-secondary,.hk-button-sm--disabled-success,.hk-button-sm--disabled-warning{font-size:12px;line-height:16px;height:26px;-webkit-font-smoothing:antialiased!important;-moz-osx-font-smoothing:grayscale;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;text-align:center;border-radius:4px;font-weight:600;padding:4px 15px;white-space:nowrap;cursor:pointer;text-decoration:none;box-sizing:border-box;background-clip:border-box!important;background-origin:border-box!important;background:none;background:#eef1f6;color:#56667d;border:1px solid #cfd7e6;cursor:not-allowed}.hk-button-sm--danger-primary:disabled,.hk-button-sm--danger:disabled,.hk-button-sm--info:disabled,.hk-button-sm--primary:disabled,.hk-button-sm--secondary:disabled,.hk-button-sm--success:disabled,.hk-button-sm--warning:disabled{background:none;background:#eef1f6;color:#56667d;border:1px solid #cfd7e6;cursor:not-allowed}.hk-button--primary:focus,.hk-button--secondary:focus,.hk-button--tertiary:focus,.hk-button-sm--primary:focus,.hk-button-sm--secondary:focus,.hk-button-sm--tertiary:focus{outline:none;border-color:#79589f;box-shadow:0 0 0 2px rgba(157,112,208,.4)}.hk-button--danger-primary:focus,.hk-button--danger:focus,.hk-button-sm--danger-primary:focus,.hk-button-sm--danger:focus{outline:none;border-color:#de0a0a;box-shadow:0 0 0 2px rgba(229,143,143,.4)}.hk-button--warning:focus,.hk-button-sm--warning:focus{outline:none;border-color:#c74c00;box-shadow:0 0 0 2px rgba(251,197,149,.4)}.hk-button--info:focus,.hk-button-sm--info:focus{outline:none;border-color:#006deb;box-shadow:0 0 0 2px rgba(142,189,241,.4)}.hk-button--success:focus,.hk-button-sm--success:focus{outline:none;border-color:#008700;box-shadow:0 0 0 2px rgba(171,215,180,.4)}.hk-button--primary:not(:disabled):hover,.hk-button-sm--primary:not(:disabled):hover{background:#4f3074}.hk-button--danger-primary:not(:disabled):hover,.hk-button-sm--danger-primary:not(:disabled):hover{background:#a70404}.hk-button--secondary:not(:disabled):hover,.hk-button--tertiary:not(:disabled):hover,.hk-button-sm--secondary:not(:disabled):hover,.hk-button-sm--tertiary:not(:disabled):hover{background:rgba(121,88,159,.1)}.hk-button--danger:not(:disabled):hover,.hk-button-sm--danger:not(:disabled):hover{background:rgba(222,10,10,.1)}.hk-button--warning:not(:disabled):hover,.hk-button-sm--warning:not(:disabled):hover{background:rgba(199,76,0,.1)}.hk-button--info:not(:disabled):hover,.hk-button-sm--info:not(:disabled):hover{background:rgba(0,109,235,.1)}.hk-button--success:not(:disabled):hover,.hk-button-sm--success:not(:disabled):hover{background:rgba(0,135,0,.1)}.hk-button--secondary:not(:disabled):active,.hk-button--tertiary:not(:disabled):active,.hk-button-sm--secondary:not(:disabled):active,.hk-button-sm--tertiary:not(:disabled):active{background:#f7f3fb}.hk-button--danger:not(:disabled):active,.hk-button-sm--danger:not(:disabled):active{background:#fdf6f6}.hk-button--warning:not(:disabled):active,.hk-button-sm--warning:not(:disabled):active{background:#fffaf6}.hk-button--info:not(:disabled):active,.hk-button-sm--info:not(:disabled):active{background:#f6faff}.hk-button--success:not(:disabled):active,.hk-button-sm--success:not(:disabled):active{background:#f8fcf9}.hk-button-group{display:-ms-flexbox;display:flex}.hk-button-group button{position:relative;z-index:0}.hk-button-group button:hover{z-index:1}.hk-button-group button:active,.hk-button-group button:focus{z-index:2}.hk-button-group button:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.hk-button-group button:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.hk-button-group button:not(:first-child){margin-left:-1px}.hk-button-group button:not(:first-child):not(:last-child){border-radius:0}.hk-dropdown-base{top:100%;min-width:200px;background-clip:padding-box;position:absolute;list-style-type:none;box-shadow:0 0 0 1px rgba(89,105,129,.1),0 3px 20px 0 rgba(89,105,129,.3),0 1px 2px 0 rgba(0,0,0,.05);font-size:13px;margin-top:5px;margin-bottom:5px;padding:5px 0;background:#fff;text-align:left;border-radius:4px}.hk-dropdown-item-base{position:relative;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:5px 15px 5px 10px;text-decoration:none;white-space:nowrap;line-height:1.5;cursor:pointer;border-style:none;border-width:0;-ms-flex:1 1 auto;flex:1 1 auto;min-width:0;min-height:0;background:#fff;transition:background-color .15s ease-in-out}.hk-dropdown,.hk-dropdown--left{left:0}.hk-dropdown,.hk-dropdown--left,.hk-dropdown--right{top:100%;min-width:200px;background-clip:padding-box;position:absolute;list-style-type:none;box-shadow:0 0 0 1px rgba(89,105,129,.1),0 3px 20px 0 rgba(89,105,129,.3),0 1px 2px 0 rgba(0,0,0,.05);font-size:13px;margin-top:5px;margin-bottom:5px;padding:5px 0;background:#fff;text-align:left;border-radius:4px}.hk-dropdown--right{right:0}.hk-dropdown--left li,.hk-dropdown--right li,.hk-dropdown li{display:-ms-flexbox;display:flex}.hk-dropdown-item{color:#475366}.hk-dropdown-item,.hk-dropdown-item--danger{position:relative;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:5px 15px 5px 10px;text-decoration:none;white-space:nowrap;line-height:1.5;cursor:pointer;border-style:none;border-width:0;-ms-flex:1 1 auto;flex:1 1 auto;min-width:0;min-height:0;background:#fff;transition:background-color .15s ease-in-out}.hk-dropdown-item--danger{color:#de0a0a}.hk-dropdown-item:active,.hk-dropdown-item:focus,.hk-dropdown-item:hover{color:#323b49;background:#f7f8fb}.hk-dropdown-item:focus{border-radius:4px;z-index:2;background:#f7f3fb;outline:none;border-color:#79589f;box-shadow:0 0 0 2px rgba(157,112,208,.4)}.hk-dropdown-item--danger:active,.hk-dropdown-item--danger:focus,.hk-dropdown-item--danger:hover{background:#fdf6f6}.hk-dropdown-item--danger:focus{border-radius:4px;z-index:2;outline:none;border-color:#de0a0a;box-shadow:0 0 0 2px rgba(229,143,143,.4)}.hk-dropdown-item--danger>svg,.hk-dropdown-item>svg{width:16px;height:16px;margin-right:10px}.hk-dropdown-item>svg{fill:url(#gradient-dark-gray)}.hk-dropdown-item--danger>svg{fill:url(#gradient-red)}.hk-dropdown-divider{border-top:1px solid;border-color:#e3e7ef;margin-top:5px;margin-bottom:5px}.hk-identicon,.hk-identicon--circle{font-size:12px;color:#79589f;font-weight:600;border:1px solid #a997bf;border-radius:4px;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;height:24px;width:24px;text-align:center}.hk-identicon--circle{border-radius:100%}.hk-input-base{padding-top:5px;padding-bottom:5px}.hk-input,.hk-input-base{line-height:20px;transition:background .1s ease,border-color .1s ease}.hk-input{-webkit-appearance:none;-moz-appearance:none;outline:0;border-radius:4px;padding:5px 10px;font-size:13px;background:#fff;border:1px solid #cfd7e6;box-shadow:inset 0 1px 2px 0 rgba(207,215,230,.4)}.hk-input::-webkit-input-placeholder{color:#62738d;opacity:.8}.hk-input:-ms-input-placeholder{color:#62738d;opacity:.8}.hk-input::placeholder{color:#62738d;opacity:.8}.hk-input:focus{outline:none;border-color:#79589f;box-shadow:0 0 0 2px rgba(157,112,208,.4)}.hk-input--read-only{line-height:20px;transition:background .1s ease,border-color .1s ease;-webkit-appearance:none;-moz-appearance:none;outline:0;border-radius:4px;padding:5px 10px;font-size:13px;background:#fff;border:1px solid #cfd7e6;box-shadow:inset 0 1px 2px 0 rgba(207,215,230,.4);color:#475366;background:#f7f8fb}.hk-input:-moz-read-only{color:#475366;background:#f7f8fb}.hk-input:read-only{color:#475366;background:#f7f8fb}.hk-input--read-only:focus{outline:none;border-color:#62738d;box-shadow:0 0 0 2px rgba(89,105,129,.2)}.hk-input:-moz-read-only:focus{outline:none;border-color:#62738d;box-shadow:0 0 0 2px rgba(89,105,129,.2)}.hk-input:read-only:focus{outline:none;border-color:#62738d;box-shadow:0 0 0 2px rgba(89,105,129,.2)}.hk-input--disabled{line-height:20px;transition:background .1s ease,border-color .1s ease;-webkit-appearance:none;-moz-appearance:none;outline:0;border-radius:4px;padding:5px 10px;font-size:13px;background:#fff;border:1px solid #cfd7e6;box-shadow:inset 0 1px 2px 0 rgba(207,215,230,.4);color:#62738d;background:#eef1f6}.hk-input:disabled{color:#62738d;background:#eef1f6}.hk-search-input{line-height:20px;transition:background .1s ease,border-color .1s ease;-webkit-appearance:none;-moz-appearance:none;outline:0;border-radius:4px;font-size:13px;background:#fff;border:1px solid #cfd7e6;box-shadow:inset 0 1px 2px 0 rgba(207,215,230,.4);padding:5px 10px 5px 30px}.hk-search-input::-webkit-input-placeholder{color:#62738d;opacity:.8}.hk-search-input:-ms-input-placeholder{color:#62738d;opacity:.8}.hk-search-input::placeholder{color:#62738d;opacity:.8}.hk-search-input:focus{outline:none;border-color:#79589f;box-shadow:0 0 0 2px rgba(157,112,208,.4)}.hk-search-input--read-only{line-height:20px;transition:background .1s ease,border-color .1s ease;-webkit-appearance:none;-moz-appearance:none;outline:0;border-radius:4px;font-size:13px;background:#fff;border:1px solid #cfd7e6;box-shadow:inset 0 1px 2px 0 rgba(207,215,230,.4);padding:5px 10px 5px 30px;color:#475366;background:#f7f8fb}.hk-search-input:-moz-read-only{color:#475366;background:#f7f8fb}.hk-search-input:read-only{color:#475366;background:#f7f8fb}.hk-search-input--read-only:focus{outline:none;border-color:#62738d;box-shadow:0 0 0 2px rgba(89,105,129,.2)}.hk-search-input:-moz-read-only:focus{outline:none;border-color:#62738d;box-shadow:0 0 0 2px rgba(89,105,129,.2)}.hk-search-input:read-only:focus{outline:none;border-color:#62738d;box-shadow:0 0 0 2px rgba(89,105,129,.2)}.hk-search-input--disabled{line-height:20px;transition:background .1s ease,border-color .1s ease;-webkit-appearance:none;-moz-appearance:none;outline:0;border-radius:4px;font-size:13px;background:#fff;border:1px solid #cfd7e6;box-shadow:inset 0 1px 2px 0 rgba(207,215,230,.4);padding:5px 10px 5px 30px;color:#62738d;background:#eef1f6}.hk-search-input:disabled{color:#62738d;background:#eef1f6}.hk-select{line-height:20px;transition:background .1s ease,border-color .1s ease;-webkit-appearance:none;-moz-appearance:none;outline:0;border-radius:4px;font-size:13px;border:1px solid #cfd7e6;box-shadow:inset 0 1px 2px 0 rgba(207,215,230,.4);box-shadow:0 1px 3px 0 rgba(89,105,129,.05),0 1px 1px 0 rgba(0,0,0,.025);padding:0 30px 0 10px;height:32px;background:#fff;background-repeat:no-repeat;background-position:100%;background-image:url('data:image/svg+xml;utf8,')}.hk-select:focus{outline:none;border-color:#79589f;box-shadow:0 0 0 2px rgba(157,112,208,.4)}.hk-select--disabled{line-height:20px;transition:background .1s ease,border-color .1s ease;-webkit-appearance:none;-moz-appearance:none;outline:0;border-radius:4px;font-size:13px;border:1px solid #cfd7e6;box-shadow:inset 0 1px 2px 0 rgba(207,215,230,.4);box-shadow:0 1px 3px 0 rgba(89,105,129,.05),0 1px 1px 0 rgba(0,0,0,.025);padding:0 30px 0 10px;height:32px;background:#fff;background-repeat:no-repeat;background-position:100%;background-image:url('data:image/svg+xml;utf8,');color:#62738d;background:#eef1f6}.hk-select:disabled{color:#62738d;background:#eef1f6}.hk-focus-ring:focus{outline:none;border-color:#79589f;box-shadow:0 0 0 2px rgba(157,112,208,.4)}.hk-focus-ring--blue:focus{outline:none;border-color:#006deb;box-shadow:0 0 0 2px rgba(142,189,241,.4)}.hk-focus-ring--green:focus{outline:none;border-color:#008700;box-shadow:0 0 0 2px rgba(171,215,180,.4)}.hk-focus-ring--orange:focus{outline:none;border-color:#c74c00;box-shadow:0 0 0 2px rgba(251,197,149,.4)}.hk-focus-ring--red:focus{outline:none;border-color:#de0a0a;box-shadow:0 0 0 2px rgba(229,143,143,.4)}.hk-focus-ring--gray:focus{outline:none;border-color:#62738d;box-shadow:0 0 0 2px rgba(89,105,129,.2)}.hk-label{font-size:13px;color:#475366;font-weight:700;margin-bottom:10px}.malibu-fill-gradient-purple{fill:url(#gradient-purple)}.malibu-fill-gradient-gray{fill:url(#gradient-gray)}.malibu-fill-gradient-dark-gray{fill:url(#gradient-dark-gray)}.malibu-fill-gradient-red{fill:url(#gradient-red)}.malibu-fill-gradient-orange{fill:url(#gradient-orange)}.malibu-fill-gradient-green{fill:url(#gradient-green)}.malibu-fill-gradient-blue{fill:url(#gradient-blue)}.hk-message{border-style:solid;border-width:1px;border-radius:4px}.hk-message,.hk-message--generic{line-height:1.5;font-size:13px;padding:5px 10px}.hk-message--generic{border-radius:4px;color:#475366;border:1px solid #cfd7e6;fill:#475366}.hk-message--info{border-radius:4px;color:#006deb;background:#f6faff;border:1px solid #8ebdf1;fill:#006deb}.hk-message--info,.hk-message--success{line-height:1.5;font-size:13px;padding:5px 10px}.hk-message--success{border-radius:4px;color:#008700;background:#f8fcf9;border:1px solid #86cf95;fill:#008700}.hk-message--warning{border-radius:4px;color:#c74c00;background:#fffaf6;border:1px solid #fa9f47;fill:#c74c00}.hk-message--danger,.hk-message--warning{line-height:1.5;font-size:13px;padding:5px 10px}.hk-message--danger{border-radius:4px;color:#de0a0a;background:#fdf6f6;border:1px solid #de7575;fill:#de0a0a}.hk-message--generic .hk-link,.hk-message--info .hk-link{color:#006deb}.hk-message--success .hk-link{color:#008700}.hk-message--warning .hk-link{color:#c74c00}.hk-message--danger .hk-link{color:#de0a0a}.hk-button__spinner,.hk-spinner{position:relative;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;min-height:7px;text-align:center}.hk-button__spinner__dot,.hk-spinner__dot{display:block;border-radius:50%;background:#475366;animation:pulse 1s infinite ease-out}.hk-button__spinner__dot{width:7px;height:7px;margin:0 2px}.hk-spinner__dot--inverted{background:#fff}.hk-button__spinner__dot{width:3px;height:3px;margin:0 1.5px}.hk-spinner__dot{width:7px;height:7px;margin:0 2px}.hk-button__spinner__dot--one,.hk-spinner__dot--one{animation-delay:-.32s;margin-left:0}.hk-button__spinner__dot--two,.hk-spinner__dot--two{animation-delay:-.16s}.hk-button__spinner__dot--three,.hk-spinner__dot--three{animation-delay:-.08s;margin-right:0}@keyframes pulse{0%{opacity:0}40%{opacity:1}80%{opacity:0}to{opacity:0}}.hk-stencil{color:#cfd7e6;background:#cfd7e6;border-radius:9999px;padding-left:5px;padding-right:5px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:12px}.hk-tabs{display:-ms-flexbox;display:flex;-ms-flex-direction:row;flex-direction:row;border-top:1px solid;border-color:#e3e7ef}.hk-tabs__tab{text-decoration:none;padding:15px;font-size:14px;color:#62738d;border-left-color:#e3e7ef;border-bottom:1px solid #e3e7ef;border-right-color:#e3e7ef;border-top-color:#e3e7ef}.hk-tabs__tab:hover{border-color:#cfd7e6;color:#475366}.hk-tabs__tab--active{text-decoration:none;padding:15px;font-size:14px;color:#62738d;color:#79589f;border-bottom:1px solid #a997bf;border-color:#a997bf #a997bf #e3e7ef}.hk-tabs__tab--active:hover{border-color:#a997bf}.hk-toast,.hk-toast--success{line-height:1.5;font-size:13px;border-radius:4px;padding:5px 10px;box-shadow:0 1px 3px 0 rgba(89,105,129,.05),0 1px 1px 0 rgba(0,0,0,.025)}.hk-toast--success{color:#008700;background:#f8fcf9}.hk-toast--error{line-height:1.5;font-size:13px;border-radius:4px;padding:5px 10px;box-shadow:0 1px 3px 0 rgba(89,105,129,.05),0 1px 1px 0 rgba(0,0,0,.025);color:#de0a0a;background:#fdf6f6}.hk-well{text-align:center;padding:20px;border-radius:6px;box-shadow:inset 0 0 0 1px rgba(0,0,0,.05),inset 0 1px 2px 0 rgba(78,83,90,.1);color:#475366;background-color:rgba(87,114,154,.05)}.bg-black{background:#000}.bg-near-black{background:#323b49}.bg-dark-gray{background:#475366}.bg-mid-gray{background:#56667d}.bg-gray{background:#62738d}.bg-light-gray{background:#cfd7e6}.bg-silver{background:#e3e7ef}.bg-light-silver{background:#eef1f6}.bg-lightest-silver{background:#f7f8fb}.bg-near-white{background:#fbfbfd}.bg-white{background:#fff}.bg-none{background:none}.bg-transparent{background-color:transparent}.bg-dark-purple{background:#4f3074}.bg-purple{background:#79589f}.bg-light-purple{background:#a997bf}.bg-lightest-purple{background:#f7f3fb}.bg-dark-blue{background:#034ca2}.bg-blue{background:#006deb}.bg-light-blue{background:#8ebdf1}.bg-lightest-blue{background:#f6faff}.bg-dark-green{background:#066515}.bg-green{background:#008700}.bg-light-green{background:#86cf95}.bg-lightest-green{background:#f8fcf9}.bg-dark-red{background:#a70404}.bg-red{background:#de0a0a}.bg-light-red{background:#de7575}.bg-lightest-red{background:#fdf6f6}.bg-dark-orange{background:#832d03}.bg-orange{background:#c74c00}.bg-light-orange{background:#fa9f47}.bg-lightest-orange{background:#fffaf6}.bg-gold{background:#ffb700}.bg-yellow{background:gold}.bg-light-yellow{background:#fbf1a9}.bg-dark-pink{background:#d5008f}.bg-hot-pink{background:#ff41b4}.bg-pink{background:#ff80cc}.bg-light-pink{background:#ffa3d7}.bg-navy{background:#001b44}.bg-washed-blue{background:#f6fffe}.bg-washed-green{background:#e8fdf5}.bg-washed-yellow{background:#fffceb}.bg-washed-red{background:#ffdfdf}.bg-gradient-primary{background:linear-gradient(135deg,#8964b4,#6a4791)}.bg-gradient-secondary{background:linear-gradient(135deg,#8964b4,#43accd)}.bg-gradient-light-gray{background:linear-gradient(135deg,#e3e7ef,#cfd7e6)}.bg-gradient-gray{background:linear-gradient(135deg,#4f5257,#96a3b6)}.bg-gradient-dark-gray{background:linear-gradient(135deg,#919cae,#596981)}.bg-gradient-silver{background:linear-gradient(#fff,#fafbfd)}.bg-gradient-blue{background:linear-gradient(135deg,#036fec,#0056ba)}.bg-gradient-green{background:linear-gradient(135deg,#038803,#026c02)}.bg-gradient-red{background:linear-gradient(135deg,#e11717,#bf0000)}.bg-gradient-orange{background:linear-gradient(135deg,#cc4e00,#a94100)}.bg-black-90{background-color:rgba(0,0,0,.9)}.bg-black-80{background-color:rgba(0,0,0,.8)}.bg-black-70{background-color:rgba(0,0,0,.7)}.bg-black-60{background-color:rgba(0,0,0,.6)}.bg-black-50{background-color:rgba(0,0,0,.5)}.bg-black-40{background-color:rgba(0,0,0,.4)}.bg-black-30{background-color:rgba(0,0,0,.3)}.bg-black-20{background-color:rgba(0,0,0,.2)}.bg-black-10{background-color:rgba(0,0,0,.1)}.bg-black-05{background-color:rgba(0,0,0,.05)}.bg-black-025{background-color:rgba(0,0,0,.025)}.bg-gray-90{background-color:rgba(89,105,129,.9)}.bg-gray-80{background-color:rgba(89,105,129,.8)}.bg-gray-70{background-color:rgba(89,105,129,.7)}.bg-gray-60{background-color:rgba(89,105,129,.6)}.bg-gray-50{background-color:rgba(89,105,129,.5)}.bg-gray-40{background-color:rgba(89,105,129,.4)}.bg-gray-30{background-color:rgba(89,105,129,.3)}.bg-gray-20{background-color:rgba(89,105,129,.2)}.bg-gray-10{background-color:rgba(89,105,129,.1)}.bg-gray-05{background-color:rgba(89,105,129,.05)}.bg-gray-025{background-color:rgba(89,105,129,.025)}.bg-mid-gray-90{background-color:rgba(87,114,154,.9)}.bg-mid-gray-80{background-color:rgba(87,114,154,.8)}.bg-mid-gray-70{background-color:rgba(87,114,154,.7)}.bg-mid-gray-60{background-color:rgba(87,114,154,.6)}.bg-mid-gray-50{background-color:rgba(87,114,154,.5)}.bg-mid-gray-40{background-color:rgba(87,114,154,.4)}.bg-mid-gray-30{background-color:rgba(87,114,154,.3)}.bg-mid-gray-20{background-color:rgba(87,114,154,.2)}.bg-mid-gray-10{background-color:rgba(87,114,154,.1)}.bg-mid-gray-05{background-color:rgba(87,114,154,.05)}.bg-mid-gray-025{background-color:rgba(87,114,154,.025)}.bg-white-90{background-color:hsla(0,0%,100%,.9)}.bg-white-80{background-color:hsla(0,0%,100%,.8)}.bg-white-70{background-color:hsla(0,0%,100%,.7)}.bg-white-60{background-color:hsla(0,0%,100%,.6)}.bg-white-50{background-color:hsla(0,0%,100%,.5)}.bg-white-40{background-color:hsla(0,0%,100%,.4)}.bg-white-30{background-color:hsla(0,0%,100%,.3)}.bg-white-20{background-color:hsla(0,0%,100%,.2)}.bg-white-10{background-color:hsla(0,0%,100%,.1)}.bg-transparent-squares{background-position:0 0,12px 12px;background-size:24px 24px;background-image:linear-gradient(45deg,rgba(0,0,0,.05) 25%,transparent 0,transparent 75%,rgba(0,0,0,.05) 0,rgba(0,0,0,.05)),linear-gradient(45deg,rgba(0,0,0,.05) 25%,transparent 0,transparent 75%,rgba(0,0,0,.05) 0,rgba(0,0,0,.05))}.hover-bg-black-90:focus,.hover-bg-black-90:hover{background-color:rgba(0,0,0,.9)}.hover-bg-black-80:focus,.hover-bg-black-80:hover{background-color:rgba(0,0,0,.8)}.hover-bg-black-70:focus,.hover-bg-black-70:hover{background-color:rgba(0,0,0,.7)}.hover-bg-black-60:focus,.hover-bg-black-60:hover{background-color:rgba(0,0,0,.6)}.hover-bg-black-50:focus,.hover-bg-black-50:hover{background-color:rgba(0,0,0,.5)}.hover-bg-black-40:focus,.hover-bg-black-40:hover{background-color:rgba(0,0,0,.4)}.hover-bg-black-30:focus,.hover-bg-black-30:hover{background-color:rgba(0,0,0,.3)}.hover-bg-black-20:focus,.hover-bg-black-20:hover{background-color:rgba(0,0,0,.2)}.hover-bg-black-10:focus,.hover-bg-black-10:hover{background-color:rgba(0,0,0,.1)}.hover-bg-black-05:focus,.hover-bg-black-05:hover{background-color:rgba(0,0,0,.05)}.hover-bg-black-025:focus,.hover-bg-black-025:hover{background-color:rgba(0,0,0,.025)}.hover-bg-gray-90:focus,.hover-bg-gray-90:hover{background-color:rgba(89,105,129,.9)}.hover-bg-gray-80:focus,.hover-bg-gray-80:hover{background-color:rgba(89,105,129,.8)}.hover-bg-gray-70:focus,.hover-bg-gray-70:hover{background-color:rgba(89,105,129,.7)}.hover-bg-gray-60:focus,.hover-bg-gray-60:hover{background-color:rgba(89,105,129,.6)}.hover-bg-gray-50:focus,.hover-bg-gray-50:hover{background-color:rgba(89,105,129,.5)}.hover-bg-gray-40:focus,.hover-bg-gray-40:hover{background-color:rgba(89,105,129,.4)}.hover-bg-gray-30:focus,.hover-bg-gray-30:hover{background-color:rgba(89,105,129,.3)}.hover-bg-gray-20:focus,.hover-bg-gray-20:hover{background-color:rgba(89,105,129,.2)}.hover-bg-gray-10:focus,.hover-bg-gray-10:hover{background-color:rgba(89,105,129,.1)}.hover-bg-gray-05:focus,.hover-bg-gray-05:hover{background-color:rgba(89,105,129,.05)}.hover-bg-gray-025:focus,.hover-bg-gray-025:hover{background-color:rgba(89,105,129,.025)}.hover-bg-white-90:focus,.hover-bg-white-90:hover{background-color:hsla(0,0%,100%,.9)}.hover-bg-white-80:focus,.hover-bg-white-80:hover{background-color:hsla(0,0%,100%,.8)}.hover-bg-white-70:focus,.hover-bg-white-70:hover{background-color:hsla(0,0%,100%,.7)}.hover-bg-white-60:focus,.hover-bg-white-60:hover{background-color:hsla(0,0%,100%,.6)}.hover-bg-white-50:focus,.hover-bg-white-50:hover{background-color:hsla(0,0%,100%,.5)}.hover-bg-white-40:focus,.hover-bg-white-40:hover{background-color:hsla(0,0%,100%,.4)}.hover-bg-white-30:focus,.hover-bg-white-30:hover{background-color:hsla(0,0%,100%,.3)}.hover-bg-white-20:focus,.hover-bg-white-20:hover{background-color:hsla(0,0%,100%,.2)}.hover-bg-white-10:focus,.hover-bg-white-10:hover{background-color:hsla(0,0%,100%,.1)}.hover-bg-none:focus,.hover-bg-none:hover{background:none}.hover-bg-transparent:focus,.hover-bg-transparent:hover{background-color:transparent}.hover-bg-black:focus,.hover-bg-black:hover{background-color:#000}.hover-bg-near-black:focus,.hover-bg-near-black:hover{background-color:#323b49}.hover-bg-dark-gray:focus,.hover-bg-dark-gray:hover{background-color:#475366}.hover-bg-mid-gray:focus,.hover-bg-mid-gray:hover{background-color:#56667d}.hover-bg-gray:focus,.hover-bg-gray:hover{background-color:#62738d}.hover-bg-light-gray:focus,.hover-bg-light-gray:hover{background-color:#cfd7e6}.hover-bg-silver:focus,.hover-bg-silver:hover{background-color:#e3e7ef}.hover-bg-light-silver:focus,.hover-bg-light-silver:hover{background-color:#eef1f6}.hover-bg-lightest-silver:focus,.hover-bg-lightest-silver:hover{background-color:#f7f8fb}.hover-bg-near-white:focus,.hover-bg-near-white:hover{background-color:#fbfbfd}.hover-bg-white:focus,.hover-bg-white:hover{background-color:#fff}.hover-bg-dark-purple:focus,.hover-bg-dark-purple:hover{background-color:#4f3074}.hover-bg-purple:focus,.hover-bg-purple:hover{background-color:#79589f}.hover-bg-light-purple:focus,.hover-bg-light-purple:hover{background-color:#a997bf}.hover-bg-lightest-purple:focus,.hover-bg-lightest-purple:hover{background-color:#f7f3fb}.hover-bg-dark-blue:focus,.hover-bg-dark-blue:hover{background-color:#034ca2}.hover-bg-blue:focus,.hover-bg-blue:hover{background-color:#006deb}.hover-bg-light-blue:focus,.hover-bg-light-blue:hover{background-color:#8ebdf1}.hover-bg-lightest-blue:focus,.hover-bg-lightest-blue:hover{background-color:#f6faff}.hover-bg-dark-green:focus,.hover-bg-dark-green:hover{background-color:#066515}.hover-bg-green:focus,.hover-bg-green:hover{background-color:#008700}.hover-bg-light-green:focus,.hover-bg-light-green:hover{background-color:#86cf95}.hover-bg-lightest-green:focus,.hover-bg-lightest-green:hover{background-color:#f8fcf9}.hover-bg-dark-red:focus,.hover-bg-dark-red:hover{background-color:#a70404}.hover-bg-red:focus,.hover-bg-red:hover{background-color:#de0a0a}.hover-bg-light-red:focus,.hover-bg-light-red:hover{background-color:#de7575}.hover-bg-lightest-red:focus,.hover-bg-lightest-red:hover{background-color:#fdf6f6}.hover-bg-dark-orange:focus,.hover-bg-dark-orange:hover{background-color:#832d03}.hover-bg-orange:focus,.hover-bg-orange:hover{background-color:#c74c00}.hover-bg-light-orange:focus,.hover-bg-light-orange:hover{background-color:#fa9f47}.hover-bg-lightest-orange:focus,.hover-bg-lightest-orange:hover{background-color:#fffaf6}.hover-bg-gold:focus,.hover-bg-gold:hover{background-color:#ffb700}.hover-bg-yellow:focus,.hover-bg-yellow:hover{background-color:gold}.hover-bg-light-yellow:focus,.hover-bg-light-yellow:hover{background-color:#fbf1a9}.hover-bg-dark-pink:focus,.hover-bg-dark-pink:hover{background-color:#d5008f}.hover-bg-hot-pink:focus,.hover-bg-hot-pink:hover{background-color:#ff41b4}.hover-bg-pink:focus,.hover-bg-pink:hover{background-color:#ff80cc}.hover-bg-light-pink:focus,.hover-bg-light-pink:hover{background-color:#ffa3d7}.hover-bg-navy:focus,.hover-bg-navy:hover{background-color:#001b44}.hover-bg-washed-blue:focus,.hover-bg-washed-blue:hover{background-color:#f6fffe}.hover-bg-washed-green:focus,.hover-bg-washed-green:hover{background-color:#e8fdf5}.hover-bg-washed-yellow:focus,.hover-bg-washed-yellow:hover{background-color:#fffceb}.hover-bg-washed-red:focus,.hover-bg-washed-red:hover{background-color:#ffdfdf}.bg-center{background-position:50%}.bg-center,.bg-top{background-repeat:no-repeat}.bg-top{background-position:top}.bg-right{background-position:100%}.bg-bottom,.bg-right{background-repeat:no-repeat}.bg-bottom{background-position:bottom}.bg-left{background-repeat:no-repeat;background-position:0}@media screen and (min-width:30em){.bg-center-ns{background-position:50%}.bg-center-ns,.bg-top-ns{background-repeat:no-repeat}.bg-top-ns{background-position:top}.bg-right-ns{background-position:100%}.bg-bottom-ns,.bg-right-ns{background-repeat:no-repeat}.bg-bottom-ns{background-position:bottom}.bg-left-ns{background-repeat:no-repeat;background-position:0}}@media screen and (min-width:30em) and (max-width:60em){.bg-center-m{background-position:50%}.bg-center-m,.bg-top-m{background-repeat:no-repeat}.bg-top-m{background-position:top}.bg-right-m{background-position:100%}.bg-bottom-m,.bg-right-m{background-repeat:no-repeat}.bg-bottom-m{background-position:bottom}.bg-left-m{background-repeat:no-repeat;background-position:0}}@media screen and (min-width:60em){.bg-center-l{background-position:50%}.bg-center-l,.bg-top-l{background-repeat:no-repeat}.bg-top-l{background-position:top}.bg-right-l{background-position:100%}.bg-bottom-l,.bg-right-l{background-repeat:no-repeat}.bg-bottom-l{background-position:bottom}.bg-left-l{background-repeat:no-repeat;background-position:0}}.cover{background-size:cover!important}.contain{background-size:contain!important}.bg--clip{background-clip:border-box!important;background-origin:border-box!important}@media screen and (min-width:30em){.cover-ns{background-size:cover!important}.contain-ns{background-size:contain!important}}@media screen and (min-width:30em) and (max-width:60em){.cover-m{background-size:cover!important}.contain-m{background-size:contain!important}}@media screen and (min-width:60em){.cover-l{background-size:cover!important}.contain-l{background-size:contain!important}}.ba{border-style:solid;border-width:1px}.bt{border-top-style:solid;border-top-width:1px}.br{border-right-style:solid;border-right-width:1px}.bb{border-bottom-style:solid;border-bottom-width:1px}.bl{border-left-style:solid;border-left-width:1px}.bn{border-style:none;border-width:0}@media screen and (min-width:30em){.ba-ns{border-style:solid;border-width:1px}.bt-ns{border-top-style:solid;border-top-width:1px}.br-ns{border-right-style:solid;border-right-width:1px}.bb-ns{border-bottom-style:solid;border-bottom-width:1px}.bl-ns{border-left-style:solid;border-left-width:1px}.bn-ns{border-style:none;border-width:0}}@media screen and (min-width:30em) and (max-width:60em){.ba-m{border-style:solid;border-width:1px}.bt-m{border-top-style:solid;border-top-width:1px}.br-m{border-right-style:solid;border-right-width:1px}.bb-m{border-bottom-style:solid;border-bottom-width:1px}.bl-m{border-left-style:solid;border-left-width:1px}.bn-m{border-style:none;border-width:0}}@media screen and (min-width:60em){.ba-l{border-style:solid;border-width:1px}.bt-l{border-top-style:solid;border-top-width:1px}.br-l{border-right-style:solid;border-right-width:1px}.bb-l{border-bottom-style:solid;border-bottom-width:1px}.bl-l{border-left-style:solid;border-left-width:1px}.bn-l{border-style:none;border-width:0}}.b--black{border-color:#000}.b--near-black{border-color:#323b49}.b--dark-gray{border-color:#475366}.b--mid-gray{border-color:#56667d}.b--gray{border-color:#62738d}.b--light-gray{border-color:#cfd7e6}.b--silver{border-color:#e3e7ef}.b--light-silver{border-color:#eef1f6}.b--near-white{border-color:#fbfbfd}.b--white{border-color:#fff}.b--dark-purple{border-color:#4f3074}.b--purple{border-color:#79589f}.b--light-purple{border-color:#a997bf}.b--lightest-purple{border-color:#f7f3fb}.b--dark-blue{border-color:#034ca2}.b--blue{border-color:#006deb}.b--light-blue{border-color:#8ebdf1}.b--lightest-blue{border-color:#f6faff}.b--dark-green{border-color:#066515}.b--green{border-color:#008700}.b--light-green{border-color:#86cf95}.b--lightest-green{border-color:#f8fcf9}.b--dark-red{border-color:#a70404}.b--red{border-color:#de0a0a}.b--light-red{border-color:#de7575}.b--lightest-red{border-color:#fdf6f6}.b--dark-orange{border-color:#832d03}.b--orange{border-color:#c74c00}.b--light-orange{border-color:#fa9f47}.b--lightest-orange{border-color:#fffaf6}.b--transparent{border-color:transparent}.b--gold{border-color:#ffb700}.b--yellow{border-color:gold}.b--light-yellow{border-color:#fbf1a9}.b--dark-pink{border-color:#d5008f}.b--hot-pink{border-color:#ff41b4}.b--pink{border-color:#ff80cc}.b--light-pink{border-color:#ffa3d7}.b--navy{border-color:#001b44}.b--washed-blue{border-color:#f6fffe}.b--washed-green{border-color:#e8fdf5}.b--washed-yellow{border-color:#fffceb}.b--washed-red{border-color:#ffdfdf}.b--black-90{border-color:rgba(0,0,0,.9)}.b--black-80{border-color:rgba(0,0,0,.8)}.b--black-70{border-color:rgba(0,0,0,.7)}.b--black-60{border-color:rgba(0,0,0,.6)}.b--black-50{border-color:rgba(0,0,0,.5)}.b--black-40{border-color:rgba(0,0,0,.4)}.b--black-30{border-color:rgba(0,0,0,.3)}.b--black-20{border-color:rgba(0,0,0,.2)}.b--black-10{border-color:rgba(0,0,0,.1)}.b--black-05{border-color:rgba(0,0,0,.05)}.b--black-025{border-color:rgba(0,0,0,.025)}.b--black-0125{border-color:rgba(0,0,0,.0125)}.b--gray-90{border-color:rgba(89,105,129,.9)}.b--gray-80{border-color:rgba(89,105,129,.8)}.b--gray-70{border-color:rgba(89,105,129,.7)}.b--gray-60{border-color:rgba(89,105,129,.6)}.b--gray-50{border-color:rgba(89,105,129,.5)}.b--gray-40{border-color:rgba(89,105,129,.4)}.b--gray-30{border-color:rgba(89,105,129,.3)}.b--gray-20{border-color:rgba(89,105,129,.2)}.b--gray-10{border-color:rgba(89,105,129,.1)}.b--gray-05{border-color:rgba(89,105,129,.05)}.b--gray-025{border-color:rgba(89,105,129,.025)}.b--gray-0125{border-color:rgba(89,105,129,.0125)}.b--white-90{border-color:hsla(0,0%,100%,.9)}.b--white-80{border-color:hsla(0,0%,100%,.8)}.b--white-70{border-color:hsla(0,0%,100%,.7)}.b--white-60{border-color:hsla(0,0%,100%,.6)}.b--white-50{border-color:hsla(0,0%,100%,.5)}.b--white-40{border-color:hsla(0,0%,100%,.4)}.b--white-30{border-color:hsla(0,0%,100%,.3)}.b--white-20{border-color:hsla(0,0%,100%,.2)}.b--white-10{border-color:hsla(0,0%,100%,.1)}.hover-b--black:focus,.hover-b--black:hover{border-color:#000}.hover-b--near-black:focus,.hover-b--near-black:hover{border-color:#323b49}.hover-b--dark-gray:focus,.hover-b--dark-gray:hover{border-color:#475366}.hover-b--mid-gray:focus,.hover-b--mid-gray:hover{border-color:#56667d}.hover-b--gray:focus,.hover-b--gray:hover{border-color:#62738d}.hover-b--light-gray:focus,.hover-b--light-gray:hover{border-color:#cfd7e6}.hover-b--silver:focus,.hover-b--silver:hover{border-color:#e3e7ef}.hover-b--light-silver:focus,.hover-b--light-silver:hover{border-color:#eef1f6}.hover-b--near-white:focus,.hover-b--near-white:hover{border-color:#fbfbfd}.hover-b--white:focus,.hover-b--white:hover{border-color:#fff}.hover-b--dark-purple:focus,.hover-b--dark-purple:hover{border-color:#4f3074}.hover-b--purple:focus,.hover-b--purple:hover{border-color:#79589f}.hover-b--light-purple:focus,.hover-b--light-purple:hover{border-color:#a997bf}.hover-b--lightest-purple:focus,.hover-b--lightest-purple:hover{border-color:#f7f3fb}.hover-b--dark-blue:focus,.hover-b--dark-blue:hover{border-color:#034ca2}.hover-b--blue:focus,.hover-b--blue:hover{border-color:#006deb}.hover-b--light-blue:focus,.hover-b--light-blue:hover{border-color:#8ebdf1}.hover-b--lightest-blue:focus,.hover-b--lightest-blue:hover{border-color:#f6faff}.hover-b--dark-green:focus,.hover-b--dark-green:hover{border-color:#066515}.hover-b--green:focus,.hover-b--green:hover{border-color:#008700}.hover-b--light-green:focus,.hover-b--light-green:hover{border-color:#86cf95}.hover-b--lightest-green:focus,.hover-b--lightest-green:hover{border-color:#f8fcf9}.hover-b--dark-red:focus,.hover-b--dark-red:hover{border-color:#a70404}.hover-b--red:focus,.hover-b--red:hover{border-color:#de0a0a}.hover-b--light-red:focus,.hover-b--light-red:hover{border-color:#de7575}.hover-b--lightest-red:focus,.hover-b--lightest-red:hover{border-color:#fdf6f6}.hover-b--dark-orange:focus,.hover-b--dark-orange:hover{border-color:#832d03}.hover-b--orange:focus,.hover-b--orange:hover{border-color:#c74c00}.hover-b--light-orange:focus,.hover-b--light-orange:hover{border-color:#fa9f47}.hover-b--lightest-orange:focus,.hover-b--lightest-orange:hover{border-color:#fffaf6}.hover-b--transparent:focus,.hover-b--transparent:hover{border-color:transparent}.hover-b--gold:focus,.hover-b--gold:hover{border-color:#ffb700}.hover-b--yellow:focus,.hover-b--yellow:hover{border-color:gold}.hover-b--light-yellow:focus,.hover-b--light-yellow:hover{border-color:#fbf1a9}.hover-b--dark-pink:focus,.hover-b--dark-pink:hover{border-color:#d5008f}.hover-b--hot-pink:focus,.hover-b--hot-pink:hover{border-color:#ff41b4}.hover-b--pink:focus,.hover-b--pink:hover{border-color:#ff80cc}.hover-b--light-pink:focus,.hover-b--light-pink:hover{border-color:#ffa3d7}.hover-b--navy:focus,.hover-b--navy:hover{border-color:#001b44}.hover-b--washed-blue:focus,.hover-b--washed-blue:hover{border-color:#f6fffe}.hover-b--washed-green:focus,.hover-b--washed-green:hover{border-color:#e8fdf5}.hover-b--washed-yellow:focus,.hover-b--washed-yellow:hover{border-color:#fffceb}.hover-b--washed-red:focus,.hover-b--washed-red:hover{border-color:#ffdfdf}.hover-b--black-90:focus,.hover-b--black-90:hover{border-color:rgba(0,0,0,.9)}.hover-b--black-80:focus,.hover-b--black-80:hover{border-color:rgba(0,0,0,.8)}.hover-b--black-70:focus,.hover-b--black-70:hover{border-color:rgba(0,0,0,.7)}.hover-b--black-60:focus,.hover-b--black-60:hover{border-color:rgba(0,0,0,.6)}.hover-b--black-50:focus,.hover-b--black-50:hover{border-color:rgba(0,0,0,.5)}.hover-b--black-40:focus,.hover-b--black-40:hover{border-color:rgba(0,0,0,.4)}.hover-b--black-30:focus,.hover-b--black-30:hover{border-color:rgba(0,0,0,.3)}.hover-b--black-20:focus,.hover-b--black-20:hover{border-color:rgba(0,0,0,.2)}.hover-b--black-10:focus,.hover-b--black-10:hover{border-color:rgba(0,0,0,.1)}.hover-b--black-05:focus,.hover-b--black-05:hover{border-color:rgba(0,0,0,.05)}.hover-b--black-025:focus,.hover-b--black-025:hover{border-color:rgba(0,0,0,.025)}.hover-b--black-0125:focus,.hover-b--black-0125:hover{border-color:rgba(0,0,0,.0125)}.hover-b--gray-90:focus,.hover-b--gray-90:hover{border-color:rgba(89,105,129,.9)}.hover-b--gray-80:focus,.hover-b--gray-80:hover{border-color:rgba(89,105,129,.8)}.hover-b--gray-70:focus,.hover-b--gray-70:hover{border-color:rgba(89,105,129,.7)}.hover-b--gray-60:focus,.hover-b--gray-60:hover{border-color:rgba(89,105,129,.6)}.hover-b--gray-50:focus,.hover-b--gray-50:hover{border-color:rgba(89,105,129,.5)}.hover-b--gray-40:focus,.hover-b--gray-40:hover{border-color:rgba(89,105,129,.4)}.hover-b--gray-30:focus,.hover-b--gray-30:hover{border-color:rgba(89,105,129,.3)}.hover-b--gray-20:focus,.hover-b--gray-20:hover{border-color:rgba(89,105,129,.2)}.hover-b--gray-10:focus,.hover-b--gray-10:hover{border-color:rgba(89,105,129,.1)}.hover-b--gray-05:focus,.hover-b--gray-05:hover{border-color:rgba(89,105,129,.05)}.hover-b--gray-025:focus,.hover-b--gray-025:hover{border-color:rgba(89,105,129,.025)}.hover-b--gray-0125:focus,.hover-b--gray-0125:hover{border-color:rgba(89,105,129,.0125)}.hover-b--white-90:focus,.hover-b--white-90:hover{border-color:hsla(0,0%,100%,.9)}.hover-b--white-80:focus,.hover-b--white-80:hover{border-color:hsla(0,0%,100%,.8)}.hover-b--white-70:focus,.hover-b--white-70:hover{border-color:hsla(0,0%,100%,.7)}.hover-b--white-60:focus,.hover-b--white-60:hover{border-color:hsla(0,0%,100%,.6)}.hover-b--white-50:focus,.hover-b--white-50:hover{border-color:hsla(0,0%,100%,.5)}.hover-b--white-40:focus,.hover-b--white-40:hover{border-color:hsla(0,0%,100%,.4)}.hover-b--white-30:focus,.hover-b--white-30:hover{border-color:hsla(0,0%,100%,.3)}.hover-b--white-20:focus,.hover-b--white-20:hover{border-color:hsla(0,0%,100%,.2)}.hover-b--white-10:focus,.hover-b--white-10:hover{border-color:hsla(0,0%,100%,.1)}.br0{border-radius:0}.br1{border-radius:4px}.br2{border-radius:6px}.br3{border-radius:8px}.br4{border-radius:13px}.br-100{border-radius:100%}.br-pill{border-radius:9999px}.br--bottom{border-top-left-radius:0;border-top-right-radius:0}.br--top{border-bottom-right-radius:0}.br--right,.br--top{border-bottom-left-radius:0}.br--right{border-top-left-radius:0}.br--left,.br--reset{border-top-right-radius:0;border-bottom-right-radius:0}.br--reset{border-top-left-radius:0;border-bottom-left-radius:0}@media screen and (min-width:30em){.br0-ns{border-radius:0}.br1-ns{border-radius:4px}.br2-ns{border-radius:6px}.br3-ns{border-radius:8px}.br4-ns{border-radius:13px}.br-100-ns{border-radius:100%}.br-pill-ns{border-radius:9999px}.br--bottom-ns{border-top-left-radius:0;border-top-right-radius:0}.br--top-ns{border-bottom-right-radius:0}.br--right-ns,.br--top-ns{border-bottom-left-radius:0}.br--right-ns{border-top-left-radius:0}.br--left-ns,.br--reset-ns{border-top-right-radius:0;border-bottom-right-radius:0}.br--reset-ns{border-top-left-radius:0;border-bottom-left-radius:0}}@media screen and (min-width:30em) and (max-width:60em){.br0-m{border-radius:0}.br1-m{border-radius:4px}.br2-m{border-radius:6px}.br3-m{border-radius:8px}.br4-m{border-radius:13px}.br-100-m{border-radius:100%}.br-pill-m{border-radius:9999px}.br--bottom-m{border-top-left-radius:0;border-top-right-radius:0}.br--top-m{border-bottom-right-radius:0}.br--right-m,.br--top-m{border-bottom-left-radius:0}.br--right-m{border-top-left-radius:0}.br--left-m,.br--reset-m{border-top-right-radius:0;border-bottom-right-radius:0}.br--reset-m{border-top-left-radius:0;border-bottom-left-radius:0}}@media screen and (min-width:60em){.br0-l{border-radius:0}.br1-l{border-radius:4px}.br2-l{border-radius:6px}.br3-l{border-radius:8px}.br4-l{border-radius:13px}.br-100-l{border-radius:100%}.br-pill-l{border-radius:9999px}.br--bottom-l{border-radius-top-left:0;border-radius-top-right:0}.br--top-l{border-bottom-right-radius:0}.br--right-l,.br--top-l{border-bottom-left-radius:0}.br--right-l{border-top-left-radius:0}.br--left-l,.br--reset-l{border-top-right-radius:0;border-bottom-right-radius:0}.br--reset-l{border-top-left-radius:0;border-bottom-left-radius:0}}.b--dotted{border-style:dotted}.b--dashed{border-style:dashed}.b--solid{border-style:solid}.b--none{border-style:none}@media screen and (min-width:30em){.b--dotted-ns{border-style:dotted}.b--dashed-ns{border-style:dashed}.b--solid-ns{border-style:solid}.b--none-ns{border-style:none}}@media screen and (min-width:30em) and (max-width:60em){.b--dotted-m{border-style:dotted}.b--dashed-m{border-style:dashed}.b--solid-m{border-style:solid}.b--none-m{border-style:none}}@media screen and (min-width:60em){.b--dotted-l{border-style:dotted}.b--dashed-l{border-style:dashed}.b--solid-l{border-style:solid}.b--none-l{border-style:none}}.bw0{border-width:0}.bw1{border-width:1px}.bw2{border-width:3px}.bw3{border-width:5px}.bw4{border-width:10px}.bw5{border-width:20px}.bt-0{border-top-width:0}.br-0{border-right-width:0}.bb-0{border-bottom-width:0}.bl-0{border-left-width:0}@media screen and (min-width:30em){.bw0-ns{border-width:0}.bw1-ns{border-width:1px}.bw2-ns{border-width:3px}.bw3-ns{border-width:5px}.bw4-ns{border-width:10px}.bw5-ns{border-width:20px}.bt-0-ns{border-top-width:0}.br-0-ns{border-right-width:0}.bb-0-ns{border-bottom-width:0}.bl-0-ns{border-left-width:0}}@media screen and (min-width:30em) and (max-width:60em){.bw0-m{border-width:0}.bw1-m{border-width:1px}.bw2-m{border-width:3px}.bw3-m{border-width:5px}.bw4-m{border-width:10px}.bw5-m{border-width:20px}.bt-0-m{border-top-width:0}.br-0-m{border-right-width:0}.bb-0-m{border-bottom-width:0}.bl-0-m{border-left-width:0}}@media screen and (min-width:60em){.bw0-l{border-width:0}.bw1-l{border-width:1px}.bw2-l{border-width:3px}.bw3-l{border-width:5px}.bw4-l{border-width:10px}.bw5-l{border-width:20px}.bt-0-l{border-top-width:0}.br-0-l{border-right-width:0}.bb-0-l{border-bottom-width:0}.bl-0-l{border-left-width:0}}.border-box,article,body,button,code,dd,div,dl,dt,fieldset,footer,form,header,html,input:not([type]),input[type=email],input[type=number],input[type=password],input[type=tel],input[type=text],input[type=url],li,main,ol,p,pre,section,textarea,ul{box-sizing:border-box}.cf:after,.cf:before{content:" ";display:table}.cf:after{clear:both}.cf{*zoom:1}.cl{clear:left}.cr{clear:right}.cb{clear:both}.cn{clear:none}@media screen and (min-width:30em){.cl-ns{clear:left}.cr-ns{clear:right}.cb-ns{clear:both}.cn-ns{clear:none}}@media screen and (min-width:30em) and (max-width:60em){.cl-m{clear:left}.cr-m{clear:right}.cb-m{clear:both}.cn-m{clear:none}}@media screen and (min-width:60em){.cl-l{clear:left}.cr-l{clear:right}.cb-l{clear:both}.cn-l{clear:none}}.pre{overflow-x:auto;overflow-y:hidden;overflow:scroll}.top-0{top:0}.right-0{right:0}.bottom-0{bottom:0}.left-0{left:0}.top-1{top:1rem}.right-1{right:1rem}.bottom-1{bottom:1rem}.left-1{left:1rem}.top-2{top:2rem}.right-2{right:2rem}.bottom-2{bottom:2rem}.left-2{left:2rem}.top--1{top:-1rem}.right--1{right:-1rem}.bottom--1{bottom:-1rem}.left--1{left:-1rem}.top--2{top:-2rem}.right--2{right:-2rem}.bottom--2{bottom:-2rem}.left--2{left:-2rem}.absolute--fill{top:0;right:0;bottom:0;left:0}@media screen and (min-width:30em){.top-0-ns{top:0}.left-0-ns{left:0}.right-0-ns{right:0}.bottom-0-ns{bottom:0}.top-1-ns{top:1rem}.left-1-ns{left:1rem}.right-1-ns{right:1rem}.bottom-1-ns{bottom:1rem}.top-2-ns{top:2rem}.left-2-ns{left:2rem}.right-2-ns{right:2rem}.bottom-2-ns{bottom:2rem}.top--1-ns{top:-1rem}.right--1-ns{right:-1rem}.bottom--1-ns{bottom:-1rem}.left--1-ns{left:-1rem}.top--2-ns{top:-2rem}.right--2-ns{right:-2rem}.bottom--2-ns{bottom:-2rem}.left--2-ns{left:-2rem}.absolute--fill-ns{top:0;right:0;bottom:0;left:0}}@media screen and (min-width:30em) and (max-width:60em){.top-0-m{top:0}.left-0-m{left:0}.right-0-m{right:0}.bottom-0-m{bottom:0}.top-1-m{top:1rem}.left-1-m{left:1rem}.right-1-m{right:1rem}.bottom-1-m{bottom:1rem}.top-2-m{top:2rem}.left-2-m{left:2rem}.right-2-m{right:2rem}.bottom-2-m{bottom:2rem}.top--1-m{top:-1rem}.right--1-m{right:-1rem}.bottom--1-m{bottom:-1rem}.left--1-m{left:-1rem}.top--2-m{top:-2rem}.right--2-m{right:-2rem}.bottom--2-m{bottom:-2rem}.left--2-m{left:-2rem}.absolute--fill-m{top:0;right:0;bottom:0;left:0}}@media screen and (min-width:60em){.top-0-l{top:0}.left-0-l{left:0}.right-0-l{right:0}.bottom-0-l{bottom:0}.top-1-l{top:1rem}.left-1-l{left:1rem}.right-1-l{right:1rem}.bottom-1-l{bottom:1rem}.top-2-l{top:2rem}.left-2-l{left:2rem}.right-2-l{right:2rem}.bottom-2-l{bottom:2rem}.top--1-l{top:-1rem}.right--1-l{right:-1rem}.bottom--1-l{bottom:-1rem}.left--1-l{left:-1rem}.top--2-l{top:-2rem}.right--2-l{right:-2rem}.bottom--2-l{bottom:-2rem}.left--2-l{left:-2rem}.absolute--fill-l{top:0;right:0;bottom:0;left:0}}.cursor-alias{cursor:alias}.cursor-all-scroll{cursor:all-scroll}.cursor-auto{cursor:auto}.cursor-cell{cursor:cell}.cursor-context-menu{cursor:context-menu}.cursor-col-resize{cursor:col-resize}.cursor-copy{cursor:copy}.cursor-crosshair{cursor:crosshair}.cursor-default{cursor:default}.cursor-e-resize{cursor:e-resize}.cursor-ew-resize{cursor:ew-resize}.cursor-grab{cursor:-webkit-grab;cursor:grab}.cursor-grabbing{cursor:-webkit-grabbing;cursor:grabbing}.cursor-help{cursor:help}.cursor-move{cursor:move}.cursor-n-resize{cursor:n-resize}.cursor-ne-resize{cursor:ne-resize}.cursor-nesw-resize{cursor:nesw-resize}.cursor-ns-resize{cursor:ns-resize}.cursor-nw-resize{cursor:nw-resize}.cursor-nwse-resize{cursor:nwse-resize}.cursor-no-drop{cursor:no-drop}.cursor-none{cursor:none}.cursor-not-allowed{cursor:not-allowed}.cursor-hand,.cursor-pointer{cursor:pointer}.cursor-progress{cursor:progress}.cursor-row-resize{cursor:row-resize}.cursor-s-resize{cursor:s-resize}.cursor-se-resize{cursor:se-resize}.cursor-sw-resize{cursor:sw-resize}.cursor-text{cursor:text}.cursor-URL{cursor:URL}.cursor-vertical-text{cursor:vertical-text}.cursor-w-resize{cursor:w-resize}.cursor-wait{cursor:wait}.cursor-zoom-in{cursor:zoom-in}.cursor-zoom-out{cursor:zoom-out}.cursor-initial{cursor:auto}.cursor-inherit{cursor:inherit}.dn{display:none}.di{display:inline}.db{display:block}.dib{display:inline-block}.dit{display:inline-table}.dt{display:table}.dtc{display:table-cell}.dt-row{display:table-row}.dt-row-group{display:table-row-group}.dt-column{display:table-column}.dt-column-group{display:table-column-group}.dt--fixed{table-layout:fixed;width:100%}@media screen and (min-width:30em){.dn-ns{display:none}.di-ns{display:inline}.db-ns{display:block}.dib-ns{display:inline-block}.dit-ns{display:inline-table}.dt-ns{display:table}.dtc-ns{display:table-cell}.dt-row-ns{display:table-row}.dt-row-group-ns{display:table-row-group}.dt-column-ns{display:table-column}.dt-column-group-ns{display:table-column-group}.dt--fixed-ns{table-layout:fixed;width:100%}}@media screen and (min-width:30em) and (max-width:60em){.dn-m{display:none}.di-m{display:inline}.db-m{display:block}.dib-m{display:inline-block}.dit-m{display:inline-table}.dt-m{display:table}.dtc-m{display:table-cell}.dt-row-m{display:table-row}.dt-row-group-m{display:table-row-group}.dt-column-m{display:table-column}.dt-column-group-m{display:table-column-group}.dt--fixed-m{table-layout:fixed;width:100%}}@media screen and (min-width:60em){.dn-l{display:none}.di-l{display:inline}.db-l{display:block}.dib-l{display:inline-block}.dit-l{display:inline-table}.dt-l{display:table}.dtc-l{display:table-cell}.dt-row-l{display:table-row}.dt-row-group-l{display:table-row-group}.dt-column-l{display:table-column}.dt-column-group-l{display:table-column-group}.dt--fixed-l{table-layout:fixed;width:100%}}.fill-black{fill:#000}.fill-near-black{fill:#323b49}.fill-dark-gray{fill:#475366}.fill-mid-gray{fill:#56667d}.fill-gray{fill:#62738d}.fill-silver{fill:#e3e7ef}.fill-light-silver{fill:#eef1f6}.fill-lightest-silver{fill:#f7f8fb}.fill-light-gray{fill:#cfd7e6}.fill-near-white{fill:#fbfbfd}.fill-white{fill:#fff}.fill-transparent{fill:transparent}.fill-dark-red{fill:#a70404}.fill-red{fill:#de0a0a}.fill-light-red{fill:#de7575}.fill-orange{fill:#c74c00}.fill-gold{fill:#ffb700}.fill-yellow{fill:gold}.fill-light-yellow{fill:#fbf1a9}.fill-purple{fill:#79589f}.fill-light-purple{fill:#a997bf}.fill-dark-pink{fill:#d5008f}.fill-hot-pink{fill:#ff41b4}.fill-pink{fill:#ff80cc}.fill-light-pink{fill:#ffa3d7}.fill-dark-green{fill:#066515}.fill-green{fill:#008700}.fill-light-green{fill:#86cf95}.fill-navy{fill:#001b44}.fill-dark-blue{fill:#034ca2}.fill-blue{fill:#006deb}.fill-light-blue{fill:#8ebdf1}.fill-lightest-blue{fill:#f6faff}.fill-washed-blue{fill:#f6fffe}.fill-washed-green{fill:#e8fdf5}.fill-washed-yellow{fill:#fffceb}.fill-washed-red{fill:#ffdfdf}.hover-fill-black:hover{fill:#000}.hover-fill-near-black:hover{fill:#323b49}.hover-fill-dark-gray:hover{fill:#475366}.hover-fill-mid-gray:hover{fill:#56667d}.hover-fill-gray:hover{fill:#62738d}.hover-fill-silver:hover{fill:#e3e7ef}.hover-fill-light-silver:hover{fill:#eef1f6}.hover-fill-lightest-silver:hover{fill:#f7f8fb}.hover-fill-light-gray:hover{fill:#cfd7e6}.hover-fill-near-white:hover{fill:#fbfbfd}.hover-fill-white:hover{fill:#fff}.hover-fill-transparent:hover{fill:transparent}.hover-fill-dark-red:hover{fill:#a70404}.hover-fill-red:hover{fill:#de0a0a}.hover-fill-light-red:hover{fill:#de7575}.hover-fill-orange:hover{fill:#c74c00}.hover-fill-gold:hover{fill:#ffb700}.hover-fill-yellow:hover{fill:gold}.hover-fill-light-yellow:hover{fill:#fbf1a9}.hover-fill-purple:hover{fill:#79589f}.hover-fill-light-purple:hover{fill:#a997bf}.hover-fill-dark-pink:hover{fill:#d5008f}.hover-fill-hot-pink:hover{fill:#ff41b4}.hover-fill-pink:hover{fill:#ff80cc}.hover-fill-light-pink:hover{fill:#ffa3d7}.hover-fill-dark-green:hover{fill:#066515}.hover-fill-green:hover{fill:#008700}.hover-fill-light-green:hover{fill:#86cf95}.hover-fill-navy:hover{fill:#001b44}.hover-fill-dark-blue:hover{fill:#034ca2}.hover-fill-blue:hover{fill:#006deb}.hover-fill-light-blue:hover{fill:#8ebdf1}.hover-fill-lightest-blue:hover{fill:#f6faff}.hover-fill-washed-blue:hover{fill:#f6fffe}.hover-fill-washed-green:hover{fill:#e8fdf5}.hover-fill-washed-yellow:hover{fill:#fffceb}.hover-fill-washed-red:hover{fill:#ffdfdf}.fill-o-05{fill-opacity:.05}.fill-o-10{fill-opacity:.1}.fill-o-20{fill-opacity:.2}.fill-o-25{fill-opacity:.25}.fill-o-30{fill-opacity:.3}.fill-o-40{fill-opacity:.4}.fill-o-50{fill-opacity:.5}.fill-o-60{fill-opacity:.6}.fill-o-75{fill-opacity:.75}.fill-o-80{fill-opacity:.8}.fill-o-90{fill-opacity:.9}.hover-fill-o-05:hover{fill-opacity:.05}.hover-fill-o-10:hover{fill-opacity:.1}.hover-fill-o-20:hover{fill-opacity:.2}.hover-fill-o-25:hover{fill-opacity:.25}.hover-fill-o-30:hover{fill-opacity:.3}.hover-fill-o-40:hover{fill-opacity:.4}.hover-fill-o-50:hover{fill-opacity:.5}.hover-fill-o-60:hover{fill-opacity:.6}.hover-fill-o-75:hover{fill-opacity:.75}.hover-fill-o-80:hover{fill-opacity:.8}.hover-fill-o-90:hover{fill-opacity:.9}.fill-nonzero{fill-rule:nonzero}.fill-evenodd{fill-rule:evenodd}.flex{display:-ms-flexbox;display:flex}.inline-flex{display:-ms-inline-flexbox;display:inline-flex}.flex-column{-ms-flex-direction:column;flex-direction:column}.flex-row{-ms-flex-direction:row;flex-direction:row}.flex-wrap{-ms-flex-wrap:wrap;flex-wrap:wrap}.flex-nowrap{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse;flex-wrap:wrap-reverse}.flex-column-reverse{-ms-flex-direction:column-reverse;flex-direction:column-reverse}.flex-row-reverse{-ms-flex-direction:row-reverse;flex-direction:row-reverse}.items-start{-ms-flex-align:start;align-items:flex-start}.items-end{-ms-flex-align:end;align-items:flex-end}.items-center{-ms-flex-align:center;align-items:center}.items-baseline{-ms-flex-align:baseline;align-items:baseline}.items-stretch{-ms-flex-align:stretch;align-items:stretch}.self-start{-ms-flex-item-align:start;align-self:flex-start}.self-end{-ms-flex-item-align:end;align-self:flex-end}.self-center{-ms-flex-item-align:center;-ms-grid-row-align:center;align-self:center}.self-baseline{-ms-flex-item-align:baseline;align-self:baseline}.self-stretch{-ms-flex-item-align:stretch;-ms-grid-row-align:stretch;align-self:stretch}.justify-start{-ms-flex-pack:start;justify-content:flex-start}.justify-end{-ms-flex-pack:end;justify-content:flex-end}.justify-center{-ms-flex-pack:center;justify-content:center}.justify-between{-ms-flex-pack:justify;justify-content:space-between}.justify-around{-ms-flex-pack:distribute;justify-content:space-around}.content-start{-ms-flex-line-pack:start;align-content:flex-start}.content-end{-ms-flex-line-pack:end;align-content:flex-end}.content-center{-ms-flex-line-pack:center;align-content:center}.content-between{-ms-flex-line-pack:justify;align-content:space-between}.content-around{-ms-flex-line-pack:distribute;align-content:space-around}.content-stretch{-ms-flex-line-pack:stretch;align-content:stretch}.flex-1{-ms-flex:1;flex:1}.flex-2{-ms-flex:2;flex:2}.flex-3{-ms-flex:3;flex:3}.flex-4{-ms-flex:4;flex:4}.flex-5{-ms-flex:5;flex:5}.flex-6{-ms-flex:6;flex:6}.flex-7{-ms-flex:7;flex:7}.flex-8{-ms-flex:8;flex:8}.flex-9{-ms-flex:9;flex:9}.flex-auto{-ms-flex:1 1 auto;flex:1 1 auto;min-width:0;min-height:0}.flex-equal{-ms-flex-positive:1;flex-grow:1;-ms-flex-preferred-size:0;flex-basis:0}.flex-none{-ms-flex:none;flex:none}.flex-grow-0{-ms-flex-positive:0;flex-grow:0}.flex-grow-1{-ms-flex-positive:1;flex-grow:1}.flex-shrink-0{-ms-flex-negative:0;flex-shrink:0}.flex-shrink-1{-ms-flex-negative:1;flex-shrink:1}.order-0{-ms-flex-order:0;order:0}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-last{-ms-flex-order:99999;order:99999}@media screen and (min-width:30em){.flex-ns{display:-ms-flexbox;display:flex}.inline-flex-ns{display:-ms-inline-flexbox;display:inline-flex}.flex-column-ns{-ms-flex-direction:column;flex-direction:column}.flex-row-ns{-ms-flex-direction:row;flex-direction:row}.flex-wrap-ns{-ms-flex-wrap:wrap;flex-wrap:wrap}.flex-nowrap-ns{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.flex-wrap-reverse-ns{-ms-flex-wrap:wrap-reverse;flex-wrap:wrap-reverse}.flex-column-reverse-ns{-ms-flex-direction:column-reverse;flex-direction:column-reverse}.flex-row-reverse-ns{-ms-flex-direction:row-reverse;flex-direction:row-reverse}.items-start-ns{-ms-flex-align:start;align-items:flex-start}.items-end-ns{-ms-flex-align:end;align-items:flex-end}.items-center-ns{-ms-flex-align:center;align-items:center}.items-baseline-ns{-ms-flex-align:baseline;align-items:baseline}.items-stretch-ns{-ms-flex-align:stretch;align-items:stretch}.self-start-ns{-ms-flex-item-align:start;align-self:flex-start}.self-end-ns{-ms-flex-item-align:end;align-self:flex-end}.self-center-ns{-ms-flex-item-align:center;-ms-grid-row-align:center;align-self:center}.self-baseline-ns{-ms-flex-item-align:baseline;align-self:baseline}.self-stretch-ns{-ms-flex-item-align:stretch;-ms-grid-row-align:stretch;align-self:stretch}.justify-start-ns{-ms-flex-pack:start;justify-content:flex-start}.justify-end-ns{-ms-flex-pack:end;justify-content:flex-end}.justify-center-ns{-ms-flex-pack:center;justify-content:center}.justify-between-ns{-ms-flex-pack:justify;justify-content:space-between}.justify-around-ns{-ms-flex-pack:distribute;justify-content:space-around}.content-start-ns{-ms-flex-line-pack:start;align-content:flex-start}.content-end-ns{-ms-flex-line-pack:end;align-content:flex-end}.content-center-ns{-ms-flex-line-pack:center;align-content:center}.content-between-ns{-ms-flex-line-pack:justify;align-content:space-between}.content-around-ns{-ms-flex-line-pack:distribute;align-content:space-around}.content-stretch-ns{-ms-flex-line-pack:stretch;align-content:stretch}.flex-1-ns{-ms-flex:1;flex:1}.flex-2-ns{-ms-flex:2;flex:2}.flex-3-ns{-ms-flex:3;flex:3}.flex-4-ns{-ms-flex:4;flex:4}.flex-5-ns{-ms-flex:5;flex:5}.flex-6-ns{-ms-flex:6;flex:6}.flex-7-ns{-ms-flex:7;flex:7}.flex-8-ns{-ms-flex:8;flex:8}.flex-9-ns{-ms-flex:9;flex:9}.flex-auto-ns{-ms-flex:1 1 auto;flex:1 1 auto;min-width:0;min-height:0}.flex-none-ns{-ms-flex:none;flex:none}.flex-grow-0-ns{-ms-flex-positive:0;flex-grow:0}.flex-grow-1-ns{-ms-flex-positive:1;flex-grow:1}.flex-shrink-0-ns{-ms-flex-negative:0;flex-shrink:0}.flex-shrink-1-ns{-ms-flex-negative:1;flex-shrink:1}.order-0-ns{-ms-flex-order:0;order:0}.order-1-ns{-ms-flex-order:1;order:1}.order-2-ns{-ms-flex-order:2;order:2}.order-3-ns{-ms-flex-order:3;order:3}.order-4-ns{-ms-flex-order:4;order:4}.order-5-ns{-ms-flex-order:5;order:5}.order-6-ns{-ms-flex-order:6;order:6}.order-7-ns{-ms-flex-order:7;order:7}.order-8-ns{-ms-flex-order:8;order:8}.order-last-ns{-ms-flex-order:99999;order:99999}}@media screen and (min-width:30em) and (max-width:60em){.flex-m{display:-ms-flexbox;display:flex}.inline-flex-m{display:-ms-inline-flexbox;display:inline-flex}.flex-column-m{-ms-flex-direction:column;flex-direction:column}.flex-row-m{-ms-flex-direction:row;flex-direction:row}.flex-wrap-m{-ms-flex-wrap:wrap;flex-wrap:wrap}.flex-nowrap-m{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.flex-wrap-reverse-m{-ms-flex-wrap:wrap-reverse;flex-wrap:wrap-reverse}.flex-column-reverse-m{-ms-flex-direction:column-reverse;flex-direction:column-reverse}.flex-row-reverse-m{-ms-flex-direction:row-reverse;flex-direction:row-reverse}.items-start-m{-ms-flex-align:start;align-items:flex-start}.items-end-m{-ms-flex-align:end;align-items:flex-end}.items-center-m{-ms-flex-align:center;align-items:center}.items-baseline-m{-ms-flex-align:baseline;align-items:baseline}.items-stretch-m{-ms-flex-align:stretch;align-items:stretch}.self-start-m{-ms-flex-item-align:start;align-self:flex-start}.self-end-m{-ms-flex-item-align:end;align-self:flex-end}.self-center-m{-ms-flex-item-align:center;-ms-grid-row-align:center;align-self:center}.self-baseline-m{-ms-flex-item-align:baseline;align-self:baseline}.self-stretch-m{-ms-flex-item-align:stretch;-ms-grid-row-align:stretch;align-self:stretch}.justify-start-m{-ms-flex-pack:start;justify-content:flex-start}.justify-end-m{-ms-flex-pack:end;justify-content:flex-end}.justify-center-m{-ms-flex-pack:center;justify-content:center}.justify-between-m{-ms-flex-pack:justify;justify-content:space-between}.justify-around-m{-ms-flex-pack:distribute;justify-content:space-around}.content-start-m{-ms-flex-line-pack:start;align-content:flex-start}.content-end-m{-ms-flex-line-pack:end;align-content:flex-end}.content-center-m{-ms-flex-line-pack:center;align-content:center}.content-between-m{-ms-flex-line-pack:justify;align-content:space-between}.content-around-m{-ms-flex-line-pack:distribute;align-content:space-around}.content-stretch-m{-ms-flex-line-pack:stretch;align-content:stretch}.flex-1-m{-ms-flex:1;flex:1}.flex-2-m{-ms-flex:2;flex:2}.flex-3-m{-ms-flex:3;flex:3}.flex-4-m{-ms-flex:4;flex:4}.flex-5-m{-ms-flex:5;flex:5}.flex-6-m{-ms-flex:6;flex:6}.flex-7-m{-ms-flex:7;flex:7}.flex-8-m{-ms-flex:8;flex:8}.flex-9-m{-ms-flex:9;flex:9}.flex-auto-m{-ms-flex:1 1 auto;flex:1 1 auto;min-width:0;min-height:0}.flex-none-m{-ms-flex:none;flex:none}.flex-grow-0-m{-ms-flex-positive:0;flex-grow:0}.flex-grow-1-m{-ms-flex-positive:1;flex-grow:1}.flex-shrink-0-m{-ms-flex-negative:0;flex-shrink:0}.flex-shrink-1-m{-ms-flex-negative:1;flex-shrink:1}.order-0-m{-ms-flex-order:0;order:0}.order-1-m{-ms-flex-order:1;order:1}.order-2-m{-ms-flex-order:2;order:2}.order-3-m{-ms-flex-order:3;order:3}.order-4-m{-ms-flex-order:4;order:4}.order-5-m{-ms-flex-order:5;order:5}.order-6-m{-ms-flex-order:6;order:6}.order-7-m{-ms-flex-order:7;order:7}.order-8-m{-ms-flex-order:8;order:8}.order-last-m{-ms-flex-order:99999;order:99999}}@media screen and (min-width:60em){.flex-l{display:-ms-flexbox;display:flex}.inline-flex-l{display:-ms-inline-flexbox;display:inline-flex}.flex-column-l{-ms-flex-direction:column;flex-direction:column}.flex-row-l{-ms-flex-direction:row;flex-direction:row}.flex-wrap-l{-ms-flex-wrap:wrap;flex-wrap:wrap}.flex-nowrap-l{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.flex-wrap-reverse-l{-ms-flex-wrap:wrap-reverse;flex-wrap:wrap-reverse}.flex-column-reverse-l{-ms-flex-direction:column-reverse;flex-direction:column-reverse}.flex-row-reverse-l{-ms-flex-direction:row-reverse;flex-direction:row-reverse}.items-start-l{-ms-flex-align:start;align-items:flex-start}.items-end-l{-ms-flex-align:end;align-items:flex-end}.items-center-l{-ms-flex-align:center;align-items:center}.items-baseline-l{-ms-flex-align:baseline;align-items:baseline}.items-stretch-l{-ms-flex-align:stretch;align-items:stretch}.self-start-l{-ms-flex-item-align:start;align-self:flex-start}.self-end-l{-ms-flex-item-align:end;align-self:flex-end}.self-center-l{-ms-flex-item-align:center;-ms-grid-row-align:center;align-self:center}.self-baseline-l{-ms-flex-item-align:baseline;align-self:baseline}.self-stretch-l{-ms-flex-item-align:stretch;-ms-grid-row-align:stretch;align-self:stretch}.justify-start-l{-ms-flex-pack:start;justify-content:flex-start}.justify-end-l{-ms-flex-pack:end;justify-content:flex-end}.justify-center-l{-ms-flex-pack:center;justify-content:center}.justify-between-l{-ms-flex-pack:justify;justify-content:space-between}.justify-around-l{-ms-flex-pack:distribute;justify-content:space-around}.content-start-l{-ms-flex-line-pack:start;align-content:flex-start}.content-end-l{-ms-flex-line-pack:end;align-content:flex-end}.content-center-l{-ms-flex-line-pack:center;align-content:center}.content-between-l{-ms-flex-line-pack:justify;align-content:space-between}.content-around-l{-ms-flex-line-pack:distribute;align-content:space-around}.content-stretch-l{-ms-flex-line-pack:stretch;align-content:stretch}.flex-1-l{-ms-flex:1;flex:1}.flex-2-l{-ms-flex:2;flex:2}.flex-3-l{-ms-flex:3;flex:3}.flex-4-l{-ms-flex:4;flex:4}.flex-5-l{-ms-flex:5;flex:5}.flex-6-l{-ms-flex:6;flex:6}.flex-7-l{-ms-flex:7;flex:7}.flex-8-l{-ms-flex:8;flex:8}.flex-9-l{-ms-flex:9;flex:9}.flex-auto-l{-ms-flex:1 1 auto;flex:1 1 auto;min-width:0;min-height:0}.flex-none-l{-ms-flex:none;flex:none}.flex-grow-0-l{-ms-flex-positive:0;flex-grow:0}.flex-grow-1-l{-ms-flex-positive:1;flex-grow:1}.flex-shrink-0-l{-ms-flex-negative:0;flex-shrink:0}.flex-shrink-1-l{-ms-flex-negative:1;flex-shrink:1}.order-0-l{-ms-flex-order:0;order:0}.order-1-l{-ms-flex-order:1;order:1}.order-2-l{-ms-flex-order:2;order:2}.order-3-l{-ms-flex-order:3;order:3}.order-4-l{-ms-flex-order:4;order:4}.order-5-l{-ms-flex-order:5;order:5}.order-6-l{-ms-flex-order:6;order:6}.order-7-l{-ms-flex-order:7;order:7}.order-8-l{-ms-flex-order:8;order:8}.order-last-l{-ms-flex-order:99999;order:99999}}.fl{float:left}.fl,.fr{_display:inline}.fr{float:right}.fn{float:none}@media screen and (min-width:30em){.fl-ns{float:left}.fl-ns,.fr-ns{_display:inline}.fr-ns{float:right}.fn-ns{float:none}}@media screen and (min-width:30em) and (max-width:60em){.fl-m{float:left}.fl-m,.fr-m{_display:inline}.fr-m{float:right}.fn-m{float:none}}@media screen and (min-width:60em){.fl-l{float:left}.fl-l,.fr-l{_display:inline}.fr-l{float:right}.fn-l{float:none}}.sans-serif{font-family:Salesforce Sans,-apple-system,BlinkMacSystemFont,avenir next,avenir,helvetica,helvetica neue,ubuntu,roboto,noto,segoe ui,arial,sans-serif}.serif{font-family:georgia,serif}.system-sans-serif{font-family:sans-serif}.system-serif{font-family:serif}.code,code{font-family:consolas,monaco,monospace}.courier{font-family:Courier Next,courier,monospace}.helvetica{font-family:helvetica neue,helvetica,sans-serif}.avenir{font-family:avenir next,avenir,sans-serif}.athelas{font-family:athelas,georgia,serif}.georgia{font-family:georgia,serif}.times{font-family:times,serif}.bodoni{font-family:Bodoni MT,serif}.calisto{font-family:Calisto MT,serif}.garamond{font-family:garamond,serif}.baskerville{font-family:baskerville,serif}.i{font-style:italic}.fs-normal{font-style:normal}@media screen and (min-width:30em){.i-ns{font-style:italic}.fs-normal-ns{font-style:normal}}@media screen and (min-width:30em) and (max-width:60em){.i-m{font-style:italic}.fs-normal-m{font-style:normal}}@media screen and (min-width:60em){.i-l{font-style:italic}.fs-normal-l{font-style:normal}}.normal{font-weight:400}.b{font-weight:700}.fw1{font-weight:100}.fw2{font-weight:200}.fw3{font-weight:300}.fw4{font-weight:400}.fw5{font-weight:500}.fw6{font-weight:600}.fw7{font-weight:700}.fw8{font-weight:800}.fw9{font-weight:900}@media screen and (min-width:30em){.normal-ns{font-weight:400}.b-ns{font-weight:700}.fw1-ns{font-weight:100}.fw2-ns{font-weight:200}.fw3-ns{font-weight:300}.fw4-ns{font-weight:400}.fw5-ns{font-weight:500}.fw6-ns{font-weight:600}.fw7-ns{font-weight:700}.fw8-ns{font-weight:800}.fw9-ns{font-weight:900}}@media screen and (min-width:30em) and (max-width:60em){.normal-m{font-weight:400}.b-m{font-weight:700}.fw1-m{font-weight:100}.fw2-m{font-weight:200}.fw3-m{font-weight:300}.fw4-m{font-weight:400}.fw5-m{font-weight:500}.fw6-m{font-weight:600}.fw7-m{font-weight:700}.fw8-m{font-weight:800}.fw9-m{font-weight:900}}@media screen and (min-width:60em){.normal-l{font-weight:400}.b-l{font-weight:700}.fw1-l{font-weight:100}.fw2-l{font-weight:200}.fw3-l{font-weight:300}.fw4-l{font-weight:400}.fw5-l{font-weight:500}.fw6-l{font-weight:600}.fw7-l{font-weight:700}.fw8-l{font-weight:800}.fw9-l{font-weight:900}}.input-reset{-webkit-appearance:none;-moz-appearance:none}.button-reset::-moz-focus-inner,.input-reset::-moz-focus-inner{border:0;padding:0}.h1{height:16px}.h2{height:24px}.h3{height:32px}.h4{height:60px}.h5{height:100px}.h6{height:200px}.h--16{height:16px}.h--20{height:20px}.h--28{height:28px}.h--32{height:32px}.h--48{height:48px}.h-25{height:25%}.h-50{height:50%}.h-75{height:75%}.h-100{height:100%}.min-h-100{min-height:100%}.vh-25{height:25vh}.vh-50{height:50vh}.vh-75{height:75vh}.vh-100{height:100vh}.min-vh-100{min-height:100vh}.h-auto{height:auto}.h-inherit{height:inherit}@media screen and (min-width:30em){.h1-ns{height:16px}.h2-ns{height:24px}.h3-ns{height:32px}.h4-ns{height:60px}.h5-ns{height:100px}.h6-ns{height:200px}.h-25-ns{height:25%}.h-50-ns{height:50%}.h-75-ns{height:75%}.h-100-ns{height:100%}.min-h-100-ns{min-height:100%}.vh-25-ns{height:25vh}.vh-50-ns{height:50vh}.vh-75-ns{height:75vh}.vh-100-ns{height:100vh}.min-vh-100-ns{min-height:100vh}.h-auto-ns{height:auto}.h-inherit-ns{height:inherit}}@media screen and (min-width:30em) and (max-width:60em){.h1-m{height:16px}.h2-m{height:24px}.h3-m{height:32px}.h4-m{height:60px}.h5-m{height:100px}.h6-m{height:200px}.h-25-m{height:25%}.h-50-m{height:50%}.h-75-m{height:75%}.h-100-m{height:100%}.min-h-100-ns{min-height:100%}.vh-25-m{height:25vh}.vh-50-m{height:50vh}.vh-75-m{height:75vh}.vh-100-m{height:100vh}.min-vh-100-m{min-height:100vh}.h-auto-m{height:auto}.h-inherit-m{height:inherit}}@media screen and (min-width:60em){.h1-l{height:16px}.h2-l{height:24px}.h3-l{height:32px}.h4-l{height:60px}.h5-l{height:100px}.h6-l{height:200px}.h-25-l{height:25%}.h-50-l{height:50%}.h-75-l{height:75%}.h-100-l{height:100%}.min-h-100-l{min-height:100%}.vh-25-l{height:25vh}.vh-50-l{height:50vh}.vh-75-l{height:75vh}.vh-100-l{height:100vh}.min-vh-100-m{min-height:100vh}.h-auto-l{height:auto}.h-inherit-l{height:inherit}}.dim{opacity:1}.dim,.dim:focus,.dim:hover{transition:opacity .15s ease-in}.dim:focus,.dim:hover{opacity:.7}.dim:active{opacity:.8;transition:opacity .15s ease-out}.hide-child .child{opacity:0;transition:opacity .15s ease-in}.hide-child:active .child,.hide-child:focus .child,.hide-child:hover .child{opacity:1;transition:opacity .15s ease-in}.underline-hover:focus,.underline-hover:hover{text-decoration:underline}.grow{-moz-osx-font-smoothing:grayscale;-webkit-backface-visibility:hidden;backface-visibility:hidden;transform:translateZ(0);transition:transform .25s ease-out}.grow:focus,.grow:hover{transform:scale(1.05)}.grow:active{transform:scale(.9)}.grow-large{-moz-osx-font-smoothing:grayscale;-webkit-backface-visibility:hidden;backface-visibility:hidden;transform:translateZ(0);transition:transform .25s ease-in-out}.grow-large:focus,.grow-large:hover{transform:scale(1.2)}.grow-large:active{transform:scale(.95)}.pointer:hover{cursor:pointer}.shadow-hover{position:relative}.shadow-hover:after{box-shadow:0 0 8px 2px rgba(0,0,0,.2);opacity:0;transition:opacity .25s ease-in-out}.shadow-hover:focus:after,.shadow-hover:hover:after{opacity:1}.bg-animate,.bg-animate:focus,.bg-animate:hover{transition:background-color .15s ease-in-out}img{max-width:100%}.tracked{letter-spacing:.1em}.tracked-tight{letter-spacing:-.05em}.tracked-mega{letter-spacing:.25em}@media screen and (min-width:30em){.tracked-ns{letter-spacing:.1em}.tracked-tight-ns{letter-spacing:-.05em}.tracked-mega-ns{letter-spacing:.25em}}@media screen and (min-width:30em) and (max-width:60em){.tracked-m{letter-spacing:.1em}.tracked-tight-m{letter-spacing:-.05em}.tracked-mega-m{letter-spacing:.25em}}@media screen and (min-width:60em){.tracked-l{letter-spacing:.1em}.tracked-tight-l{letter-spacing:-.05em}.tracked-mega-l{letter-spacing:.25em}}.lh-solid{line-height:1}.lh-title{line-height:1.25}.lh-copy{line-height:1.5}.lh-12{line-height:12px}@media screen and (min-width:30em){.lh-solid-ns{line-height:1}.lh-title-ns{line-height:1.25}.lh-copy-ns{line-height:1.5}.lh-12-ns{line-height:12px}}@media screen and (min-width:30em) and (max-width:60em){.lh-solid-m{line-height:1}.lh-title-m{line-height:1.25}.lh-copy-m{line-height:1.5}.lh-12-m{line-height:12px}}@media screen and (min-width:60em){.lh-solid-l{line-height:1}.lh-title-l{line-height:1.25}.lh-copy-l{line-height:1.5}.lh-12-l{line-height:12px}}.link{text-decoration:none}.link:focus{outline:1px dotted currentColor}.hk-link{text-decoration:underline;color:#006deb}.hk-link:focus{border-radius:4px;background:#f6faff;outline:none;border-color:#006deb;box-shadow:0 0 0 2px rgba(142,189,241,.4)}.list{list-style-type:none}.mw-100{max-width:100%}.mw1{max-width:1rem}.mw2{max-width:2rem}.mw3{max-width:4rem}.mw4{max-width:8rem}.mw5{max-width:16rem}.mw6{max-width:32rem}.mw7{max-width:48rem}.mw8{max-width:64rem}.mw9{max-width:96rem}.mw-none{max-width:none}@media screen and (min-width:30em){.mw-100-ns{max-width:100%}.mw1-ns{max-width:1rem}.mw2-ns{max-width:2rem}.mw3-ns{max-width:4rem}.mw4-ns{max-width:8rem}.mw5-ns{max-width:16rem}.mw6-ns{max-width:32rem}.mw7-ns{max-width:48rem}.mw8-ns{max-width:64rem}.mw9-ns{max-width:96rem}.mw-none-ns{max-width:none}}@media screen and (min-width:30em) and (max-width:60em){.mw-100-m{max-width:100%}.mw1-m{max-width:1rem}.mw2-m{max-width:2rem}.mw3-m{max-width:4rem}.mw4-m{max-width:8rem}.mw5-m{max-width:16rem}.mw6-m{max-width:32rem}.mw7-m{max-width:48rem}.mw8-m{max-width:64rem}.mw9-m{max-width:96rem}.mw-none-m{max-width:none}}@media screen and (min-width:60em){.mw-100-l{max-width:100%}.mw1-l{max-width:1rem}.mw2-l{max-width:2rem}.mw3-l{max-width:4rem}.mw4-l{max-width:8rem}.mw5-l{max-width:16rem}.mw6-l{max-width:32rem}.mw7-l{max-width:48rem}.mw8-l{max-width:64rem}.mw9-l{max-width:96rem}.mw-none-l{max-width:none}}.na1{margin:-5px}.na2{margin:-10px}.na3{margin:-15px}.na4{margin:-20px}.na5{margin:-30px}.na6{margin:-40px}.na7{margin:-80px}.nv1{margin-top:-5px;margin-bottom:-5px}.nv2{margin-top:-10px;margin-bottom:-10px}.nv3{margin-top:-15px;margin-bottom:-15px}.nv4{margin-top:-20px;margin-bottom:-20px}.nv5{margin-top:-30px;margin-bottom:-30px}.nv6{margin-top:-40px;margin-bottom:-40px}.nv7{margin-top:-80px;margin-bottom:-80px}.nh1{margin-left:-5px;margin-right:-5px}.nh2{margin-left:-10px;margin-right:-10px}.nh3{margin-left:-15px;margin-right:-15px}.nh4{margin-left:-20px;margin-right:-20px}.nh5{margin-left:-30px;margin-right:-30px}.nh6{margin-left:-40px;margin-right:-40px}.nh7{margin-left:-80px;margin-right:-80px}.nl1{margin-left:-5px}.nl2{margin-left:-10px}.nl3{margin-left:-15px}.nl4{margin-left:-20px}.nl5{margin-left:-30px}.nl6{margin-left:-40px}.nl7{margin-left:-80px}.nr1{margin-right:-5px}.nr2{margin-right:-10px}.nr3{margin-right:-15px}.nr4{margin-right:-20px}.nr5{margin-right:-30px}.nr6{margin-right:-40px}.nr7{margin-right:-80px}.nb1{margin-bottom:-5px}.nb2{margin-bottom:-10px}.nb3{margin-bottom:-15px}.nb4{margin-bottom:-20px}.nb5{margin-bottom:-30px}.nb6{margin-bottom:-40px}.nb7{margin-bottom:-80px}.nt1{margin-top:-5px}.nt2{margin-top:-10px}.nt3{margin-top:-15px}.nt4{margin-top:-20px}.nt5{margin-top:-30px}.nt6{margin-top:-40px}.nt7{margin-top:-80px}.na--1{margin:-1px}.na--2{margin:-2px}.na--3{margin:-3px}.na--4{margin:-4px}.na--5{margin:-5px}.nv--1{margin-top:-1px;margin-bottom:-1px}.nv--2{margin-top:-2px;margin-bottom:-2px}.nv--3{margin-top:-3px;margin-bottom:-3px}.nv--4{margin-top:-4px;margin-bottom:-4px}.nv--5{margin-top:-5px;margin-bottom:-5px}.nh--1{margin-left:-1px;margin-right:-1px}.nh--2{margin-left:-2px;margin-right:-2px}.nh--3{margin-left:-3px;margin-right:-3px}.nh--4{margin-left:-4px;margin-right:-4px}.nh--5{margin-left:-5px;margin-right:-5px}.nl--1{margin-left:-1px}.nl--2{margin-left:-2px}.nl--3{margin-left:-3px}.nl--4{margin-left:-4px}.nl--5{margin-left:-5px}.nr--1{margin-right:-1px}.nr--2{margin-right:-2px}.nr--3{margin-right:-3px}.nr--4{margin-right:-4px}.nr--5{margin-right:-5px}.nb--1{margin-bottom:-1px}.nb--2{margin-bottom:-2px}.nb--3{margin-bottom:-3px}.nb--4{margin-bottom:-4px}.nb--5{margin-bottom:-5px}.nt--1{margin-top:-1px}.nt--2{margin-top:-2px}.nt--3{margin-top:-3px}.nt--4{margin-top:-4px}.nt--5{margin-top:-5px}@media screen and (min-width:30em){.na1-ns{margin:-5px}.na2-ns{margin:-10px}.na3-ns{margin:-15px}.na4-ns{margin:-20px}.na5-ns{margin:-30px}.na6-ns{margin:-40px}.na7-ns{margin:-80px}.nv1-ns{margin-top:-5px;margin-bottom:-5px}.nv2-ns{margin-top:-10px;margin-bottom:-10px}.nv3-ns{margin-top:-15px;margin-bottom:-15px}.nv4-ns{margin-top:-20px;margin-bottom:-20px}.nv5-ns{margin-top:-30px;margin-bottom:-30px}.nv6-ns{margin-top:-40px;margin-bottom:-40px}.nv7-ns{margin-top:-80px;margin-bottom:-80px}.nh1-ns{margin-left:-5px;margin-right:-5px}.nh2-ns{margin-left:-10px;margin-right:-10px}.nh3-ns{margin-left:-15px;margin-right:-15px}.nh4-ns{margin-left:-20px;margin-right:-20px}.nh5-ns{margin-left:-30px;margin-right:-30px}.nh6-ns{margin-left:-40px;margin-right:-40px}.nh7-ns{margin-left:-80px;margin-right:-80px}.nl1-ns{margin-left:-5px}.nl2-ns{margin-left:-10px}.nl3-ns{margin-left:-15px}.nl4-ns{margin-left:-20px}.nl5-ns{margin-left:-30px}.nl6-ns{margin-left:-40px}.nl7-ns{margin-left:-80px}.nr1-ns{margin-right:-5px}.nr2-ns{margin-right:-10px}.nr3-ns{margin-right:-15px}.nr4-ns{margin-right:-20px}.nr5-ns{margin-right:-30px}.nr6-ns{margin-right:-40px}.nr7-ns{margin-right:-80px}.nb1-ns{margin-bottom:-5px}.nb2-ns{margin-bottom:-10px}.nb3-ns{margin-bottom:-15px}.nb4-ns{margin-bottom:-20px}.nb5-ns{margin-bottom:-30px}.nb6-ns{margin-bottom:-40px}.nb7-ns{margin-bottom:-80px}.nt1-ns{margin-top:-5px}.nt2-ns{margin-top:-10px}.nt3-ns{margin-top:-15px}.nt4-ns{margin-top:-20px}.nt5-ns{margin-top:-30px}.nt6-ns{margin-top:-40px}.nt7-ns{margin-top:-80px}.na--1-ns{margin:-1px}.na--2-ns{margin:-2px}.na--3-ns{margin:-3px}.na--4-ns{margin:-4px}.na--5-ns{margin:-5px}.nv--1-ns{margin-top:-1px;margin-bottom:-1px}.nv--2-ns{margin-top:-2px;margin-bottom:-2px}.nv--3-ns{margin-top:-3px;margin-bottom:-3px}.nv--4-ns{margin-top:-4px;margin-bottom:-4px}.nv--5-ns{margin-top:-5px;margin-bottom:-5px}.nh--1-ns{margin-left:-1px;margin-right:-1px}.nh--2-ns{margin-left:-2px;margin-right:-2px}.nh--3-ns{margin-left:-3px;margin-right:-3px}.nh--4-ns{margin-left:-4px;margin-right:-4px}.nh--5-ns{margin-left:-5px;margin-right:-5px}.nl--1-ns{margin-left:-1px}.nl--2-ns{margin-left:-2px}.nl--3-ns{margin-left:-3px}.nl--4-ns{margin-left:-4px}.nl--5-ns{margin-left:-5px}.nr--1-ns{margin-right:-1px}.nr--2-ns{margin-right:-2px}.nr--3-ns{margin-right:-3px}.nr--4-ns{margin-right:-4px}.nr--5-ns{margin-right:-5px}.nb--1-ns{margin-bottom:-1px}.nb--2-ns{margin-bottom:-2px}.nb--3-ns{margin-bottom:-3px}.nb--4-ns{margin-bottom:-4px}.nb--5-ns{margin-bottom:-5px}.nt--1-ns{margin-top:-1px}.nt--2-ns{margin-top:-2px}.nt--3-ns{margin-top:-3px}.nt--4-ns{margin-top:-4px}.nt--5-ns{margin-top:-5px}}@media screen and (min-width:30em) and (max-width:60em){.na1-m{margin:-5px}.na2-m{margin:-10px}.na3-m{margin:-15px}.na4-m{margin:-20px}.na5-m{margin:-30px}.na6-m{margin:-40px}.na7-m{margin:-80px}.nv1-m{margin-top:-5px;margin-bottom:-5px}.nv2-m{margin-top:-10px;margin-bottom:-10px}.nv3-m{margin-top:-15px;margin-bottom:-15px}.nv4-m{margin-top:-20px;margin-bottom:-20px}.nv5-m{margin-top:-30px;margin-bottom:-30px}.nv6-m{margin-top:-40px;margin-bottom:-40px}.nv7-m{margin-top:-80px;margin-bottom:-80px}.nh1-m{margin-left:-5px;margin-right:-5px}.nh2-m{margin-left:-10px;margin-right:-10px}.nh3-m{margin-left:-15px;margin-right:-15px}.nh4-m{margin-left:-20px;margin-right:-20px}.nh5-m{margin-left:-30px;margin-right:-30px}.nh6-m{margin-left:-40px;margin-right:-40px}.nh7-m{margin-left:-80px;margin-right:-80px}.nl1-m{margin-left:-5px}.nl2-m{margin-left:-10px}.nl3-m{margin-left:-15px}.nl4-m{margin-left:-20px}.nl5-m{margin-left:-30px}.nl6-m{margin-left:-40px}.nl7-m{margin-left:-80px}.nr1-m{margin-right:-5px}.nr2-m{margin-right:-10px}.nr3-m{margin-right:-15px}.nr4-m{margin-right:-20px}.nr5-m{margin-right:-30px}.nr6-m{margin-right:-40px}.nr7-m{margin-right:-80px}.nb1-m{margin-bottom:-5px}.nb2-m{margin-bottom:-10px}.nb3-m{margin-bottom:-15px}.nb4-m{margin-bottom:-20px}.nb5-m{margin-bottom:-30px}.nb6-m{margin-bottom:-40px}.nb7-m{margin-bottom:-80px}.nt1-m{margin-top:-5px}.nt2-m{margin-top:-10px}.nt3-m{margin-top:-15px}.nt4-m{margin-top:-20px}.nt5-m{margin-top:-30px}.nt6-m{margin-top:-40px}.nt7-m{margin-top:-80px}.na--1-m{margin:-1px}.na--2-m{margin:-2px}.na--3-m{margin:-3px}.na--4-m{margin:-4px}.na--5-m{margin:-5px}.nv--1-m{margin-top:-1px;margin-bottom:-1px}.nv--2-m{margin-top:-2px;margin-bottom:-2px}.nv--3-m{margin-top:-3px;margin-bottom:-3px}.nv--4-m{margin-top:-4px;margin-bottom:-4px}.nv--5-m{margin-top:-5px;margin-bottom:-5px}.nh--1-m{margin-left:-1px;margin-right:-1px}.nh--2-m{margin-left:-2px;margin-right:-2px}.nh--3-m{margin-left:-3px;margin-right:-3px}.nh--4-m{margin-left:-4px;margin-right:-4px}.nh--5-m{margin-left:-5px;margin-right:-5px}.nl--1-m{margin-left:-1px}.nl--2-m{margin-left:-2px}.nl--3-m{margin-left:-3px}.nl--4-m{margin-left:-4px}.nl--5-m{margin-left:-5px}.nr--1-m{margin-right:-1px}.nr--2-m{margin-right:-2px}.nr--3-m{margin-right:-3px}.nr--4-m{margin-right:-4px}.nr--5-m{margin-right:-5px}.nb--1-m{margin-bottom:-1px}.nb--2-m{margin-bottom:-2px}.nb--3-m{margin-bottom:-3px}.nb--4-m{margin-bottom:-4px}.nb--5-m{margin-bottom:-5px}.nt--1-m{margin-top:-1px}.nt--2-m{margin-top:-2px}.nt--3-m{margin-top:-3px}.nt--4-m{margin-top:-4px}.nt--5-m{margin-top:-5px}}@media screen and (min-width:60em){.na1-l{margin:-5px}.na2-l{margin:-10px}.na3-l{margin:-15px}.na4-l{margin:-20px}.na5-l{margin:-30px}.na6-l{margin:-40px}.na7-l{margin:-80px}.nv1-l{margin-top:-5px;margin-bottom:-5px}.nv2-l{margin-top:-10px;margin-bottom:-10px}.nv3-l{margin-top:-15px;margin-bottom:-15px}.nv4-l{margin-top:-20px;margin-bottom:-20px}.nv5-l{margin-top:-30px;margin-bottom:-30px}.nv6-l{margin-top:-40px;margin-bottom:-40px}.nv7-l{margin-top:-80px;margin-bottom:-80px}.nh1-l{margin-left:-5px;margin-right:-5px}.nh2-l{margin-left:-10px;margin-right:-10px}.nh3-l{margin-left:-15px;margin-right:-15px}.nh4-l{margin-left:-20px;margin-right:-20px}.nh5-l{margin-left:-30px;margin-right:-30px}.nh6-l{margin-left:-40px;margin-right:-40px}.nh7-l{margin-left:-80px;margin-right:-80px}.nl1-l{margin-left:-5px}.nl2-l{margin-left:-10px}.nl3-l{margin-left:-15px}.nl4-l{margin-left:-20px}.nl5-l{margin-left:-30px}.nl6-l{margin-left:-40px}.nl7-l{margin-left:-80px}.nr1-l{margin-right:-5px}.nr2-l{margin-right:-10px}.nr3-l{margin-right:-15px}.nr4-l{margin-right:-20px}.nr5-l{margin-right:-30px}.nr6-l{margin-right:-40px}.nr7-l{margin-right:-80px}.nb1-l{margin-bottom:-5px}.nb2-l{margin-bottom:-10px}.nb3-l{margin-bottom:-15px}.nb4-l{margin-bottom:-20px}.nb5-l{margin-bottom:-30px}.nb6-l{margin-bottom:-40px}.nb7-l{margin-bottom:-80px}.nt1-l{margin-top:-5px}.nt2-l{margin-top:-10px}.nt3-l{margin-top:-15px}.nt4-l{margin-top:-20px}.nt5-l{margin-top:-30px}.nt6-l{margin-top:-40px}.nt7-l{margin-top:-80px}.na--1-l{margin:-1px}.na--2-l{margin:-2px}.na--3-l{margin:-3px}.na--4-l{margin:-4px}.na--5-l{margin:-5px}.nv--1-l{margin-top:-1px;margin-bottom:-1px}.nv--2-l{margin-top:-2px;margin-bottom:-2px}.nv--3-l{margin-top:-3px;margin-bottom:-3px}.nv--4-l{margin-top:-4px;margin-bottom:-4px}.nv--5-l{margin-top:-5px;margin-bottom:-5px}.nh--1-l{margin-left:-1px;margin-right:-1px}.nh--2-l{margin-left:-2px;margin-right:-2px}.nh--3-l{margin-left:-3px;margin-right:-3px}.nh--4-l{margin-left:-4px;margin-right:-4px}.nh--5-l{margin-left:-5px;margin-right:-5px}.nl--1-l{margin-left:-1px}.nl--2-l{margin-left:-2px}.nl--3-l{margin-left:-3px}.nl--4-l{margin-left:-4px}.nl--5-l{margin-left:-5px}.nr--1-l{margin-right:-1px}.nr--2-l{margin-right:-2px}.nr--3-l{margin-right:-3px}.nr--4-l{margin-right:-4px}.nr--5-l{margin-right:-5px}.nb--1-l{margin-bottom:-1px}.nb--2-l{margin-bottom:-2px}.nb--3-l{margin-bottom:-3px}.nb--4-l{margin-bottom:-4px}.nb--5-l{margin-bottom:-5px}.nt--1-l{margin-top:-1px}.nt--2-l{margin-top:-2px}.nt--3-l{margin-top:-3px}.nt--4-l{margin-top:-4px}.nt--5-l{margin-top:-5px}}.nudge-right--1{position:relative;left:1px}.nudge-right--2{position:relative;left:2px}.nudge-right--3{position:relative;left:3px}.nudge-right--4{position:relative;left:4px}.nudge-right--5{position:relative;left:5px}.nudge-left--1{position:relative;right:1px}.nudge-left--2{position:relative;right:2px}.nudge-left--3{position:relative;right:3px}.nudge-left--4{position:relative;right:4px}.nudge-left--5{position:relative;right:5px}.nudge-down--1{position:relative;top:1px}.nudge-down--2{position:relative;top:2px}.nudge-down--3{position:relative;top:3px}.nudge-down--4{position:relative;top:4px}.nudge-down--5{position:relative;top:5px}.nudge-up--1{position:relative;bottom:1px}.nudge-up--2{position:relative;bottom:2px}.nudge-up--3{position:relative;bottom:3px}.nudge-up--4{position:relative;bottom:4px}.nudge-up--5{position:relative;bottom:5px}@media screen and (min-width:30em){.nudge-right--1-ns{position:relative;left:1px}.nudge-right--2-ns{position:relative;left:2px}.nudge-right--3-ns{position:relative;left:3px}.nudge-right--4-ns{position:relative;left:4px}.nudge-right--5-ns{position:relative;left:5px}.nudge-left--1-ns{position:relative;right:1px}.nudge-left--2-ns{position:relative;right:2px}.nudge-left--3-ns{position:relative;right:3px}.nudge-left--4-ns{position:relative;right:4px}.nudge-left--5-ns{position:relative;right:5px}.nudge-down--1-ns{position:relative;top:1px}.nudge-down--2-ns{position:relative;top:2px}.nudge-down--3-ns{position:relative;top:3px}.nudge-down--4-ns{position:relative;top:4px}.nudge-down--5-ns{position:relative;top:5px}.nudge-up--1-ns{position:relative;bottom:1px}.nudge-up--2-ns{position:relative;bottom:2px}.nudge-up--3-ns{position:relative;bottom:3px}.nudge-up--4-ns{position:relative;bottom:4px}.nudge-up--5-ns{position:relative;bottom:5px}}@media screen and (min-width:30em) and (max-width:60em){.nudge-right--1-m{position:relative;left:1px}.nudge-right--2-m{position:relative;left:2px}.nudge-right--3-m{position:relative;left:3px}.nudge-right--4-m{position:relative;left:4px}.nudge-right--5-m{position:relative;left:5px}.nudge-left--1-m{position:relative;right:1px}.nudge-left--2-m{position:relative;right:2px}.nudge-left--3-m{position:relative;right:3px}.nudge-left--4-m{position:relative;right:4px}.nudge-left--5-m{position:relative;right:5px}.nudge-down--1-m{position:relative;top:1px}.nudge-down--2-m{position:relative;top:2px}.nudge-down--3-m{position:relative;top:3px}.nudge-down--4-m{position:relative;top:4px}.nudge-down--5-m{position:relative;top:5px}.nudge-up--1-m{position:relative;bottom:1px}.nudge-up--2-m{position:relative;bottom:2px}.nudge-up--3-m{position:relative;bottom:3px}.nudge-up--4-m{position:relative;bottom:4px}.nudge-up--5-m{position:relative;bottom:5px}}@media screen and (min-width:60em){.nudge-right--1-l{position:relative;left:1px}.nudge-right--2-l{position:relative;left:2px}.nudge-right--3-l{position:relative;left:3px}.nudge-right--4-l{position:relative;left:4px}.nudge-right--5-l{position:relative;left:5px}.nudge-left--1-l{position:relative;right:1px}.nudge-left--2-l{position:relative;right:2px}.nudge-left--3-l{position:relative;right:3px}.nudge-left--4-l{position:relative;right:4px}.nudge-left--5-l{position:relative;right:5px}.nudge-down--1-l{position:relative;top:1px}.nudge-down--2-l{position:relative;top:2px}.nudge-down--3-l{position:relative;top:3px}.nudge-down--4-l{position:relative;top:4px}.nudge-down--5-l{position:relative;top:5px}.nudge-up--1-l{position:relative;bottom:1px}.nudge-up--2-l{position:relative;bottom:2px}.nudge-up--3-l{position:relative;bottom:3px}.nudge-up--4-l{position:relative;bottom:4px}.nudge-up--5-l{position:relative;bottom:5px}}.o-100{opacity:1}.o-90{opacity:.9}.o-80{opacity:.8}.o-70{opacity:.7}.o-60{opacity:.6}.o-50{opacity:.5}.o-40{opacity:.4}.o-30{opacity:.3}.o-20{opacity:.2}.o-10{opacity:.1}.o-05{opacity:.05}.o-025{opacity:.025}.o-0{opacity:0}.outline{outline:1px solid}.outline-transparent{outline:1px solid transparent}.outline-0{outline:0}@media screen and (min-width:30em){.outline-ns{outline:1px solid}.outline-transparent-ns{outline:1px solid transparent}.outline-0-ns{outline:0}}@media screen and (min-width:30em) and (max-width:60em){.outline-m{outline:1px solid}.outline-transparent-m{outline:1px solid transparent}.outline-0-m{outline:0}}@media screen and (min-width:30em) and (max-width:60em){.outline-l{outline:1px solid}.outline-transparent-l{outline:1px solid transparent}.outline-0-l{outline:0}}.overflow-visible{overflow:visible}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.overflow-auto{overflow:auto}.overflow-x-visible{overflow-x:visible}.overflow-x-hidden{overflow-x:hidden}.overflow-x-scroll{overflow-x:scroll}.overflow-x-auto{overflow-x:auto}.overflow-y-visible{overflow-y:visible}.overflow-y-hidden{overflow-y:hidden}.overflow-y-scroll{overflow-y:scroll}.overflow-y-auto{overflow-y:auto}@media screen and (min-width:30em){.overflow-visible-ns{overflow:visible}.overflow-hidden-ns{overflow:hidden}.overflow-scroll-ns{overflow:scroll}.overflow-auto-ns{overflow:auto}.overflow-x-visible-ns{overflow-x:visible}.overflow-x-hidden-ns{overflow-x:hidden}.overflow-x-scroll-ns{overflow-x:scroll}.overflow-x-auto-ns{overflow-x:auto}.overflow-y-visible-ns{overflow-y:visible}.overflow-y-hidden-ns{overflow-y:hidden}.overflow-y-scroll-ns{overflow-y:scroll}.overflow-y-auto-ns{overflow-y:auto}}@media screen and (min-width:30em) and (max-width:60em){.overflow-visible-m{overflow:visible}.overflow-hidden-m{overflow:hidden}.overflow-scroll-m{overflow:scroll}.overflow-auto-m{overflow:auto}.overflow-x-visible-m{overflow-x:visible}.overflow-x-hidden-m{overflow-x:hidden}.overflow-x-scroll-m{overflow-x:scroll}.overflow-x-auto-m{overflow-x:auto}.overflow-y-visible-m{overflow-y:visible}.overflow-y-hidden-m{overflow-y:hidden}.overflow-y-scroll-m{overflow-y:scroll}.overflow-y-auto-m{overflow-y:auto}}@media screen and (min-width:60em){.overflow-visible-l{overflow:visible}.overflow-hidden-l{overflow:hidden}.overflow-scroll-l{overflow:scroll}.overflow-auto-l{overflow:auto}.overflow-x-visible-l{overflow-x:visible}.overflow-x-hidden-l{overflow-x:hidden}.overflow-x-scroll-l{overflow-x:scroll}.overflow-x-auto-l{overflow-x:auto}.overflow-y-visible-l{overflow-y:visible}.overflow-y-hidden-l{overflow-y:hidden}.overflow-y-scroll-l{overflow-y:scroll}.overflow-y-auto-l{overflow-y:auto}}.pe-auto{pointer-events:auto}.pe-none{pointer-events:none}.static{position:static}.relative{position:relative}.absolute{position:absolute}.fixed{position:fixed}.sticky{position:-webkit-sticky;position:sticky}@media screen and (min-width:30em){.static-ns{position:static}.relative-ns{position:relative}.absolute-ns{position:absolute}.fixed-ns{position:fixed}.sticky-ns{position:-webkit-sticky;position:sticky}}@media screen and (min-width:30em) and (max-width:60em){.static-m{position:static}.relative-m{position:relative}.absolute-m{position:absolute}.fixed-m{position:fixed}.sticky-m{position:-webkit-sticky;position:sticky}}@media screen and (min-width:60em){.static-l{position:static}.relative-l{position:relative}.absolute-l{position:absolute}.fixed-l{position:fixed}.sticky-l{position:-webkit-sticky;position:sticky}}.shadow-1{box-shadow:0 0 2px 1px rgba(0,0,0,.2)}.shadow-2{box-shadow:0 0 4px 1px rgba(0,0,0,.2)}.shadow-3{box-shadow:0 2px 4px 1px rgba(0,0,0,.2)}.shadow-4{box-shadow:0 2px 8px 0 rgba(0,0,0,.2)}.shadow-5{box-shadow:0 4px 14px 0 rgba(0,0,0,.2)}@media screen and (min-width:30em){.shadow-1-ns{box-shadow:0 0 2px 1px rgba(0,0,0,.2)}.shadow-2-ns{box-shadow:0 0 4px 1px rgba(0,0,0,.2)}.shadow-3-ns{box-shadow:0 2px 4px 1px rgba(0,0,0,.2)}.shadow-4-ns{box-shadow:0 2px 8px 0 rgba(0,0,0,.2)}.shadow-5-ns{box-shadow:0 4px 14px 0 rgba(0,0,0,.2)}}@media screen and (min-width:30em) and (max-width:60em){.shadow-1-m{box-shadow:0 0 2px 1px rgba(0,0,0,.2)}.shadow-2-m{box-shadow:0 0 4px 1px rgba(0,0,0,.2)}.shadow-3-m{box-shadow:0 2px 4px 1px rgba(0,0,0,.2)}.shadow-4-m{box-shadow:0 2px 8px 0 rgba(0,0,0,.2)}.shadow-5-m{box-shadow:0 4px 14px 0 rgba(0,0,0,.2)}}@media screen and (min-width:60em){.shadow-1-l{box-shadow:0 0 2px 1px rgba(0,0,0,.2)}.shadow-2-l{box-shadow:0 0 4px 1px rgba(0,0,0,.2)}.shadow-3-l{box-shadow:0 2px 4px 1px rgba(0,0,0,.2)}.shadow-4-l{box-shadow:0 2px 8px 0 rgba(0,0,0,.2)}.shadow-5-l{box-shadow:0 4px 14px 0 rgba(0,0,0,.2)}}.shadow-inner-1{box-shadow:inset 0 0 0 1px rgba(89,105,129,.1),inset 0 1px 3px 0 rgba(207,215,230,.6)}.shadow-inner-2{box-shadow:inset 0 1px 2px 0 rgba(207,215,230,.4)}.shadow-inner-3{box-shadow:inset 0 0 0 1px rgba(0,0,0,.05),inset 0 1px 2px 0 rgba(78,83,90,.1)}.shadow-outer-1{box-shadow:0 0 0 1px rgba(89,105,129,.1),0 1px 3px 0 rgba(89,105,129,.1),0 1px 2px 0 rgba(0,0,0,.05)}.shadow-outer-2{box-shadow:0 0 0 1px rgba(89,105,129,.1),0 3px 20px 0 rgba(89,105,129,.3),0 1px 2px 0 rgba(0,0,0,.05)}.shadow-outer-3{box-shadow:0 1px 3px 0 rgba(89,105,129,.05),0 1px 1px 0 rgba(0,0,0,.025)}.black-90{color:rgba(0,0,0,.9)}.black-80{color:rgba(0,0,0,.8)}.black-70{color:rgba(0,0,0,.7)}.black-60{color:rgba(0,0,0,.6)}.black-50{color:rgba(0,0,0,.5)}.black-40{color:rgba(0,0,0,.4)}.black-30{color:rgba(0,0,0,.3)}.black-20{color:rgba(0,0,0,.2)}.black-10{color:rgba(0,0,0,.1)}.black-05{color:rgba(0,0,0,.05)}.gray-90{color:rgba(89,105,129,.9)}.gray-80{color:rgba(89,105,129,.8)}.gray-70{color:rgba(89,105,129,.7)}.gray-60{color:rgba(89,105,129,.6)}.gray-50{color:rgba(89,105,129,.5)}.gray-40{color:rgba(89,105,129,.4)}.gray-30{color:rgba(89,105,129,.3)}.gray-20{color:rgba(89,105,129,.2)}.gray-10{color:rgba(89,105,129,.1)}.gray-05{color:rgba(89,105,129,.05)}.white-90{color:hsla(0,0%,100%,.9)}.white-80{color:hsla(0,0%,100%,.8)}.white-70{color:hsla(0,0%,100%,.7)}.white-60{color:hsla(0,0%,100%,.6)}.white-50{color:hsla(0,0%,100%,.5)}.white-40{color:hsla(0,0%,100%,.4)}.white-30{color:hsla(0,0%,100%,.3)}.white-20{color:hsla(0,0%,100%,.2)}.white-10{color:hsla(0,0%,100%,.1)}.black{color:#000}.near-black{color:#323b49}.dark-gray{color:#475366}.mid-gray{color:#56667d}.gray{color:#62738d}.light-gray{color:#cfd7e6}.silver{color:#e3e7ef}.light-silver{color:#eef1f6}.lightest-silver{color:#f7f8fb}.near-white{color:#fbfbfd}.white{color:#fff}.dark-purple{color:#4f3074}.purple{color:#79589f}.light-purple{color:#a997bf}.lightest-purple{color:#f7f3fb}.dark-blue{color:#034ca2}.blue{color:#006deb}.light-blue{color:#8ebdf1}.lightest-blue{color:#f6faff}.dark-green{color:#066515}.green{color:#008700}.light-green{color:#86cf95}.lightest-green{color:#f8fcf9}.dark-red{color:#a70404}.red{color:#de0a0a}.light-red{color:#de7575}.lightest-red{color:#fdf6f6}.dark-orange{color:#832d03}.orange{color:#c74c00}.light-orange{color:#fa9f47}.lightest-orange{color:#fffaf6}.gold{color:#ffb700}.yellow{color:gold}.light-yellow{color:#fbf1a9}.dark-pink{color:#d5008f}.hot-pink{color:#ff41b4}.pink{color:#ff80cc}.light-pink{color:#ffa3d7}.navy{color:#001b44}.washed-blue{color:#f6fffe}.washed-green{color:#e8fdf5}.washed-yellow{color:#fffceb}.washed-red{color:#ffdfdf}.hover-black-90:focus,.hover-black-90:hover{color:rgba(0,0,0,.9)}.hover-black-80:focus,.hover-black-80:hover{color:rgba(0,0,0,.8)}.hover-black-70:focus,.hover-black-70:hover{color:rgba(0,0,0,.7)}.hover-black-60:focus,.hover-black-60:hover{color:rgba(0,0,0,.6)}.hover-black-50:focus,.hover-black-50:hover{color:rgba(0,0,0,.5)}.hover-black-40:focus,.hover-black-40:hover{color:rgba(0,0,0,.4)}.hover-black-30:focus,.hover-black-30:hover{color:rgba(0,0,0,.3)}.hover-black-20:focus,.hover-black-20:hover{color:rgba(0,0,0,.2)}.hover-black-10:focus,.hover-black-10:hover{color:rgba(0,0,0,.1)}.hover-black-05:focus,.hover-black-05:hover{color:rgba(0,0,0,.05)}.hover-gray-90:focus,.hover-gray-90:hover{color:rgba(89,105,129,.9)}.hover-gray-80:focus,.hover-gray-80:hover{color:rgba(89,105,129,.8)}.hover-gray-70:focus,.hover-gray-70:hover{color:rgba(89,105,129,.7)}.hover-gray-60:focus,.hover-gray-60:hover{color:rgba(89,105,129,.6)}.hover-gray-50:focus,.hover-gray-50:hover{color:rgba(89,105,129,.5)}.hover-gray-40:focus,.hover-gray-40:hover{color:rgba(89,105,129,.4)}.hover-gray-30:focus,.hover-gray-30:hover{color:rgba(89,105,129,.3)}.hover-gray-20:focus,.hover-gray-20:hover{color:rgba(89,105,129,.2)}.hover-gray-10:focus,.hover-gray-10:hover{color:rgba(89,105,129,.1)}.hover-gray-05:focus,.hover-gray-05:hover{color:rgba(89,105,129,.05)}.hover-white-90:focus,.hover-white-90:hover{color:hsla(0,0%,100%,.9)}.hover-white-80:focus,.hover-white-80:hover{color:hsla(0,0%,100%,.8)}.hover-white-70:focus,.hover-white-70:hover{color:hsla(0,0%,100%,.7)}.hover-white-60:focus,.hover-white-60:hover{color:hsla(0,0%,100%,.6)}.hover-white-50:focus,.hover-white-50:hover{color:hsla(0,0%,100%,.5)}.hover-white-40:focus,.hover-white-40:hover{color:hsla(0,0%,100%,.4)}.hover-white-30:focus,.hover-white-30:hover{color:hsla(0,0%,100%,.3)}.hover-white-20:focus,.hover-white-20:hover{color:hsla(0,0%,100%,.2)}.hover-white-10:focus,.hover-white-10:hover{color:hsla(0,0%,100%,.1)}.hover-black:focus,.hover-black:hover{color:#000}.hover-near-black:focus,.hover-near-black:hover{color:#323b49}.hover-dark-gray:focus,.hover-dark-gray:hover{color:#475366}.hover-mid-gray:focus,.hover-mid-gray:hover{color:#56667d}.hover-gray:focus,.hover-gray:hover{color:#62738d}.hover-light-gray:focus,.hover-light-gray:hover{color:#cfd7e6}.hover-silver:focus,.hover-silver:hover{color:#e3e7ef}.hover-light-silver:focus,.hover-light-silver:hover{color:#eef1f6}.hover-lightest-silver:focus,.hover-lightest-silver:hover{color:#f7f8fb}.hover-near-white:focus,.hover-near-white:hover{color:#fbfbfd}.hover-white:focus,.hover-white:hover{color:#fff}.hover-dark-purple:focus,.hover-dark-purple:hover{color:#4f3074}.hover-purple:focus,.hover-purple:hover{color:#79589f}.hover-light-purple:focus,.hover-light-purple:hover{color:#a997bf}.hover-lightest-purple:focus,.hover-lightest-purple:hover{color:#f7f3fb}.hover-dark-blue:focus,.hover-dark-blue:hover{color:#034ca2}.hover-blue:focus,.hover-blue:hover{color:#006deb}.hover-light-blue:focus,.hover-light-blue:hover{color:#8ebdf1}.hover-dark-green:focus,.hover-dark-green:hover{color:#066515}.hover-green:focus,.hover-green:hover{color:#008700}.hover-light-green:focus,.hover-light-green:hover{color:#86cf95}.hover-lightest-green:focus,.hover-lightest-green:hover{color:#f8fcf9}.hover-dark-red:focus,.hover-dark-red:hover{color:#a70404}.hover-red:focus,.hover-red:hover{color:#de0a0a}.hover-light-red:focus,.hover-light-red:hover{color:#de7575}.hover-lightest-red:focus,.hover-lightest-red:hover{color:#fdf6f6}.hover-dark-orange:focus,.hover-dark-orange:hover{color:#832d03}.hover-orange:focus,.hover-orange:hover{color:#c74c00}.hover-light-orange:focus,.hover-light-orange:hover{color:#fa9f47}.hover-lightest-orange:focus,.hover-lightest-orange:hover{color:#fffaf6}.hover-gold:focus,.hover-gold:hover{color:#ffb700}.hover-yellow:focus,.hover-yellow:hover{color:gold}.hover-light-yellow:focus,.hover-light-yellow:hover{color:#fbf1a9}.hover-dark-pink:focus,.hover-dark-pink:hover{color:#d5008f}.hover-hot-pink:focus,.hover-hot-pink:hover{color:#ff41b4}.hover-pink:focus,.hover-pink:hover{color:#ff80cc}.hover-light-pink:focus,.hover-light-pink:hover{color:#ffa3d7}.hover-navy:focus,.hover-navy:hover{color:#001b44}.hover-lightest-blue:focus,.hover-lightest-blue:hover{color:#f6faff}.hover-washed-blue:focus,.hover-washed-blue:hover{color:#f6fffe}.hover-washed-green:focus,.hover-washed-green:hover{color:#e8fdf5}.hover-washed-yellow:focus,.hover-washed-yellow:hover{color:#fffceb}.hover-washed-red:focus,.hover-washed-red:hover{color:#ffdfdf}.pa0{padding:0}.pa1{padding:5px}.pa2{padding:10px}.pa3{padding:15px}.pa4{padding:20px}.pa5{padding:30px}.pa6{padding:40px}.pa7{padding:80px}.pl0{padding-left:0}.pl1{padding-left:5px}.pl2{padding-left:10px}.pl3{padding-left:15px}.pl4{padding-left:20px}.pl5{padding-left:30px}.pl6{padding-left:40px}.pl7{padding-left:80px}.pr0{padding-right:0}.pr1{padding-right:5px}.pr2{padding-right:10px}.pr3{padding-right:15px}.pr4{padding-right:20px}.pr5{padding-right:30px}.pr6{padding-right:40px}.pr7{padding-right:80px}.pb0{padding-bottom:0}.pb1{padding-bottom:5px}.pb2{padding-bottom:10px}.pb3{padding-bottom:15px}.pb4{padding-bottom:20px}.pb5{padding-bottom:30px}.pb6{padding-bottom:40px}.pb7{padding-bottom:80px}.pt0{padding-top:0}.pt1{padding-top:5px}.pt2{padding-top:10px}.pt3{padding-top:15px}.pt4{padding-top:20px}.pt5{padding-top:30px}.pt6{padding-top:40px}.pt7{padding-top:80px}.pv0{padding-top:0;padding-bottom:0}.pv1{padding-top:5px;padding-bottom:5px}.pv2{padding-top:10px;padding-bottom:10px}.pv3{padding-top:15px;padding-bottom:15px}.pv4{padding-top:20px;padding-bottom:20px}.pv5{padding-top:30px;padding-bottom:30px}.pv6{padding-top:40px;padding-bottom:40px}.pv7{padding-top:80px;padding-bottom:80px}.ph0{padding-left:0;padding-right:0}.ph1{padding-left:5px;padding-right:5px}.ph2{padding-left:10px;padding-right:10px}.ph3{padding-left:15px;padding-right:15px}.ph4{padding-left:20px;padding-right:20px}.ph5{padding-left:30px;padding-right:30px}.ph6{padding-left:40px;padding-right:40px}.ph7{padding-left:80px;padding-right:80px}.pa--1{padding:1px}.pa--2{padding:2px}.pa--3{padding:3px}.pa--4{padding:4px}.pa--5{padding:5px}.pl--1{padding-left:1px}.pl--2{padding-left:2px}.pl--3{padding-left:3px}.pl--4{padding-left:4px}.pl--5{padding-left:5px}.pr--1{padding-right:1px}.pr--2{padding-right:2px}.pr--3{padding-right:3px}.pr--4{padding-right:4px}.pr--5{padding-right:5px}.pb--1{padding-bottom:1px}.pb--2{padding-bottom:2px}.pb--3{padding-bottom:3px}.pb--4{padding-bottom:4px}.pb--5{padding-bottom:5px}.pt--1{padding-top:1px}.pt--2{padding-top:2px}.pt--3{padding-top:3px}.pt--4{padding-top:4px}.pt--5{padding-top:5px}.pv--1{padding-top:1px;padding-bottom:1px}.pv--2{padding-top:2px;padding-bottom:2px}.pv--3{padding-top:3px;padding-bottom:3px}.pv--4{padding-top:4px;padding-bottom:4px}.pv--5{padding-top:5px;padding-bottom:5px}.ph--1{padding-left:1px;padding-right:1px}.ph--2{padding-left:2px;padding-right:2px}.ph--3{padding-left:3px;padding-right:3px}.ph--4{padding-left:4px;padding-right:4px}.ph--5{padding-left:5px;padding-right:5px}.ma0{margin:0}.ma1{margin:5px}.ma2{margin:10px}.ma3{margin:15px}.ma4{margin:20px}.ma5{margin:30px}.ma6{margin:40px}.ma7{margin:80px}.ml0{margin-left:0}.ml1{margin-left:5px}.ml2{margin-left:10px}.ml3{margin-left:15px}.ml4{margin-left:20px}.ml5{margin-left:30px}.ml6{margin-left:40px}.ml7{margin-left:80px}.mr0{margin-right:0}.mr1{margin-right:5px}.mr2{margin-right:10px}.mr3{margin-right:15px}.mr4{margin-right:20px}.mr5{margin-right:30px}.mr6{margin-right:40px}.mr7{margin-right:80px}.mb0{margin-bottom:0}.mb1{margin-bottom:5px}.mb2{margin-bottom:10px}.mb3{margin-bottom:15px}.mb4{margin-bottom:20px}.mb5{margin-bottom:30px}.mb6{margin-bottom:40px}.mb7{margin-bottom:80px}.mt0{margin-top:0}.mt1{margin-top:5px}.mt2{margin-top:10px}.mt3{margin-top:15px}.mt4{margin-top:20px}.mt5{margin-top:30px}.mt6{margin-top:40px}.mt7{margin-top:80px}.mv0{margin-top:0;margin-bottom:0}.mv1{margin-top:5px;margin-bottom:5px}.mv2{margin-top:10px;margin-bottom:10px}.mv3{margin-top:15px;margin-bottom:15px}.mv4{margin-top:20px;margin-bottom:20px}.mv5{margin-top:30px;margin-bottom:30px}.mv6{margin-top:40px;margin-bottom:40px}.mv7{margin-top:80px;margin-bottom:80px}.mh0{margin-left:0;margin-right:0}.mh1{margin-left:5px;margin-right:5px}.mh2{margin-left:10px;margin-right:10px}.mh3{margin-left:15px;margin-right:15px}.mh4{margin-left:20px;margin-right:20px}.mh5{margin-left:30px;margin-right:30px}.mh6{margin-left:40px;margin-right:40px}.mh7{margin-left:80px;margin-right:80px}.ma--1{margin:1px}.ma--2{margin:2px}.ma--3{margin:3px}.ma--4{margin:4px}.ma--5{margin:5px}.ml--1{margin-left:1px}.ml--2{margin-left:2px}.ml--3{margin-left:3px}.ml--4{margin-left:4px}.ml--5{margin-left:5px}.mr--1{margin-right:1px}.mr--2{margin-right:2px}.mr--3{margin-right:3px}.mr--4{margin-right:4px}.mr--5{margin-right:5px}.mb--1{margin-bottom:1px}.mb--2{margin-bottom:2px}.mb--3{margin-bottom:3px}.mb--4{margin-bottom:4px}.mb--5{margin-bottom:5px}.mt--1{margin-top:1px}.mt--2{margin-top:2px}.mt--3{margin-top:3px}.mt--4{margin-top:4px}.mt--5{margin-top:5px}.mv--1{margin-top:1px;margin-bottom:1px}.mv--2{margin-top:2px;margin-bottom:2px}.mv--3{margin-top:3px;margin-bottom:3px}.mv--4{margin-top:4px;margin-bottom:4px}.mv--5{margin-top:5px;margin-bottom:5px}.mh--1{margin-left:1px;margin-right:1px}.mh--2{margin-left:2px;margin-right:2px}.mh--3{margin-left:3px;margin-right:3px}.mh--4{margin-left:4px;margin-right:4px}.mh--5{margin-left:5px;margin-right:5px}@media screen and (min-width:30em){.pa0-ns{padding:0}.pa1-ns{padding:5px}.pa2-ns{padding:10px}.pa3-ns{padding:15px}.pa4-ns{padding:20px}.pa5-ns{padding:30px}.pa6-ns{padding:40px}.pa7-ns{padding:80px}.pl0-ns{padding-left:0}.pl1-ns{padding-left:5px}.pl2-ns{padding-left:10px}.pl3-ns{padding-left:15px}.pl4-ns{padding-left:20px}.pl5-ns{padding-left:30px}.pl6-ns{padding-left:40px}.pl7-ns{padding-left:80px}.pr0-ns{padding-right:0}.pr1-ns{padding-right:5px}.pr2-ns{padding-right:10px}.pr3-ns{padding-right:15px}.pr4-ns{padding-right:20px}.pr5-ns{padding-right:30px}.pr6-ns{padding-right:40px}.pr7-ns{padding-right:80px}.pb0-ns{padding-bottom:0}.pb1-ns{padding-bottom:5px}.pb2-ns{padding-bottom:10px}.pb3-ns{padding-bottom:15px}.pb4-ns{padding-bottom:20px}.pb5-ns{padding-bottom:30px}.pb6-ns{padding-bottom:40px}.pb7-ns{padding-bottom:80px}.pt0-ns{padding-top:0}.pt1-ns{padding-top:5px}.pt2-ns{padding-top:10px}.pt3-ns{padding-top:15px}.pt4-ns{padding-top:20px}.pt5-ns{padding-top:30px}.pt6-ns{padding-top:40px}.pt7-ns{padding-top:80px}.pv0-ns{padding-top:0;padding-bottom:0}.pv1-ns{padding-top:5px;padding-bottom:5px}.pv2-ns{padding-top:10px;padding-bottom:10px}.pv3-ns{padding-top:15px;padding-bottom:15px}.pv4-ns{padding-top:20px;padding-bottom:20px}.pv5-ns{padding-top:30px;padding-bottom:30px}.pv6-ns{padding-top:40px;padding-bottom:40px}.pv7-ns{padding-top:80px;padding-bottom:80px}.ph0-ns{padding-left:0;padding-right:0}.ph1-ns{padding-left:5px;padding-right:5px}.ph2-ns{padding-left:10px;padding-right:10px}.ph3-ns{padding-left:15px;padding-right:15px}.ph4-ns{padding-left:20px;padding-right:20px}.ph5-ns{padding-left:30px;padding-right:30px}.ph6-ns{padding-left:40px;padding-right:40px}.ph7-ns{padding-left:80px;padding-right:80px}.pa--1-ns{padding:1px}.pa--2-ns{padding:2px}.pa--3-ns{padding:3px}.pa--4-ns{padding:4px}.pa--5-ns{padding:5px}.pl--1-ns{padding-left:1px}.pl--2-ns{padding-left:2px}.pl--3-ns{padding-left:3px}.pl--4-ns{padding-left:4px}.pl--5-ns{padding-left:5px}.pr--1-ns{padding-right:1px}.pr--2-ns{padding-right:2px}.pr--3-ns{padding-right:3px}.pr--4-ns{padding-right:4px}.pr--5-ns{padding-right:5px}.pb--1-ns{padding-bottom:1px}.pb--2-ns{padding-bottom:2px}.pb--3-ns{padding-bottom:3px}.pb--4-ns{padding-bottom:4px}.pb--5-ns{padding-bottom:5px}.pt--1-ns{padding-top:1px}.pt--2-ns{padding-top:2px}.pt--3-ns{padding-top:3px}.pt--4-ns{padding-top:4px}.pt--5-ns{padding-top:5px}.pv--1-ns{padding-top:1px;padding-bottom:1px}.pv--2-ns{padding-top:2px;padding-bottom:2px}.pv--3-ns{padding-top:3px;padding-bottom:3px}.pv--4-ns{padding-top:4px;padding-bottom:4px}.pv--5-ns{padding-top:5px;padding-bottom:5px}.ph--1-ns{padding-left:1px;padding-right:1px}.ph--2-ns{padding-left:2px;padding-right:2px}.ph--3-ns{padding-left:3px;padding-right:3px}.ph--4-ns{padding-left:4px;padding-right:4px}.ph--5-ns{padding-left:5px;padding-right:5px}.ma0-ns{margin:0}.ma1-ns{margin:5px}.ma2-ns{margin:10px}.ma3-ns{margin:15px}.ma4-ns{margin:20px}.ma5-ns{margin:30px}.ma6-ns{margin:40px}.ma7-ns{margin:80px}.ml0-ns{margin-left:0}.ml1-ns{margin-left:5px}.ml2-ns{margin-left:10px}.ml3-ns{margin-left:15px}.ml4-ns{margin-left:20px}.ml5-ns{margin-left:30px}.ml6-ns{margin-left:40px}.ml7-ns{margin-left:80px}.mr0-ns{margin-right:0}.mr1-ns{margin-right:5px}.mr2-ns{margin-right:10px}.mr3-ns{margin-right:15px}.mr4-ns{margin-right:20px}.mr5-ns{margin-right:30px}.mr6-ns{margin-right:40px}.mr7-ns{margin-right:80px}.mb0-ns{margin-bottom:0}.mb1-ns{margin-bottom:5px}.mb2-ns{margin-bottom:10px}.mb3-ns{margin-bottom:15px}.mb4-ns{margin-bottom:20px}.mb5-ns{margin-bottom:30px}.mb6-ns{margin-bottom:40px}.mb7-ns{margin-bottom:80px}.mt0-ns{margin-top:0}.mt1-ns{margin-top:5px}.mt2-ns{margin-top:10px}.mt3-ns{margin-top:15px}.mt4-ns{margin-top:20px}.mt5-ns{margin-top:30px}.mt6-ns{margin-top:40px}.mt7-ns{margin-top:80px}.mv0-ns{margin-top:0;margin-bottom:0}.mv1-ns{margin-top:5px;margin-bottom:5px}.mv2-ns{margin-top:10px;margin-bottom:10px}.mv3-ns{margin-top:15px;margin-bottom:15px}.mv4-ns{margin-top:20px;margin-bottom:20px}.mv5-ns{margin-top:30px;margin-bottom:30px}.mv6-ns{margin-top:40px;margin-bottom:40px}.mv7-ns{margin-top:80px;margin-bottom:80px}.mh0-ns{margin-left:0;margin-right:0}.mh1-ns{margin-left:5px;margin-right:5px}.mh2-ns{margin-left:10px;margin-right:10px}.mh3-ns{margin-left:15px;margin-right:15px}.mh4-ns{margin-left:20px;margin-right:20px}.mh5-ns{margin-left:30px;margin-right:30px}.mh6-ns{margin-left:40px;margin-right:40px}.mh7-ns{margin-left:80px;margin-right:80px}.ma--1-ns{margin:1px}.ma--2-ns{margin:2px}.ma--3-ns{margin:3px}.ma--4-ns{margin:4px}.ma--5-ns{margin:5px}.ml--1-ns{margin-left:1px}.ml--2-ns{margin-left:2px}.ml--3-ns{margin-left:3px}.ml--4-ns{margin-left:4px}.ml--5-ns{margin-left:5px}.mr--1-ns{margin-right:1px}.mr--2-ns{margin-right:2px}.mr--3-ns{margin-right:3px}.mr--4-ns{margin-right:4px}.mr--5-ns{margin-right:5px}.mb--1-ns{margin-bottom:1px}.mb--2-ns{margin-bottom:2px}.mb--3-ns{margin-bottom:3px}.mb--4-ns{margin-bottom:4px}.mb--5-ns{margin-bottom:5px}.mt--1-ns{margin-top:1px}.mt--2-ns{margin-top:2px}.mt--3-ns{margin-top:3px}.mt--4-ns{margin-top:4px}.mt--5-ns{margin-top:5px}.mv--1-ns{margin-top:1px;margin-bottom:1px}.mv--2-ns{margin-top:2px;margin-bottom:2px}.mv--3-ns{margin-top:3px;margin-bottom:3px}.mv--4-ns{margin-top:4px;margin-bottom:4px}.mv--5-ns{margin-top:5px;margin-bottom:5px}.mh--1-ns{margin-left:1px;margin-right:1px}.mh--2-ns{margin-left:2px;margin-right:2px}.mh--3-ns{margin-left:3px;margin-right:3px}.mh--4-ns{margin-left:4px;margin-right:4px}.mh--5-ns{margin-left:5px;margin-right:5px}}@media screen and (min-width:30em) and (max-width:60em){.pa0-m{padding:0}.pa1-m{padding:5px}.pa2-m{padding:10px}.pa3-m{padding:15px}.pa4-m{padding:20px}.pa5-m{padding:30px}.pa6-m{padding:40px}.pa7-m{padding:80px}.pl0-m{padding-left:0}.pl1-m{padding-left:5px}.pl2-m{padding-left:10px}.pl3-m{padding-left:15px}.pl4-m{padding-left:20px}.pl5-m{padding-left:30px}.pl6-m{padding-left:40px}.pl7-m{padding-left:80px}.pr0-m{padding-right:0}.pr1-m{padding-right:5px}.pr2-m{padding-right:10px}.pr3-m{padding-right:15px}.pr4-m{padding-right:20px}.pr5-m{padding-right:30px}.pr6-m{padding-right:40px}.pr7-m{padding-right:80px}.pb0-m{padding-bottom:0}.pb1-m{padding-bottom:5px}.pb2-m{padding-bottom:10px}.pb3-m{padding-bottom:15px}.pb4-m{padding-bottom:20px}.pb5-m{padding-bottom:30px}.pb6-m{padding-bottom:40px}.pb7-m{padding-bottom:80px}.pt0-m{padding-top:0}.pt1-m{padding-top:5px}.pt2-m{padding-top:10px}.pt3-m{padding-top:15px}.pt4-m{padding-top:20px}.pt5-m{padding-top:30px}.pt6-m{padding-top:40px}.pt7-m{padding-top:80px}.pv0-m{padding-top:0;padding-bottom:0}.pv1-m{padding-top:5px;padding-bottom:5px}.pv2-m{padding-top:10px;padding-bottom:10px}.pv3-m{padding-top:15px;padding-bottom:15px}.pv4-m{padding-top:20px;padding-bottom:20px}.pv5-m{padding-top:30px;padding-bottom:30px}.pv6-m{padding-top:40px;padding-bottom:40px}.pv7-m{padding-top:80px;padding-bottom:80px}.ph0-m{padding-left:0;padding-right:0}.ph1-m{padding-left:5px;padding-right:5px}.ph2-m{padding-left:10px;padding-right:10px}.ph3-m{padding-left:15px;padding-right:15px}.ph4-m{padding-left:20px;padding-right:20px}.ph5-m{padding-left:30px;padding-right:30px}.ph6-m{padding-left:40px;padding-right:40px}.ph7-m{padding-left:80px;padding-right:80px}.pa--1-m{padding:1px}.pa--2-m{padding:2px}.pa--3-m{padding:3px}.pa--4-m{padding:4px}.pa--5-m{padding:5px}.pl--1-m{padding-left:1px}.pl--2-m{padding-left:2px}.pl--3-m{padding-left:3px}.pl--4-m{padding-left:4px}.pl--5-m{padding-left:5px}.pr--1-m{padding-right:1px}.pr--2-m{padding-right:2px}.pr--3-m{padding-right:3px}.pr--4-m{padding-right:4px}.pr--5-m{padding-right:5px}.pb--1-m{padding-bottom:1px}.pb--2-m{padding-bottom:2px}.pb--3-m{padding-bottom:3px}.pb--4-m{padding-bottom:4px}.pb--5-m{padding-bottom:5px}.pt--1-m{padding-top:1px}.pt--2-m{padding-top:2px}.pt--3-m{padding-top:3px}.pt--4-m{padding-top:4px}.pt--5-m{padding-top:5px}.pv--1-m{padding-top:1px;padding-bottom:1px}.pv--2-m{padding-top:2px;padding-bottom:2px}.pv--3-m{padding-top:3px;padding-bottom:3px}.pv--4-m{padding-top:4px;padding-bottom:4px}.pv--5-m{padding-top:5px;padding-bottom:5px}.ph--1-m{padding-left:1px;padding-right:1px}.ph--2-m{padding-left:2px;padding-right:2px}.ph--3-m{padding-left:3px;padding-right:3px}.ph--4-m{padding-left:4px;padding-right:4px}.ph--5-m{padding-left:5px;padding-right:5px}.ma0-m{margin:0}.ma1-m{margin:5px}.ma2-m{margin:10px}.ma3-m{margin:15px}.ma4-m{margin:20px}.ma5-m{margin:30px}.ma6-m{margin:40px}.ma7-m{margin:80px}.ml0-m{margin-left:0}.ml1-m{margin-left:5px}.ml2-m{margin-left:10px}.ml3-m{margin-left:15px}.ml4-m{margin-left:20px}.ml5-m{margin-left:30px}.ml6-m{margin-left:40px}.ml7-m{margin-left:80px}.mr0-m{margin-right:0}.mr1-m{margin-right:5px}.mr2-m{margin-right:10px}.mr3-m{margin-right:15px}.mr4-m{margin-right:20px}.mr5-m{margin-right:30px}.mr6-m{margin-right:40px}.mr7-m{margin-right:80px}.mb0-m{margin-bottom:0}.mb1-m{margin-bottom:5px}.mb2-m{margin-bottom:10px}.mb3-m{margin-bottom:15px}.mb4-m{margin-bottom:20px}.mb5-m{margin-bottom:30px}.mb6-m{margin-bottom:40px}.mb7-m{margin-bottom:80px}.mt0-m{margin-top:0}.mt1-m{margin-top:5px}.mt2-m{margin-top:10px}.mt3-m{margin-top:15px}.mt4-m{margin-top:20px}.mt5-m{margin-top:30px}.mt6-m{margin-top:40px}.mt7-m{margin-top:80px}.mv0-m{margin-top:0;margin-bottom:0}.mv1-m{margin-top:5px;margin-bottom:5px}.mv2-m{margin-top:10px;margin-bottom:10px}.mv3-m{margin-top:15px;margin-bottom:15px}.mv4-m{margin-top:20px;margin-bottom:20px}.mv5-m{margin-top:30px;margin-bottom:30px}.mv6-m{margin-top:40px;margin-bottom:40px}.mv7-m{margin-top:80px;margin-bottom:80px}.mh0-m{margin-left:0;margin-right:0}.mh1-m{margin-left:5px;margin-right:5px}.mh2-m{margin-left:10px;margin-right:10px}.mh3-m{margin-left:15px;margin-right:15px}.mh4-m{margin-left:20px;margin-right:20px}.mh5-m{margin-left:30px;margin-right:30px}.mh6-m{margin-left:40px;margin-right:40px}.mh7-m{margin-left:80px;margin-right:80px}.ma--1-m{margin:1px}.ma--2-m{margin:2px}.ma--3-m{margin:3px}.ma--4-m{margin:4px}.ma--5-m{margin:5px}.ml--1-m{margin-left:1px}.ml--2-m{margin-left:2px}.ml--3-m{margin-left:3px}.ml--4-m{margin-left:4px}.ml--5-m{margin-left:5px}.mr--1-m{margin-right:1px}.mr--2-m{margin-right:2px}.mr--3-m{margin-right:3px}.mr--4-m{margin-right:4px}.mr--5-m{margin-right:5px}.mb--1-m{margin-bottom:1px}.mb--2-m{margin-bottom:2px}.mb--3-m{margin-bottom:3px}.mb--4-m{margin-bottom:4px}.mb--5-m{margin-bottom:5px}.mt--1-m{margin-top:1px}.mt--2-m{margin-top:2px}.mt--3-m{margin-top:3px}.mt--4-m{margin-top:4px}.mt--5-m{margin-top:5px}.mv--1-m{margin-top:1px;margin-bottom:1px}.mv--2-m{margin-top:2px;margin-bottom:2px}.mv--3-m{margin-top:3px;margin-bottom:3px}.mv--4-m{margin-top:4px;margin-bottom:4px}.mv--5-m{margin-top:5px;margin-bottom:5px}.mh--1-m{margin-left:1px;margin-right:1px}.mh--2-m{margin-left:2px;margin-right:2px}.mh--3-m{margin-left:3px;margin-right:3px}.mh--4-m{margin-left:4px;margin-right:4px}.mh--5-m{margin-left:5px;margin-right:5px}}@media screen and (min-width:60em){.pa0-l{padding:0}.pa1-l{padding:5px}.pa2-l{padding:10px}.pa3-l{padding:15px}.pa4-l{padding:20px}.pa5-l{padding:30px}.pa6-l{padding:40px}.pa7-l{padding:80px}.pl0-l{padding-left:0}.pl1-l{padding-left:5px}.pl2-l{padding-left:10px}.pl3-l{padding-left:15px}.pl4-l{padding-left:20px}.pl5-l{padding-left:30px}.pl6-l{padding-left:40px}.pl7-l{padding-left:80px}.pr0-l{padding-right:0}.pr1-l{padding-right:5px}.pr2-l{padding-right:10px}.pr3-l{padding-right:15px}.pr4-l{padding-right:20px}.pr5-l{padding-right:30px}.pr6-l{padding-right:40px}.pr7-l{padding-right:80px}.pb0-l{padding-bottom:0}.pb1-l{padding-bottom:5px}.pb2-l{padding-bottom:10px}.pb3-l{padding-bottom:15px}.pb4-l{padding-bottom:20px}.pb5-l{padding-bottom:30px}.pb6-l{padding-bottom:40px}.pb7-l{padding-bottom:80px}.pt0-l{padding-top:0}.pt1-l{padding-top:5px}.pt2-l{padding-top:10px}.pt3-l{padding-top:15px}.pt4-l{padding-top:20px}.pt5-l{padding-top:30px}.pt6-l{padding-top:40px}.pt7-l{padding-top:80px}.pv0-l{padding-top:0;padding-bottom:0}.pv1-l{padding-top:5px;padding-bottom:5px}.pv2-l{padding-top:10px;padding-bottom:10px}.pv3-l{padding-top:15px;padding-bottom:15px}.pv4-l{padding-top:20px;padding-bottom:20px}.pv5-l{padding-top:30px;padding-bottom:30px}.pv6-l{padding-top:40px;padding-bottom:40px}.pv7-l{padding-top:80px;padding-bottom:80px}.ph0-l{padding-left:0;padding-right:0}.ph1-l{padding-left:5px;padding-right:5px}.ph2-l{padding-left:10px;padding-right:10px}.ph3-l{padding-left:15px;padding-right:15px}.ph4-l{padding-left:20px;padding-right:20px}.ph5-l{padding-left:30px;padding-right:30px}.ph6-l{padding-left:40px;padding-right:40px}.ph7-l{padding-left:80px;padding-right:80px}.pa--1-l{padding:1px}.pa--2-l{padding:2px}.pa--3-l{padding:3px}.pa--4-l{padding:4px}.pa--5-l{padding:5px}.pl--1-l{padding-left:1px}.pl--2-l{padding-left:2px}.pl--3-l{padding-left:3px}.pl--4-l{padding-left:4px}.pl--5-l{padding-left:5px}.pr--1-l{padding-right:1px}.pr--2-l{padding-right:2px}.pr--3-l{padding-right:3px}.pr--4-l{padding-right:4px}.pr--5-l{padding-right:5px}.pb--1-l{padding-bottom:1px}.pb--2-l{padding-bottom:2px}.pb--3-l{padding-bottom:3px}.pb--4-l{padding-bottom:4px}.pb--5-l{padding-bottom:5px}.pt--1-l{padding-top:1px}.pt--2-l{padding-top:2px}.pt--3-l{padding-top:3px}.pt--4-l{padding-top:4px}.pt--5-l{padding-top:5px}.pv--1-l{padding-top:1px;padding-bottom:1px}.pv--2-l{padding-top:2px;padding-bottom:2px}.pv--3-l{padding-top:3px;padding-bottom:3px}.pv--4-l{padding-top:4px;padding-bottom:4px}.pv--5-l{padding-top:5px;padding-bottom:5px}.ph--1-l{padding-left:1px;padding-right:1px}.ph--2-l{padding-left:2px;padding-right:2px}.ph--3-l{padding-left:3px;padding-right:3px}.ph--4-l{padding-left:4px;padding-right:4px}.ph--5-l{padding-left:5px;padding-right:5px}.ma0-l{margin:0}.ma1-l{margin:5px}.ma2-l{margin:10px}.ma3-l{margin:15px}.ma4-l{margin:20px}.ma5-l{margin:30px}.ma6-l{margin:40px}.ma7-l{margin:80px}.ml0-l{margin-left:0}.ml1-l{margin-left:5px}.ml2-l{margin-left:10px}.ml3-l{margin-left:15px}.ml4-l{margin-left:20px}.ml5-l{margin-left:30px}.ml6-l{margin-left:40px}.ml7-l{margin-left:80px}.mr0-l{margin-right:0}.mr1-l{margin-right:5px}.mr2-l{margin-right:10px}.mr3-l{margin-right:15px}.mr4-l{margin-right:20px}.mr5-l{margin-right:30px}.mr6-l{margin-right:40px}.mr7-l{margin-right:80px}.mb0-l{margin-bottom:0}.mb1-l{margin-bottom:5px}.mb2-l{margin-bottom:10px}.mb3-l{margin-bottom:15px}.mb4-l{margin-bottom:20px}.mb5-l{margin-bottom:30px}.mb6-l{margin-bottom:40px}.mb7-l{margin-bottom:80px}.mt0-l{margin-top:0}.mt1-l{margin-top:5px}.mt2-l{margin-top:10px}.mt3-l{margin-top:15px}.mt4-l{margin-top:20px}.mt5-l{margin-top:30px}.mt6-l{margin-top:40px}.mt7-l{margin-top:80px}.mv0-l{margin-top:0;margin-bottom:0}.mv1-l{margin-top:5px;margin-bottom:5px}.mv2-l{margin-top:10px;margin-bottom:10px}.mv3-l{margin-top:15px;margin-bottom:15px}.mv4-l{margin-top:20px;margin-bottom:20px}.mv5-l{margin-top:30px;margin-bottom:30px}.mv6-l{margin-top:40px;margin-bottom:40px}.mv7-l{margin-top:80px;margin-bottom:80px}.mh0-l{margin-left:0;margin-right:0}.mh1-l{margin-left:5px;margin-right:5px}.mh2-l{margin-left:10px;margin-right:10px}.mh3-l{margin-left:15px;margin-right:15px}.mh4-l{margin-left:20px;margin-right:20px}.mh5-l{margin-left:30px;margin-right:30px}.mh6-l{margin-left:40px;margin-right:40px}.mh7-l{margin-left:80px;margin-right:80px}.ma--1-l{margin:1px}.ma--2-l{margin:2px}.ma--3-l{margin:3px}.ma--4-l{margin:4px}.ma--5-l{margin:5px}.ml--1-l{margin-left:1px}.ml--2-l{margin-left:2px}.ml--3-l{margin-left:3px}.ml--4-l{margin-left:4px}.ml--5-l{margin-left:5px}.mr--1-l{margin-right:1px}.mr--2-l{margin-right:2px}.mr--3-l{margin-right:3px}.mr--4-l{margin-right:4px}.mr--5-l{margin-right:5px}.mb--1-l{margin-bottom:1px}.mb--2-l{margin-bottom:2px}.mb--3-l{margin-bottom:3px}.mb--4-l{margin-bottom:4px}.mb--5-l{margin-bottom:5px}.mt--1-l{margin-top:1px}.mt--2-l{margin-top:2px}.mt--3-l{margin-top:3px}.mt--4-l{margin-top:4px}.mt--5-l{margin-top:5px}.mv--1-l{margin-top:1px;margin-bottom:1px}.mv--2-l{margin-top:2px;margin-bottom:2px}.mv--3-l{margin-top:3px;margin-bottom:3px}.mv--4-l{margin-top:4px;margin-bottom:4px}.mv--5-l{margin-top:5px;margin-bottom:5px}.mh--1-l{margin-left:1px;margin-right:1px}.mh--2-l{margin-left:2px;margin-right:2px}.mh--3-l{margin-left:3px;margin-right:3px}.mh--4-l{margin-left:4px;margin-right:4px}.mh--5-l{margin-left:5px;margin-right:5px}}.stroke{stroke-width:2;paint-order:stroke}.stroke-none{stroke:none}.stroke-black{stroke:#000}.stroke-near-black{stroke:#323b49}.stroke-dark-gray{stroke:#475366}.stroke-mid-gray{stroke:#56667d}.stroke-gray{stroke:#62738d}.stroke-silver{stroke:#e3e7ef}.stroke-light-silver{stroke:#eef1f6}.stroke-lightest-silver{stroke:#f7f8fb}.stroke-light-gray{stroke:#cfd7e6}.stroke-near-white{stroke:#fbfbfd}.stroke-white{stroke:#fff}.stroke-transparent{stroke:transparent}.stroke-dark-red{stroke:#a70404}.stroke-red{stroke:#de0a0a}.stroke-light-red{stroke:#de7575}.stroke-orange{stroke:#c74c00}.stroke-gold{stroke:#ffb700}.stroke-yellow{stroke:gold}.stroke-light-yellow{stroke:#fbf1a9}.stroke-purple{stroke:#79589f}.stroke-light-purple{stroke:#a997bf}.stroke-dark-pink{stroke:#d5008f}.stroke-hot-pink{stroke:#ff41b4}.stroke-pink{stroke:#ff80cc}.stroke-light-pink{stroke:#ffa3d7}.stroke-dark-green{stroke:#066515}.stroke-green{stroke:#008700}.stroke-light-green{stroke:#86cf95}.stroke-navy{stroke:#001b44}.stroke-dark-blue{stroke:#034ca2}.stroke-blue{stroke:#006deb}.stroke-light-blue{stroke:#8ebdf1}.stroke-lightest-blue{stroke:#f6faff}.stroke-washed-blue{stroke:#f6fffe}.stroke-washed-green{stroke:#e8fdf5}.stroke-washed-yellow{stroke:#fffceb}.stroke-washed-red{stroke:#ffdfdf}.hover-stroke-black:hover{stroke:#000}.hover-stroke-near-black:hover{stroke:#323b49}.hover-stroke-dark-gray:hover{stroke:#475366}.hover-stroke-mid-gray:hover{stroke:#56667d}.hover-stroke-gray:hover{stroke:#62738d}.hover-stroke-silver:hover{stroke:#e3e7ef}.hover-stroke-light-silver:hover{stroke:#eef1f6}.hover-stroke-lightest-silver:hover{stroke:#f7f8fb}.hover-stroke-light-gray:hover{stroke:#cfd7e6}.hover-stroke-near-white:hover{stroke:#fbfbfd}.hover-stroke-white:hover{stroke:#fff}.hover-stroke-transparent:hover{stroke:transparent}.hover-stroke-dark-red:hover{stroke:#a70404}.hover-stroke-red:hover{stroke:#de0a0a}.hover-stroke-light-red:hover{stroke:#de7575}.hover-stroke-orange:hover{stroke:#c74c00}.hover-stroke-gold:hover{stroke:#ffb700}.hover-stroke-yellow:hover{stroke:gold}.hover-stroke-light-yellow:hover{stroke:#fbf1a9}.hover-stroke-purple:hover{stroke:#79589f}.hover-stroke-light-purple:hover{stroke:#a997bf}.hover-stroke-dark-pink:hover{stroke:#d5008f}.hover-stroke-hot-pink:hover{stroke:#ff41b4}.hover-stroke-pink:hover{stroke:#ff80cc}.hover-stroke-light-pink:hover{stroke:#ffa3d7}.hover-stroke-dark-green:hover{stroke:#066515}.hover-stroke-green:hover{stroke:#008700}.hover-stroke-light-green:hover{stroke:#86cf95}.hover-stroke-navy:hover{stroke:#001b44}.hover-stroke-dark-blue:hover{stroke:#034ca2}.hover-stroke-blue:hover{stroke:#006deb}.hover-stroke-light-blue:hover{stroke:#8ebdf1}.hover-stroke-lightest-blue:hover{stroke:#f6faff}.hover-stroke-washed-blue:hover{stroke:#f6fffe}.hover-stroke-washed-green:hover{stroke:#e8fdf5}.hover-stroke-washed-yellow:hover{stroke:#fffceb}.hover-stroke-washed-red:hover{stroke:#ffdfdf}.stroke-o-05{stroke-opacity:.05}.stroke-o-10{stroke-opacity:.1}.stroke-o-20{stroke-opacity:.2}.stroke-o-25{stroke-opacity:.25}.stroke-o-30{stroke-opacity:.3}.stroke-o-40{stroke-opacity:.4}.stroke-o-50{stroke-opacity:.5}.stroke-o-60{stroke-opacity:.6}.stroke-o-75{stroke-opacity:.75}.stroke-o-80{stroke-opacity:.8}.stroke-o-90{stroke-opacity:.9}.hover-stroke-o-05:hover{stroke-opacity:.05}.hover-stroke-o-10:hover{stroke-opacity:.1}.hover-stroke-o-20:hover{stroke-opacity:.2}.hover-stroke-o-25:hover{stroke-opacity:.25}.hover-stroke-o-30:hover{stroke-opacity:.3}.hover-stroke-o-40:hover{stroke-opacity:.4}.hover-stroke-o-50:hover{stroke-opacity:.5}.hover-stroke-o-60:hover{stroke-opacity:.6}.hover-stroke-o-75:hover{stroke-opacity:.75}.hover-stroke-o-80:hover{stroke-opacity:.8}.hover-stroke-o-90:hover{stroke-opacity:.9}.stroke-dash--1{stroke-dasharray:1}.stroke-dash--2{stroke-dasharray:2}.stroke-dash--3{stroke-dasharray:3}.stroke-dash--4{stroke-dasharray:4}.stroke-dash--5{stroke-dasharray:5}.stroke-dash--6{stroke-dasharray:6}.stroke-join-bevel{stroke-linejoin:bevel}.stroke-join-miter{stroke-linejoin:miter}.stroke-join-round{stroke-linejoin:round}.stroke-cap-butt{stroke-linecap:butt}.stroke-cap-round{stroke-linecap:round}.stroke-cap-square{stroke-linecap:square}.collapse{border-collapse:collapse;border-spacing:0}.striped--light-silver:nth-child(odd){background-color:#eef1f6}.striped--light-gray:nth-child(odd){background-color:#cfd7e6}.striped--near-white:nth-child(odd){background-color:#fbfbfd}.stripe-light:nth-child(odd){background-color:hsla(0,0%,100%,.1)}.stripe-dark:nth-child(odd){background-color:rgba(0,0,0,.1)}.hk-hide-bb-last-row>.dt-row:last-child>.dtc,.hk-hide-bb-last-row>:last-child{border-width:0;border-style:none}.tl{text-align:left}.tr{text-align:right}.tc{text-align:center}@media screen and (min-width:30em){.tl-ns{text-align:left}.tr-ns{text-align:right}.tc-ns{text-align:center}}@media screen and (min-width:30em) and (max-width:60em){.tl-m{text-align:left}.tr-m{text-align:right}.tc-m{text-align:center}}@media screen and (min-width:60em){.tl-l{text-align:left}.tr-l{text-align:right}.tc-l{text-align:center}}.strike{text-decoration:line-through}.underline{text-decoration:underline}.no-underline{text-decoration:none}@media screen and (min-width:30em){.strike-ns{text-decoration:line-through}.underline-ns{text-decoration:underline}.no-underline-ns{text-decoration:none}}@media screen and (min-width:30em) and (max-width:60em){.strike-m{text-decoration:line-through}.underline-m{text-decoration:underline}.no-underline-m{text-decoration:none}}@media screen and (min-width:60em){.strike-l{text-decoration:line-through}.underline-l{text-decoration:underline}.no-underline-l{text-decoration:none}}.ttc{text-transform:capitalize}.ttl{text-transform:lowercase}.ttu{text-transform:uppercase}.ttn{text-transform:none}@media screen and (min-width:30em){.ttc-ns{text-transform:capitalize}.ttl-ns{text-transform:lowercase}.ttu-ns{text-transform:uppercase}.ttn-ns{text-transform:none}}@media screen and (min-width:30em) and (max-width:60em){.ttc-m{text-transform:capitalize}.ttl-m{text-transform:lowercase}.ttu-m{text-transform:uppercase}.ttn-m{text-transform:none}}@media screen and (min-width:60em){.ttc-l{text-transform:capitalize}.ttl-l{text-transform:lowercase}.ttu-l{text-transform:uppercase}.ttn-l{text-transform:none}}.f-6,.f-headline{font-size:6rem}.f-5,.f-subheadline{font-size:5rem}.f1{font-size:22px}.f2{font-size:17px}.f3{font-size:15px}.f4{font-size:14px}.f5{font-size:13px}.f6{font-size:12px}.f7{font-size:11px}@media screen and (min-width:30em){.f-6-ns,.f-headline-ns{font-size:6rem}.f-5-ns,.f-subheadline-ns{font-size:5rem}.f1-ns{font-size:22px}.f2-ns{font-size:17px}.f3-ns{font-size:15px}.f4-ns{font-size:14px}.f5-ns{font-size:13px}.f6-ns{font-size:12px}.f7-ns{font-size:11px}}@media screen and (min-width:30em) and (max-width:60em){.f-6-m,.f-headline-m{font-size:6rem}.f-5-m,.f-subheadline-m{font-size:5rem}.f1-m{font-size:22px}.f2-m{font-size:17px}.f3-m{font-size:15px}.f4-m{font-size:14px}.f5-m{font-size:13px}.f6-m{font-size:12px}.f7-m{font-size:11px}}@media screen and (min-width:60em){.f-6-l,.f-headline-l{font-size:6rem}.f-5-l,.f-subheadline-l{font-size:5rem}.f1-l{font-size:22px}.f2-l{font-size:17px}.f3-l{font-size:15px}.f4-l{font-size:14px}.f5-l{font-size:13px}.f6-l{font-size:12px}.f7-l{font-size:11px}}.measure{max-width:30em}.measure-wide{max-width:34em}.measure-narrow{max-width:20em}.indent{text-indent:1em;margin-top:0;margin-bottom:0}.truncate{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.small-caps{font-variant:small-caps}@media screen and (min-width:30em){.measure-ns{max-width:30em}.measure-wide-ns{max-width:34em}.measure-narrow-ns{max-width:20em}.indent-ns{text-indent:1em;margin-top:0;margin-bottom:0}.small-caps-ns{font-variant:small-caps}.truncate-ns{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}}@media screen and (min-width:30em) and (max-width:60em){.measure-m{max-width:30em}.measure-wide-m{max-width:34em}.measure-narrow-m{max-width:20em}.indent-m{text-indent:1em;margin-top:0;margin-bottom:0}.small-caps-m{font-variant:small-caps}.truncate-m{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}}@media screen and (min-width:60em){.measure-l{max-width:30em}.measure-wide-l{max-width:34em}.measure-narrow-l{max-width:20em}.indent-l{text-indent:1em;margin-top:0;margin-bottom:0}.small-caps-l{font-variant:small-caps}.truncate-l{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}}.aspect-ratio{height:0;position:relative}.aspect-ratio--16x9{padding-bottom:56.25%}.aspect-ratio--9x16{padding-bottom:177.77%}.aspect-ratio--4x3{padding-bottom:75%}.aspect-ratio--3x4{padding-bottom:133.33%}.aspect-ratio--6x4{padding-bottom:66.6%}.aspect-ratio--4x6{padding-bottom:150%}.aspect-ratio--8x5{padding-bottom:62.5%}.aspect-ratio--5x8{padding-bottom:160%}.aspect-ratio--7x5{padding-bottom:71.42%}.aspect-ratio--5x7{padding-bottom:140%}.aspect-ratio--1x1{padding-bottom:100%}.aspect-ratio--object{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}.overflow-container{overflow-y:scroll}.center{margin-right:auto;margin-left:auto}.no-select{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.v-base{vertical-align:baseline}.v-mid{vertical-align:middle}.v-top{vertical-align:top}.v-btm{vertical-align:bottom}@media screen and (min-width:30em){.v-base-ns{vertical-align:baseline}.v-mid-ns{vertical-align:middle}.v-top-ns{vertical-align:top}.v-btm-ns{vertical-align:bottom}}@media screen and (min-width:30em) and (max-width:60em){.v-base-m{vertical-align:baseline}.v-mid-m{vertical-align:middle}.v-top-m{vertical-align:top}.v-btm-m{vertical-align:bottom}}@media screen and (min-width:60em){.v-base-l{vertical-align:baseline}.v-mid-l{vertical-align:middle}.v-top-l{vertical-align:top}.v-btm-l{vertical-align:bottom}}.clip{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}@media screen and (min-width:30em){.clip-ns{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}}@media screen and (min-width:30em) and (max-width:60em){.clip-m{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}}@media screen and (min-width:60em){.clip-l{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}}.ws-normal{white-space:normal}.nowrap{white-space:nowrap}.pre{white-space:pre}@media screen and (min-width:30em){.ws-normal-ns{white-space:normal}.nowrap-ns{white-space:nowrap}.pre-ns{white-space:pre}}@media screen and (min-width:30em) and (max-width:60em){.ws-normal-m{white-space:normal}.nowrap-m{white-space:nowrap}.pre-m{white-space:pre}}@media screen and (min-width:60em){.ws-normal-l{white-space:normal}.nowrap-l{white-space:nowrap}.pre-l{white-space:pre}}.w1{width:16px}.w2{width:24px}.w3{width:32px}.w4{width:60px}.w5{width:100px}.w6{width:200px}.w--16{width:16px}.w--20{width:20px}.w--28{width:28px}.w--32{width:32px}.w--48{width:48px}.w-10{width:10%}.w-20{width:20%}.w-25{width:25%}.w-30{width:30%}.w-33{width:33%}.w-34{width:34%}.w-40{width:40%}.w-50{width:50%}.w-60{width:60%}.w-70{width:70%}.w-75{width:75%}.w-80{width:80%}.w-90{width:90%}.w-100{width:100%}.w-third{width:33.33333%}.w-two-thirds{width:66.66667%}.w-auto{width:auto}@media screen and (min-width:30em){.w1-ns{width:16px}.w2-ns{width:24px}.w3-ns{width:32px}.w4-ns{width:60px}.w5-ns{width:100px}.w6-ns{width:200px}.w-10-ns{width:10%}.w-20-ns{width:20%}.w-25-ns{width:25%}.w-30-ns{width:30%}.w-33-ns{width:33%}.w-34-ns{width:34%}.w-40-ns{width:40%}.w-50-ns{width:50%}.w-60-ns{width:60%}.w-70-ns{width:70%}.w-75-ns{width:75%}.w-80-ns{width:80%}.w-90-ns{width:90%}.w-100-ns{width:100%}.w-third-ns{width:33.33333%}.w-two-thirds-ns{width:66.66667%}.w-auto-ns{width:auto}}@media screen and (min-width:30em) and (max-width:60em){.w1-m{width:16px}.w2-m{width:24px}.w3-m{width:32px}.w4-m{width:60px}.w5-m{width:100px}.w6-m{width:200px}.w-10-m{width:10%}.w-20-m{width:20%}.w-25-m{width:25%}.w-30-m{width:30%}.w-33-m{width:33%}.w-34-m{width:34%}.w-40-m{width:40%}.w-50-m{width:50%}.w-60-m{width:60%}.w-70-m{width:70%}.w-75-m{width:75%}.w-80-m{width:80%}.w-90-m{width:90%}.w-100-m{width:100%}.w-third-m{width:33.33333%}.w-two-thirds-m{width:66.66667%}.w-auto-m{width:auto}}@media screen and (min-width:60em){.w1-l{width:16px}.w2-l{width:24px}.w3-l{width:32px}.w4-l{width:60px}.w5-l{width:100px}.w6-l{width:200px}.w-10-l{width:10%}.w-20-l{width:20%}.w-25-l{width:25%}.w-30-l{width:30%}.w-33-l{width:33%}.w-34-l{width:34%}.w-40-l{width:40%}.w-50-l{width:50%}.w-60-l{width:60%}.w-70-l{width:70%}.w-75-l{width:75%}.w-80-l{width:80%}.w-90-l{width:90%}.w-100-l{width:100%}.w-third-l{width:33.33333%}.w-two-thirds-l{width:66.66667%}.w-auto-l{width:auto}}.word-normal{word-break:normal}.word-wrap{word-break:break-all}.word-nowrap{word-break:keep-all}@media screen and (min-width:30em){.word-normal-ns{word-break:normal}.word-wrap-ns{word-break:break-all}.word-nowrap-ns{word-break:keep-all}}@media screen and (min-width:30em) and (max-width:60em){.word-normal-m{word-break:normal}.word-wrap-m{word-break:break-all}.word-nowrap-m{word-break:keep-all}}@media screen and (min-width:60em){.word-normal-l{word-break:normal}.word-wrap-l{word-break:break-all}.word-nowrap-l{word-break:keep-all}}.z-0{z-index:0}.z-1{z-index:1}.z-2{z-index:2}.z-3{z-index:3}.z-4{z-index:4}.z-5{z-index:5}.z-999{z-index:999}.z-9999{z-index:9999}.z-max{z-index:2147483647}.z-inherit{z-index:inherit}.z-initial{z-index:auto}.z-unset{z-index:unset}:root{font-size:13px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale} \ No newline at end of file diff --git a/rootfs/web/src/components/AccessTokenDelete.js b/rootfs/web/src/components/AccessTokenDelete.js deleted file mode 100644 index 0b1eb41..0000000 --- a/rootfs/web/src/components/AccessTokenDelete.js +++ /dev/null @@ -1,33 +0,0 @@ -import { reactive, toRefs } from 'vue' -import { Toast } from "vant"; -import {deleteAccessToken} from "../services/tokens"; - -export default { - name: "AccessTokenDelete", - props: { - token: [Object, Function], - }, - setup(props, context) { - const state = reactive({ - token: props.token, - }) - - const canelDelete = () => { - context.emit('closeDelete', { hasAccessTokenDeleted: false }) - } - - const deleteToken = () => { - deleteAccessToken(state.token.id).then(res=>{ - if (res.status == 204) { - Toast.success("OK") - context.emit('closeDelete', { hasAccessTokenDeleted: true }) - } - }) - } - return { - ...toRefs(state), - canelDelete, - deleteToken - } - } -} diff --git a/rootfs/web/src/components/AccessTokenDelete.vue b/rootfs/web/src/components/AccessTokenDelete.vue index 5420465..f7473cf 100644 --- a/rootfs/web/src/components/AccessTokenDelete.vue +++ b/rootfs/web/src/components/AccessTokenDelete.vue @@ -1,31 +1,30 @@ - diff --git a/rootfs/web/src/components/AccountSidebar.vue b/rootfs/web/src/components/AccountSidebar.vue new file mode 100644 index 0000000..9d13f00 --- /dev/null +++ b/rootfs/web/src/components/AccountSidebar.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/rootfs/web/src/components/Dropdown.vue b/rootfs/web/src/components/Dropdown.vue new file mode 100644 index 0000000..7d8a926 --- /dev/null +++ b/rootfs/web/src/components/Dropdown.vue @@ -0,0 +1,184 @@ + + + + + diff --git a/rootfs/web/src/components/MainFooter.vue b/rootfs/web/src/components/MainFooter.vue new file mode 100644 index 0000000..c8931d8 --- /dev/null +++ b/rootfs/web/src/components/MainFooter.vue @@ -0,0 +1,52 @@ + + + + \ No newline at end of file diff --git a/rootfs/web/src/components/MainNav.js b/rootfs/web/src/components/MainNav.js deleted file mode 100644 index 095e494..0000000 --- a/rootfs/web/src/components/MainNav.js +++ /dev/null @@ -1,32 +0,0 @@ -import { reactive, toRefs} from 'vue' -import { useRouter } from 'vue-router' - -export default { - name: "MainNav", - props: { - isAccessTokenActive: { - type: Boolean, - default: false - }, - isAccountSettingActive: { - type: Boolean, - default: false - }, - }, - setup(props) { - const router = useRouter() - const goToAccessToken = () => { - router.push({ path: `/access-tokens` }) - } - - const goToAccountSetting = () => { - router.push({ path: `/account-setting` }) - } - - return { - goToAccessToken, - goToAccountSetting, - } - }, - -} diff --git a/rootfs/web/src/components/MainNav.vue b/rootfs/web/src/components/MainNav.vue deleted file mode 100644 index 1175c29..0000000 --- a/rootfs/web/src/components/MainNav.vue +++ /dev/null @@ -1,35 +0,0 @@ - - - - - diff --git a/rootfs/web/src/components/MessageRightSidebar.vue b/rootfs/web/src/components/MessageRightSidebar.vue new file mode 100644 index 0000000..2d2a6d8 --- /dev/null +++ b/rootfs/web/src/components/MessageRightSidebar.vue @@ -0,0 +1,119 @@ + + + \ No newline at end of file diff --git a/rootfs/web/src/components/MessageSidebar.vue b/rootfs/web/src/components/MessageSidebar.vue new file mode 100644 index 0000000..126a21f --- /dev/null +++ b/rootfs/web/src/components/MessageSidebar.vue @@ -0,0 +1,111 @@ + + + \ No newline at end of file diff --git a/rootfs/web/src/components/NavBar.js b/rootfs/web/src/components/NavBar.js deleted file mode 100644 index 821a924..0000000 --- a/rootfs/web/src/components/NavBar.js +++ /dev/null @@ -1,10 +0,0 @@ -import NavMenu from "./NavMenu.vue"; -import UserMenu from "./UserMenu.vue"; - -export default { - name: "NavBar", - components: { - 'nav-menu': NavMenu, - 'user-menu': UserMenu - } -} diff --git a/rootfs/web/src/components/NavBar.vue b/rootfs/web/src/components/NavBar.vue index da2838a..c5f3317 100755 --- a/rootfs/web/src/components/NavBar.vue +++ b/rootfs/web/src/components/NavBar.vue @@ -1,26 +1,140 @@ - + - diff --git a/rootfs/web/src/components/NavBox.js b/rootfs/web/src/components/NavBox.js deleted file mode 100644 index 9aea2f7..0000000 --- a/rootfs/web/src/components/NavBox.js +++ /dev/null @@ -1,3 +0,0 @@ -export default { - name: "NavBox" -} diff --git a/rootfs/web/src/components/NavBox.vue b/rootfs/web/src/components/NavBox.vue deleted file mode 100644 index 957087c..0000000 --- a/rootfs/web/src/components/NavBox.vue +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - diff --git a/rootfs/web/src/components/NavMenu.js b/rootfs/web/src/components/NavMenu.js deleted file mode 100644 index a55826d..0000000 --- a/rootfs/web/src/components/NavMenu.js +++ /dev/null @@ -1,23 +0,0 @@ -export default { - name: "NavMenu", - data() { - return { - isMenuActived: false - } - }, - methods: { - openOrCloseMenu() { - this.isMenuActived = !this.isMenuActived; - } - }, - mounted() { - let _this = this - document.addEventListener('click', function (e) { - // 下面这句代码是获取 点击的区域是否包含你的菜单,如果包含,说明点击的是菜单以外,不包含则为菜单以内 - if (e.target.id !== 'menu-nav') { - _this.isMenuActived = false - } - - }) - } -} diff --git a/rootfs/web/src/components/NavMenu.vue b/rootfs/web/src/components/NavMenu.vue index 5a4112e..2442d6a 100644 --- a/rootfs/web/src/components/NavMenu.vue +++ b/rootfs/web/src/components/NavMenu.vue @@ -1,22 +1,82 @@ - diff --git a/rootfs/web/src/components/UserMenu.js b/rootfs/web/src/components/UserMenu.js deleted file mode 100644 index d018cc0..0000000 --- a/rootfs/web/src/components/UserMenu.js +++ /dev/null @@ -1,62 +0,0 @@ -import {onMounted, reactive, toRefs} from "vue"; -import { useRouter } from 'vue-router' -import {dealUser, getUser, postLogout} from "../services/user"; - -export default { - name: "UserMenu", - data() { - return { - isMenuActived: false - } - }, - methods: { - openOrCloseMenu() { - this.isMenuActived = !this.isMenuActived; - } - }, - setup() { - const router = useRouter() - const state = reactive({ - user :{ - username: null, - email: null, - is_superuser: null - }, - }) - const logout = () => { - postLogout().then(res=>{ - if (res.status == 200) { - sessionStorage.clear() - router.push({ path: '/'}) - } - }) - location.reload(true) - } - onMounted(async () => { - let user = sessionStorage.getItem('user') - if (user){ - state.user = JSON.parse(user) - }else { - const res = await getUser() - state.user = dealUser(res) - if (state.user){ - sessionStorage.setItem('user', JSON.stringify(state.user)) - } - } - }) - - return { - ...toRefs(state), - logout - } - }, - mounted() { - let _this = this - document.addEventListener('click', function (e) { - // 下面这句代码是获取 点击的区域是否包含你的菜单,如果包含,说明点击的是菜单以外,不包含则为菜单以内 - if (e.target.id !== 'menu-account') { - _this.isMenuActived = false - } - }) - } -} diff --git a/rootfs/web/src/components/UserMenu.vue b/rootfs/web/src/components/UserMenu.vue index e52bb6c..95bfc36 100644 --- a/rootfs/web/src/components/UserMenu.vue +++ b/rootfs/web/src/components/UserMenu.vue @@ -1,43 +1,152 @@ - + - + diff --git a/rootfs/web/src/env.d.ts b/rootfs/web/src/env.d.ts new file mode 100644 index 0000000..95ee9df --- /dev/null +++ b/rootfs/web/src/env.d.ts @@ -0,0 +1,6 @@ +/// +declare module '*.vue' { + import { DefineComponent } from 'vue' + const component: DefineComponent<{}, {}, any> + export default component +} diff --git a/rootfs/web/src/lang/en_US.js b/rootfs/web/src/lang/en_US.js index f3ccb24..c8ff4e2 100644 --- a/rootfs/web/src/lang/en_US.js +++ b/rootfs/web/src/lang/en_US.js @@ -7,97 +7,5 @@ const customEnUS = { newToDrycc: "New To Drycc? Please contact your adminstrator", } - -const vantEnUS = { - // vant default - name: 'Name', - tel: 'Phone', - save: 'Save', - confirm: 'Confirm', - cancel: 'Cancel', - delete: 'Delete', - complete: 'Complete', - loading: 'Loading...', - telEmpty: 'Please fill in the tel', - nameEmpty: 'Please fill in the name', - nameInvalid: 'Malformed name', - confirmDelete: 'Are you sure you want to delete?', - telInvalid: 'Malformed phone number', - vanCalendar: { - end: 'End', - start: 'Start', - title: 'Calendar', - startEnd: 'Start/End', - weekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], - monthTitle: function monthTitle(year, month) { - return year + "/" + month; - }, - rangePrompt: function rangePrompt(maxRange) { - return "Choose no more than " + maxRange + " days"; - } - }, - vanContactCard: { - addText: 'Add contact info' - }, - vanContactList: { - addText: 'Add new contact' - }, - vanPagination: { - prev: 'Previous', - next: 'Next' - }, - vanPullRefresh: { - pulling: 'Pull to refresh...', - loosing: 'Loose to refresh...' - }, - vanSubmitBar: { - label: 'Total:' - }, - vanCoupon: { - unlimited: 'Unlimited', - discount: function discount(_discount) { - return _discount * 10 + "% off"; - }, - condition: function condition(_condition) { - return "At least " + _condition; - } - }, - vanCouponCell: { - title: 'Coupon', - tips: 'No coupons', - count: function count(_count) { - return "You have " + _count + " coupons"; - } - }, - vanCouponList: { - empty: 'No coupons', - exchange: 'Exchange', - close: 'Close', - enable: 'Available', - disabled: 'Unavailable', - placeholder: 'Coupon code' - }, - vanAddressEdit: { - area: 'Area', - postal: 'Postal', - areaEmpty: 'Please select a receiving area', - addressEmpty: 'Address can not be empty', - postalEmpty: 'Wrong postal code', - defaultAddress: 'Set as the default address', - telPlaceholder: 'Phone', - namePlaceholder: 'Name', - areaPlaceholder: 'Area' - }, - vanAddressEditDetail: { - label: 'Address', - placeholder: 'Address' - }, - vanAddressList: { - add: 'Add new address' - } -} - -const message = Object.assign(customEnUS, vantEnUS) - -export default message +export default customEnUS diff --git a/rootfs/web/src/lang/index.js b/rootfs/web/src/lang/index.js index 786a17e..0796d08 100644 --- a/rootfs/web/src/lang/index.js +++ b/rootfs/web/src/lang/index.js @@ -11,6 +11,7 @@ const ENUM_LANG = { export const i18n = createI18n({ + legacy: false, locale: ENUM_LANG.zhCN, messages: { [ENUM_LANG.enUS]: { @@ -23,16 +24,14 @@ export const i18n = createI18n({ }) export const setLang = (lang) => { - // i18n.global.locale.value = lang - i18n.global.locale = lang + i18n.global.locale.value = lang } export const getLang = () => { - // return i18n && i18n.global.locale.value - return i18n && i18n.global.locale + return i18n && i18n.global.locale.value } -// 获取UA语言类型 +// Get the UA language type export const getUAgentLang = () => { const UA = window.navigator.userAgent const regx = new RegExp(`LANG/(${ENUM_LANG.enUS}|${ENUM_LANG.zhHK}|${ENUM_LANG.zhCN})`, 'g') diff --git a/rootfs/web/src/lang/zh_CN.js b/rootfs/web/src/lang/zh_CN.js index 2c34c83..4a5ad29 100644 --- a/rootfs/web/src/lang/zh_CN.js +++ b/rootfs/web/src/lang/zh_CN.js @@ -7,97 +7,4 @@ const customZhCN = { newToDrycc: "如果您是Drycc的新用户,请联系管理员", } - -const vantZhCN = { - // vant default - name: '姓名', - tel: '电话', - save: '保存', - confirm: '确认', - cancel: '取消', - delete: '删除', - complete: '完成', - loading: '加载中...', - telEmpty: '请填写电话', - nameEmpty: '请填写姓名', - nameInvalid: '请输入正确的姓名', - confirmDelete: '确定要删除吗', - telInvalid: '请输入正确的手机号', - vanCalendar: { - end: '结束', - start: '开始', - title: '日期选择', - confirm: '确定', - startEnd: '开始/结束', - weekdays: ['日', '一', '二', '三', '四', '五', '六'], - monthTitle: function monthTitle(year, month) { - return year + "\u5E74" + month + "\u6708"; - }, - rangePrompt: function rangePrompt(maxRange) { - return "\u9009\u62E9\u5929\u6570\u4E0D\u80FD\u8D85\u8FC7 " + maxRange + " \u5929"; - } - }, - vanContactCard: { - addText: '添加联系人' - }, - vanContactList: { - addText: '新建联系人' - }, - vanPagination: { - prev: '上一页', - next: '下一页' - }, - vanPullRefresh: { - pulling: '下拉即可刷新...', - loosing: '释放即可刷新...' - }, - vanSubmitBar: { - label: '合计:' - }, - vanCoupon: { - unlimited: '无使用门槛', - discount: function discount(_discount) { - return _discount + "\u6298"; - }, - condition: function condition(_condition) { - return "\u6EE1" + _condition + "\u5143\u53EF\u7528"; - } - }, - vanCouponCell: { - title: '优惠券', - tips: '暂无可用', - count: function count(_count) { - return _count + "\u5F20\u53EF\u7528"; - } - }, - vanCouponList: { - empty: '暂无优惠券', - exchange: '兑换', - close: '不使用优惠券', - enable: '可用', - disabled: '不可用', - placeholder: '请输入优惠码' - }, - vanAddressEdit: { - area: '地区', - postal: '邮政编码', - areaEmpty: '请选择地区', - addressEmpty: '请填写详细地址', - postalEmpty: '邮政编码格式不正确', - defaultAddress: '设为默认收货地址', - telPlaceholder: '收货人手机号', - namePlaceholder: '收货人姓名', - areaPlaceholder: '选择省 / 市 / 区' - }, - vanAddressEditDetail: { - label: '详细地址', - placeholder: '街道门牌、楼层房间号等信息' - }, - vanAddressList: { - add: '新增地址' - } -} - -const message = Object.assign(customZhCN, vantZhCN) - -export default message +export default customZhCN diff --git a/rootfs/web/src/main.js b/rootfs/web/src/main.ts similarity index 52% rename from rootfs/web/src/main.js rename to rootfs/web/src/main.ts index 16fb05f..a4d7815 100644 --- a/rootfs/web/src/main.js +++ b/rootfs/web/src/main.ts @@ -1,26 +1,27 @@ import App from './App.vue' import router from './router' import { createApp } from 'vue' -import { Toast } from 'vant'; import { i18n, setLang, getUAgentLang } from './lang' -import 'vant/lib/index.css'; +import './styles/unified.css' + +declare global { + interface Date { + format(format: string): string; + } +} /** - * 时间对象的格式化; + * Date object formatting; */ -Date.prototype.format = function(format) { - /* - * eg:format="yyyy-MM-dd hh:mm:ss"; - */ - var o = { - "M+" : this.getMonth() + 1, // month - "d+" : this.getDate(), // day - "h+" : this.getHours(), // hour - "m+" : this.getMinutes(), // minute - "s+" : this.getSeconds(), // second - "q+" : Math.floor((this.getMonth() + 3) / 3), // quarter +Date.prototype.format = function(format: string) { + var o: Record = { + "M+" : this.getMonth() + 1, + "d+" : this.getDate(), + "h+" : this.getHours(), + "m+" : this.getMinutes(), + "s+" : this.getSeconds(), + "q+" : Math.floor((this.getMonth() + 3) / 3), "S" : this.getMilliseconds() - // millisecond } if (/(y+)/.test(format)) { @@ -29,15 +30,15 @@ Date.prototype.format = function(format) { for (var k in o) { if (new RegExp("(" + k + ")").test(format)) { - format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)); + format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k].toString() : ("00" + o[k]).substr(("" + o[k]).length)); } } return format; } -// 初始化 +// Initialization function init () { - // 语言初始化 + // Language initialization const lang = getUAgentLang() setLang(lang) } @@ -47,5 +48,4 @@ init() const app = createApp(App) app.use(router) app.use(i18n) -app.use(Toast); app.mount('#app') diff --git a/rootfs/web/src/router/index.js b/rootfs/web/src/router/index.js deleted file mode 100644 index 4ebbb19..0000000 --- a/rootfs/web/src/router/index.js +++ /dev/null @@ -1,28 +0,0 @@ -import { createRouter, createWebHistory } from 'vue-router' -import AccessTokenList from "../views/AccessTokenList.vue"; -import AccountSetting from "../views/AccountSetting.vue"; - - -const routes = [ - { - path: '/', - redirect: '/access-tokens', - }, - { - path: '/access-tokens', - name: 'AccessTokenList', - component: AccessTokenList - }, - { - path: '/account-setting', - name: 'AccountSetting', - component: AccountSetting - }, -] - -const router = createRouter({ - history: createWebHistory(), - routes -}) - -export default router diff --git a/rootfs/web/src/router/index.ts b/rootfs/web/src/router/index.ts new file mode 100644 index 0000000..2995668 --- /dev/null +++ b/rootfs/web/src/router/index.ts @@ -0,0 +1,45 @@ +import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router' +import AccessTokenList from "../views/AccessTokenList.vue"; +import AccountSetting from "../views/AccountSetting.vue"; + + +const routes: Array = [ + { + path: '/', + name: 'Overview', + component: () => import('../views/Overview.vue') + }, + { + path: '/access-tokens', + name: 'AccessTokenList', + component: AccessTokenList + }, + { + path: '/account-setting', + name: 'AccountSetting', + component: AccountSetting + }, + { + path: '/messages', + name: 'messages', + component: () => import('../views/MessageList.vue') + }, + { + path: '/messages/preferences', + name: 'message-preferences', + component: () => import('../views/MessagePreferences.vue') + }, + { + path: '/messages/:id', + name: 'message-detail', + component: () => import('../views/MessageDetail.vue'), + props: true + }, +] + +const router = createRouter({ + history: createWebHistory(), + routes +}) + +export default router diff --git a/rootfs/web/src/services/identities.js b/rootfs/web/src/services/identities.js new file mode 100644 index 0000000..3081dea --- /dev/null +++ b/rootfs/web/src/services/identities.js @@ -0,0 +1,21 @@ +import axios from "../utils/axios"; + +export const getIdentityProviders = () => { + return axios.get('/user/identity-providers/') +} + +export const getLinkedIdentities = () => { + return axios.get('/user/identities/') +} + +export const unlinkIdentity = (identityId) => { + return axios.delete(`/user/identities/${identityId}`) +} + +export const getOAuthPending = () => { + return axios.get('/user/oauth/pending/') +} + +export const createOAuthUser = (payload) => { + return axios.post('/user/oauth/create/', payload) +} \ No newline at end of file diff --git a/rootfs/web/src/services/messages.js b/rootfs/web/src/services/messages.js new file mode 100644 index 0000000..4db0665 --- /dev/null +++ b/rootfs/web/src/services/messages.js @@ -0,0 +1,65 @@ +import axios from "../utils/axios"; + +export function getMessages(category, limit = 30, offset = 0, isRead = undefined, search = undefined) { + const params = { limit, offset }; + if (category && category !== 'all') { + params.category = category; + } + if (isRead !== undefined) { + params.is_read = isRead; + } + if (search) { + params.search = search; + } + return axios.get(`/user/messages/`, { params }) +} + +export function dealMessages(obj) { + return { + count: obj.data.count, + next: obj.data.next, + previous: obj.data.previous, + results: obj.data.results.map(item => { + return { + id: item.id, + category: item.category, + title: item.title, + content: item.content, + date: item.date, + isRead: item.is_read, + severity: item.severity + } + }) + } +} + +export function getMessageDetail(id) { + return axios.get(`/user/messages/` + id) +} + +export function dealMessageDetail(obj) { + const item = obj.data; + return { + id: item.id, + category: item.category, + title: item.title, + fullContent: item.full_content || item.content, + date: item.date, + isRead: item.is_read, + severity: item.severity, + actionLink: item.action_link, + actionText: item.action_text + } +} + +export function markAllAsRead() { + return axios.put(`/user/messages/mark-all-read/`) +} + +export function getMessagePreferences() { + return axios.get(`/user/message-preferences/`) +} + +export function updateMessagePreferences(data) { + return axios.put(`/user/message-preferences/`, data) +} diff --git a/rootfs/web/src/services/settings.js b/rootfs/web/src/services/settings.js new file mode 100644 index 0000000..92f5724 --- /dev/null +++ b/rootfs/web/src/services/settings.js @@ -0,0 +1,5 @@ +import axios from "../utils/axios"; + +export function getSettings() { + return axios.get(`/settings/`) +} \ No newline at end of file diff --git a/rootfs/web/src/services/tokens.js b/rootfs/web/src/services/tokens.js index 42a702a..e628add 100644 --- a/rootfs/web/src/services/tokens.js +++ b/rootfs/web/src/services/tokens.js @@ -5,7 +5,7 @@ export function getAccessTokenList() { } export function dealAccessTokenList(obj) { - return obj.data.map(item => { + return obj.data.results.map(item => { return { id: item.id, application: item.application, diff --git a/rootfs/web/src/services/user.js b/rootfs/web/src/services/user.js index 0fb7d9d..0eae35a 100644 --- a/rootfs/web/src/services/user.js +++ b/rootfs/web/src/services/user.js @@ -8,6 +8,8 @@ export function dealUser(obj) { return { username: obj.data.username, email: obj.data.email, + first_name: obj.data.first_name, + last_name: obj.data.last_name, } } diff --git a/rootfs/web/src/store.ts b/rootfs/web/src/store.ts new file mode 100644 index 0000000..40e5905 --- /dev/null +++ b/rootfs/web/src/store.ts @@ -0,0 +1,31 @@ +import { reactive } from 'vue' +import { getSettings } from './services/settings' + +export const globalState = reactive({ + dashboardUrl: '/', + contactSupportUrl: 'https://community.drycc.cc/', + settingsLoaded: false, + // Bumped whenever the user's message read-state changes (e.g. mark-all-read, + // mark single message as read). Components that display messages should + // watch this value and refresh their local state. + messagesVersion: 0, +}) + +/** Notify all message-aware components to refresh. */ +export const invalidateMessages = () => { + globalState.messagesVersion += 1 +} + +export const fetchGlobalSettings = async () => { + if (globalState.settingsLoaded) return; + try { + const res = await getSettings() + if (res.data) { + if (res.data.dashboard_url) globalState.dashboardUrl = res.data.dashboard_url + if (res.data.contact_support_url) globalState.contactSupportUrl = res.data.contact_support_url + } + globalState.settingsLoaded = true + } catch (e) { + console.error("Failed to fetch settings", e) + } +} diff --git a/rootfs/web/src/styles/unified.css b/rootfs/web/src/styles/unified.css new file mode 100644 index 0000000..deaf7d0 --- /dev/null +++ b/rootfs/web/src/styles/unified.css @@ -0,0 +1,20 @@ +@import "tailwindcss"; + +@theme { + --color-primary: #409eff; + --color-primary-50: #ecf5ff; + --color-primary-100: #d9ecff; + --color-primary-200: #c6e2ff; + --color-primary-300: #8cc5ff; + --color-primary-400: #66b1ff; + --color-primary-500: #409eff; + --color-primary-600: #337ecc; + --color-primary-700: #2966a3; + --color-primary-800: #1f4c7a; + --color-primary-900: #143352; +} + +body { + background-color: #f3f4f6; + min-height: 100vh; +} diff --git a/rootfs/web/src/utils/axios.js b/rootfs/web/src/utils/axios.js index 77927d6..b410a62 100755 --- a/rootfs/web/src/utils/axios.js +++ b/rootfs/web/src/utils/axios.js @@ -1,14 +1,19 @@ import axios from 'axios' -import { Toast } from 'vant' +const ElMessage = { success: alert, error: alert }; const ElLoading = { service: () => ({ close: () => {} }) } import {getCookie} from "./array"; -axios.defaults.baseURL = import.meta.env.VITE_APP_BASE_API +axios.defaults.baseURL = process.env.VUE_APP_BASE_URL axios.defaults.withCredentials = true -axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest' axios.defaults.headers.post['Content-Type'] = 'application/json' +const loadingToast = []; axios.interceptors.request.use( (config)=>{ + loadingToast.push(ElLoading.service({ + lock: true, + text: "Loading...", + background: "rgba(0, 0, 0, 0.2)", + })); let csrftoken = getCookie('csrftoken') if(csrftoken){ config.headers['X-CSRFToken'] = csrftoken; @@ -19,6 +24,9 @@ axios.interceptors.request.use( axios.interceptors.response.use( response => { + if (loadingToast.length > 0) { + loadingToast.pop().close(); + } if ([200, 201, 204].indexOf(response.status) >= 0) { return Promise.resolve(response); } else { @@ -26,7 +34,10 @@ axios.interceptors.response.use( } }, error => { - if (error.response.status) { + if (loadingToast.length > 0) { + loadingToast.pop().close(); + } + if (error.response && error.response.status) { switch (error.response.status) { case 401: window.location.replace("/user/login/"); @@ -43,36 +54,37 @@ axios.interceptors.response.use( forbidClick: true }); } + break; case 404: console.log('error.response: ', error.response) if(error.response.data){ - Toast({ - message: error.response.data.replace("\"","").replace("\"",""), - duration: 1500, - forbidClick: true - }); + ElMessage({ + message: error.response.data.replace("\"","").replace("\"",""), + type: "error", + duration: 1500, + }); }else { - Toast({ - message: 'The request does not exist.', - duration: 1500, - forbidClick: true - }); + ElMessage({ + message: 'The request does not exist.', + type: "error", + duration: 1500, + }); } break; case 400: console.log('error.response: ', error.response) if(error.response.data.detail){ - Toast({ - message: error.response.data.detail.replace("\"","").replace("\"",""), - duration: 1500, - forbidClick: true - }); + ElMessage({ + message: error.response.data.detail.replace("\"","").replace("\"",""), + type: "error", + duration: 1500, + }); }else { - Toast({ - message: 'The request parameter error', - duration: 1500, - forbidClick: true - }); + ElMessage({ + message: 'The request parameter error', + type: "error", + duration: 1500, + }); } break; // other error @@ -83,8 +95,9 @@ axios.interceptors.response.use( forbidClick: true }); } - return Promise.reject(error.response); + return Promise.reject(error); } + return Promise.reject(error); } ); diff --git a/rootfs/web/src/views/AccessTokenList.js b/rootfs/web/src/views/AccessTokenList.js deleted file mode 100644 index 2c64764..0000000 --- a/rootfs/web/src/views/AccessTokenList.js +++ /dev/null @@ -1,50 +0,0 @@ -import NavBar from "../components/NavBar.vue"; -import NavBox from "../components/NavBox.vue"; -import {onBeforeMount, reactive, toRefs} from 'vue' -import MainNav from "../components/MainNav.vue"; -import AccessTokenDelete from "../components/AccessTokenDelete.vue" -import {dealAccessTokenList, getAccessTokenList, deleteAccessToken} from "../services/tokens"; - -export default { - name: "AccessTokenList", - components: { - 'nav-bar': NavBar, - 'nav-box': NavBox, - 'main-nav': MainNav, - 'access-token-delete': AccessTokenDelete - }, - setup() { - const state = reactive({ - tokens: [], - token: Object, - isShowDelete: false, - }) - - onBeforeMount(async () => { - await fetchAccessTokenList() - }) - - const fetchAccessTokenList = (async () => { - let res = await getAccessTokenList() - state.tokens = res.data ? dealAccessTokenList(res) : [] - }) - - const showDelete = (index) => { - state.isShowDelete = true - state.token = state.tokens.slice(index, index + 1)[0]; - } - - const closeDelete = (param) => { - state.isShowDelete = false - if (param.hasAccessTokenDeleted) { - fetchAccessTokenList() - } - } - - return { - ...toRefs(state), - showDelete, - closeDelete - } - }, -} diff --git a/rootfs/web/src/views/AccessTokenList.vue b/rootfs/web/src/views/AccessTokenList.vue index f754d50..0d2d46d 100644 --- a/rootfs/web/src/views/AccessTokenList.vue +++ b/rootfs/web/src/views/AccessTokenList.vue @@ -1,60 +1,170 @@ - + - diff --git a/rootfs/web/src/views/AccountSetting.js b/rootfs/web/src/views/AccountSetting.js deleted file mode 100644 index 483d7e1..0000000 --- a/rootfs/web/src/views/AccountSetting.js +++ /dev/null @@ -1,149 +0,0 @@ -import NavBar from "../components/NavBar.vue"; -import NavBox from "../components/NavBox.vue"; -import {onBeforeMount, reactive, toRefs} from 'vue' -import MainNav from "../components/MainNav.vue"; -import { useRouter } from 'vue-router' -import { putAccount, putAccountPassword } from "../services/user"; -import { Toast } from "vant" - -export default { - name: "AccountSetting", - components: { - 'nav-bar': NavBar, - 'nav-box': NavBox, - 'main-nav': MainNav, - }, - setup() { - const showBTN = "flex items-center mb2" - const hiddenBTN = "flex items-center mb2 clip" - const hiddenUpdateBTN = "async-button default hk-button--disabled-primary ember-view" - const showUpdateBTN = "async-button default hk-button--primary ember-view" - - var currentPassword, newPassword, confirmNewPassword - - const router = useRouter() - const state = reactive({ - user: Object, - originUser: Object, - emailBTN: hiddenBTN, - nameBTN: hiddenBTN, - updateBTN: hiddenUpdateBTN - }) - - onBeforeMount(async () => { - state.user = JSON.parse(sessionStorage.getItem('user')) - state.originUser = JSON.parse(sessionStorage.getItem('user')) - }) - - const updateUser = () => { - sessionStorage.setItem('user', JSON.stringify(state.user)) - state.originUser = state.user - } - - const emailInputChage = (event) => { - let newEmail = event.currentTarget.value - if (newEmail != state.originUser.email) { - state.emailBTN = showBTN - } else { - state.emailBTN = hiddenBTN - } - state.user.email = newEmail - } - - const nameInputChage = (event) => { - let newName = event.currentTarget.value - if (newName != state.originUser.username) { - state.nameBTN = showBTN - } else { - state.nameBTN = hiddenBTN - } - state.user.username = newName - } - - const currentPasswordChage = (event) => { - currentPassword = event.currentTarget.value - if (currentPassword && newPassword && confirmNewPassword) { - state.updateBTN = showUpdateBTN - } else { - state.updateBTN = hiddenUpdateBTN - } - } - const newPasswordChage = (event) => { - newPassword = event.currentTarget.value - if (currentPassword && newPassword && confirmNewPassword) { - state.updateBTN = showUpdateBTN - } else { - state.updateBTN = hiddenUpdateBTN - } - } - const confirmNewPasswordChage = (event) => { - confirmNewPassword = event.currentTarget.value - if (currentPassword && newPassword && confirmNewPassword) { - state.updateBTN = showUpdateBTN - } else { - state.updateBTN = hiddenUpdateBTN - } - } - const submitEmail = () => { - var re = /^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$/; - if(!re.test(state.user.email)) { - Toast.fail("this email is not valid.") - } else { - putAccount({email: state.user.email}).then(res=>{ - if (res.status == 204) { - updateUser() - state.emailBTN = hiddenBTN - } - }) - } - } - - const submitName = () => { - putAccount({username: state.user.username}).then(res=>{ - if (res.status == 204) { - updateUser() - state.nameBTN = hiddenBTN - } - }) - } - - const submitPassowrd = () => { - if (currentPassword == newPassword){ - Toast.fail("Current Password and New Password are the same.") - } else if( newPassword.length >= 8){ - Toast.fail("this New Password is not valid.") - } else if (newPassword != confirmNewPassword){ - Toast.fail("New Password Confirm and New Password are different.") - }else { - putAccountPassword({password: currentPassword, new_password: newPassword}).then(res=>{ - if (res.status == 204) { - router.push({ path: `/` }) - } - }) - } - } - - const cancelEmail = () => { - state.emailBTN = hiddenBTN - state.user.email = state.originUser.email - } - - const cancelName = () => { - state.nameBTN = hiddenBTN - state.user.username = state.originUser.username - } - return { - ...toRefs(state), - emailInputChage, - nameInputChage, - submitEmail, - cancelEmail, - submitName, - cancelName, - currentPasswordChage, - newPasswordChage, - confirmNewPasswordChage, - submitPassowrd - } - }, -} diff --git a/rootfs/web/src/views/AccountSetting.vue b/rootfs/web/src/views/AccountSetting.vue index aaf5058..2c579f1 100644 --- a/rootfs/web/src/views/AccountSetting.vue +++ b/rootfs/web/src/views/AccountSetting.vue @@ -1,149 +1,558 @@ - + + + +export default { + name: "AccountSetting", + components: { + 'nav-bar': NavBar, + 'account-sidebar': AccountSidebar, + 'main-footer': MainFooter, + }, + setup() { + const showBTN = "ui-inline-actions" + const hiddenBTN = "ui-inline-actions is-hidden" + + const router = useRouter() + const state = reactive({ + user: { + username: null, + email: null, + first_name: null, + last_name: null + }, + originUser: { + username: null, + email: null, + first_name: null, + last_name: null + }, + passwords: { + current: '', + new: '', + confirm: '' + }, + emailBTN: hiddenBTN, + nameBTN: hiddenBTN, + firstNameBTN: hiddenBTN, + lastNameBTN: hiddenBTN, + providers: [], + identities: [], + loading: false, + }) + + const isProfileChanged = computed(() => { + return state.user.email !== state.originUser.email || + state.user.first_name !== state.originUser.first_name || + state.user.last_name !== state.originUser.last_name; + }) + + const isPasswordFormValid = computed(() => { + return state.passwords.current && state.passwords.new && state.passwords.confirm; + }) - + const passwordMismatch = computed(() => { + if (!state.passwords.new || !state.passwords.confirm) return false; + return state.passwords.new !== state.passwords.confirm; + }) + + onMounted(async () => { + const res = await getUser() + const userData = dealUser(res) + state.user = { ...userData } + state.originUser = { ...userData } + await fetchProviders() + await fetchIdentities() + }) + + const fetchProviders = async () => { + state.loading = true + try { + const res = await getIdentityProviders() + state.providers = res.data?.results || [] + } finally { + state.loading = false + } + } + + const fetchIdentities = async () => { + state.loading = true + try { + const res = await getLinkedIdentities() + state.identities = res.data?.results || [] + } finally { + state.loading = false + } + } + + const handleLink = (provider) => { + if (!provider?.login_url) { + ElMessage.error("Provider login URL missing.") + return + } + window.location.href = provider.login_url + } + + const handleUnlink = async (identity) => { + if (!identity?.id) { + return + } + await unlinkIdentity(identity.id) + ElMessage.success("Unlinked successfully.") + await fetchIdentities() + } + + const updateUser = () => { + state.originUser = { ...state.user } + } + + const emailInputChange = (event) => { + let newEmail = event.currentTarget.value + if (newEmail != state.originUser.email) { + state.emailBTN = showBTN + } else { + state.emailBTN = hiddenBTN + } + state.user.email = newEmail + } + + const firstNameInputChange = (event) => { + let newFirstName = event.currentTarget.value + if (newFirstName != state.originUser.first_name) { + state.firstNameBTN = showBTN + } else { + state.firstNameBTN = hiddenBTN + } + state.user.first_name = newFirstName + } + + const lastNameInputChange = (event) => { + let newLastName = event.currentTarget.value + if (newLastName != state.originUser.last_name) { + state.lastNameBTN = showBTN + } else { + state.lastNameBTN = hiddenBTN + } + state.user.last_name = newLastName + } + + const currentPasswordChange = (event) => { + state.passwords.current = event.currentTarget.value + } + const newPasswordChange = (event) => { + state.passwords.new = event.currentTarget.value + } + const confirmNewPasswordChange = (event) => { + state.passwords.confirm = event.currentTarget.value + } + const submitProfile = () => { + var re = /^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$/; + if(!re.test(state.user.email)) { + ElMessage.error("This email is not valid.") + return; + } + putAccount({ + email: state.user.email, + first_name: state.user.first_name, + last_name: state.user.last_name + }).then(res=>{ + if (res.status == 204) { + updateUser() + ElMessage.success("Profile updated successfully") + } + }) + } + + const submitPassowrd = () => { + if (state.passwords.current == state.passwords.new){ + ElMessage.error("Current Password and New Password are the same.") + } else if( state.passwords.new.length < 8){ + ElMessage.error("this New Password is not valid.") + } else if (state.passwords.new != state.passwords.confirm){ + ElMessage.error("New Password Confirm and New Password are different.") + }else { + putAccountPassword({password: state.passwords.current, new_password: state.passwords.new}).then(res=>{ + if (res.status == 204) { + router.push({ path: `/` }) + } + }) + } + } + + const cancelEmail = () => { + state.emailBTN = hiddenBTN + state.user.email = state.originUser.email + } + + const cancelFirstName = () => { + state.firstNameBTN = hiddenBTN + state.user.first_name = state.originUser.first_name + } + + const cancelLastName = () => { + state.lastNameBTN = hiddenBTN + state.user.last_name = state.originUser.last_name + } + + const getProviderIcon = (providerName) => { + const provider = state.providers.find((p) => p.name === providerName) + if (provider) { + return provider.icon + } + return null + } + + return { + getProviderIcon, + ...toRefs(state), + isProfileChanged, + isPasswordFormValid, + passwordMismatch, + emailInputChange, + firstNameInputChange, + lastNameInputChange, + submitProfile, + currentPasswordChange, + newPasswordChange, + confirmNewPasswordChange, + submitPassowrd, + handleLink, + handleUnlink + } + }, +} + + diff --git a/rootfs/web/src/views/MessageDetail.vue b/rootfs/web/src/views/MessageDetail.vue new file mode 100644 index 0000000..74a91ef --- /dev/null +++ b/rootfs/web/src/views/MessageDetail.vue @@ -0,0 +1,164 @@ + + + diff --git a/rootfs/web/src/views/MessageList.vue b/rootfs/web/src/views/MessageList.vue new file mode 100644 index 0000000..4848c6c --- /dev/null +++ b/rootfs/web/src/views/MessageList.vue @@ -0,0 +1,252 @@ + + + + + diff --git a/rootfs/web/src/views/MessagePreferences.vue b/rootfs/web/src/views/MessagePreferences.vue new file mode 100644 index 0000000..a5b905a --- /dev/null +++ b/rootfs/web/src/views/MessagePreferences.vue @@ -0,0 +1,310 @@ + + + diff --git a/rootfs/web/src/views/Overview.vue b/rootfs/web/src/views/Overview.vue new file mode 100644 index 0000000..058bf24 --- /dev/null +++ b/rootfs/web/src/views/Overview.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/rootfs/web/tsconfig.json b/rootfs/web/tsconfig.json new file mode 100644 index 0000000..9c3e181 --- /dev/null +++ b/rootfs/web/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "moduleResolution": "bundler", + "strict": false, + "jsx": "preserve", + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "lib": ["ESNext", "DOM"], + "skipLibCheck": true, + "noEmit": true + }, + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/rootfs/web/tsconfig.node.json b/rootfs/web/tsconfig.node.json new file mode 100644 index 0000000..36b98be --- /dev/null +++ b/rootfs/web/tsconfig.node.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "composite": true, + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": false, + "jsx": "preserve", + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "lib": ["ESNext", "DOM"], + "skipLibCheck": true + }, + "include": ["vite.config.ts"] +} diff --git a/rootfs/web/vite.config.js b/rootfs/web/vite.config.js deleted file mode 100644 index 315212d..0000000 --- a/rootfs/web/vite.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue()] -}) diff --git a/rootfs/web/vite.config.ts b/rootfs/web/vite.config.ts new file mode 100644 index 0000000..8b2a5de --- /dev/null +++ b/rootfs/web/vite.config.ts @@ -0,0 +1,27 @@ +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; +import tailwindcss from "@tailwindcss/vite"; + +const VUE_APP_BASE_URL = process.env.VUE_APP_BASE_URL || ""; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], + build: { + minify: true, + chunkSizeWarningLimit: 3000, + }, + server: { + proxy: { + "/orgs": { target: VUE_APP_BASE_URL, changeOrigin: false, xfwd: true }, + "/user": { target: VUE_APP_BASE_URL, changeOrigin: false, xfwd: true }, + "/auth": { target: VUE_APP_BASE_URL, changeOrigin: false, xfwd: true }, + "/oauth": { target: VUE_APP_BASE_URL, changeOrigin: false, xfwd: true }, + "/assets": { target: VUE_APP_BASE_URL, changeOrigin: false, xfwd: true }, + "/settings": { target: VUE_APP_BASE_URL, changeOrigin: false, xfwd: true } + }, + }, + define: { + "process.env.VUE_APP_BASE_URL": JSON.stringify(VUE_APP_BASE_URL), + }, +}); diff --git a/rootfs/web/yarn.lock b/rootfs/web/yarn.lock deleted file mode 100644 index 0cad52e..0000000 --- a/rootfs/web/yarn.lock +++ /dev/null @@ -1,522 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/helper-validator-identifier@^7.14.9": - version "7.14.9" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48" - integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g== - -"@babel/parser@^7.12.0", "@babel/parser@^7.13.9": - version "7.15.2" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.2.tgz#08d4ffcf90d211bf77e7cc7154c6f02d468d2b1d" - integrity sha512-bMJXql1Ss8lFnvr11TZDH4ArtwlAS5NG9qBmdiFW2UHHm6MVoR+GDc5XE2b9K938cyjc9O6/+vjjcffLDtfuDg== - -"@babel/types@^7.12.0", "@babel/types@^7.13.0": - version "7.15.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.0.tgz#61af11f2286c4e9c69ca8deb5f4375a73c72dcbd" - integrity sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ== - dependencies: - "@babel/helper-validator-identifier" "^7.14.9" - to-fast-properties "^2.0.0" - -"@intlify/core-base@9.1.7": - version "9.1.7" - resolved "https://registry.nlark.com/@intlify/core-base/download/@intlify/core-base-9.1.7.tgz#a454a492683690bc3d0abab82605ab5a23645bd0" - integrity sha1-pFSkkmg2kLw9Crq4JgWrWiNkW9A= - dependencies: - "@intlify/devtools-if" "9.1.7" - "@intlify/message-compiler" "9.1.7" - "@intlify/message-resolver" "9.1.7" - "@intlify/runtime" "9.1.7" - "@intlify/shared" "9.1.7" - "@intlify/vue-devtools" "9.1.7" - -"@intlify/devtools-if@9.1.7": - version "9.1.7" - resolved "https://registry.nlark.com/@intlify/devtools-if/download/@intlify/devtools-if-9.1.7.tgz#a5df0f33e06c3ead3e53b7f4d4b10a2d52309361" - integrity sha1-pd8PM+BsPq0+U7f01LEKLVIwk2E= - dependencies: - "@intlify/shared" "9.1.7" - -"@intlify/message-compiler@9.1.7": - version "9.1.7" - resolved "https://registry.nlark.com/@intlify/message-compiler/download/@intlify/message-compiler-9.1.7.tgz#4663fcc2a190f3cc6970e12565c8d6f22beeb719" - integrity sha1-RmP8wqGQ88xpcOElZcjW8ivutxk= - dependencies: - "@intlify/message-resolver" "9.1.7" - "@intlify/shared" "9.1.7" - source-map "0.6.1" - -"@intlify/message-resolver@9.1.7": - version "9.1.7" - resolved "https://registry.nlark.com/@intlify/message-resolver/download/@intlify/message-resolver-9.1.7.tgz#a95d13866c8de85784358039c8845668152e4162" - integrity sha1-qV0ThmyN6FeENYA5yIRWaBUuQWI= - -"@intlify/runtime@9.1.7": - version "9.1.7" - resolved "https://registry.nlark.com/@intlify/runtime/download/@intlify/runtime-9.1.7.tgz#67e0d6b2fd85a5b0b301a151c2f436f93154c3c6" - integrity sha1-Z+DWsv2FpbCzAaFRwvQ2+TFUw8Y= - dependencies: - "@intlify/message-compiler" "9.1.7" - "@intlify/message-resolver" "9.1.7" - "@intlify/shared" "9.1.7" - -"@intlify/shared@9.1.7": - version "9.1.7" - resolved "https://registry.nlark.com/@intlify/shared/download/@intlify/shared-9.1.7.tgz#e7d8bc90cb59dc17dd7b4c85a73db16fcb7891fc" - integrity sha1-59i8kMtZ3Bfde0yFpz2xb8t4kfw= - -"@intlify/vue-devtools@9.1.7": - version "9.1.7" - resolved "https://registry.nlark.com/@intlify/vue-devtools/download/@intlify/vue-devtools-9.1.7.tgz#b08d39bb5f21ba9b1954eab9466e9408129425a7" - integrity sha1-sI05u18hupsZVOq5Rm6UCBKUJac= - dependencies: - "@intlify/message-resolver" "9.1.7" - "@intlify/runtime" "9.1.7" - "@intlify/shared" "9.1.7" - -"@popperjs/core@^2.9.2": - version "2.9.3" - resolved "https://registry.nlark.com/@popperjs/core/download/@popperjs/core-2.9.3.tgz#8b68da1ebd7fc603999cf6ebee34a4899a14b88e" - integrity sha1-i2jaHr1/xgOZnPbr7jSkiZoUuI4= - -"@types/estree@^0.0.48": - version "0.0.48" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.48.tgz#18dc8091b285df90db2f25aa7d906cfc394b7f74" - integrity sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew== - -"@vant/icons@^1.7.0": - version "1.7.0" - resolved "https://registry.nlark.com/@vant/icons/download/@vant/icons-1.7.0.tgz#02d427532a8142c35db159da9c364fe6890c3ac9" - integrity sha1-AtQnUyqBQsNdsVnanDZP5okMOsk= - -"@vant/lazyload@^1.2.0": - version "1.2.0" - resolved "https://registry.nlark.com/@vant/lazyload/download/@vant/lazyload-1.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40vant%2Flazyload%2Fdownload%2F%40vant%2Flazyload-1.2.0.tgz#62e9779bd7844ad8f71c2ca2bf852e6147c7a86d" - integrity sha1-Yul3m9eEStj3HCyiv4UuYUfHqG0= - -"@vant/popperjs@^1.1.0": - version "1.1.0" - resolved "https://registry.npm.taobao.org/@vant/popperjs/download/@vant/popperjs-1.1.0.tgz#b4edee5bbfa6fb18705986e313d4fd5f17942a0f" - integrity sha1-tO3uW7+m+xhwWYbjE9T9XxeUKg8= - dependencies: - "@popperjs/core" "^2.9.2" - -"@vant/use@^1.2.2": - version "1.3.0" - resolved "https://registry.nlark.com/@vant/use/download/@vant/use-1.3.0.tgz?cache=0&sync_timestamp=1628323555739&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40vant%2Fuse%2Fdownload%2F%40vant%2Fuse-1.3.0.tgz#b7d461c00078f7501ff7678771f1431fbf747b42" - integrity sha1-t9RhwAB491Af92eHcfFDH790e0I= - -"@vitejs/plugin-vue@^1.3.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-1.4.0.tgz#962ae01b7fd16ad4007898c64ed639136e12215b" - integrity sha512-RkqfJHz9wdLKBp5Yi+kQL8BAljdrvPoccQm2PTZc/UcL4EjD11xsv2PPCduYx2oV1a/bpSKA3sD5sxOHFhz+LA== - -"@vue/compiler-core@3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.1.tgz#8e13232f7aef8e308fb2d4a10571a5640257064b" - integrity sha512-UEJf2ZGww5wGVdrWIXIZo04KdJFGPmI2bHRUsBZ3AdyCAqJ5ykRXKOBn1OR1hvA2YzimudOEyHM+DpbBv91Kww== - dependencies: - "@babel/parser" "^7.12.0" - "@babel/types" "^7.12.0" - "@vue/shared" "3.2.1" - estree-walker "^2.0.1" - source-map "^0.6.1" - -"@vue/compiler-dom@3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.1.tgz#5cc68873f1928c7b9aee8c8a2846f7f362cb1ab9" - integrity sha512-tXg8tkPb3j54zNfWqoao9T1JI41yWPz8TROzmif/QNNA46eq8/SRuRsBd36i47GWaz7mh+yg3vOJ87/YBjcMyQ== - dependencies: - "@vue/compiler-core" "3.2.1" - "@vue/shared" "3.2.1" - -"@vue/compiler-sfc@^3.0.5": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.1.tgz#7809b298cf0fbce62a2c628b7dfc1e82dd9a3a9b" - integrity sha512-fVLdme5RZVkBt+jxv2LCSRM72o4FX7BR2eu2FpjjEi1kEtUMKBDnjKwGWy7TyhTju0t0CocctyoM+G56vH7NpQ== - dependencies: - "@babel/parser" "^7.13.9" - "@babel/types" "^7.13.0" - "@types/estree" "^0.0.48" - "@vue/compiler-core" "3.2.1" - "@vue/compiler-dom" "3.2.1" - "@vue/compiler-ssr" "3.2.1" - "@vue/shared" "3.2.1" - consolidate "^0.16.0" - estree-walker "^2.0.1" - hash-sum "^2.0.0" - lru-cache "^5.1.1" - magic-string "^0.25.7" - merge-source-map "^1.1.0" - postcss "^8.1.10" - postcss-modules "^4.0.0" - postcss-selector-parser "^6.0.4" - source-map "^0.6.1" - -"@vue/compiler-ssr@3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.1.tgz#f900762f83482e44e9260c2322e3d332c711826c" - integrity sha512-6YAOtQunuEyYlVSjK1F7a7BXi7rxVfiTiJ0Ro7eq0q0MNCFV9Z+sN68lfa/E4ABVb0ledEY/Rt8kL23nwCoTCQ== - dependencies: - "@vue/compiler-dom" "3.2.1" - "@vue/shared" "3.2.1" - -"@vue/devtools-api@^6.0.0-beta.14", "@vue/devtools-api@^6.0.0-beta.7": - version "6.0.0-beta.15" - resolved "https://registry.nlark.com/@vue/devtools-api/download/@vue/devtools-api-6.0.0-beta.15.tgz#ad7cb384e062f165bcf9c83732125bffbc2ad83d" - integrity sha1-rXyzhOBi8WW8+cg3MhJb/7wq2D0= - -"@vue/reactivity@3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.2.1.tgz#0e71d4ee00b0d0ca6a6141966c30b68b3f685002" - integrity sha512-4Lja2KmyiKvuraDed6dXK2A6+r/7x7xGDA7vVR2Aqc8hQVu0+FWeVX+IBfiVOSpbZXFlHLNmCBFkbuWLQSlgxg== - dependencies: - "@vue/shared" "3.2.1" - -"@vue/runtime-core@3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.1.tgz#39641110b2f84fdda3b80b86830827b7b5ef041a" - integrity sha512-IsgelRM/5hYeRhz5+ECi66XvYDdjG2t4lARjHvCXw5s9Q4N6uIbjLMwtLzAWRxYf3/y258BrD+ehxAi943ScJg== - dependencies: - "@vue/reactivity" "3.2.1" - "@vue/shared" "3.2.1" - -"@vue/runtime-dom@3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.1.tgz#087cf36f40ad0869712c4154693c620e478061a8" - integrity sha512-bUAHUSe49A5wYdHQ8wsLU1CMPXaG2fRuv2661mx/6Q9+20QxglT3ss8ZeL6AVRu16JNJMcdvTTsNpbnMbVc/lQ== - dependencies: - "@vue/runtime-core" "3.2.1" - "@vue/shared" "3.2.1" - csstype "^2.6.8" - -"@vue/shared@3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.1.tgz#1f1fe26fe0334404cce10740b5ffb2654f1281aa" - integrity sha512-INN92dVBNgd0TW9BqfQQKx/HWGCHhUUbAV5EZ5FgSCiEdwuZsJbGt1mdnaD9IxGhpiyOjP2ClxGG8SFp7ELcWg== - -axios@^0.21.1: - version "0.21.1" - resolved "https://registry.npm.taobao.org/axios/download/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" - integrity sha1-IlY0gZYvTWvemnbVFu8OXTwJsrg= - dependencies: - follow-redirects "^1.10.0" - -big.js@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" - integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== - -bluebird@^3.7.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - -colorette@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" - integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== - -consolidate@^0.16.0: - version "0.16.0" - resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.16.0.tgz#a11864768930f2f19431660a65906668f5fbdc16" - integrity sha512-Nhl1wzCslqXYTJVDyJCu3ODohy9OfBMB5uD2BiBTzd7w+QY0lBzafkR8y8755yMYHAaMD4NuzbAw03/xzfw+eQ== - dependencies: - bluebird "^3.7.2" - -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - -csstype@^2.6.8: - version "2.6.17" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.17.tgz#4cf30eb87e1d1a005d8b6510f95292413f6a1c0e" - integrity sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A== - -emojis-list@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" - integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== - -esbuild@^0.12.8: - version "0.12.19" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.12.19.tgz#ab849766705a5093df5acd8ec2f6ba2159a38a6c" - integrity sha512-5NuT1G6THW7l3fsSCDkcPepn24R0XtyPjKoqKHD8LfhqMXzCdz0mrS9HgO6hIhzVT7zt0T+JGbzCqF5AH8hS9w== - -estree-walker@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" - integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== - -follow-redirects@^1.10.0: - version "1.14.1" - resolved "https://registry.nlark.com/follow-redirects/download/follow-redirects-1.14.1.tgz?cache=0&sync_timestamp=1620555246888&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffollow-redirects%2Fdownload%2Ffollow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43" - integrity sha1-2RFN7Qoc/dM04WTmZirQK/2R/0M= - -fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -generic-names@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/generic-names/-/generic-names-2.0.1.tgz#f8a378ead2ccaa7a34f0317b05554832ae41b872" - integrity sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ== - dependencies: - loader-utils "^1.1.0" - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hash-sum@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a" - integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg== - -icss-replace-symbols@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" - integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= - -icss-utils@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" - integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== - -is-core-module@^2.2.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.5.0.tgz#f754843617c70bfd29b7bd87327400cda5c18491" - integrity sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg== - dependencies: - has "^1.0.3" - -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - -loader-utils@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" - integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^1.0.1" - -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -magic-string@^0.25.7: - version "0.25.7" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" - integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== - dependencies: - sourcemap-codec "^1.4.4" - -merge-source-map@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646" - integrity sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw== - dependencies: - source-map "^0.6.1" - -minimist@^1.2.0: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -nanoid@^3.1.23: - version "3.1.23" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81" - integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw== - -path-parse@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -postcss-modules-extract-imports@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" - integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== - -postcss-modules-local-by-default@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" - integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ== - dependencies: - icss-utils "^5.0.0" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.1.0" - -postcss-modules-scope@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" - integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== - dependencies: - postcss-selector-parser "^6.0.4" - -postcss-modules-values@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" - integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== - dependencies: - icss-utils "^5.0.0" - -postcss-modules@^4.0.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/postcss-modules/-/postcss-modules-4.2.2.tgz#5e7777c5a8964ea176919d90b2e54ef891321ce5" - integrity sha512-/H08MGEmaalv/OU8j6bUKi/kZr2kqGF6huAW8m9UAgOLWtpFdhA14+gPBoymtqyv+D4MLsmqaF2zvIegdCxJXg== - dependencies: - generic-names "^2.0.1" - icss-replace-symbols "^1.1.0" - lodash.camelcase "^4.3.0" - postcss-modules-extract-imports "^3.0.0" - postcss-modules-local-by-default "^4.0.0" - postcss-modules-scope "^3.0.0" - postcss-modules-values "^4.0.0" - string-hash "^1.1.1" - -postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: - version "6.0.6" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" - integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - -postcss-value-parser@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" - integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== - -postcss@^8.1.10, postcss@^8.3.6: - version "8.3.6" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea" - integrity sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A== - dependencies: - colorette "^1.2.2" - nanoid "^3.1.23" - source-map-js "^0.6.2" - -resolve@^1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" - integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== - dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" - -rollup@^2.38.5: - version "2.56.2" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.56.2.tgz#a045ff3f6af53ee009b5f5016ca3da0329e5470f" - integrity sha512-s8H00ZsRi29M2/lGdm1u8DJpJ9ML8SUOpVVBd33XNeEeL3NVaTiUcSBHzBdF3eAyR0l7VSpsuoVUGrRHq7aPwQ== - optionalDependencies: - fsevents "~2.3.2" - -source-map-js@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" - integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug== - -source-map@0.6.1, source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -sourcemap-codec@^1.4.4: - version "1.4.8" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" - integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== - -string-hash@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" - integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs= - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -util-deprecate@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -vant@^3.0.17: - version "3.1.5" - resolved "https://registry.nlark.com/vant/download/vant-3.1.5.tgz?cache=0&sync_timestamp=1627287732546&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fvant%2Fdownload%2Fvant-3.1.5.tgz#3e80b5b8a8431d0c2221129fea89c4cc21a6f2b2" - integrity sha1-PoC1uKhDHQwiIRKf6onEzCGm8rI= - dependencies: - "@vant/icons" "^1.7.0" - "@vant/lazyload" "^1.2.0" - "@vant/popperjs" "^1.1.0" - "@vant/use" "^1.2.2" - -vite@^2.4.4: - version "2.4.4" - resolved "https://registry.yarnpkg.com/vite/-/vite-2.4.4.tgz#8c402a07ad45f168f6eb5428bead38f3e4363e47" - integrity sha512-m1wK6pFJKmaYA6AeZIUXyiAgUAAJzVXhIMYCdZUpCaFMGps0v0IlNJtbmPvkUhVEyautalajmnW5X6NboUPsnw== - dependencies: - esbuild "^0.12.8" - postcss "^8.3.6" - resolve "^1.20.0" - rollup "^2.38.5" - optionalDependencies: - fsevents "~2.3.2" - -vue-i18n@^9.0.0-alpha.16: - version "9.1.7" - resolved "https://registry.nlark.com/vue-i18n/download/vue-i18n-9.1.7.tgz#6f28dd2135197066508e2e65ab204a019750d773" - integrity sha1-byjdITUZcGZQji5lqyBKAZdQ13M= - dependencies: - "@intlify/core-base" "9.1.7" - "@intlify/shared" "9.1.7" - "@intlify/vue-devtools" "9.1.7" - "@vue/devtools-api" "^6.0.0-beta.7" - -vue-router@^4.0.0-rc.1: - version "4.0.11" - resolved "https://registry.nlark.com/vue-router/download/vue-router-4.0.11.tgz?cache=0&sync_timestamp=1628495505697&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fvue-router%2Fdownload%2Fvue-router-4.0.11.tgz#cd649a0941c635281763a20965b599643ddc68ed" - integrity sha1-zWSaCUHGNSgXY6IJZbWZZD3caO0= - dependencies: - "@vue/devtools-api" "^6.0.0-beta.14" - -vue@^3.0.5: - version "3.2.1" - resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.1.tgz#30dde152f2fdad0669ea9854d5a90a00ef96974b" - integrity sha512-0jhXluF5mzTAK5bXw/8yq4McvsI8HwEWI4cnQwJeN8NYGRbwh9wwuE4FNv1Kej9pxBB5ajTNsWr0M6DPs5EJZg== - dependencies: - "@vue/compiler-dom" "3.2.1" - "@vue/runtime-dom" "3.2.1" - "@vue/shared" "3.2.1" - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== diff --git a/versioning.mk b/versioning.mk index 02ebe33..4396eab 100644 --- a/versioning.mk +++ b/versioning.mk @@ -10,13 +10,13 @@ info: @echo "Immutable tag: ${IMAGE}" @echo "Mutable tag: ${MUTABLE_IMAGE}" -.PHONY: docker-push -docker-push: docker-mutable-push docker-immutable-push +.PHONY: podman-push +podman-push: podman-mutable-push podman-immutable-push -.PHONY: docker-immutable-push -docker-immutable-push: - docker push ${IMAGE} +.PHONY: podman-immutable-push +podman-immutable-push: + podman push ${IMAGE} -.PHONY: docker-mutable-push -docker-mutable-push: - docker push ${MUTABLE_IMAGE} +.PHONY: podman-mutable-push +podman-mutable-push: + podman push ${MUTABLE_IMAGE}