masks-server 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/concerns/masks/server/client_authentication.rb +4 -3
- data/app/controllers/concerns/masks/server/resource_token.rb +12 -3
- data/app/controllers/masks/server/addresses_controller.rb +6 -1
- data/app/controllers/masks/server/application_controller.rb +36 -6
- data/app/controllers/masks/server/authorize_controller.rb +24 -19
- data/app/controllers/masks/server/device_verifications_controller.rb +1 -1
- data/app/controllers/masks/server/logins_controller.rb +3 -1
- data/app/controllers/masks/server/notifications_controller.rb +11 -1
- data/app/controllers/masks/server/profiles_controller.rb +5 -0
- data/app/controllers/masks/server/registrations_controller.rb +9 -1
- data/app/controllers/masks/server/saml_controller.rb +1 -7
- data/app/controllers/masks/server/scim/metadata_controller.rb +1 -1
- data/app/controllers/masks/server/tokens_controller.rb +9 -1
- data/app/graphql/masks/server/manage/mutations/add_app.rb +1 -1
- data/app/graphql/masks/server/manage/mutations/create_actor.rb +1 -0
- data/app/graphql/masks/server/manage/mutations/update_actor.rb +1 -0
- data/app/graphql/masks/server/manage/mutations/update_client.rb +4 -0
- data/app/graphql/masks/server/manage/types/client_type.rb +2 -0
- data/app/graphql/masks/server/manage/types/query_type.rb +7 -0
- data/app/helpers/masks/server/account_helper.rb +1 -1
- data/app/jobs/masks/server/cleanup_job.rb +1 -0
- data/app/ldap/masks/server/ldap/listener.rb +16 -3
- data/app/logins/masks/server/login_states/confirmation.rb +9 -3
- data/app/logins/masks/server/login_states/signup.rb +1 -0
- data/app/models/masks/server/actor.rb +28 -5
- data/app/models/masks/server/client.rb +61 -6
- data/app/models/masks/server/client_keys.rb +12 -1
- data/app/models/masks/server/declared.rb +2 -1
- data/app/models/masks/server/event.rb +1 -0
- data/app/models/masks/server/handshake.rb +12 -6
- data/app/models/masks/server/login.rb +3 -6
- data/app/models/masks/server/notifications.rb +8 -0
- data/app/models/masks/server/pending_handshake.rb +2 -1
- data/app/models/masks/server/pending_request.rb +8 -0
- data/app/models/masks/server/refresh_token.rb +8 -0
- data/app/models/masks/server/released_nickname.rb +26 -0
- data/app/models/masks/server/scim/filter.rb +45 -5
- data/app/models/masks/server/scim/user.rb +1 -0
- data/app/models/masks/server/session.rb +6 -5
- data/app/policies/masks/server/exchange_policy.rb +1 -1
- data/app/policies/masks/server/grant_checks.rb +1 -1
- data/app/views/masks/server/account/_info.html.erb +13 -5
- data/app/views/masks/server/account/_organizations.html.erb +4 -4
- data/app/views/masks/server/account/index.html.erb +1 -1
- data/app/views/masks/server/application/_actor.html.erb +27 -0
- data/app/views/masks/server/authorize/error.html.erb +2 -2
- data/app/views/masks/server/handshakes/refused.html.erb +1 -1
- data/app/views/masks/server/handshakes/show.html.erb +1 -1
- data/app/views/masks/server/logins/_choose_organization.html.erb +1 -1
- data/app/views/masks/server/logins/_consent.html.erb +1 -1
- data/app/views/masks/server/sessions/confirm.html.erb +1 -1
- data/config/locales/de/account.yml +6 -2
- data/config/locales/de/actors.yml +2 -0
- data/config/locales/de/application.yml +1 -1
- data/config/locales/de/authorize.yml +2 -0
- data/config/locales/de/events.yml +7 -5
- data/config/locales/de/flashes.yml +1 -0
- data/config/locales/de/logins.yml +1 -0
- data/config/locales/de/manage/client.yml +3 -0
- data/config/locales/de/manage/groups.yml +1 -1
- data/config/locales/de/manage/ldap.yml +1 -0
- data/config/locales/de/manage/organization.yml +1 -1
- data/config/locales/de/notifications.yml +1 -0
- data/config/locales/en/account.yml +6 -2
- data/config/locales/en/actors.yml +2 -0
- data/config/locales/en/application.yml +1 -1
- data/config/locales/en/authorize.yml +2 -0
- data/config/locales/en/events.yml +7 -5
- data/config/locales/en/flashes.yml +1 -0
- data/config/locales/en/logins.yml +1 -0
- data/config/locales/en/manage/client.yml +3 -0
- data/config/locales/en/manage/groups.yml +1 -1
- data/config/locales/en/manage/ldap.yml +1 -0
- data/config/locales/en/manage/organization.yml +1 -1
- data/config/locales/en/notifications.yml +1 -0
- data/config/locales/es/account.yml +6 -2
- data/config/locales/es/actors.yml +2 -0
- data/config/locales/es/application.yml +1 -1
- data/config/locales/es/authorize.yml +2 -0
- data/config/locales/es/events.yml +7 -5
- data/config/locales/es/flashes.yml +1 -0
- data/config/locales/es/logins.yml +1 -0
- data/config/locales/es/manage/client.yml +3 -0
- data/config/locales/es/manage/groups.yml +1 -1
- data/config/locales/es/manage/ldap.yml +1 -0
- data/config/locales/es/manage/organization.yml +1 -1
- data/config/locales/es/notifications.yml +1 -0
- data/config/locales/fr/account.yml +6 -2
- data/config/locales/fr/actors.yml +2 -0
- data/config/locales/fr/application.yml +1 -1
- data/config/locales/fr/authorize.yml +2 -0
- data/config/locales/fr/events.yml +7 -5
- data/config/locales/fr/flashes.yml +1 -0
- data/config/locales/fr/logins.yml +1 -0
- data/config/locales/fr/manage/client.yml +3 -0
- data/config/locales/fr/manage/groups.yml +1 -1
- data/config/locales/fr/manage/ldap.yml +1 -0
- data/config/locales/fr/manage/organization.yml +1 -1
- data/config/locales/fr/notifications.yml +1 -0
- data/config/routes.rb +1 -0
- data/db/migrate/20261013010000_add_handshake_return_to_to_clients.rb +5 -0
- data/db/migrate/20261018100000_create_released_nicknames.rb +22 -0
- data/db/migrate/20261018110000_add_refresh_token_absolute_lifetime_to_clients.rb +5 -0
- data/lib/generators/masks/server/install/install_generator.rb +2 -2
- data/lib/masks/server/browser_access.rb +35 -0
- data/lib/masks/server/configuration.rb +11 -3
- data/lib/masks/server/engine.rb +1 -0
- data/lib/masks/server/schema_reference.rb +17 -4
- data/lib/masks/server/tenancy/middleware.rb +9 -1
- data/lib/masks/server.rb +1 -0
- data/public/masks-assets/.vite/manifest.json +7 -7
- data/public/masks-assets/assets/app-D7W0gAyT.css +2 -0
- data/public/masks-assets/assets/{initial-D99AzFOd.js → initial-C1GpCiEh.js} +2 -2
- data/public/masks-assets/assets/{initial-D99AzFOd.js.map → initial-C1GpCiEh.js.map} +1 -1
- data/public/masks-assets/assets/login-C_6igRZ3.js +4 -0
- data/public/masks-assets/assets/login-C_6igRZ3.js.map +1 -0
- data/public/masks-assets/assets/manage-DR9qQiBU.js +569 -0
- data/public/masks-assets/assets/manage-DR9qQiBU.js.map +1 -0
- data/version.txt +1 -1
- metadata +14 -9
- data/app/views/masks/server/application/_person.html.erb +0 -27
- data/public/masks-assets/assets/app-DoQZrM_J.css +0 -2
- data/public/masks-assets/assets/login-CNs1UpxJ.js +0 -4
- data/public/masks-assets/assets/login-CNs1UpxJ.js.map +0 -1
- data/public/masks-assets/assets/manage-isLCrWiU.js +0 -567
- data/public/masks-assets/assets/manage-isLCrWiU.js.map +0 -1
|
@@ -155,7 +155,7 @@ fr:
|
|
|
155
155
|
lede_owner: "En tant que propriétaire, vous décidez qui fait partie de l’organisation et quel rôle chaque personne occupe. Les applications qui demandent votre organisation voient ce rôle."
|
|
156
156
|
lede_member: "Les applications qui demandent votre organisation voient que vous en faites partie, ainsi que votre rôle."
|
|
157
157
|
members: "Membres"
|
|
158
|
-
|
|
158
|
+
member_count:
|
|
159
159
|
one: "1 membre"
|
|
160
160
|
other: "%{count} membres"
|
|
161
161
|
owners:
|
|
@@ -182,7 +182,7 @@ fr:
|
|
|
182
182
|
decline: "Refuser"
|
|
183
183
|
confirm_decline: "Refuser l’invitation à %{organization} ? Un propriétaire devra vous inviter à nouveau."
|
|
184
184
|
set_role: "Définir le rôle"
|
|
185
|
-
role_of: "Rôle de %{
|
|
185
|
+
role_of: "Rôle de %{name}"
|
|
186
186
|
remove: "Retirer"
|
|
187
187
|
withdraw: "Annuler"
|
|
188
188
|
resend: "Renvoyer"
|
|
@@ -251,6 +251,10 @@ fr:
|
|
|
251
251
|
lede: "Tout ce qui figure ici est activé jusqu’à ce que vous le désactiviez. Ces e-mails arrivent au fil des événements, et il n’est pas possible d’y répondre."
|
|
252
252
|
silent: "Rien n’est envoyé, car ces e-mails ne partent que vers une adresse e-mail confirmée."
|
|
253
253
|
submit: "Enregistrer"
|
|
254
|
+
kept: "Un mot de passe modifié ou réinitialisé et une connexion à risque sont toujours signalés."
|
|
255
|
+
always: "Toujours"
|
|
256
|
+
again: "Votre dernière connexion remonte à un moment, vous devrez donc d’abord vous reconnecter."
|
|
257
|
+
submit_again: "Se reconnecter"
|
|
254
258
|
|
|
255
259
|
export:
|
|
256
260
|
heading: "Télécharger votre compte"
|
|
@@ -5,3 +5,5 @@ fr:
|
|
|
5
5
|
stopped: "Interrompu"
|
|
6
6
|
heading: "L’application a demandé quelque chose que ce serveur refuse de faire."
|
|
7
7
|
contact: "Rien n’a été partagé. C’est à l’application de corriger le problème."
|
|
8
|
+
refused: "Cette connexion a été refusée."
|
|
9
|
+
nothing_shared: "Rien n’a été partagé avec l’application. Vous pouvez fermer cette page."
|
|
@@ -6,6 +6,8 @@ fr:
|
|
|
6
6
|
ended: "Déconnexion"
|
|
7
7
|
revoked: "Session révoquée"
|
|
8
8
|
expired: "Session expirée"
|
|
9
|
+
notifications:
|
|
10
|
+
changed: "Notifications modifiées"
|
|
9
11
|
logout:
|
|
10
12
|
undelivered: "Déconnexion non transmise à une application"
|
|
11
13
|
login:
|
|
@@ -94,14 +96,14 @@ fr:
|
|
|
94
96
|
refused: "Échange de jeton refusé"
|
|
95
97
|
actor:
|
|
96
98
|
approved: "Compte approuvé"
|
|
97
|
-
created: "
|
|
98
|
-
provisioned: "
|
|
99
|
+
created: "Compte ajouté"
|
|
100
|
+
provisioned: "Compte ajouté par un fournisseur"
|
|
99
101
|
updated: "Profil modifié"
|
|
100
|
-
deleted: "
|
|
102
|
+
deleted: "Compte supprimé"
|
|
101
103
|
scopes_changed: "Portées modifiées"
|
|
102
104
|
signed_out: "Déconnecté partout"
|
|
103
|
-
suspended: "
|
|
104
|
-
restored: "
|
|
105
|
+
suspended: "Compte suspendu"
|
|
106
|
+
restored: "Compte rétabli"
|
|
105
107
|
idle_warned: "Compte inactif averti"
|
|
106
108
|
client:
|
|
107
109
|
created: "Application ajoutée"
|
|
@@ -129,6 +129,7 @@ fr:
|
|
|
129
129
|
directed: "L’annuaire de votre organisation gère votre nom."
|
|
130
130
|
invalid: "%{errors}"
|
|
131
131
|
updated: "Vos informations ont été enregistrées."
|
|
132
|
+
again: "Reconnectez-vous pour changer votre pseudo. Votre dernière connexion remonte à un moment."
|
|
132
133
|
|
|
133
134
|
verifications:
|
|
134
135
|
too_many_requests: "Trop de demandes. Attendez quelques minutes."
|
|
@@ -238,6 +238,7 @@ fr:
|
|
|
238
238
|
too-many-attempts: "Trop de tentatives. Patientez quelques minutes."
|
|
239
239
|
too-many-attempts-for-account: "Trop de tentatives pour ce compte."
|
|
240
240
|
too-many-codes: "Trop de codes ont été envoyés à cette adresse. Patientez quelques minutes."
|
|
241
|
+
too-many-texts: "Trop de codes ont été envoyés à ce numéro. Patientez quelques minutes."
|
|
241
242
|
prove-email-first: "Saisissez d’abord le code envoyé à cette adresse."
|
|
242
243
|
no-account-for-email: "Aucun compte ici n’utilise cette adresse."
|
|
243
244
|
invalid-setup-token: "Ce jeton de configuration est incorrect."
|
|
@@ -115,6 +115,8 @@ fr:
|
|
|
115
115
|
sector_placeholder: "nécessaire quand ses URI de redirection couvrent plusieurs hôtes"
|
|
116
116
|
unattended: "Se connecte en son propre nom (client_credentials)"
|
|
117
117
|
rotate: "Renouveler le secret"
|
|
118
|
+
secret_expires: "Le secret expire le %{day}."
|
|
119
|
+
secret_expired: "Le secret a expiré le %{day}. Renouvelez-le, sinon rien ne peut se connecter avec."
|
|
118
120
|
archive: "Archiver"
|
|
119
121
|
saml:
|
|
120
122
|
title: "SAML"
|
|
@@ -146,6 +148,7 @@ fr:
|
|
|
146
148
|
consent: "Demander le consentement des acteurs"
|
|
147
149
|
access: "Durée des jetons d’accès (minutes, vide pour une heure)"
|
|
148
150
|
refresh: "Durée des jetons d’actualisation sans utilisation (jours, vide pour 30)"
|
|
151
|
+
refresh_absolute: "Fin des jetons d’actualisation après la connexion (jours, vide pour 90)"
|
|
149
152
|
consent_lifetime: "Durée du consentement (jours, vide jusqu’à révocation)"
|
|
150
153
|
logout: "URI de déconnexion back-channel"
|
|
151
154
|
logout_session: "Son jeton de déconnexion indique la session (sid)"
|
|
@@ -6,7 +6,7 @@ fr:
|
|
|
6
6
|
added: "%{name} est prêt. Ajoutez des acteurs depuis leur propre page."
|
|
7
7
|
delete_confirm: "Supprimer %{name} ? Les clients limités à ce groupe refusent ses acteurs."
|
|
8
8
|
deleted: "%{name} est supprimé."
|
|
9
|
-
|
|
9
|
+
actors:
|
|
10
10
|
one: "%{count} acteur"
|
|
11
11
|
other: "%{count} acteurs"
|
|
12
12
|
delete: "Supprimer %{name}"
|
|
@@ -17,6 +17,7 @@ fr:
|
|
|
17
17
|
address: "Adresse"
|
|
18
18
|
port: "Port %{port}"
|
|
19
19
|
ldaps: "Port %{port}, LDAPS"
|
|
20
|
+
local_only: "Sans certificat, l’annuaire ne répond que sur la machine de ce serveur, pour qu’aucun mot de passe ne traverse le réseau en clair. Définissez MASKS_LDAP_CERT et MASKS_LDAP_KEY pour servir LDAPS sur toutes les adresses, ou MASKS_LDAP_PLAINTEXT=true sur un réseau privé de confiance."
|
|
20
21
|
label: "Libellé"
|
|
21
22
|
issue: "Émettre un identifiant"
|
|
22
23
|
shown_once: "Ce secret n'est affiché qu'une fois. Copiez-le maintenant."
|
|
@@ -66,7 +66,7 @@ fr:
|
|
|
66
66
|
invite: "Inviter"
|
|
67
67
|
cancel: "Annuler"
|
|
68
68
|
hint: "L’invité rejoint l’organisation dès qu’il accepte, depuis l’adresse que vous invitez. Quelqu’un qui n’est pas encore un acteur reçoit une invitation à s’inscrire."
|
|
69
|
-
|
|
69
|
+
actor: "Acteur"
|
|
70
70
|
empty:
|
|
71
71
|
invited: "Aucune invitation en attente."
|
|
72
72
|
owners: "Cette organisation n’a aucun propriétaire. Faites d’un membre un propriétaire pour que quelqu’un puisse la gérer."
|
data/config/routes.rb
CHANGED
|
@@ -18,6 +18,7 @@ Masks::Server::Engine.routes.draw do
|
|
|
18
18
|
post "/ssf/events", to: "received_signals#create", as: :received_signals
|
|
19
19
|
|
|
20
20
|
match "/authorize", to: "authorize#show", via: %i[get post], as: :authorize
|
|
21
|
+
get "/authorize/refused", to: "authorize#refused", as: :authorize_refused
|
|
21
22
|
post "/par", to: "pushed_authorizations#create", as: :pushed_authorization
|
|
22
23
|
post "/device_authorization", to: "device_authorizations#create", as: :device_authorization
|
|
23
24
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class CreateReleasedNicknames < ActiveRecord::Migration[8.1]
|
|
2
|
+
include Masks::Server::TenantIsolation
|
|
3
|
+
|
|
4
|
+
def up
|
|
5
|
+
create_table :released_nicknames do |t|
|
|
6
|
+
t.references :tenant, null: false, foreign_key: { on_delete: :cascade }, index: false
|
|
7
|
+
t.references :actor, foreign_key: { on_delete: :nullify }, index: false
|
|
8
|
+
t.string :nickname, null: false
|
|
9
|
+
t.datetime :released_at, null: false
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
add_index :released_nicknames, %i[tenant_id nickname], unique: true
|
|
13
|
+
add_index :released_nicknames, :released_at
|
|
14
|
+
|
|
15
|
+
enable_row_level_security(:released_nicknames)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def down
|
|
19
|
+
disable_row_level_security(:released_nicknames)
|
|
20
|
+
drop_table :released_nicknames
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -95,8 +95,8 @@ module Masks
|
|
|
95
95
|
say " migrations_paths: <%= Masks::Server::Engine.root.join(\"db/migrate\") %>"
|
|
96
96
|
say " schema_dump: false"
|
|
97
97
|
say ""
|
|
98
|
-
say "Its role must hold neither SUPERUSER nor BYPASSRLS, or masks refuses
|
|
99
|
-
say "security is what keeps one tenant's accounts and keys away from another's."
|
|
98
|
+
say "Its role must hold neither SUPERUSER nor BYPASSRLS, or masks refuses every request that needs"
|
|
99
|
+
say "a tenant: row-level security is what keeps one tenant's accounts and keys away from another's."
|
|
100
100
|
say ""
|
|
101
101
|
say "Controllers that need the signed-in account include Masks::Server::Host, which gives them"
|
|
102
102
|
say "masks_actor and require_masks_actor!." unless subdomain?
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Masks
|
|
2
|
+
module Server
|
|
3
|
+
class BrowserAccess
|
|
4
|
+
OPEN = %r{\A/(?:\.well-known/(?:openid-configuration|oauth-authorization-server|jwks\.json|oauth-protected-resource(?:/.*)?)|token|revoke|userinfo|avatars/.+)\z}
|
|
5
|
+
ALLOWED_HEADERS = "Authorization, Content-Type, DPoP".freeze
|
|
6
|
+
EXPOSED_HEADERS = "DPoP-Nonce, WWW-Authenticate".freeze
|
|
7
|
+
PREFLIGHT_LIFETIME = 1.hour.to_i.to_s
|
|
8
|
+
|
|
9
|
+
def initialize(app)
|
|
10
|
+
@app = app
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call(env)
|
|
14
|
+
return @app.call(env) unless env["HTTP_ORIGIN"] && OPEN.match?(env["PATH_INFO"].to_s)
|
|
15
|
+
return preflight if env["REQUEST_METHOD"] == "OPTIONS"
|
|
16
|
+
|
|
17
|
+
status, headers, body = @app.call(env)
|
|
18
|
+
headers["access-control-allow-origin"] = "*"
|
|
19
|
+
headers["access-control-expose-headers"] = EXPOSED_HEADERS
|
|
20
|
+
|
|
21
|
+
[ status, headers, body ]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
def preflight
|
|
26
|
+
[ 204, {
|
|
27
|
+
"access-control-allow-origin" => "*",
|
|
28
|
+
"access-control-allow-methods" => "GET, POST",
|
|
29
|
+
"access-control-allow-headers" => ALLOWED_HEADERS,
|
|
30
|
+
"access-control-max-age" => PREFLIGHT_LIFETIME
|
|
31
|
+
}, [] ]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -42,8 +42,10 @@ module Masks
|
|
|
42
42
|
config.email_verification_lifetime = ENV.fetch("MASKS_EMAIL_VERIFICATION_LIFETIME", 2 * 24 * 60 * 60).to_i.seconds
|
|
43
43
|
config.outbound_allowed = outbound_allowed(ENV["MASKS_OUTBOUND_ALLOWED"])
|
|
44
44
|
config.ldap_port = ENV.fetch("MASKS_LDAP_PORT", 3389).to_i
|
|
45
|
+
config.on_demand_tls = ENV.fetch("MASKS_ON_DEMAND_TLS", "false")
|
|
45
46
|
config.ldap_cert = ENV["MASKS_LDAP_CERT"].presence
|
|
46
47
|
config.ldap_key = ENV["MASKS_LDAP_KEY"].presence
|
|
48
|
+
config.ldap_plaintext = ENV.fetch("MASKS_LDAP_PLAINTEXT", "false") == "true"
|
|
47
49
|
config
|
|
48
50
|
end
|
|
49
51
|
|
|
@@ -93,15 +95,21 @@ module Masks
|
|
|
93
95
|
if config.named_by && !%w[nickname email either].include?(config.named_by)
|
|
94
96
|
raise "MASKS_NAMED_BY is #{config.named_by.inspect}, and the only things an " \
|
|
95
97
|
"account can be named by are a nickname, an email address, or either one. " \
|
|
96
|
-
"Set it to nickname, email or either, or leave it unset
|
|
97
|
-
"
|
|
98
|
+
"Set it to nickname, email or either, or leave it unset so each tenant's managers " \
|
|
99
|
+
"choose in /manage."
|
|
98
100
|
end
|
|
99
101
|
|
|
100
102
|
if config.dynamic_registration && !%w[off anything bounded].include?(config.dynamic_registration)
|
|
101
103
|
raise "MASKS_DYNAMIC_REGISTRATION is #{config.dynamic_registration.inspect}. " \
|
|
102
104
|
"Dynamic registration is off, on for anything a manager does not have to grant, " \
|
|
103
105
|
"or on and bounded by MASKS_DYNAMIC_CLIENT_SCOPES. Set it to off, anything or " \
|
|
104
|
-
"bounded, or leave it unset
|
|
106
|
+
"bounded, or leave it unset so each tenant's managers choose in /manage."
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
unless [ true, false, "true", "false" ].include?(config.on_demand_tls)
|
|
110
|
+
raise "MASKS_ON_DEMAND_TLS is #{config.on_demand_tls.inspect}. Set it to true to answer a " \
|
|
111
|
+
"proxy's certificate check at /tls/allowed, or to false, or leave it unset, to keep " \
|
|
112
|
+
"that path closed."
|
|
105
113
|
end
|
|
106
114
|
|
|
107
115
|
return if local || building
|
data/lib/masks/server/engine.rb
CHANGED
|
@@ -26,9 +26,12 @@ module Masks
|
|
|
26
26
|
<<~HEAD
|
|
27
27
|
---
|
|
28
28
|
title: Manage API
|
|
29
|
-
description: The GraphQL schema served at /manage/graphql.
|
|
29
|
+
description: The GraphQL schema served at /manage/graphql, with an explorer to browse it.
|
|
30
30
|
---
|
|
31
31
|
|
|
32
|
+
import sdl from "../../../assets/manage.graphql?raw";
|
|
33
|
+
import Explorer from "../../../components/Explorer.tsx";
|
|
34
|
+
|
|
32
35
|
Everything `/manage` can ask for and everything it can change. `/manage/graphql` accepts a
|
|
33
36
|
bearer carrying `masks:manage` or one of the narrower
|
|
34
37
|
[manage roles](/guides/security/#manage-roles), issued for this tenant's manage resource and
|
|
@@ -37,6 +40,17 @@ module Masks
|
|
|
37
40
|
|
|
38
41
|
Generated from `ManageSchema` by `./dev reference`. CI fails when this page and the
|
|
39
42
|
schema disagree.
|
|
43
|
+
|
|
44
|
+
## Explorer
|
|
45
|
+
|
|
46
|
+
The explorer shows this schema in GraphiQL, an in-browser tool for writing GraphQL
|
|
47
|
+
queries. Autocomplete, the docs pane, and validation all work on this page. The explorer
|
|
48
|
+
answers only introspection queries, which ask about the schema itself. It sends nothing
|
|
49
|
+
to a server.
|
|
50
|
+
|
|
51
|
+
To run a query, send it to your own server's `/manage/graphql`.
|
|
52
|
+
|
|
53
|
+
<Explorer client:only="react" sdl={sdl} />
|
|
40
54
|
HEAD
|
|
41
55
|
end
|
|
42
56
|
|
|
@@ -50,7 +64,7 @@ module Masks
|
|
|
50
64
|
body = if type.kind.enum?
|
|
51
65
|
values(type)
|
|
52
66
|
elsif type.kind.scalar?
|
|
53
|
-
"A scalar
|
|
67
|
+
"A scalar.\n"
|
|
54
68
|
else
|
|
55
69
|
fields(type)
|
|
56
70
|
end
|
|
@@ -97,8 +111,7 @@ module Masks
|
|
|
97
111
|
"#{named}#{taken.join}"
|
|
98
112
|
end
|
|
99
113
|
|
|
100
|
-
#
|
|
101
|
-
# comments. An empty column on every row is noise, so it only appears when
|
|
114
|
+
# An empty column on every row is noise, so it only appears when
|
|
102
115
|
# something in that table actually filled it in.
|
|
103
116
|
def cells(values, described)
|
|
104
117
|
kept = described.any?(&:present?) ? values : values[0..-2]
|
|
@@ -8,6 +8,14 @@ module Masks
|
|
|
8
8
|
TENANTLESS = %w[/up /metrics].freeze
|
|
9
9
|
TLS_ASK = "/tls/allowed".freeze
|
|
10
10
|
|
|
11
|
+
def self.excluded_from_host_check?(request)
|
|
12
|
+
TENANTLESS.include?(request.path) || certificate_check?(request) || Tenant.serving(request.host).present?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.certificate_check?(request)
|
|
16
|
+
request.path == TLS_ASK && ::Rails.configuration.masks.on_demand_tls.to_s == "true"
|
|
17
|
+
end
|
|
18
|
+
|
|
11
19
|
def initialize(app)
|
|
12
20
|
@app = app
|
|
13
21
|
end
|
|
@@ -16,7 +24,7 @@ module Masks
|
|
|
16
24
|
request = ActionDispatch::Request.new(env)
|
|
17
25
|
|
|
18
26
|
return @app.call(env) if TENANTLESS.include?(request.path)
|
|
19
|
-
return allowed(request) if request
|
|
27
|
+
return allowed(request) if self.class.certificate_check?(request)
|
|
20
28
|
|
|
21
29
|
tenant = Tenant.serving(request.host)
|
|
22
30
|
|
data/lib/masks/server.rb
CHANGED
|
@@ -105,6 +105,7 @@ end
|
|
|
105
105
|
|
|
106
106
|
require_relative "server/version"
|
|
107
107
|
require_relative "server/configuration"
|
|
108
|
+
require_relative "server/browser_access"
|
|
108
109
|
require_relative "server/isolation"
|
|
109
110
|
require_relative "server/tenant_key_provider"
|
|
110
111
|
require_relative "server/forwarding"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_initial-
|
|
3
|
-
"file": "assets/initial-
|
|
2
|
+
"_initial-C1GpCiEh.js": {
|
|
3
|
+
"file": "assets/initial-C1GpCiEh.js",
|
|
4
4
|
"name": "initial"
|
|
5
5
|
},
|
|
6
6
|
"_passkey-DIj_5LCY.js": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
]
|
|
18
18
|
},
|
|
19
19
|
"entrypoints/app.css": {
|
|
20
|
-
"file": "assets/app-
|
|
20
|
+
"file": "assets/app-D7W0gAyT.css",
|
|
21
21
|
"name": "entrypoints/app.css",
|
|
22
22
|
"names": [
|
|
23
23
|
"entrypoints/app.css"
|
|
@@ -41,22 +41,22 @@
|
|
|
41
41
|
"isEntry": true
|
|
42
42
|
},
|
|
43
43
|
"entrypoints/login.js": {
|
|
44
|
-
"file": "assets/login-
|
|
44
|
+
"file": "assets/login-C_6igRZ3.js",
|
|
45
45
|
"name": "entrypoints/login.js",
|
|
46
46
|
"src": "entrypoints/login.js",
|
|
47
47
|
"isEntry": true,
|
|
48
48
|
"imports": [
|
|
49
49
|
"_passkey-DIj_5LCY.js",
|
|
50
|
-
"_initial-
|
|
50
|
+
"_initial-C1GpCiEh.js"
|
|
51
51
|
]
|
|
52
52
|
},
|
|
53
53
|
"entrypoints/manage.js": {
|
|
54
|
-
"file": "assets/manage-
|
|
54
|
+
"file": "assets/manage-DR9qQiBU.js",
|
|
55
55
|
"name": "entrypoints/manage.js",
|
|
56
56
|
"src": "entrypoints/manage.js",
|
|
57
57
|
"isEntry": true,
|
|
58
58
|
"imports": [
|
|
59
|
-
"_initial-
|
|
59
|
+
"_initial-C1GpCiEh.js"
|
|
60
60
|
]
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-font-weight:initial}}}@layer theme{:root,:host{--font-sans:system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--font-mono:ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;--spacing:.25rem;--container-xs:20rem;--container-sm:24rem;--container-xl:36rem;--container-6xl:72rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--radius-lg:.5rem;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-base-100:#fff;--color-base-200:#fcf9f7;--color-base-300:#e5ded9;--color-base-content:#211c18;--color-primary:#b04000;--color-primary-content:#fff;--color-secondary:#87611e;--color-accent:#6d4702;--color-neutral:#211c18;--color-neutral-content:#fcf9f7;--color-info:#0077b2;--color-success:#008450;--color-warning:#8b6200;--color-error:#b53530;--color-error-content:#fff;--radius-box:5px;--radius-field:3px}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components{.btn{border-radius:var(--radius-box);border:1px solid var(--edge);background:var(--color-base-100);color:inherit;font:inherit;white-space:nowrap;cursor:pointer;justify-content:center;align-items:center;gap:.4375rem;padding:.5625rem .9375rem;font-size:.875rem;font-weight:500;line-height:1.2;text-decoration:none;transition:border-color .15s,background-color .15s,color .15s;display:inline-flex}.btn:hover:not(:disabled){border-color:#211c18}@supports (color:color-mix(in lab, red, red)){.btn:hover:not(:disabled){border-color:color-mix(in oklab, var(--color-base-content) 30%, var(--edge))}}.btn:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.btn:disabled,.btn[aria-disabled=true]{opacity:.45;cursor:not-allowed}.btn-sm{padding:.375rem .75rem;font-size:.8125rem}.btn-xs{padding:.25rem .5rem;font-size:.75rem}.btn-primary{background:var(--color-primary);border-color:var(--color-primary);color:var(--color-primary-content)}.btn-primary:hover:not(:disabled){background:#973700}@supports (color:color-mix(in lab, red, red)){.btn-primary:hover:not(:disabled){background:color-mix(in oklab, var(--color-primary) 86%, black)}}.btn-primary:hover:not(:disabled){border-color:#973700}@supports (color:color-mix(in lab, red, red)){.btn-primary:hover:not(:disabled){border-color:color-mix(in oklab, var(--color-primary) 86%, black)}}.btn-error{background:var(--color-error);border-color:var(--color-error);color:var(--color-error-content)}.btn-error:hover:not(:disabled){background:#9c2e29}@supports (color:color-mix(in lab, red, red)){.btn-error:hover:not(:disabled){background:color-mix(in oklab, var(--color-error) 86%, black)}}.btn-error:hover:not(:disabled){border-color:#9c2e29}@supports (color:color-mix(in lab, red, red)){.btn-error:hover:not(:disabled){border-color:color-mix(in oklab, var(--color-error) 86%, black)}}.btn-ghost{background:0 0;border-color:#0000}.btn-ghost:hover:not(:disabled){background:var(--sunk);border-color:#0000}.btn-outline{background:0 0}.btn-error.btn-outline{color:var(--color-error);border-color:#b5353073}@supports (color:color-mix(in lab, red, red)){.btn-error.btn-outline{border-color:color-mix(in oklab, var(--color-error) 45%, transparent)}}.btn-error.btn-outline:hover:not(:disabled){background:#b535301f}@supports (color:color-mix(in lab, red, red)){.btn-error.btn-outline:hover:not(:disabled){background:color-mix(in oklab, var(--color-error) 12%, transparent)}}.btn-error.btn-outline:hover:not(:disabled){border-color:var(--color-error)}.link{color:inherit;text-underline-offset:2px;cursor:pointer;text-decoration:underline;text-decoration-thickness:1px}.link-hover{text-decoration:none}.link-hover:hover,.link:hover{text-decoration:underline}.badge{border:1px solid var(--edge);background:var(--color-base-100);white-space:nowrap;border-radius:999px;align-items:center;gap:.25rem;padding:.125rem .4375rem;font-size:.75rem;font-weight:500;line-height:1.5;display:inline-flex}.badge-sm{padding:.0625rem .375rem;font-size:.6875rem}.badge-xs{padding:0 .3125rem;font-size:.625rem}.badge-ghost{background:var(--sunk);border-color:#0000}.badge-success{color:var(--color-success);border-color:#00845066}@supports (color:color-mix(in lab, red, red)){.badge-success{border-color:color-mix(in oklab, var(--color-success) 40%, transparent)}}.badge-success{background:#0084501f}@supports (color:color-mix(in lab, red, red)){.badge-success{background:color-mix(in oklab, var(--color-success) 12%, transparent)}}.badge-warning{color:var(--color-warning);border-color:#8b620066}@supports (color:color-mix(in lab, red, red)){.badge-warning{border-color:color-mix(in oklab, var(--color-warning) 40%, transparent)}}.badge-warning{background:#8b62001f}@supports (color:color-mix(in lab, red, red)){.badge-warning{background:color-mix(in oklab, var(--color-warning) 12%, transparent)}}.badge-error{color:var(--color-error);border-color:#b5353066}@supports (color:color-mix(in lab, red, red)){.badge-error{border-color:color-mix(in oklab, var(--color-error) 40%, transparent)}}.badge-error{background:#b535301f}@supports (color:color-mix(in lab, red, red)){.badge-error{background:color-mix(in oklab, var(--color-error) 12%, transparent)}}.badge-info{color:var(--color-info);border-color:#0077b266}@supports (color:color-mix(in lab, red, red)){.badge-info{border-color:color-mix(in oklab, var(--color-info) 40%, transparent)}}.badge-info{background:#0077b21f}@supports (color:color-mix(in lab, red, red)){.badge-info{background:color-mix(in oklab, var(--color-info) 12%, transparent)}}.alert{border-radius:var(--radius-box);border:1px solid var(--edge);background:var(--color-base-100);align-items:flex-start;gap:.625rem;padding:.75rem .875rem;font-size:.875rem;line-height:1.45;display:flex}.alert-soft{background:var(--sunk);border-color:#0000}.alert-error{color:var(--color-error);border-color:#b5353059}@supports (color:color-mix(in lab, red, red)){.alert-error{border-color:color-mix(in oklab, var(--color-error) 35%, transparent)}}.alert-error{background:#b535301a}@supports (color:color-mix(in lab, red, red)){.alert-error{background:color-mix(in oklab, var(--color-error) 10%, transparent)}}.alert-warning{color:var(--color-warning);border-color:#8b620059}@supports (color:color-mix(in lab, red, red)){.alert-warning{border-color:color-mix(in oklab, var(--color-warning) 35%, transparent)}}.alert-warning{background:#8b62001a}@supports (color:color-mix(in lab, red, red)){.alert-warning{background:color-mix(in oklab, var(--color-warning) 10%, transparent)}}.alert-success{color:var(--color-success);border-color:#00845059}@supports (color:color-mix(in lab, red, red)){.alert-success{border-color:color-mix(in oklab, var(--color-success) 35%, transparent)}}.alert-success{background:#0084501a}@supports (color:color-mix(in lab, red, red)){.alert-success{background:color-mix(in oklab, var(--color-success) 10%, transparent)}}.alert-info{color:var(--color-info);border-color:#0077b259}@supports (color:color-mix(in lab, red, red)){.alert-info{border-color:color-mix(in oklab, var(--color-info) 35%, transparent)}}.alert-info{background:#0077b21a}@supports (color:color-mix(in lab, red, red)){.alert-info{background:color-mix(in oklab, var(--color-info) 10%, transparent)}}.input,.select,.textarea{border-radius:var(--radius-box);border:1px solid var(--edge);background:var(--color-base-100);width:100%;color:inherit;font:inherit;padding:.5625rem .75rem;font-size:.875rem;line-height:1.4}.input:focus,.select:focus,.textarea:focus{outline:2px solid var(--color-primary);outline-offset:-1px}.input-sm,.select-sm,.textarea-sm{padding:.375rem .5625rem;font-size:.8125rem}.textarea{resize:vertical;min-height:5rem}.select{appearance:none;background-image:linear-gradient(45deg,#0000 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,#0000 50%);background-position:calc(100% - .9375rem) 55%,calc(100% - .625rem) 55%;background-repeat:no-repeat;background-size:.3125rem .3125rem,.3125rem .3125rem;padding-right:1.75rem}.checkbox{width:1rem;height:1rem;accent-color:var(--color-primary);cursor:pointer;flex:none;margin:0}.toggle{appearance:none;border:1px solid var(--edge);background:var(--sunk);cursor:pointer;border-radius:999px;flex:none;width:2.25rem;height:1.3125rem;transition:background-color .15s;position:relative}.toggle:after{content:"";background:var(--color-base-content);border-radius:50%;width:.9375rem;height:.9375rem;transition:transform .15s;position:absolute;top:50%;left:.125rem;transform:translateY(-50%)}.toggle:checked{background:var(--color-primary);border-color:var(--color-primary)}.toggle:checked:after{background:var(--color-primary-content);transform:translate(.9375rem,-50%)}.toggle-sm{width:1.875rem;height:1.125rem}.toggle-sm:after{width:.75rem;height:.75rem}.toggle-sm:checked:after{transform:translate(.75rem,-50%)}.range{width:100%;accent-color:var(--color-primary)}.join{display:inline-flex}.join-item:not(:first-child){border-start-start-radius:0;border-end-start-radius:0;margin-inline-start:-1px}.join-item:not(:last-child){border-start-end-radius:0;border-end-end-radius:0}.card{border-radius:var(--radius-box);border:1px solid var(--edge);background:var(--color-base-100);flex-direction:column;display:flex}.table{border-collapse:collapse;text-align:left;width:100%;font-size:.875rem}.table :where(th){color:#211c1899;padding:.625rem .75rem;font-size:.75rem;font-weight:500}@supports (color:color-mix(in lab, red, red)){.table :where(th){color:color-mix(in oklab, var(--color-base-content) 60%, transparent)}}.table :where(th){border-bottom:1px solid var(--edge)}.table :where(td){border-bottom:1px solid var(--edge);vertical-align:top;padding:.6875rem .75rem}.table :where(tbody tr:last-child td){border-bottom:0}.table-sm :where(th,td){padding:.4375rem .625rem}.loading{border:2px solid;border-top-color:#0000;border-radius:50%;width:1.125rem;height:1.125rem;animation:.62s linear infinite spin;display:inline-block}.loading-spinner{border-style:solid}.auth-page{--ground:#ececed;--surface:#f7f7f8;--line:#d9d9dc;--line-firm:#c4c4c8;--ink:#18181b;--ink-soft:#5c5c63;--brass:#8a5a1c;--brass-lit:#9b6a26;--signal:#b3380f;--signal-ink:#fff;--ring:#b3380f4d;--bad:#b0183f;--bad-field:#fbeef1;--warn:#8b6200;--warn-field:#fbf5e8;--info:#0077b2;--info-field:#edf5fa;--glow:#b3380f0d;--window:url(/masks-public/icon.svg);--window-strength:.2;--pane:var(--surface)}@supports (color:color-mix(in lab, red, red)){.auth-page{--pane:color-mix(in oklab, var(--surface) 58%, transparent)}}.auth-page{--pane-rim:var(--brass)}@supports (color:color-mix(in lab, red, red)){.auth-page{--pane-rim:color-mix(in oklab, var(--brass) 30%, var(--line))}}.auth-page{--pane-shine:#ffffffb3;--pane-sheen:#ffffff73;--pane-shadow:0 1px 1px #14141812, 0 18px 40px -24px #14141866;--bend:8px;--swing:cubic-bezier(.2, .8, .2, 1)}@media (prefers-color-scheme:dark){.auth-page{--ground:#0b0b0c;--surface:#1c1c1f;--line:#2a2a2e;--line-firm:#3e3e44;--ink:#ededef;--ink-soft:#9a9a9f;--brass:#c9a14a;--brass-lit:#e8c27a;--signal:#ff7a4a;--signal-ink:#1f0c06;--ring:#ff7a4a66;--bad:#ff7396;--bad-field:#ff73961a;--warn:#d4ad03;--warn-field:#d4ad031a;--info:#00c2fe;--info-field:#00c2fe1a;--glow:#ff7a4a0f;--window-strength:.36;--pane:var(--surface)}@supports (color:color-mix(in lab, red, red)){.auth-page{--pane:color-mix(in oklab, var(--surface) 52%, transparent)}}.auth-page{--pane-shine:#ffffff1a;--pane-sheen:#ffffff0b;--pane-shadow:0 1px 0 #0009, 0 22px 50px -24px #000c}}.auth-page{background:var(--ground);min-height:100svh;color:var(--ink);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;margin:0;padding:2.5rem 1.25rem 3rem;display:flex}.auth-page:before{--window-size:min(64rem, 150vw);content:"";top:calc(var(--window-size) * -.42);right:calc(var(--window-size) * -.2);width:var(--window-size);aspect-ratio:1;pointer-events:none;background:var(--window) center / contain no-repeat;filter:blur(56px)saturate(1.2);opacity:var(--window-strength);position:fixed}.auth-col{flex-direction:column;gap:1.5rem;width:100%;max-width:24rem;margin:auto;display:flex;position:relative}.surface-grant{max-width:30rem}.setup-ready{--signal:var(--glass-emerald);--signal-ink:#fff;--ring:var(--glass-emerald)}@supports (color:color-mix(in lab, red, red)){.setup-ready{--ring:color-mix(in oklab, var(--glass-emerald) 26%, transparent)}}@media (prefers-color-scheme:dark){.setup-ready{--signal-ink:#06231a}}.surface-terminus{max-width:21rem}.disclosure{flex-direction:column;gap:.5rem;display:flex}.disclosure>summary{cursor:pointer;width:fit-content;color:var(--signal);text-underline-offset:3px;font-size:.9375rem;text-decoration:underline;list-style:none}.disclosure>summary::-webkit-details-marker{display:none}.surface-terminus .prompt-head{text-align:left;align-items:flex-start}.surface-terminus .prompt-title{letter-spacing:-.012em;font-size:1.125rem;font-weight:500;line-height:1.4}.surface-terminus .prompt-lede{max-width:none;font-size:.9375rem}.state{letter-spacing:.14em;text-transform:uppercase;color:var(--brass);align-items:center;gap:.5rem;font-size:.6875rem;font-weight:700;display:flex}.state:before{content:"";background:currentColor;border-radius:1px;flex:none;width:1.5rem;height:2px}.state-bad{color:var(--bad)}.state-done{color:var(--signal)}.said{border-radius:var(--bend);background:var(--surface);border:1px solid var(--line);font-family:var(--font-mono);color:var(--ink-soft);overflow-wrap:anywhere;margin:0;padding:.6875rem .8125rem;font-size:.75rem;line-height:1.5}.auth-id{text-align:center;flex-direction:column;align-items:center;gap:.75rem;display:flex}.auth-mark{border-radius:var(--bend);background:var(--surface);border:1px solid var(--brass);place-items:center;width:2.75rem;height:2.75rem;display:grid}@supports (color:color-mix(in lab, red, red)){.auth-mark{border:1px solid color-mix(in oklab, var(--brass) 55%, var(--line))}}.auth-mark{color:var(--signal);letter-spacing:-.02em;font-size:1.0625rem;font-weight:700}.avatar{border-radius:var(--bend);border:1px solid var(--line);background:var(--surface);object-fit:cover;display:block}.avatar-photo{border-radius:50%}.avatar-identicon,.avatar-initials{border-radius:22%}.auth-tenant{letter-spacing:.12em;text-transform:uppercase;color:var(--brass);overflow-wrap:anywhere;font-size:.75rem;font-weight:700}.auth-pair{justify-content:center;align-items:center;gap:.875rem;display:flex}.auth-pair .auth-mark{width:2.5rem;height:2.5rem;font-size:1rem}.auth-mark-client{color:var(--ink);border-color:var(--line-firm)}.auth-mark-logo{object-fit:cover;background:var(--surface)}.item-logo{border-radius:.3rem}.app-tiles{grid-template-columns:repeat(auto-fill,minmax(7rem,1fr));gap:.5rem;margin:0;padding:0;list-style:none;display:grid}.app-tile{border:1px solid var(--pane-rim);background:var(--pane);box-shadow:var(--pane-shadow);color:inherit;text-align:center;border-radius:1rem;flex-direction:column;align-items:center;gap:.5rem;padding:1rem .5rem .875rem;text-decoration:none;display:flex}.app-tile:hover,.app-tile:focus-visible{border-color:var(--brass)}.app-tile-logo{border-radius:.45rem;width:2rem;height:2rem}.app-tile-initial{background:var(--brass);place-items:center;display:grid}@supports (color:color-mix(in lab, red, red)){.app-tile-initial{background:color-mix(in oklab, var(--brass) 14%, transparent)}}.app-tile-initial{color:var(--brass);font-weight:600}.app-tile-name{overflow-wrap:anywhere;font-size:.875rem;font-weight:500}.client-links{flex-wrap:wrap;gap:.25rem 1rem;display:flex}.auth-mark-pending{color:var(--brass);border-style:dashed}.auth-mark-rose{background:0 0;border:0;border-radius:50%}.auth-wire{background:var(--line-firm);flex:0 0 3.5rem;height:1px;position:relative}.auth-wire:after{content:"";border-top:1px solid var(--line-firm);border-right:1px solid var(--line-firm);width:5px;height:5px;position:absolute;top:50%;right:0;transform:translateY(-50%)rotate(45deg)}.auth-wire-live{background:var(--signal)}.auth-wire-live:after{background:var(--signal);border:0;border-radius:50%;width:6px;height:6px;transform:translate(50%,-50%)}.slab,.entry,.actor{background:linear-gradient(160deg, var(--pane-sheen), transparent 45%), var(--pane);border:1px solid var(--pane-rim);box-shadow:inset 0 1px 0 var(--pane-shine), var(--pane-shadow);-webkit-backdrop-filter:blur(22px)saturate(1.5);backdrop-filter:blur(22px)saturate(1.5)}.slab{border-radius:var(--bend);flex-direction:column;gap:1rem;padding:1.125rem;display:flex}.grant-scope-hot,.grant-scope-hot .chip-key{color:var(--warn)}.grant-scope-split{background:var(--line-firm);height:1px;margin:.25rem 0;list-style:none}.record-cap{letter-spacing:.16em;text-transform:uppercase;color:var(--brass);font-size:.6875rem;font-weight:700}.place{--accent:var(--glass-gold);flex-direction:column;gap:1.75rem;display:flex}.plaque{isolation:isolate;text-align:center;flex-direction:column;align-items:center;gap:.25rem;padding:0 1rem .5rem;display:flex;position:relative}.plaque-top{text-align:left;align-self:stretch;align-items:center;gap:.5rem;display:flex}.plaque-top .auth-mark{width:1.75rem;height:1.75rem;font-size:.75rem}.plaque-title{border-bottom:1px solid var(--line);letter-spacing:-.02em;text-align:left;align-self:stretch;margin:.5rem 0 1.75rem;padding-bottom:1rem;font-size:1.25rem;font-weight:600}.plaque-notes{text-align:left;flex-direction:column;align-self:stretch;gap:.5rem;margin:-.75rem 0 1.75rem;display:flex}.plaque:before{content:"";z-index:-1;pointer-events:none;background:radial-gradient(44% 58% at 50% 0%, var(--glass-amber), transparent 72%);height:18rem;position:absolute;inset:-3rem 0 auto}@supports (color:color-mix(in lab, red, red)){.plaque:before{background:radial-gradient(44% 58% at 50% 0%, color-mix(in oklab, var(--glass-amber) 20%, transparent), transparent 72%)}}.plaque-shot{display:inline-block;position:relative}.plaque-pick{cursor:pointer;display:block}.plaque-badge-form{z-index:1;position:absolute;bottom:-.1875rem;right:-.1875rem}.plaque-badge{background:var(--surface);border:1px solid var(--line-firm);width:1.75rem;height:1.75rem;color:var(--ink-soft);cursor:pointer;border-radius:50%;place-items:center;padding:0;display:grid}.plaque-badge svg{width:.875rem;height:.875rem}.plaque-badge:hover{border-color:var(--bad);color:var(--bad)}.plaque-done{z-index:2;background:var(--glass-emerald);width:1.75rem;height:1.75rem;color:var(--surface);pointer-events:none;opacity:0;border-radius:50%;place-items:center;animation:2.4s ease-out plaque-done;display:grid;position:absolute;bottom:-.1875rem;right:-.1875rem}.plaque-done svg{stroke-width:2.2px;width:.875rem;height:.875rem}.plaque-shot-done .plaque-avatar{animation:2.4s ease-out plaque-ring}@keyframes plaque-done{0%,65%{opacity:1}to{opacity:0}}@keyframes plaque-ring{0%,65%{box-shadow:0 0 0 2px var(--glass-emerald), 0 16px 34px -18px color-mix(in oklab, var(--glass-amber) 55%, transparent)}}.plaque-file{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.plaque-file-label{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;margin:-1px;position:absolute;overflow:hidden}.plaque-pick:focus-within .plaque-avatar{outline:2px solid var(--accent);outline-offset:3px}.plaque-avatar{object-fit:cover;width:5.5rem;height:5.5rem;box-shadow:0 0 0 1px var(--line-firm), 0 16px 34px -18px var(--glass-amber);flex:none;display:block}@supports (color:color-mix(in lab, red, red)){.plaque-avatar{box-shadow:0 0 0 1px var(--line-firm), 0 16px 34px -18px color-mix(in oklab, var(--glass-amber) 55%, transparent)}}.plaque-name{letter-spacing:-.03em;margin:.75rem 0 0;font-size:1.625rem;font-weight:700;line-height:1.15}.plaque-sub{color:var(--ink-soft);margin:0;font-size:1rem}.plaque-pills{flex-wrap:wrap;justify-content:center;align-items:flex-start;gap:.5rem;margin-top:1rem;display:flex}.signout{display:contents}.pill{border:1px solid var(--line-firm);background:var(--glow);color:var(--ink-soft);cursor:pointer;border-radius:999px;align-items:center;gap:.4375rem;padding:.5rem 1rem;font-family:inherit;font-size:.875rem;font-weight:600;text-decoration:none;display:inline-flex}.pill:hover{border-color:var(--brass);color:var(--ink)}.pill-accent{color:var(--accent);border-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.pill-accent{border-color:color-mix(in oklab, var(--accent) 40%, var(--line))}}.pill-accent:hover{color:var(--accent);border-color:var(--accent)}.pill svg{width:1rem;height:1rem}.group{flex-direction:column;gap:.5rem;scroll-margin-top:1.25rem;display:flex}.group>h2{color:var(--brass);margin:0 0 .125rem .25rem;font-size:.875rem;font-weight:500}.entries{flex-direction:column;gap:.5rem;display:flex}.entry{border-radius:1rem;scroll-margin-top:1.25rem}.entry[open]{border-color:var(--brass)}@supports (color:color-mix(in lab, red, red)){.entry[open]{border-color:color-mix(in oklab, var(--brass) 45%, var(--line-firm))}}.entry>summary{cursor:pointer;align-items:center;gap:.875rem;padding:.9375rem 1rem;list-style:none;display:flex}.entry>summary::-webkit-details-marker{display:none}.entry-icon{border:1px solid var(--line-firm);width:2.25rem;height:2.25rem;color:var(--ink-soft);border-radius:50%;flex:none;place-items:center;display:grid}.entry-icon svg{width:1.125rem;height:1.125rem}.entry-label{overflow-wrap:anywhere;letter-spacing:-.012em;min-width:0;font-size:1rem;font-weight:500}.entry-state{color:var(--brass);text-align:right;flex:none;margin-left:auto;font-size:.875rem}.entry-state-warn{color:var(--accent)}.entry-state-bad{color:var(--bad)}.entry-mark{border-right:1.5px solid var(--line-firm);border-bottom:1.5px solid var(--line-firm);width:.4375rem;height:.4375rem;transition:transform .2s var(--swing);flex:none;transform:rotate(-45deg)}.entry[open] .entry-mark{transform:rotate(45deg)}@media (prefers-reduced-motion:reduce){.entry-mark{transition:none}}.entry-body{flex-direction:column;gap:.875rem;padding:0 1rem 1.125rem;display:flex}.entry-body>.aside{max-width:52ch}.items{flex-direction:column;display:flex}.item{grid-template-columns:minmax(0,1fr) auto;align-items:start;gap:.375rem 1rem;padding:.875rem 0;display:grid}.item+.item{border-top:1px solid var(--line)}.item:first-child{padding-top:.25rem}.item:last-child{padding-bottom:.25rem}.item-name{overflow-wrap:anywhere;letter-spacing:-.01em;flex-wrap:wrap;grid-column:1;align-items:center;gap:.5rem;min-width:0;font-size:.9375rem;font-weight:600;display:flex}.item-meta{color:var(--ink-soft);grid-column:1;font-size:.8125rem;line-height:1.5}.item-list{color:var(--ink-soft);flex-direction:column;grid-column:1;gap:.1875rem;margin:0;padding:0;font-size:.8125rem;line-height:1.4;list-style:none;display:flex}.item-more{color:var(--brass)}.item-delegations{color:var(--ink-soft);flex-direction:column;grid-column:1/-1;gap:.375rem;margin:.25rem 0 0;padding:0;font-size:.8125rem;list-style:none;display:flex}.item-delegations li{border-left:2px solid var(--line);justify-content:space-between;align-items:center;gap:1rem;padding-left:.75rem;display:flex}.item-act{grid-area:1/2;justify-self:end}.item-act .action{white-space:nowrap}.item-acts{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:.5rem;display:flex}.item-acts .control{width:auto}.item-member .item-act{grid-row:1/span 2;align-self:center}@media (width<=34rem){.item-member{grid-template-columns:minmax(0,1fr)}.item-member .item-act{grid-area:auto/1;justify-self:start}.item-member .item-acts{justify-content:flex-start}}.entry-invited{border-color:var(--warn)}@supports (color:color-mix(in lab, red, red)){.entry-invited{border-color:color-mix(in oklab, var(--warn) 55%, var(--line-firm))}}.member-add{border-top:1px solid var(--line);grid-template-columns:minmax(0,1fr) minmax(7rem,auto) auto;align-items:end;gap:.625rem .75rem;padding-top:1rem;display:grid}.member-add-hint{grid-column:1/-1}.member-add .control{height:3.25rem;padding-block:0}.member-add .member-add-go{height:3.25rem}@media (width<=34rem){.member-add{grid-template-columns:minmax(0,1fr) auto}.member-add-email{grid-column:1/-1}}.member-leave{border-top:1px solid var(--line);padding-top:1rem;display:flex}.switches{flex-direction:column;display:flex}.switch{cursor:pointer;justify-content:space-between;align-items:center;gap:1rem;padding:.6875rem 0;font-size:.9375rem;display:flex}.switch+.switch{border-top:1px solid var(--line)}.switch input[type=checkbox]{width:1.0625rem;height:1.0625rem;accent-color:var(--accent);flex:none;margin:0}.switch-kept{color:var(--brass);flex:none;font-size:.75rem;font-weight:500}.switch-set{flex-direction:column;gap:.25rem;display:flex}.switch-set>legend{color:var(--brass);padding:0;font-size:.75rem;font-weight:500}.flow{flex-direction:column;gap:1.25rem;display:flex}.flow-tight{flex-direction:column;gap:.625rem;display:flex}.prompt-head{text-align:center;flex-direction:column;align-items:center;gap:.4375rem;display:flex}.prompt-title{letter-spacing:-.03em;text-wrap:balance;margin:0;font-size:clamp(1.75rem,1.4rem + 1.5vw,2.125rem);font-weight:700;line-height:1.06}.prompt-lede{color:var(--ink-soft);max-width:38ch;margin:0;font-size:1rem;line-height:1.5}.prompt-lede strong{color:var(--ink);font-weight:500}.pulse{background:var(--brass);border-radius:1px;width:2.75rem;height:2px;margin-bottom:.625rem;position:relative}@supports (color:color-mix(in lab, red, red)){.pulse{background:color-mix(in oklab, var(--brass) 60%, transparent)}}.pulse{overflow:hidden}.pulse:after{content:"";background:var(--signal);inset-block:0;border-radius:1px;width:55%;position:absolute;left:0;translate:-100%}.pulse-on:after{animation:1.15s cubic-bezier(.66,0,.34,1) infinite sweep}.pulse-done{background:var(--signal)}.pulse-bad{background:var(--bad)}.ledger-row{border-top:1px solid var(--line);flex-direction:column;gap:.5rem;padding:.9375rem 0;display:flex}.ledger-row:first-child{border-top:0;padding-top:0}.ledger-row:last-child{padding-bottom:0}.ledger-step+.ledger-step{border-top:0}.setup .prompt-head{margin-bottom:.75rem}.tabset{gap:.25rem;display:flex}.tabset-tab{border-bottom:2px solid var(--line);letter-spacing:.06em;text-transform:uppercase;text-align:center;color:var(--ink-soft);flex:1;padding:0 0 .5rem;font-size:.6875rem;font-weight:700;transition:color .2s,border-color .2s}.tabset-done{border-bottom-color:var(--glass-emerald);color:var(--brass)}.tabset-now{border-bottom-color:var(--signal);color:var(--ink)}.ledger-row-aside{grid-template-rows:auto auto;grid-template-columns:1fr auto;align-items:center;column-gap:.75rem;display:grid}.ledger-aside{grid-area:1/2/span 2;justify-self:end}.ledger-label{letter-spacing:.08em;text-transform:uppercase;color:var(--brass);font-size:.75rem;font-weight:700}.ledger-value{overflow-wrap:anywhere;font-size:.9375rem;line-height:1.5}.ledger-row-tight{gap:.25rem;padding:.625rem 0}.ledger-row-tight .ledger-value{font-size:.8125rem}.ledger-step{--step:var(--line-firm)}.ledger-step-done{--step:var(--glass-emerald)}.ledger-step .ledger-label{color:var(--ink-soft);align-items:center;gap:.5rem;transition:color .2s;display:flex}.ledger-step .ledger-label:before{content:"";background:var(--step);border-radius:50%;width:.4375rem;height:.4375rem;transition:background-color .2s}.ledger-step-done .ledger-label{color:var(--step)}.ledger-step-done .control:not(:focus){border-color:var(--step)}@supports (color:color-mix(in lab, red, red)){.ledger-step-done .control:not(:focus){border-color:color-mix(in oklab, var(--step) 45%, var(--line))}}.enrol{flex-wrap:wrap;align-items:center;gap:1rem;display:flex}.enrol-qr{aspect-ratio:1;border-radius:var(--bend);border:1px solid var(--line);background:#fff;flex:none;width:10rem;max-width:100%;overflow:hidden}.enrol-qr svg{width:100%;height:100%;display:block}.enrol-key{flex-direction:column;flex:10rem;gap:.375rem;min-width:0;display:flex}.enrol-secret{overflow-wrap:anywhere;letter-spacing:.06em;-webkit-user-select:all;user-select:all}.codes{font-variant-numeric:tabular-nums;grid-template-columns:repeat(auto-fill,minmax(10rem,1fr));gap:.375rem 1rem;margin:0;padding:0;list-style:none;display:grid}.codes li{-webkit-user-select:all;user-select:all}.codes-actions{flex-wrap:wrap;align-self:flex-start;gap:.5rem 1.25rem;display:flex}.grant-scopes{flex-direction:column;gap:.5rem;margin:0;padding:0;list-style:none;display:flex}.grant-fields{color:var(--ink-soft);flex-basis:100%;grid-template-columns:auto 1fr;gap:.125rem .75rem;margin:.25rem 0 0;font-size:.8125rem;display:grid}.grant-fields dt{font-weight:600}.grant-fields dd{overflow-wrap:anywhere;margin:0}.grant-scope{flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:.1875rem .875rem;font-size:.9375rem;line-height:1.45;display:flex}.field{flex-direction:column;gap:.4375rem;display:flex}.field-label{letter-spacing:-.002em;font-size:.875rem;font-weight:500}.field-line{justify-content:space-between;align-items:baseline;gap:1rem;display:flex}.field-line .textlink{font-size:.875rem}.field-hint{color:var(--ink-soft);font-size:.8125rem;line-height:1.45}.field-hint-bad{color:var(--bad);font-weight:500}.control{width:100%;font:inherit;border-radius:var(--bend);border:1px solid var(--line);background:var(--surface);padding:.9375rem 1rem;font-size:1rem}@supports (color:color-mix(in lab, red, red)){.control{background:color-mix(in oklab, var(--surface) 72%, transparent)}}.control{color:var(--ink);caret-color:var(--signal);transition:border-color .15s,box-shadow .15s,background-color .15s}.control:autofill{-webkit-text-fill-color:var(--ink);caret-color:var(--signal);box-shadow:inset 0 0 0 100vmax var(--surface)}.control:autofill:focus{box-shadow:inset 0 0 0 1px var(--brass-lit), inset 0 0 0 100vmax var(--surface)}.control::placeholder{color:var(--ink-soft)}@supports (color:color-mix(in lab, red, red)){.control::placeholder{color:color-mix(in oklab, var(--ink-soft) 78%, transparent)}}.control:hover:not(:disabled):not([readonly]){border-color:var(--line-firm)}.control:focus{border-color:var(--brass-lit);box-shadow:inset 0 0 0 1px var(--brass-lit);outline:none}.control[readonly]{background:var(--ground);color:var(--ink-soft);border-color:var(--line)}.control-sm{padding:.5625rem .75rem;font-size:.9375rem}.control-mono{font-family:var(--font-mono);letter-spacing:.14em;font-size:1rem}.control-code{font-family:var(--font-mono);text-align:center;letter-spacing:.4em;text-indent:.4em;font-variant-numeric:tabular-nums;padding:.875rem .5rem;font-size:1.5rem;font-weight:500}.check{color:var(--ink-soft);cursor:pointer;align-items:center;gap:.625rem;font-size:.875rem;line-height:1.4;display:flex}.check input[type=checkbox],.check input[type=radio]{width:1rem;height:1rem;accent-color:var(--signal);flex:none;margin:0}.check input[type=checkbox]:focus-visible,.check input[type=radio]:focus-visible{outline:2px solid var(--signal);outline-offset:2px}.action{width:100%;font:inherit;letter-spacing:-.014em;text-align:center;border-radius:var(--bend);border:1px solid var(--signal);justify-content:center;align-items:center;gap:.5rem;padding:.9375rem 1.125rem;font-size:1rem;font-weight:500;display:inline-flex;position:relative}@supports (color:color-mix(in lab, red, red)){.action{border:1px solid color-mix(in oklab, var(--signal) 60%, transparent)}}.action{background:var(--signal)}@supports (color:color-mix(in lab, red, red)){.action{background:color-mix(in oklab, var(--signal) 14%, var(--ground))}}.action{color:var(--signal);cursor:pointer;transition:background-color .15s,color .15s,border-color .15s}.action:hover:not(:disabled){border-color:var(--signal);background:var(--signal)}@supports (color:color-mix(in lab, red, red)){.action:hover:not(:disabled){background:color-mix(in oklab, var(--signal) 24%, var(--ground))}}.action:focus-visible{outline:2px solid var(--brass-lit);outline-offset:2px}.action:disabled{border-color:var(--line-firm);color:var(--ink-soft);background:0 0}@supports (color:color-mix(in lab, red, red)){.action:disabled{color:color-mix(in oklab, var(--ink-soft) 66%, transparent)}}.action:disabled{cursor:not-allowed}.action-busy,.action-busy:disabled{background:var(--surface);border-color:var(--line-firm);color:var(--ink-soft);cursor:progress}.action-mark{position:absolute;top:50%;left:1.0625rem;translate:0 -50%}.action-quiet{background:var(--surface);color:var(--ink);border-color:var(--line)}.action-quiet:hover:not(:disabled){background:var(--surface);border-color:var(--line-firm)}.action-plain{color:var(--ink-soft);background:0 0;padding:.6875rem 1rem;font-size:.9375rem;font-weight:400}.action-plain:hover:not(:disabled){background:var(--surface);color:var(--ink)}.action-sm{align-self:flex-start;width:auto;padding:.5625rem .9375rem;font-size:.9375rem}.providers{flex-direction:column;gap:.625rem;display:flex}.providers>form{display:contents}.org-picks{flex-direction:column;gap:.5rem;margin:0;padding:0;list-style:none;display:flex}.org-pick{border:1px solid var(--line);border-radius:var(--bend);background:var(--surface);width:100%;color:var(--ink);font:inherit;text-align:left;cursor:pointer;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:.875rem;padding:.75rem 1rem .75rem .75rem;transition:border-color .15s,background-color .15s;display:grid}.org-pick:hover:not(:disabled){border-color:var(--signal)}@supports (color:color-mix(in lab, red, red)){.org-pick:hover:not(:disabled){border-color:color-mix(in oklab, var(--signal) 60%, var(--line-firm))}}.org-pick:focus-visible{outline:2px solid var(--brass-lit);outline-offset:2px}.org-pick:disabled{cursor:not-allowed;opacity:.6}.org-pick[aria-busy=true]{opacity:1;cursor:progress;border-color:var(--signal)}.org-pick-mark{border-radius:calc(var(--bend) * .75);border:1px solid var(--line-firm);background:var(--ground);width:2.25rem;height:2.25rem;color:var(--signal);letter-spacing:.02em;place-items:center;font-size:.8125rem;font-weight:700;display:grid}.org-pick-name{overflow-wrap:anywhere;letter-spacing:-.014em;min-width:0;font-size:1rem;font-weight:600}.org-pick-role{color:var(--ink-soft);font-size:.8125rem}.credential-ways{grid-template-columns:1fr 1fr;gap:.5rem;display:grid}.credential-way{font:inherit;border-radius:var(--bend);border:1px solid var(--line);background:var(--surface);padding:.75rem 1rem;font-size:.9375rem}@supports (color:color-mix(in lab, red, red)){.credential-way{background:color-mix(in oklab, var(--surface) 72%, transparent)}}.credential-way{color:var(--ink-soft);cursor:pointer;transition:border-color .15s,color .15s}.credential-way[aria-checked=true]{border-color:var(--signal);color:var(--ink);font-weight:600}.credential-way:focus-visible{outline:2px solid var(--signal);outline-offset:2px}.providers-rule{color:var(--ink-soft);text-transform:lowercase;align-items:center;gap:.75rem;font-size:.8125rem;display:flex}.providers-rule:before,.providers-rule:after{content:"";background:var(--line);flex:auto;height:1px}.otherwise{flex-direction:column;gap:.625rem;display:flex}.otherwise>.providers-rule{margin-bottom:.3125rem}.otherwise .providers{gap:.625rem}.action-row{align-items:stretch;gap:.625rem;display:flex}.action-row>form{display:flex}.action-countdown{font-variant-numeric:tabular-nums}.action-grow{flex:auto}.action-row .action-sm{align-self:auto}.action-fit{flex:none;width:auto}.textlink{font:inherit;color:var(--signal);cursor:pointer;text-underline-offset:3px;text-decoration:underline;text-decoration-thickness:1px;-webkit-text-decoration-color:var(--signal);-webkit-text-decoration-color:var(--signal);-webkit-text-decoration-color:var(--signal);text-decoration-color:var(--signal);background:0 0;border:0;padding:0;font-size:.9375rem;font-weight:400}@supports (color:color-mix(in lab, red, red)){.textlink{-webkit-text-decoration-color:color-mix(in oklab, var(--signal) 38%, transparent);-webkit-text-decoration-color:color-mix(in oklab, var(--signal) 38%, transparent);-webkit-text-decoration-color:color-mix(in oklab, var(--signal) 38%, transparent);text-decoration-color:color-mix(in oklab, var(--signal) 38%, transparent)}}.textlink{transition:text-decoration-color .15s}.textlink:hover{text-decoration-color:currentColor}.textlink:focus-visible{outline:2px solid var(--signal);outline-offset:3px;border-radius:3px}.textlink:disabled{opacity:.5;cursor:not-allowed}.whom{border-bottom:1px solid var(--line);flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:.25rem 1rem;padding-bottom:.8125rem;display:flex}.whom-name{font-family:var(--font-mono);color:var(--ink-soft);overflow-wrap:anywhere;font-size:.8125rem;line-height:1.5}.whom .textlink{flex:none;font-size:.875rem}.handshake-warn{color:var(--warn)}.handshake-more>summary{color:var(--ink-soft);-webkit-text-decoration-color:var(--line-firm);-webkit-text-decoration-color:var(--line-firm);-webkit-text-decoration-color:var(--line-firm);text-decoration-color:var(--line-firm);align-self:center;font-size:.8125rem}.handshake-more[open]>summary{margin-bottom:.25rem}.handshake-origin{border:1px solid var(--line-firm);background:var(--surface);border-radius:999px;flex-wrap:wrap;justify-content:center;align-items:baseline;gap:.25rem .5rem;max-width:100%;margin:.375rem 0 .25rem;padding:.375rem .875rem;display:flex}.handshake-origin-label{color:var(--ink-soft);font-size:.75rem}.handshake-origin-value{font-family:var(--font-mono);color:var(--ink);overflow-wrap:anywhere;font-size:.875rem;font-weight:600}.handshake-replacing strong{font-weight:600}.handshake-replacing span{color:var(--ink-soft);font-size:.875rem}.handshake-as{flex-direction:column;gap:.4375rem;display:flex}.handshake-caption{color:var(--ink-soft);padding-inline:.125rem;font-size:.8125rem}.handshake-as .actor{box-shadow:none;-webkit-backdrop-filter:none;backdrop-filter:none;border-color:var(--line);background:0 0}.handshake-as .actor-note{color:var(--ink-soft);font-style:italic}.handshake-as .actor-role{color:var(--brass);letter-spacing:.06em}.handshake-heeds{flex-direction:column;gap:.625rem;margin:0;padding:0;list-style:none;display:flex}.handshake-heed{border-left:2px solid var(--warn);flex-direction:column;gap:.1875rem;padding:.125rem 0 .125rem .75rem;display:flex}.handshake-heed-what{color:var(--warn);font-size:.9375rem;font-weight:600;line-height:1.4}.handshake-heed-why{color:var(--ink-soft);font-size:.875rem;line-height:1.45}.handshake-heed-alarm{border-left-color:var(--bad)}.handshake-heed-alarm .handshake-heed-what,.handshake-heed-alarm .handshake-heed-why{color:var(--bad)}.handshake-sees{flex-wrap:wrap;gap:.375rem;margin:0;padding:0;list-style:none;display:flex}.handshake-sees li{border:1px solid var(--line);background:var(--surface);border-radius:999px;padding:.25rem .625rem;font-size:.875rem;line-height:1.4}.handshake-say{margin:0;font-size:.9375rem;line-height:1.5}.handshake-say .chip-key{color:var(--ink);font-size:.8125rem}.actor{border-radius:.75rem;grid-template-columns:auto 1fr auto;align-items:center;gap:.875rem;padding:.75rem .875rem;display:grid}.actor-avatar{object-fit:cover;border-radius:999px;width:2.75rem;height:2.75rem}.actor-who{flex-direction:column;gap:.125rem;min-width:0;display:flex}.actor-name{overflow-wrap:anywhere;font-weight:600;line-height:1.3}.actor-sub{color:var(--ink-soft);overflow-wrap:anywhere;font-size:.8125rem;line-height:1.4}.actor-note{color:var(--brass)}.actor-role{letter-spacing:.08em;text-transform:uppercase;width:fit-content;color:var(--signal);margin-top:.25rem;font-size:.6875rem;font-weight:700}.actor .textlink{font-size:.875rem}.chip-key{font-family:var(--font-mono);color:var(--ink-soft);flex:none;font-size:.75rem}.tag{border:1px solid var(--line-firm);background:var(--ground);color:var(--ink-soft);border-radius:999px;flex:none;padding:.0625rem .4375rem;font-size:.75rem;font-weight:500;line-height:1.6}.tag-bad{background:var(--bad-field);color:var(--bad);border-color:currentColor}.aside{color:var(--ink-soft);overflow-wrap:anywhere;margin:0;font-size:.875rem;line-height:1.5}.aside-mono{font-family:var(--font-mono);font-size:.8125rem}.aside-bad{color:var(--bad)}.approval-code{letter-spacing:.12em;color:var(--ink);text-align:center;font-size:2rem}.note{border-radius:var(--bend);color:var(--info);background:var(--info-field);border:1px solid;flex-direction:column;gap:.1875rem;padding:.8125rem .875rem;font-size:.9375rem;line-height:1.45;display:flex}.note-bad{color:var(--bad);background:var(--bad-field)}.note-plain{color:var(--ink);background:var(--glow);border-color:var(--line-firm)}.note-warn{color:var(--warn);background:var(--warn-field)}.spinner{border:2px solid;border-top-color:#0000;border-radius:50%;flex:none;width:1.05em;height:1.05em;animation:.62s linear infinite spin}.waiting{color:var(--ink-soft);align-items:center;gap:.625rem;margin:0;font-size:1rem;display:flex}.over{text-align:center;flex-direction:column;align-items:center;gap:1.5rem;display:flex}.over .prompt-lede{max-width:30ch}.over .action{width:auto;min-width:11rem}.empty{color:var(--ink-soft);margin:0;padding:.375rem 0;font-size:.9375rem;line-height:1.5}.recover{flex-flow:wrap;justify-content:space-between;align-items:baseline;gap:.375rem 1rem;display:flex}.recover>span{flex:14rem}.recover .textlink{color:inherit;flex:none;font-size:.9375rem}.recover .textlink:focus-visible{outline-color:currentColor}}@layer utilities{.collapse{visibility:collapse}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.top-0{top:0}.z-20{z-index:20}.m-0{margin:0}.mx-auto{margin-inline:auto}.ms-auto{margin-inline-start:auto}.-me-3{margin-inline-end:calc(var(--spacing) * -3)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.-mr-1{margin-right:calc(var(--spacing) * -1)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.table{display:table}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.size-14{width:calc(var(--spacing) * 14);height:calc(var(--spacing) * 14)}.size-16{width:calc(var(--spacing) * 16);height:calc(var(--spacing) * 16)}.min-h-screen{min-height:100vh}.w-0{width:0}.w-16{width:calc(var(--spacing) * 16)}.w-44{width:calc(var(--spacing) * 44)}.w-auto{width:auto}.w-full{width:100%}.max-w-0{max-width:0}.max-w-6xl{max-width:var(--container-6xl)}.max-w-48{max-width:calc(var(--spacing) * 48)}.max-w-60{max-width:calc(var(--spacing) * 60)}.max-w-64{max-width:calc(var(--spacing) * 64)}.max-w-\[16rem\]{max-width:16rem}.max-w-\[18rem\]{max-width:18rem}.max-w-full{max-width:100%}.max-w-sm{max-width:var(--container-sm)}.max-w-xl{max-width:var(--container-xl)}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:0}.min-w-28{min-width:calc(var(--spacing) * 28)}.min-w-44{min-width:calc(var(--spacing) * 44)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.basis-28{flex-basis:calc(var(--spacing) * 28)}.cursor-pointer{cursor:pointer}.scroll-mt-20{scroll-margin-top:calc(var(--spacing) * 20)}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}.gap-x-2{column-gap:calc(var(--spacing) * 2)}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-x-5{column-gap:calc(var(--spacing) * 5)}.gap-x-6{column-gap:calc(var(--spacing) * 6)}.gap-y-0\.5{row-gap:calc(var(--spacing) * .5)}.gap-y-1{row-gap:var(--spacing)}.gap-y-2{row-gap:calc(var(--spacing) * 2)}.gap-y-4{row-gap:calc(var(--spacing) * 4)}.self-center{align-self:center}.self-start{align-self:flex-start}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-x-auto{overflow-x:auto}.rounded{border-radius:.25rem}.rounded-lg{border-radius:var(--radius-lg)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-\[var\(--line\)\]{border-color:var(--line)}.border-base-300{border-color:var(--color-base-300)}.bg-base-200{background-color:var(--color-base-200)}.object-cover{object-fit:cover}.p-3{padding:calc(var(--spacing) * 3)}.px-1{padding-inline:var(--spacing)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-1{padding-block:var(--spacing)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-14{padding-block:calc(var(--spacing) * 14)}.py-16{padding-block:calc(var(--spacing) * 16)}.pt-1{padding-top:var(--spacing)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-5{padding-top:calc(var(--spacing) * 5)}.pb-1{padding-bottom:var(--spacing)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pl-2{padding-left:calc(var(--spacing) * 2)}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-error{color:var(--color-error)}.text-warning{color:var(--color-warning)}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-75{opacity:.75}.opacity-80{opacity:.8}.opacity-85{opacity:.85}.outline-none{--tw-outline-style:none;outline-style:none}.last\:border-0:last-child{border-style:var(--tw-border-style);border-width:0}.last\:pb-0:last-child{padding-bottom:0}@media (hover:hover){.hover\:opacity-100:hover{opacity:1}}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}@media (width>=40rem){.sm\:col-span-2{grid-column:span 2/span 2}.sm\:size-16{width:calc(var(--spacing) * 16);height:calc(var(--spacing) * 16)}.sm\:w-48{width:calc(var(--spacing) * 48)}.sm\:w-auto{width:auto}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-\[2fr_1fr\]{grid-template-columns:2fr 1fr}.sm\:grid-cols-\[minmax\(0\,1fr\)_10rem_auto\]{grid-template-columns:minmax(0,1fr) 10rem auto}.sm\:items-end{align-items:flex-end}.sm\:gap-y-2{row-gap:calc(var(--spacing) * 2)}.sm\:pb-0{padding-bottom:0}}@media (width>=48rem){.md\:ml-auto{margin-left:auto}.md\:hidden{display:none}.md\:table-cell{display:table-cell}.md\:w-56{width:calc(var(--spacing) * 56)}.md\:w-auto{width:auto}.md\:max-w-none{max-width:none}.md\:flex-1{flex:1}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.md\:grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}}@media (width>=64rem){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}@media (prefers-color-scheme:dark){:root{--color-base-100:#15110e;--color-base-200:#1e1915;--color-base-300:#3d352f;--color-base-content:#f3efec;--color-primary:#ff8f53;--color-primary-content:#1a1614;--color-secondary:#b58a41;--color-secondary-content:#000;--color-accent:#deaf56;--color-accent-content:#000;--color-neutral:#1a1614;--color-neutral-content:#e9e5e2;--color-info:#00c2fe;--color-info-content:#000;--color-success:#1dcf98;--color-success-content:#000;--color-warning:#d4ad03;--color-warning-content:#000;--color-error:#ff867a;--color-error-content:#1a1614}}:root{--glass-ruby:#b53530;--glass-ember:#b04000;--glass-amber:#a44f00;--glass-gold:#8b6200;--glass-verdant:#267e05;--glass-emerald:#008450;--glass-cyan:#008386;--glass-sky:#0077b2;--glass-cobalt:#2065c5;--glass-violet:#6e50be}@media (prefers-color-scheme:dark){:root{--glass-ruby:#ff867a;--glass-ember:#ff8f53;--glass-amber:#f19c29;--glass-gold:#d4ad03;--glass-verdant:#78c966;--glass-emerald:#1dcf98;--glass-cyan:#00cecf;--glass-sky:#00c2fe;--glass-cobalt:#70b1ff;--glass-violet:#b49dff}}@keyframes rise{0%{opacity:0;translate:0 4px}to{opacity:1;translate:none}}@keyframes sweep{0%{translate:-100%}to{translate:240%}}@keyframes spin{to{transform:rotate(360deg)}}.gate{flex-direction:column;gap:1.25rem;display:flex}.gate-moving{overflow-clip-margin:8px;overflow:visible clip}.gate-enter>*{animation:rise .34s var(--swing) both}.gate-enter>:nth-child(2){animation-delay:40ms}.gate-enter>:nth-child(3){animation-delay:80ms}.gate-enter>:nth-child(4){animation-delay:.11s}.gate-enter>:nth-child(n+5){animation-delay:.13s}@media (prefers-reduced-motion:reduce){.gate-enter>*{animation:none}.pulse-on:after{animation-duration:2.4s}.spinner{animation-duration:2s}}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}
|