Validaciones mandatorias — Sección 8 — IDs concretos

This commit is contained in:
markosbenitez
2026-06-04 21:52:39 -03:00
parent d91ea6b2ff
commit b1ca0e0795
32 changed files with 1325 additions and 121 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -6,3 +6,7 @@ NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon-key-publica>
# NUNCA agregar SUPABASE_SERVICE_ROLE_KEY como variable NEXT_PUBLIC_ ni en el cliente
# La service_role bypasa RLS — solo para Edge Functions / backend server-side
# IP hash — variable server-only (NUNCA NEXT_PUBLIC_)
# Usada para deduplicación anónima. Generá un string aleatorio largo.
IP_HASH_SALT=

View File

@@ -0,0 +1,109 @@
'use server'
import { headers } from 'next/headers'
import { createHash, randomUUID } from 'crypto'
import { createClient as createSupabaseClient } from '@supabase/supabase-js'
export type SubmitResult =
| { success: true }
| { success: false; error: string }
export async function submitSurvey(payload: {
surveyId: string
answers: Record<string, unknown>
questionMap: Record<string, string> // código → question_id UUID
consentOperativo: boolean
consentMacroN1: boolean
}): Promise<SubmitResult> {
// 1. ip_hash: server-only, nunca en texto plano
const headersList = await headers()
const rawIp =
headersList.get('x-forwarded-for')?.split(',')[0]?.trim() ?? 'unknown'
const salt = process.env.IP_HASH_SALT ?? ''
const ipHash = createHash('sha256').update(rawIp + salt).digest('hex')
// 2. Cliente Supabase con anon key (RLS policies permiten INSERT a anon)
// NUNCA usar service_role — el anon key respeta RLS
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL ?? ''
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY ?? ''
const supabase = createSupabaseClient(supabaseUrl, supabaseAnonKey)
// 3. Leer survey para obtener org_id y consent_version_id
const { data: survey, error: sErr } = await supabase
.from('surveys')
.select('org_id, consent_version_id')
.eq('id', payload.surveyId)
.single()
if (sErr || !survey) return { success: false, error: 'survey_not_found' }
// 4. Pre-generar UUIDs server-side para evitar .select().single() post-INSERT.
//
// DIAGNÓSTICO: el Supabase JS client usa RETURNING * en .select().single(), lo que
// requiere SELECT policy para anon en consent_records/responses. Esa policy no existe
// (correcto — anon no debe leer consent_records de otros respondentes).
// Solución: pre-generar UUIDs con randomUUID() y NO hacer SELECT after INSERT.
const consentId = randomUUID()
const responseId = randomUUID()
// 5. INSERT consent_record (inmutable, ADR-003)
// Sin .select() para no activar RETURNING y evitar el error RLS 42501.
const { error: cErr } = await supabase
.from('consent_records')
.insert({
id: consentId,
consent_version_id: survey.consent_version_id,
granted_scopes: {
operativo: payload.consentOperativo,
macro_n1: payload.consentMacroN1,
},
granted_at: new Date().toISOString(),
})
if (cErr) return { success: false, error: `consent_insert_failed: ${cErr.message}` }
// 6. Extraer qi_* de las respuestas
const qi_age_bucket =
typeof payload.answers['A5'] === 'string' ? payload.answers['A5'] : null
const qi_sector =
typeof payload.answers['A4'] === 'string' ? payload.answers['A4'] : null
// 7. INSERT response (respondent_id=null — encuesta anónima, regla 2 CLAUDE.md)
const { error: rErr } = await supabase
.from('responses')
.insert({
id: responseId,
survey_id: payload.surveyId,
company_id: survey.org_id,
respondent_id: null,
ip_hash: ipHash,
consent_record_id: consentId,
qi_age_bucket: qi_age_bucket || null,
qi_sector: qi_sector || null,
qi_zone: null,
})
if (rErr) return { success: false, error: `response_insert_failed: ${rErr.message}` }
// 8. INSERT answers — una fila por pregunta respondida
const answerRows = Object.entries(payload.answers)
.map(([code, value]) => ({
response_id: responseId,
question_id: payload.questionMap[code],
value,
}))
.filter(
(row) =>
row.question_id &&
row.value !== null &&
row.value !== undefined &&
row.value !== '' &&
!(Array.isArray(row.value) && row.value.length === 0)
)
if (answerRows.length > 0) {
const { error: aErr } = await supabase.from('answers').insert(answerRows)
if (aErr) return { success: false, error: `answers_insert_failed: ${aErr.message}` }
}
return { success: true }
}

View File

@@ -398,6 +398,61 @@ body {
justify-content: flex-start;
}
/* ── Geo select widget ── */
.geo-select-wrapper { display: flex; flex-direction: column; gap: 16px; }
.geo-select-group { display: flex; flex-direction: column; gap: 8px; }
.geo-select {
display: block; width: 100%;
padding: 10px 12px;
border: 1.5px solid var(--color-border); border-radius: var(--radius);
font-size: 1rem; font-family: inherit; background: var(--color-surface);
color: var(--color-text); cursor: pointer; appearance: auto;
transition: border-color 0.15s;
}
.geo-select:focus { outline: none; border-color: var(--color-border-focus); box-shadow: 0 0 0 3px rgba(37,99,235,0.15); }
.geo-select-disabled { opacity: 0.5; cursor: not-allowed; background: #f3f4f6; }
.geo-label-disabled { color: var(--color-text-muted); }
.geo-disabled-hint { font-size: 0.8125rem; font-weight: 400; color: var(--color-text-muted); }
/* ── Brand header ── */
.brand-header {
background: var(--color-primary-light); border-left: 4px solid var(--color-primary);
border-radius: 0 var(--radius) var(--radius) 0;
padding: 10px 14px; margin: 16px 0 0;
}
.brand-text { margin: 0; font-size: 0.875rem; color: var(--color-primary-hover); line-height: 1.5; }
/* ── Consent screen ── */
.consent-container { max-width: 720px; margin: 0 auto; padding: 32px 16px 80px; }
.consent-title { font-size: 1.5rem; font-weight: 700; margin: 0 0 24px; }
.consent-section { margin-bottom: 24px; }
.consent-section-title { font-size: 1.0625rem; font-weight: 700; margin: 0 0 10px; }
.consent-list { margin: 8px 0 0; padding-left: 20px; line-height: 1.7; display: flex; flex-direction: column; gap: 8px; }
.consent-anon-box {
background: var(--color-sensitive); border: 1px solid var(--color-sensitive-border);
border-radius: var(--radius); padding: 14px 16px; margin-bottom: 24px;
font-size: 0.9375rem; line-height: 1.6;
}
.consent-checkboxes { margin-bottom: 28px; display: flex; flex-direction: column; gap: 14px; }
.consent-checkbox-label {
display: flex; align-items: flex-start; gap: 12px;
padding: 14px 16px; border: 1.5px solid var(--color-border); border-radius: var(--radius);
cursor: pointer; transition: border-color 0.15s, background 0.15s; line-height: 1.5;
}
.consent-checkbox-label:has(input:checked) { border-color: var(--color-primary); background: var(--color-primary-light); }
.consent-checkbox-input { width: 20px; height: 20px; flex-shrink: 0; margin-top: 1px; accent-color: var(--color-primary); cursor: pointer; }
.consent-checkbox-text { flex: 1; }
.consent-required-badge { display: inline-block; font-size: 0.75rem; font-weight: 600; color: var(--color-primary); background: var(--color-primary-light); padding: 1px 6px; border-radius: 4px; }
.consent-optional-badge { display: inline-block; font-size: 0.75rem; font-weight: 600; color: var(--color-text-muted); background: #f3f4f6; padding: 1px 6px; border-radius: 4px; }
.consent-footer { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
.consent-required-hint { margin: 0; font-size: 0.875rem; color: var(--color-text-muted); }
.btn-disabled { opacity: 0.5; cursor: not-allowed; }
/* ── Thank you / error screens ── */
.thank-you-container, .error-container { max-width: 560px; margin: 80px auto; padding: 0 16px; }
.thank-you-title, .error-title { font-size: 1.5rem; font-weight: 700; margin: 0 0 16px; }
.thank-you-body { color: var(--color-text-muted); line-height: 1.7; margin: 0 0 12px; }
/* ── No survey state ── */
.no-survey {
max-width: 480px;

View File

@@ -1,21 +1,27 @@
import { createClient } from '@/lib/supabase'
import type { Question, Survey } from '@/lib/types'
import type { BrandConfig, Question, Survey } from '@/lib/types'
import { SurveyForm } from '@/components/survey-form'
// Force dynamic rendering — page fetches from Supabase at request time.
// Never statically generated: credentials live in .env.local (runtime only).
export const dynamic = 'force-dynamic'
// Server Component — fetches survey with anon key; RLS ensures only status='live' is returned.
export default async function Page() {
// In Next.js 15, searchParams is a Promise and must be awaited.
interface PageProps {
searchParams: Promise<{ s?: string }>
}
export default async function Page({ searchParams }: PageProps) {
const { s: surveyId } = await searchParams
const supabase = createClient()
// 1. Fetch the live survey
const { data: surveyRow, error: surveyError } = await supabase
// 1. Fetch survey — by ?s=UUID if provided, otherwise first live survey
const surveyQuery = supabase
.from('surveys')
.select('id, title, status, is_anonymous, k_threshold')
.eq('status', 'live')
.maybeSingle()
.select('id, org_id, title, status, is_anonymous, k_threshold, consent_version_id, brand_config')
const { data: surveyRow, error: surveyError } = surveyId
? await surveyQuery.eq('id', surveyId).maybeSingle()
: await surveyQuery.eq('status', 'live').maybeSingle()
if (surveyError) {
return (
@@ -32,10 +38,11 @@ export default async function Page() {
<div className="no-survey" role="main">
<h1 className="no-survey-title">No hay encuesta activa</h1>
<p>
Para ver el formulario, la encuesta debe estar en estado <code>live</code>.
Para ver el formulario, la encuesta debe estar en estado <code>live</code>,
o pasá el UUID por parámetro: <code>?s=UUID</code>.
</p>
<pre className="no-survey-hint">
{`-- Activar la encuesta en Supabase Cloud:\nUPDATE surveys\nSET status = 'live'\nWHERE id = '30000000-0000-0000-0000-000000000001';`}
{`-- Activar en Supabase Cloud:\nUPDATE surveys SET status = 'live'\nWHERE id = '30000000-0000-0000-0000-000000000001';`}
</pre>
</div>
)
@@ -61,20 +68,19 @@ export default async function Page() {
const questions = questionRows as Question[]
// 3. Log question count for validation (visible in server logs and browser Network tab)
console.log(
`[2A] Survey loaded: id=${surveyRow.id} | questions=${questions.length}`
)
console.log(`[2B] Survey loaded: id=${surveyRow.id} | questions=${questions.length}`)
const survey: Survey = {
...(surveyRow as Omit<Survey, 'questions'>),
id: surveyRow.id,
org_id: surveyRow.org_id,
title: surveyRow.title,
status: surveyRow.status,
is_anonymous: surveyRow.is_anonymous,
k_threshold: surveyRow.k_threshold,
consent_version_id: surveyRow.consent_version_id,
brand_config: (surveyRow.brand_config as BrandConfig) ?? null,
questions,
}
return (
<SurveyForm
survey={survey}
questions={questions}
/>
)
return <SurveyForm survey={survey} questions={questions} />
}

BIN
assets/.DS_Store vendored Normal file

Binary file not shown.

BIN
assets/fundacion/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,380 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="535.614px" height="308.44px" viewBox="0 0 535.614 308.44" enable-background="new 0 0 535.614 308.44"
xml:space="preserve">
<path fill-rule="evenodd" clip-rule="evenodd" fill="#129539" d="M181.184,99.452c-0.34-0.962-0.875-1.782-1.596-2.409
c-0.729-0.643-1.628-1.059-2.608-1.183c-2.093-0.275-4.58,0.708-6.829,3.731c-1.76,1.805-4.482,5.509-7.164,9.176
c-2.851,3.915-5.667,7.738-7.12,9.029c-0.727,0.664-1.556,0.967-2.206,0.945c-0.281-0.027-0.548-0.098-0.732-0.238h-0.021
c-0.165-0.14-0.303-0.323-0.4-0.588c-0.167-0.584-0.046-1.432,0.492-2.549c2.257-4.683,6.057-12.303,9.529-19.074
c2.979-5.827,5.676-11.001,6.939-13.166c2.279-3.803,2.374-7.205,1.248-9.457c-0.494-0.939-1.199-1.711-2.065-2.182
c-0.843-0.491-1.855-0.723-2.933-0.604c-2.441,0.232-5.228,2.177-7.482,6.47c-2.673,5.163-5.185,9.78-7.674,14.381
c-2.981,5.466-5.913,10.86-8.935,16.779c-0.521,0.815-1.193,1.426-1.828,1.701c-0.289,0.124-0.524,0.194-0.737,0.151
c-0.162-0.027-0.319-0.124-0.44-0.308c-0.259-0.324-0.421-0.913-0.421-1.831c-0.027-3.052,3.124-12.577,5.627-20.154
c1.037-3.191,1.971-6.021,2.536-7.933c0.891-3.116,2.374-8.484,3.521-12.945c1.032-3.937,1.828-7.177,1.828-7.625
c-0.021-2.23-0.516-3.916-1.291-5.114c-0.748-1.129-1.709-1.81-2.819-2.128c-1.075-0.34-2.252-0.286-3.391,0.043
c-1.512,0.47-2.962,1.432-4.094,2.787c-1.755,2.139-4.102,10.217-6.045,16.968l-0.608,2.058c-0.542,1.879-1.574,5.59-2.724,9.764
c-2.09,7.646-4.623,16.871-5.422,19.031c-0.373,1.053-1.01,1.798-1.685,2.149c-0.275,0.146-0.591,0.216-0.851,0.194
c-0.232-0.027-0.438-0.124-0.632-0.308c-0.395-0.378-0.702-1.097-0.748-2.252c-0.327-5.654,0.256-13.118,0.845-20.506
c0.491-6.194,0.958-12.313,0.915-17.319c0.235-3.32-0.842-5.643-2.468-6.934c-0.775-0.632-1.685-1.01-2.646-1.156
c-0.942-0.135-1.928-0.021-2.86,0.324c-2.068,0.756-3.896,2.685-4.601,5.676c-1.269,5.455-1.925,13.686-2.533,21.311
c-0.588,7.463-1.15,14.332-2.16,17.222c-0.448,1.215-1.199,3.24-2.136,4.854c-0.821,1.383-1.736,2.506-2.536,2.35
c-2.533-0.48-2.859-2.587-3.14-4.396c-0.046-0.389-0.119-0.793-0.189-1.16c-0.235-1.912-0.603-3.904-1.078-5.801
c-0.448-1.922-1.007-3.774-1.593-5.4c-1.064-2.835-3.005-5.551-5.239-7.344c-1.08-0.838-2.249-1.496-3.416-1.831
c-1.226-0.318-2.468-0.318-3.664,0.118c-1.013,0.373-1.974,1.086-2.841,2.166c-2.136,2.674-0.632,6.658,1.288,11.849
c1.95,5.228,4.393,11.751,3.832,19.042c-0.127,1.522-0.24,3.057-0.383,4.53c-0.762,9.202-1.38,17.33-0.148,26.965
c1.045,0.34,2.092,0.681,3.181,1.074c0,0-0.256-0.967,1.248-11.789c2.787-20.073,27.423-29.054,45.787-18.923
c12.418,6.854,17.333,18.696,18.124,31.619c3.98-6.604,6.618-12.285,7.59-15.429c0.443-1.501,2.959-5.396,6-9.808
c4.577-6.62,10.398-14.321,12.461-16.8C181.532,104.62,181.951,101.683,181.184,99.452z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#163F75" d="M153.942,161.811c-0.454,0-0.856,0-1.302,0
c-0.934,8.527-3.151,17-5.765,24.361c-8.868,25.03-8.111,45.039-45.396,37.861c-11.679-2.246-24.604-4.73-36.032-8.883
c14.938,42.295,79.458,45.109,90.397,6.248C159.669,207.789,161.961,181.332,153.942,161.811z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#E00914" d="M91.254,160.644c3.381,2.273-0.47-4.86,2.627-17.275
c4.412-17.567,20.135-29.179,36.528-20.128c21.699,11.968,17.783,40.968,10.744,60.857c-7.925,22.357-7.272,40.238-40.563,33.833
c-26.197-5.065-59.521-11.405-60.733-39.601C39.311,165.963,57.051,133.426,91.254,160.644L91.254,160.644z"/>
<path fill="#E00914" d="M199.191,221.652c4.323,0,7.555-1.291,9.834-3.916c1.733-1.943,2.6-4.504,2.6-7.604
c0-3.37-1.288-6.658-3.823-9.872c-1.167-1.458-2.487-2.884-3.848-4.271c-3.378-3.327-5.77-6.118-7.131-8.489
c-1.547-2.582-2.301-5.298-2.301-8.182c0-3.041,0.548-5.471,1.577-7.302c1.245-2.208,3.07-3.326,5.422-3.326
c3.256,0,5.365,1.998,6.421,5.908c0.467,1.755,0.678,3.71,0.678,5.789c0,2.819-0.278,5.54-0.842,8.235
c-0.07,0.384-0.116,0.751-0.116,1.129c0,1.388,0.681,2.09,2.063,2.09c1.528,0,2.605-1.388,3.243-4.175
c0.488-2.024,0.721-4.46,0.721-7.279c0-11.276-4.404-16.888-13.25-16.888c-4.226,0-7.625,1.167-10.158,3.56
c-1.312,1.22-2.344,2.689-3.075,4.438c-1.007,2.463-1.526,5.282-1.526,8.377c0,4.525,1.196,8.678,3.621,12.383
c1.658,2.581,4.072,5.465,7.345,8.635c1.142,1.178,2.228,2.279,3.227,3.381c2.182,2.42,3.238,4.672,3.238,6.756
c0,3.262-1.48,4.903-4.429,4.903c-2.651,0-4.366-1.388-5.076-4.196c-0.33-1.145-0.486-2.327-0.486-3.45
c0-1.858-0.751-2.792-2.252-2.792c-1.645,0-2.671,1.571-2.671,3.64c0,3.656,0.772,6.54,2.387,8.646
C192.557,220.361,195.419,221.652,199.191,221.652L199.191,221.652z M234.038,216.235c-3.008,0-5.238-1.755-6.71-5.249
c-1.296-3.121-1.947-7.345-1.947-12.691c0-10.963,3.138-16.428,9.402-16.428c2.889,0,4.95,1.782,6.267,5.373
c1.013,2.781,1.499,6.243,1.499,10.461c0,5.093-0.635,9.321-1.877,12.669C239.192,214.291,236.989,216.235,234.038,216.235
L234.038,216.235z M231.667,221.587c5.819,0,10.134-2.278,12.853-6.848c2.39-4.062,3.591-9.612,3.591-16.703
c0-5.563-0.872-10.164-2.632-13.749c-2.417-4.926-6.189-7.394-11.395-7.394c-6.011,0-10.487,2.273-13.425,6.874
c-2.603,3.991-3.918,9.451-3.918,16.348c0,5.897,1.034,10.66,3.124,14.365C222.519,219.238,226.48,221.587,231.667,221.587
L231.667,221.587z M263.008,221.728c0.889,0,1.974-0.141,3.211-0.491c1.218-0.33,2.233-0.768,2.983-1.41
c0.554-0.47,0.861-0.988,0.861-1.62c0-0.794-0.486-1.198-1.499-1.198c-0.324,0-0.821,0.075-1.477,0.265
c-0.426,0.118-0.918,0.184-1.474,0.184c-1.855,0-2.187-1.523-2.187-9.219v-38.548c0-1.62-0.284-2.9-0.77-3.915
c-0.732-1.523-2.001-2.274-3.751-2.274c-3.103,0-4.137,1.707-4.137,6.497v33.126c0,2.933,0.076,5.697,0.262,8.214
c0.21,2.717,0.772,4.925,1.663,6.681C257.958,220.485,260.049,221.728,263.008,221.728L263.008,221.728z M279.279,174.36
c1.653,0,2.825-0.61,3.594-1.755c0.545-0.777,0.805-1.717,0.805-2.797c0-1.193-0.4-2.317-1.205-3.327
c-0.767-1.01-1.831-1.534-3.122-1.534c-2.53,0-4.331,2.215-4.331,5.331C275.021,173,276.447,174.36,279.279,174.36L279.279,174.36z
M279.123,221.652c3.019,0,4.556-2.08,4.556-6.238v-32.023c0-4.828-1.129-6.497-4.129-6.497c-2.983,0-4.528,2.16-4.528,6.199v32.02
c0,1.102,0.089,2.133,0.232,3.143C275.583,220.556,276.849,221.652,279.123,221.652L279.123,221.652z M309.905,193.721
c0,2.9-0.237,5.936-0.683,9.073c-0.421,3.1-1.08,5.746-1.947,7.884c-1.571,3.965-3.542,5.936-5.935,5.936
c-3.029,0.162-3.988-6.729-3.988-14.009c0-4.963,1.482-20.43,8.587-20.43c1.949,0,3.138,0.47,3.634,1.447
c0.211,0.476,0.332,1.037,0.332,1.642V193.721z M318.535,169.997c0-3.208-0.138-6.497-4.131-6.497c-3.467,0-4.499,3.009-4.499,6.189
v7.458c0,0.572-0.078,0.875-0.259,0.875c-0.189,0-0.5-0.119-0.867-0.303c-1.083-0.572-2.279-0.826-3.521-0.826
c-4.698,0-8.352,2.673-11.006,8.073c-2.481,5.109-3.729,11.806-3.729,20.035c0,8.83,3.238,16.796,9.602,16.65
c3.375,0,6.186-1.756,8.435-5.229c0.662-1.068,1.04-1.642,1.153-1.642s0.191,0.232,0.191,0.632c0,3.191,1.032,6.238,4.499,6.238
c3.994,0,4.131-3.278,4.131-6.54V169.997z M348.777,221.652c3.964,0.075,4.061-3.322,4.129-6.54v-31.722
c-0.068-3.139-0.165-6.563-4.129-6.497c-1.385,0-2.443,0.427-3.075,1.226c-0.208,0.281-0.462,0.416-0.815,0.416
c-0.241,0-0.6-0.107-0.97-0.329c-1.501-0.864-2.951-1.313-4.355-1.313c-4.72,0-8.387,2.673-11.03,8.073
c-2.484,5.109-3.729,11.806-3.729,20.035c0,8.83,3.265,16.796,9.597,16.65c3.794,0,6.826-2.08,9.121-6.26
c0.259-0.496,0.448-0.729,0.567-0.729c0.116,0,0.167,0.275,0.167,0.75C344.254,218.605,345.299,221.652,348.777,221.652
L348.777,221.652z M335.616,216.613c-3.027,0.162-3.991-6.729-3.991-14.009c0-4.963,1.477-20.43,8.586-20.43
c2.7,0,4.042,0.967,4.042,2.911v10.342c0,1.879-0.216,4.336-0.664,7.366c-0.467,3.029-1.128,5.681-2.042,7.884
C339.999,214.643,338.006,216.613,335.616,216.613L335.616,216.613z M365.996,221.652c3.027,0,4.525-2.08,4.525-6.238v-9.996
c0-6.988,0.889-12.664,2.649-17c1.763-4.391,3.78-6.551,5.986-6.551c0.651,0,1.212,0.211,1.712,0.653
c0.632,0.572,1.24,0.87,1.828,0.87c1.62,0,2.887-1.664,2.887-3.44c0-1.977-2.322-3.057-5.16-3.057c-3.705,0-6.731,2.068-9.081,6.199
c-0.259,0.486-0.489,0.751-0.629,0.751c-0.122,0-0.192-0.265-0.192-0.805c0-4.104-1.499-6.146-4.525-6.146
c-3.894,0-4.128,3.262-4.128,6.448v31.771c0,1.069,0.097,2.133,0.235,3.143C362.429,220.556,363.739,221.652,365.996,221.652
L365.996,221.652z M393.254,174.36c1.645,0,2.841-0.61,3.616-1.755c0.516-0.777,0.799-1.717,0.799-2.797
c0-1.193-0.427-2.317-1.207-3.327c-0.789-1.01-1.823-1.534-3.138-1.534c-2.533,0-4.315,2.215-4.315,5.331
C389.01,173,390.414,174.36,393.254,174.36L393.254,174.36z M393.12,221.652c2.997,0,4.55-2.08,4.55-6.238v-32.023
c0-4.828-1.134-6.497-4.137-6.497c-2.997,0-4.523,2.16-4.523,6.199v32.02c0,1.102,0.067,2.133,0.229,3.143
C389.571,220.556,390.838,221.652,393.12,221.652L393.12,221.652z M423.867,193.721c0,2.9-0.205,5.936-0.656,9.073
c-0.418,3.1-1.077,5.746-1.95,7.884c-1.566,3.965-3.534,5.936-5.951,5.936c-3.029,0.162-3.999-6.729-3.999-14.009
c0-4.963,1.51-20.43,8.619-20.43c1.917,0,3.122,0.47,3.613,1.447c0.235,0.476,0.324,1.037,0.324,1.642V193.721z M432.529,169.997
c0-3.208-0.167-6.497-4.128-6.497c-3.473,0-4.534,3.009-4.534,6.189v7.458c0,0.572-0.043,0.875-0.254,0.875
c-0.184,0-0.467-0.119-0.867-0.303c-1.083-0.572-2.255-0.826-3.494-0.826c-4.72,0-8.378,2.673-11.003,8.073
c-2.511,5.109-3.731,11.806-3.731,20.035c0,8.83,3.237,16.796,9.575,16.65c3.4,0,6.187-1.756,8.444-5.229
c0.675-1.068,1.053-1.642,1.169-1.642c0.119,0,0.162,0.232,0.162,0.632c0,3.191,1.061,6.238,4.534,6.238
c3.961,0,4.128-3.278,4.128-6.54V169.997z M462.744,221.652c3.985,0.075,4.058-3.322,4.15-6.54v-31.722
c-0.092-3.139-0.165-6.563-4.15-6.497c-1.364,0-2.417,0.427-3.049,1.226c-0.21,0.281-0.494,0.416-0.823,0.416
c-0.257,0-0.607-0.107-0.961-0.329c-1.501-0.864-2.957-1.313-4.391-1.313c-4.714,0-8.373,2.673-10.995,8.073
c-2.492,5.109-3.737,11.806-3.737,20.035c0,8.83,3.24,16.796,9.578,16.65c3.82,0,6.848-2.08,9.121-6.26
c0.259-0.496,0.454-0.729,0.567-0.729c0.119,0,0.178,0.275,0.178,0.75C458.232,218.605,459.271,221.652,462.744,221.652
L462.744,221.652z M449.602,216.613c-3.024,0.162-4.001-6.729-4.001-14.009c0-4.963,1.499-20.43,8.605-20.43
c2.697,0,4.026,0.967,4.026,2.911v10.342c0,1.879-0.203,4.336-0.648,7.366c-0.467,3.029-1.131,5.681-2.044,7.884
C453.974,214.643,452,216.613,449.602,216.613L449.602,216.613z M492.913,193.721c0,2.9-0.208,5.936-0.656,9.073
c-0.427,3.1-1.08,5.746-1.95,7.884c-1.563,3.965-3.54,5.936-5.935,5.936c-3.027,0.162-4.013-6.729-4.013-14.009
c0-4.963,1.507-20.43,8.614-20.43c1.944,0,3.143,0.47,3.616,1.447c0.232,0.476,0.324,1.037,0.324,1.642V193.721z M501.573,169.997
c0-3.208-0.148-6.497-4.137-6.497c-3.461,0-4.523,3.009-4.523,6.189v7.458c0,0.572-0.048,0.875-0.237,0.875
c-0.203,0-0.492-0.119-0.867-0.303c-1.102-0.572-2.274-0.826-3.519-0.826c-4.717,0-8.373,2.673-11.003,8.073
c-2.484,5.109-3.729,11.806-3.729,20.035c0,8.83,3.24,16.796,9.57,16.65c3.405,0,6.224-1.756,8.449-5.229
c0.681-1.068,1.053-1.642,1.169-1.642c0.119,0,0.167,0.232,0.167,0.632c0,3.191,1.062,6.238,4.523,6.238
c3.988,0,4.137-3.278,4.137-6.54V169.997z"/>
<path fill="#2A2A2B" d="M190.7,230.309v11.546h-1.399v-11.546H190.7z M194.639,236.648v5.206h-1.334v-8.651h1.288v1.361h0.122
c0.213-0.454,0.516-0.805,0.913-1.086c0.424-0.265,0.964-0.395,1.62-0.395c0.864,0,1.574,0.275,2.111,0.816
c0.54,0.518,0.821,1.365,0.821,2.462v5.492h-1.336v-5.4c0-0.702-0.184-1.215-0.54-1.587c-0.348-0.4-0.824-0.589-1.458-0.589
c-0.632,0-1.145,0.21-1.569,0.637C194.853,235.314,194.639,235.903,194.639,236.648L194.639,236.648z M206.377,233.203v1.123h-1.855
v5.045c0,0.399,0.07,0.652,0.165,0.842c0.122,0.194,0.256,0.335,0.427,0.378c0.181,0.07,0.367,0.098,0.556,0.098
c0.138,0,0.281,0,0.375-0.027c0.092-0.026,0.162-0.026,0.213-0.043l0.281,1.188c-0.097,0.048-0.211,0.069-0.381,0.118
c-0.159,0.021-0.373,0.043-0.629,0.043c-0.378,0-0.721-0.064-1.099-0.237c-0.356-0.156-0.656-0.41-0.894-0.751
c-0.24-0.318-0.351-0.739-0.351-1.231v-5.422h-1.293v-1.123h1.293v-2.073h1.337v2.073H206.377z M211.915,242.044
c-0.826,0-1.55-0.189-2.144-0.557c-0.607-0.389-1.075-0.896-1.41-1.556c-0.324-0.675-0.486-1.457-0.486-2.344
c0-0.863,0.162-1.663,0.486-2.349c0.335-0.675,0.781-1.199,1.364-1.566c0.594-0.41,1.267-0.589,2.071-0.589
c0.442,0,0.885,0.07,1.336,0.232c0.418,0.141,0.845,0.4,1.199,0.724c0.346,0.33,0.653,0.772,0.861,1.34
c0.208,0.545,0.308,1.22,0.308,2.041v0.562h-6.284c0.046,0.918,0.303,1.62,0.789,2.111c0.494,0.497,1.134,0.751,1.909,0.751
c0.535,0,0.978-0.113,1.361-0.324c0.37-0.237,0.651-0.562,0.815-1.036l1.293,0.372c-0.216,0.664-0.61,1.172-1.218,1.583
C213.551,241.833,212.803,242.044,211.915,242.044L211.915,242.044z M209.217,236.838h4.95c0-0.734-0.219-1.334-0.665-1.831
c-0.416-0.47-0.982-0.729-1.706-0.729c-0.524,0-0.967,0.113-1.315,0.351c-0.375,0.238-0.688,0.567-0.894,0.939
C209.377,235.969,209.263,236.395,209.217,236.838L209.217,236.838z M217.54,241.854v-8.651h1.291v1.307h0.076
c0.154-0.416,0.435-0.767,0.861-1.053c0.427-0.254,0.87-0.395,1.41-0.395c0.089,0,0.208,0,0.351,0
c0.143,0.021,0.262,0.021,0.334,0.021v1.367c-0.021-0.033-0.143-0.033-0.311-0.06c-0.146-0.021-0.327-0.044-0.494-0.044
c-0.632,0-1.145,0.189-1.569,0.589c-0.429,0.378-0.604,0.87-0.604,1.458v5.46H217.54z M230.797,233.203l-3.189,8.651h-1.363
l-3.219-8.651h1.455l2.393,6.891h0.097l2.395-6.891H230.797z M235.857,242.044c-0.807,0-1.539-0.189-2.155-0.557
c-0.583-0.389-1.056-0.896-1.382-1.556c-0.33-0.675-0.491-1.457-0.491-2.344c0-0.863,0.162-1.663,0.491-2.349
c0.327-0.675,0.772-1.199,1.361-1.566c0.589-0.41,1.269-0.589,2.068-0.589c0.443,0,0.886,0.07,1.334,0.232
c0.416,0.141,0.848,0.4,1.193,0.724c0.354,0.33,0.665,0.772,0.87,1.34c0.21,0.545,0.305,1.22,0.305,2.041v0.562h-6.286
c0.046,0.918,0.302,1.62,0.796,2.111c0.492,0.497,1.129,0.751,1.896,0.751c0.545,0,0.988-0.113,1.364-0.324
c0.375-0.237,0.659-0.562,0.826-1.036l1.285,0.372c-0.216,0.664-0.607,1.172-1.215,1.583
C237.5,241.833,236.751,242.044,235.857,242.044L235.857,242.044z M233.166,236.838h4.952c0-0.734-0.21-1.334-0.664-1.831
c-0.419-0.47-1.007-0.729-1.704-0.729c-0.521,0-0.967,0.113-1.315,0.351c-0.375,0.238-0.686,0.567-0.891,0.939
C233.333,235.969,233.211,236.395,233.166,236.838L233.166,236.838z M242.83,236.648v5.206h-1.337v-8.651h1.293v1.361h0.089
c0.213-0.454,0.516-0.805,0.939-1.086c0.397-0.265,0.945-0.395,1.596-0.395c0.87,0,1.596,0.275,2.136,0.816
c0.535,0.518,0.793,1.365,0.793,2.462v5.492h-1.333v-5.4c0-0.702-0.162-1.215-0.516-1.587c-0.354-0.4-0.839-0.589-1.453-0.589
c-0.634,0-1.177,0.21-1.593,0.637C243.013,235.314,242.83,235.903,242.83,236.648L242.83,236.648z M254.303,242.044
c-0.821,0-1.526-0.189-2.117-0.578c-0.556-0.384-1.023-0.896-1.334-1.577c-0.327-0.68-0.467-1.452-0.467-2.301
c0-0.891,0.14-1.663,0.467-2.349c0.333-0.675,0.802-1.199,1.383-1.566c0.588-0.41,1.269-0.589,2.049-0.589
c0.607,0,1.14,0.119,1.636,0.352c0.492,0.205,0.889,0.535,1.199,0.935c0.324,0.399,0.519,0.896,0.581,1.437h-1.333
c-0.089-0.405-0.327-0.751-0.659-1.064c-0.346-0.291-0.815-0.464-1.404-0.464c-0.778,0-1.412,0.308-1.874,0.891
c-0.494,0.583-0.729,1.388-0.729,2.371c0,0.982,0.235,1.798,0.708,2.392c0.464,0.616,1.096,0.913,1.896,0.913
c0.513,0,0.964-0.135,1.336-0.394c0.378-0.287,0.613-0.638,0.727-1.129h1.333c-0.062,0.518-0.256,0.988-0.556,1.388
c-0.283,0.421-0.688,0.756-1.15,0.978C255.499,241.925,254.935,242.044,254.303,242.044L254.303,242.044z M259.652,241.854v-8.651
h1.312v8.651H259.652z M260.33,231.767c-0.281,0-0.494-0.092-0.678-0.28c-0.184-0.162-0.284-0.379-0.284-0.633
c0-0.253,0.1-0.469,0.284-0.637c0.184-0.184,0.397-0.248,0.678-0.248c0.256,0,0.472,0.064,0.664,0.248
c0.184,0.168,0.275,0.384,0.275,0.637c0,0.254-0.092,0.471-0.275,0.633C260.802,231.675,260.586,231.767,260.33,231.767
L260.33,231.767z M266.923,242.044c-0.775,0-1.453-0.189-2.039-0.557c-0.591-0.389-1.059-0.896-1.385-1.556
c-0.332-0.675-0.492-1.457-0.492-2.344c0-0.912,0.16-1.685,0.492-2.37c0.327-0.681,0.794-1.199,1.385-1.577
c0.586-0.378,1.264-0.557,2.039-0.557c0.772,0,1.477,0.179,2.065,0.557c0.589,0.378,1.029,0.896,1.364,1.577
c0.324,0.686,0.491,1.458,0.491,2.37c0,0.887-0.167,1.669-0.491,2.344c-0.335,0.659-0.775,1.167-1.364,1.556
C268.4,241.854,267.695,242.044,266.923,242.044L266.923,242.044z M266.923,240.845c0.588,0,1.077-0.156,1.477-0.438
c0.375-0.313,0.651-0.729,0.848-1.226c0.187-0.491,0.284-1.026,0.284-1.594c0-0.588-0.097-1.134-0.284-1.619
c-0.197-0.519-0.473-0.913-0.848-1.227c-0.4-0.291-0.889-0.464-1.477-0.464c-0.586,0-1.075,0.173-1.453,0.464
c-0.408,0.313-0.683,0.708-0.875,1.227c-0.187,0.485-0.256,1.031-0.256,1.619c0,0.567,0.07,1.103,0.256,1.594
c0.192,0.497,0.467,0.912,0.875,1.226C265.849,240.688,266.337,240.845,266.923,240.845L266.923,240.845z M266.313,232.031
l1.382-2.635h1.553l-1.763,2.635H266.313z M274.222,236.648v5.206h-1.342v-8.651h1.288v1.361h0.122
c0.189-0.454,0.491-0.805,0.918-1.086c0.424-0.265,0.937-0.395,1.596-0.395c0.889,0,1.593,0.275,2.128,0.816
c0.542,0.518,0.805,1.365,0.805,2.462v5.492h-1.318v-5.4c0-0.702-0.192-1.215-0.54-1.587c-0.356-0.4-0.848-0.589-1.453-0.589
c-0.629,0-1.172,0.21-1.569,0.637C274.427,235.314,274.222,235.903,274.222,236.648L274.222,236.648z M287.45,245.214
c-0.208,0-0.416,0-0.605-0.049c-0.17-0.021-0.283-0.07-0.359-0.092l0.329-1.177c0.492,0.118,0.894,0.118,1.223-0.027
c0.327-0.113,0.608-0.508,0.84-1.145l0.284-0.821l-3.191-8.7h1.431l2.398,6.891h0.089l2.4-6.891h1.423l-3.702,10.066
C289.51,244.576,288.671,245.214,287.45,245.214L287.45,245.214z M303.8,233.203v1.123h-1.917v7.528h-1.342v-7.528h-1.401v-1.123
h1.401v-1.199c0-0.491,0.122-0.912,0.351-1.242c0.238-0.329,0.516-0.566,0.894-0.729c0.375-0.189,0.775-0.265,1.196-0.265
c0.33,0,0.586,0.032,0.797,0.075c0.216,0.076,0.356,0.125,0.467,0.162l-0.392,1.156c-0.076-0.032-0.173-0.07-0.287-0.098
c-0.119-0.021-0.256-0.049-0.472-0.049c-0.416,0-0.748,0.092-0.935,0.33c-0.189,0.216-0.278,0.54-0.278,0.988v0.869H303.8z
M308.854,242.044c-0.802,0-1.488-0.189-2.071-0.557c-0.589-0.389-1.053-0.896-1.388-1.556c-0.324-0.675-0.486-1.457-0.486-2.344
c0-0.912,0.162-1.685,0.486-2.37c0.335-0.681,0.799-1.199,1.388-1.577c0.583-0.378,1.269-0.557,2.071-0.557
c0.767,0,1.445,0.179,2.031,0.557s1.056,0.896,1.385,1.577c0.334,0.686,0.497,1.458,0.497,2.37c0,0.887-0.162,1.669-0.497,2.344
c-0.33,0.659-0.799,1.167-1.385,1.556C310.299,241.854,309.622,242.044,308.854,242.044L308.854,242.044z M308.854,240.845
c0.575,0,1.072-0.156,1.445-0.438c0.378-0.313,0.653-0.729,0.842-1.226c0.194-0.491,0.286-1.026,0.286-1.594
c0-0.588-0.092-1.134-0.286-1.619c-0.189-0.519-0.464-0.913-0.842-1.227c-0.373-0.291-0.87-0.464-1.445-0.464
c-0.624,0-1.11,0.173-1.488,0.464c-0.37,0.313-0.659,0.708-0.84,1.227c-0.194,0.485-0.283,1.031-0.283,1.619
c0,0.567,0.089,1.103,0.283,1.594c0.181,0.497,0.47,0.912,0.84,1.226C307.745,240.688,308.231,240.845,308.854,240.845
L308.854,240.845z M314.782,241.854v-8.651h1.285v1.307h0.1c0.165-0.416,0.443-0.767,0.867-1.053
c0.396-0.254,0.864-0.395,1.385-0.395c0.095,0,0.211,0,0.375,0c0.135,0.021,0.262,0.021,0.33,0.021v1.367
c-0.049-0.033-0.143-0.033-0.305-0.06c-0.167-0.021-0.33-0.044-0.516-0.044c-0.632,0-1.15,0.189-1.55,0.589
c-0.421,0.378-0.634,0.87-0.634,1.458v5.46H314.782z M320.689,241.854v-8.651h1.299v1.361h0.113c0.195-0.471,0.473-0.821,0.87-1.086
s0.891-0.395,1.445-0.395c0.569,0,1.063,0.13,1.439,0.395s0.678,0.615,0.891,1.086h0.1c0.208-0.454,0.532-0.821,0.977-1.086
c0.448-0.265,0.988-0.395,1.604-0.395c0.767,0,1.404,0.249,1.896,0.734c0.494,0.481,0.746,1.237,0.746,2.242v5.794h-1.334v-5.794
c0-0.633-0.165-1.102-0.519-1.361c-0.351-0.281-0.767-0.421-1.239-0.421c-0.61,0-1.083,0.188-1.41,0.562
c-0.33,0.356-0.513,0.826-0.513,1.383v5.632h-1.336v-5.93c0-0.497-0.165-0.896-0.491-1.183c-0.308-0.291-0.735-0.464-1.223-0.464
c-0.356,0-0.681,0.092-0.988,0.286c-0.278,0.178-0.538,0.442-0.702,0.75c-0.189,0.33-0.286,0.702-0.286,1.14v5.4H320.689z
M337.044,242.065c-0.537,0-1.031-0.119-1.474-0.335c-0.454-0.173-0.821-0.48-1.083-0.886c-0.259-0.394-0.396-0.886-0.396-1.452
c0-0.492,0.121-0.887,0.308-1.193c0.184-0.309,0.443-0.567,0.772-0.729c0.332-0.189,0.699-0.303,1.104-0.399
c0.37-0.092,0.77-0.168,1.194-0.211c0.513-0.064,0.942-0.119,1.271-0.162c0.321-0.021,0.583-0.098,0.721-0.194
c0.165-0.07,0.235-0.227,0.235-0.442v-0.044c0-0.566-0.165-0.988-0.47-1.29c-0.284-0.309-0.751-0.476-1.364-0.476
c-0.629,0-1.129,0.141-1.499,0.427c-0.351,0.281-0.602,0.588-0.748,0.891l-1.272-0.442c0.238-0.54,0.516-0.945,0.918-1.247
c0.378-0.281,0.772-0.486,1.223-0.616c0.464-0.108,0.886-0.179,1.331-0.179c0.286,0,0.594,0.038,0.967,0.092
c0.351,0.065,0.702,0.217,1.05,0.422c0.332,0.194,0.616,0.496,0.851,0.912c0.232,0.405,0.329,0.962,0.329,1.643v5.702h-1.317v-1.166
h-0.07c-0.094,0.178-0.229,0.394-0.448,0.604c-0.21,0.216-0.489,0.395-0.842,0.54C337.981,241.995,337.561,242.065,337.044,242.065
L337.044,242.065z M337.255,240.866c0.518,0,0.961-0.092,1.339-0.297c0.348-0.216,0.632-0.476,0.823-0.799
c0.187-0.335,0.278-0.687,0.278-1.037v-1.215c-0.07,0.069-0.189,0.113-0.373,0.161c-0.189,0.065-0.405,0.119-0.659,0.168
c-0.232,0.016-0.472,0.064-0.705,0.086c-0.235,0.027-0.421,0.049-0.562,0.076c-0.354,0.043-0.686,0.113-0.958,0.211
c-0.313,0.097-0.548,0.254-0.732,0.447c-0.184,0.217-0.281,0.471-0.281,0.795c0,0.469,0.162,0.82,0.51,1.058
C336.294,240.753,336.712,240.866,337.255,240.866L337.255,240.866z M346.971,242.044c-0.799,0-1.507-0.189-2.084-0.578
c-0.6-0.384-1.04-0.896-1.367-1.577c-0.302-0.68-0.467-1.452-0.467-2.301c0-0.891,0.165-1.663,0.491-2.349
c0.332-0.675,0.775-1.199,1.361-1.566c0.589-0.41,1.267-0.589,2.039-0.589c0.613,0,1.172,0.119,1.666,0.352
c0.473,0.205,0.873,0.535,1.194,0.935c0.308,0.399,0.5,0.896,0.591,1.437h-1.337c-0.097-0.405-0.324-0.751-0.678-1.064
c-0.348-0.291-0.823-0.464-1.409-0.464c-0.772,0-1.413,0.308-1.879,0.891c-0.475,0.583-0.705,1.388-0.705,2.371
c0,0.982,0.23,1.798,0.705,2.392c0.467,0.616,1.107,0.913,1.879,0.913c0.516,0,0.958-0.135,1.333-0.394
c0.378-0.287,0.635-0.638,0.753-1.129h1.337c-0.092,0.518-0.284,0.988-0.564,1.388c-0.302,0.421-0.678,0.756-1.169,0.978
C348.161,241.925,347.626,242.044,346.971,242.044L346.971,242.044z M352.317,241.854v-8.651h1.336v8.651H352.317z M352.995,231.767
c-0.254,0-0.486-0.092-0.678-0.28c-0.165-0.162-0.262-0.379-0.262-0.633c0-0.253,0.097-0.469,0.262-0.637
c0.192-0.184,0.424-0.248,0.678-0.248c0.259,0,0.5,0.064,0.659,0.248c0.195,0.168,0.287,0.384,0.287,0.637
c0,0.254-0.092,0.471-0.287,0.633C353.494,231.675,353.254,231.767,352.995,231.767L352.995,231.767z M359.613,242.044
c-0.799,0-1.482-0.189-2.06-0.557c-0.589-0.389-1.059-0.896-1.388-1.556c-0.329-0.675-0.491-1.457-0.491-2.344
c0-0.912,0.162-1.685,0.491-2.37c0.33-0.681,0.799-1.199,1.388-1.577c0.578-0.378,1.261-0.557,2.06-0.557
c0.778,0,1.453,0.179,2.042,0.557c0.591,0.378,1.056,0.896,1.38,1.577c0.334,0.686,0.497,1.458,0.497,2.37
c0,0.887-0.162,1.669-0.497,2.344c-0.324,0.659-0.789,1.167-1.38,1.556C361.065,241.854,360.391,242.044,359.613,242.044
L359.613,242.044z M359.613,240.845c0.591,0,1.08-0.156,1.453-0.438c0.405-0.313,0.681-0.729,0.845-1.226
c0.192-0.491,0.284-1.026,0.284-1.594c0-0.588-0.092-1.134-0.284-1.619c-0.165-0.519-0.44-0.913-0.845-1.227
c-0.373-0.291-0.861-0.464-1.453-0.464c-0.607,0-1.077,0.173-1.482,0.464c-0.37,0.313-0.651,0.708-0.837,1.227
c-0.189,0.485-0.281,1.031-0.281,1.619c0,0.567,0.092,1.103,0.281,1.594c0.186,0.497,0.467,0.912,0.837,1.226
C358.536,240.688,359.005,240.845,359.613,240.845L359.613,240.845z M359.005,232.031l1.385-2.635h1.544l-1.758,2.635H359.005z
M366.887,236.648v5.206h-1.342v-8.651h1.293v1.361h0.119c0.213-0.454,0.513-0.805,0.937-1.086c0.399-0.265,0.937-0.395,1.596-0.395
c0.869,0,1.571,0.275,2.114,0.816c0.535,0.518,0.818,1.365,0.818,2.462v5.492h-1.339v-5.4c0-0.702-0.157-1.215-0.535-1.587
c-0.351-0.4-0.827-0.589-1.456-0.589c-0.637,0-1.147,0.21-1.577,0.637C367.101,235.314,366.887,235.903,366.887,236.648
L366.887,236.648z M379.322,245.116v-11.913h1.291v1.383h0.162c0.094-0.168,0.208-0.356,0.402-0.589
c0.156-0.237,0.418-0.442,0.745-0.638c0.33-0.184,0.775-0.275,1.339-0.275c0.731,0,1.385,0.179,1.922,0.557
c0.567,0.356,1.007,0.869,1.313,1.556c0.302,0.659,0.472,1.452,0.472,2.37c0,0.908-0.17,1.713-0.472,2.365
c-0.305,0.687-0.746,1.199-1.288,1.556c-0.562,0.367-1.199,0.557-1.917,0.557c-0.57,0-0.991-0.098-1.348-0.281
c-0.324-0.188-0.583-0.399-0.767-0.632c-0.165-0.232-0.308-0.442-0.402-0.61h-0.116v4.596H379.322z M380.628,237.54
c0,0.966,0.219,1.761,0.643,2.392c0.416,0.616,1.029,0.913,1.85,0.913c0.535,0,1.016-0.135,1.391-0.438
c0.37-0.286,0.651-0.686,0.837-1.198c0.189-0.497,0.287-1.054,0.287-1.669c0-0.616-0.097-1.178-0.287-1.669
c-0.186-0.491-0.467-0.864-0.815-1.145c-0.396-0.309-0.851-0.448-1.412-0.448c-0.821,0-1.434,0.308-1.85,0.891
C380.847,235.785,380.628,236.557,380.628,237.54L380.628,237.54z M391.542,242.065c-0.542,0-1.061-0.119-1.504-0.335
c-0.445-0.173-0.799-0.48-1.056-0.886c-0.259-0.394-0.397-0.886-0.397-1.452c0-0.492,0.097-0.887,0.305-1.193
c0.186-0.309,0.445-0.567,0.77-0.729c0.33-0.189,0.678-0.303,1.088-0.399c0.4-0.092,0.794-0.168,1.191-0.211
c0.54-0.064,0.961-0.119,1.288-0.162c0.33-0.021,0.57-0.098,0.732-0.194c0.143-0.07,0.208-0.227,0.208-0.442v-0.044
c0-0.566-0.135-0.988-0.442-1.29c-0.308-0.309-0.751-0.476-1.361-0.476c-0.629,0-1.155,0.141-1.504,0.427
c-0.351,0.281-0.61,0.588-0.748,0.891l-1.269-0.442c0.213-0.54,0.516-0.945,0.891-1.247c0.378-0.281,0.802-0.486,1.25-0.616
c0.437-0.108,0.888-0.179,1.328-0.179c0.289,0,0.589,0.038,0.964,0.092c0.356,0.065,0.712,0.217,1.061,0.422
c0.324,0.194,0.602,0.496,0.84,0.912c0.216,0.405,0.332,0.962,0.332,1.643v5.702h-1.342v-1.166h-0.04
c-0.095,0.178-0.265,0.394-0.473,0.604c-0.208,0.216-0.489,0.395-0.824,0.54C392.479,241.995,392.059,242.065,391.542,242.065
L391.542,242.065z M391.756,240.866c0.513,0,0.956-0.092,1.334-0.297c0.356-0.216,0.635-0.476,0.824-0.799
c0.189-0.335,0.253-0.687,0.253-1.037v-1.215c-0.04,0.069-0.154,0.113-0.345,0.161c-0.189,0.065-0.427,0.119-0.656,0.168
c-0.265,0.016-0.494,0.064-0.732,0.086c-0.216,0.027-0.397,0.049-0.562,0.076c-0.33,0.043-0.664,0.113-0.958,0.211
c-0.286,0.097-0.551,0.254-0.732,0.447c-0.162,0.217-0.254,0.471-0.254,0.795c0,0.469,0.162,0.82,0.511,1.058
C390.792,240.753,391.208,240.866,391.756,240.866L391.756,240.866z M397.945,241.854v-8.651h1.296v1.307h0.086
c0.148-0.416,0.424-0.767,0.848-1.053c0.424-0.254,0.891-0.395,1.404-0.395c0.243,0,0.448,0.038,0.637,0.092
c0.17,0.049,0.33,0.108,0.47,0.238l-0.448,1.117c-0.089-0.043-0.211-0.092-0.33-0.118c-0.138-0.021-0.278-0.044-0.438-0.044
c-0.64,0-1.158,0.189-1.577,0.589c-0.395,0.378-0.608,0.87-0.608,1.458v5.46H397.945z M406.58,242.065
c-0.538,0-1.029-0.119-1.475-0.335c-0.451-0.173-0.826-0.48-1.08-0.886c-0.262-0.394-0.402-0.886-0.402-1.452
c0-0.492,0.119-0.887,0.305-1.193c0.192-0.309,0.448-0.567,0.772-0.729c0.33-0.189,0.708-0.303,1.102-0.399
c0.378-0.092,0.802-0.168,1.202-0.211c0.51-0.064,0.937-0.119,1.267-0.162c0.329-0.021,0.583-0.098,0.726-0.194
c0.165-0.07,0.235-0.227,0.235-0.442v-0.044c0-0.566-0.162-0.988-0.47-1.29c-0.281-0.309-0.753-0.476-1.361-0.476
c-0.637,0-1.124,0.141-1.501,0.427c-0.348,0.281-0.61,0.588-0.753,0.891l-1.266-0.442c0.24-0.54,0.521-0.945,0.916-1.247
c0.373-0.281,0.777-0.486,1.223-0.616c0.47-0.108,0.888-0.179,1.339-0.179c0.278,0,0.613,0.038,0.967,0.092
c0.349,0.065,0.694,0.217,1.048,0.422c0.327,0.194,0.61,0.496,0.851,0.912c0.229,0.405,0.321,0.962,0.321,1.643v5.702h-1.313v-1.166
h-0.07c-0.092,0.178-0.232,0.394-0.446,0.604c-0.213,0.216-0.494,0.395-0.845,0.54C407.514,241.995,407.099,242.065,406.58,242.065
L406.58,242.065z M406.791,240.866c0.519,0,0.964-0.092,1.337-0.297c0.354-0.216,0.634-0.476,0.826-0.799
c0.186-0.335,0.278-0.687,0.278-1.037v-1.215c-0.07,0.069-0.189,0.113-0.378,0.161c-0.181,0.065-0.397,0.119-0.651,0.168
c-0.232,0.016-0.475,0.064-0.705,0.086c-0.235,0.027-0.424,0.049-0.564,0.076c-0.354,0.043-0.678,0.113-0.964,0.211
c-0.302,0.097-0.535,0.254-0.726,0.447c-0.192,0.217-0.281,0.471-0.281,0.795c0,0.469,0.165,0.82,0.513,1.058
C405.827,240.753,406.256,240.866,406.791,240.866L406.791,240.866z M418.809,230.309v11.546h-1.345v-11.546H418.809z
M423.777,242.065c-0.54,0-1.061-0.119-1.506-0.335c-0.438-0.173-0.792-0.48-1.056-0.886c-0.253-0.394-0.394-0.886-0.394-1.452
c0-0.492,0.097-0.887,0.308-1.193c0.184-0.309,0.44-0.567,0.77-0.729c0.329-0.189,0.683-0.303,1.077-0.399
c0.399-0.092,0.802-0.168,1.196-0.211c0.545-0.064,0.961-0.119,1.296-0.162c0.324-0.021,0.559-0.098,0.727-0.194
c0.146-0.07,0.213-0.227,0.213-0.442v-0.044c0-0.566-0.146-0.988-0.451-1.29c-0.294-0.309-0.748-0.476-1.358-0.476
c-0.635,0-1.145,0.141-1.499,0.427c-0.383,0.281-0.613,0.588-0.777,0.891l-1.24-0.442c0.208-0.54,0.513-0.945,0.886-1.247
c0.378-0.281,0.802-0.486,1.242-0.616c0.451-0.108,0.896-0.179,1.342-0.179c0.281,0,0.58,0.038,0.958,0.092
c0.348,0.065,0.705,0.217,1.058,0.422c0.33,0.194,0.613,0.496,0.845,0.912c0.206,0.405,0.321,0.962,0.321,1.643v5.702h-1.328v-1.166
h-0.049c-0.097,0.178-0.262,0.394-0.47,0.604c-0.208,0.216-0.497,0.395-0.821,0.54C424.717,241.995,424.271,242.065,423.777,242.065
L423.777,242.065z M423.988,240.866c0.516,0,0.961-0.092,1.339-0.297c0.354-0.216,0.629-0.476,0.821-0.799
c0.165-0.335,0.259-0.687,0.259-1.037v-1.215c-0.049,0.069-0.165,0.113-0.356,0.161c-0.192,0.065-0.413,0.119-0.659,0.168
c-0.259,0.016-0.486,0.064-0.721,0.086c-0.24,0.027-0.429,0.049-0.564,0.076c-0.33,0.043-0.653,0.113-0.961,0.211
c-0.313,0.097-0.537,0.254-0.724,0.447c-0.165,0.217-0.267,0.471-0.267,0.795c0,0.469,0.167,0.82,0.521,1.058
C423.002,240.753,423.454,240.866,423.988,240.866L423.988,240.866z M434.641,241.854v-8.651h1.336v8.651H434.641z M435.321,231.767
c-0.259,0-0.47-0.092-0.656-0.28c-0.194-0.162-0.286-0.379-0.286-0.633c0-0.253,0.092-0.469,0.286-0.637
c0.187-0.184,0.397-0.248,0.656-0.248c0.256,0,0.492,0.064,0.678,0.248c0.192,0.168,0.284,0.384,0.284,0.637
c0,0.254-0.092,0.471-0.284,0.633C435.813,231.675,435.577,231.767,435.321,231.767L435.321,231.767z M439.754,236.648v5.206h-1.342
v-8.651h1.291v1.361h0.122c0.187-0.454,0.492-0.805,0.916-1.086c0.421-0.265,0.937-0.395,1.593-0.395
c0.896,0,1.596,0.275,2.136,0.816c0.535,0.518,0.799,1.365,0.799,2.462v5.492h-1.313v-5.4c0-0.702-0.192-1.215-0.54-1.587
c-0.356-0.4-0.851-0.589-1.461-0.589c-0.634,0-1.164,0.21-1.571,0.637C439.965,235.314,439.754,235.903,439.754,236.648
L439.754,236.648z M451.228,242.044c-0.826,0-1.506-0.189-2.087-0.578c-0.589-0.384-1.062-0.896-1.364-1.577
c-0.305-0.68-0.47-1.452-0.47-2.301c0-0.891,0.165-1.663,0.491-2.349c0.305-0.675,0.786-1.199,1.364-1.566
c0.586-0.41,1.264-0.589,2.039-0.589c0.613,0,1.15,0.119,1.642,0.352c0.492,0.205,0.891,0.535,1.199,0.935
c0.321,0.399,0.516,0.896,0.588,1.437h-1.32c-0.116-0.405-0.327-0.751-0.678-1.064c-0.348-0.291-0.818-0.464-1.404-0.464
c-0.772,0-1.412,0.308-1.874,0.891c-0.476,0.583-0.71,1.388-0.71,2.371c0,0.982,0.213,1.798,0.71,2.392
c0.461,0.616,1.072,0.913,1.874,0.913c0.516,0,0.958-0.135,1.329-0.394c0.378-0.287,0.616-0.638,0.753-1.129h1.32
c-0.073,0.518-0.267,0.988-0.54,1.388c-0.311,0.421-0.705,0.756-1.177,0.978C452.418,241.925,451.857,242.044,451.228,242.044
L451.228,242.044z M457.911,230.309v11.546h-1.336v-11.546H457.911z M465.792,238.317v-5.114h1.339v8.651h-1.339v-1.447h-0.089
c-0.192,0.411-0.521,0.794-0.945,1.102c-0.418,0.324-0.985,0.459-1.617,0.459c-0.815,0-1.499-0.253-2.02-0.794
c-0.513-0.539-0.794-1.36-0.794-2.462v-5.509h1.342v5.417c0,0.637,0.184,1.128,0.535,1.501c0.356,0.373,0.794,0.567,1.361,0.567
c0.327,0,0.656-0.07,1.013-0.26c0.345-0.167,0.632-0.427,0.869-0.777C465.682,239.301,465.792,238.857,465.792,238.317
L465.792,238.317z"/>
<path fill="#2A2A2B" d="M475.694,235.147l-1.202,0.324c-0.113-0.303-0.3-0.589-0.581-0.843c-0.289-0.259-0.699-0.399-1.291-0.399
c-0.519,0-0.961,0.118-1.313,0.378c-0.354,0.232-0.543,0.54-0.543,0.907c0,0.341,0.138,0.589,0.378,0.777
c0.24,0.211,0.604,0.356,1.128,0.503l1.285,0.297c1.526,0.378,2.298,1.177,2.298,2.344c0,0.523-0.14,0.945-0.418,1.339
c-0.281,0.399-0.686,0.713-1.202,0.913c-0.516,0.237-1.104,0.356-1.76,0.356c-0.891,0-1.615-0.189-2.204-0.578
c-0.586-0.384-0.934-0.945-1.099-1.674l1.266-0.329c0.235,0.944,0.916,1.403,2.015,1.403c0.615,0,1.104-0.135,1.479-0.394
c0.354-0.26,0.538-0.584,0.538-0.967c0-0.605-0.421-1-1.286-1.21l-1.437-0.335c-0.793-0.184-1.38-0.491-1.733-0.891
c-0.378-0.373-0.559-0.896-0.559-1.48c0-0.491,0.138-0.912,0.395-1.29c0.283-0.373,0.656-0.675,1.15-0.892
c0.472-0.205,1.012-0.324,1.62-0.324c0.861,0,1.55,0.179,2.014,0.557C475.132,234.019,475.483,234.51,475.694,235.147
L475.694,235.147z M477.854,241.854v-8.651h1.336v8.651H477.854z M478.535,231.767c-0.262,0-0.47-0.092-0.659-0.28
c-0.192-0.162-0.284-0.379-0.284-0.633c0-0.253,0.092-0.469,0.284-0.637c0.189-0.184,0.397-0.248,0.659-0.248
c0.254,0,0.492,0.064,0.681,0.248c0.186,0.168,0.286,0.384,0.286,0.637c0,0.254-0.1,0.471-0.286,0.633
C479.026,231.675,478.789,231.767,478.535,231.767L478.535,231.767z M485.147,242.044c-0.796,0-1.474-0.189-2.068-0.557
c-0.581-0.389-1.026-0.896-1.35-1.556c-0.335-0.675-0.505-1.457-0.505-2.344c0-0.912,0.17-1.685,0.505-2.37
c0.324-0.681,0.77-1.199,1.35-1.577c0.594-0.378,1.272-0.557,2.068-0.557c0.778,0,1.456,0.179,2.044,0.557
c0.608,0.378,1.056,0.896,1.38,1.577c0.327,0.686,0.494,1.458,0.494,2.37c0,0.887-0.167,1.669-0.494,2.344
c-0.324,0.659-0.772,1.167-1.38,1.556C486.603,241.854,485.925,242.044,485.147,242.044L485.147,242.044z M485.147,240.845
c0.589,0,1.083-0.156,1.456-0.438c0.399-0.313,0.678-0.729,0.867-1.226c0.165-0.491,0.262-1.026,0.262-1.594
c0-0.588-0.097-1.134-0.262-1.619c-0.189-0.519-0.467-0.913-0.867-1.227c-0.373-0.291-0.867-0.464-1.456-0.464
c-0.61,0-1.077,0.173-1.474,0.464c-0.381,0.313-0.662,0.708-0.848,1.227c-0.189,0.485-0.278,1.031-0.278,1.619
c0,0.567,0.089,1.103,0.278,1.594c0.187,0.497,0.467,0.912,0.848,1.226C484.07,240.688,484.537,240.845,485.147,240.845
L485.147,240.845z M484.537,232.031l1.388-2.635h1.544l-1.755,2.635H484.537z M492.425,236.648v5.206h-1.315v-8.651h1.288v1.361
h0.095c0.213-0.454,0.516-0.805,0.937-1.086c0.402-0.265,0.939-0.395,1.596-0.395c0.867,0,1.59,0.275,2.117,0.816
c0.535,0.518,0.818,1.365,0.818,2.462v5.492h-1.345v-5.4c0-0.702-0.162-1.215-0.508-1.587c-0.356-0.4-0.848-0.589-1.455-0.589
c-0.637,0-1.172,0.21-1.599,0.637C492.63,235.314,492.425,235.903,492.425,236.648L492.425,236.648z"/>
<path fill="#163F75" d="M250.517,155.119c3.775,0,3.982-3.133,3.982-6.216v-30.609c0-3.148-0.208-6.318-3.982-6.318
c-3.402,0-4.35,2.98-4.35,5.983v7.484c0,3.641-0.205,7.162-0.626,10.58c-0.429,3.424-1.059,6.27-1.971,8.543
c-1.499,3.872-3.402,5.768-5.751,5.768c-2.552,0-3.818-3.71-3.818-11.092c0-7.037,0.259-13.35,0.753-18.961
c0.235-2.273,0.354-4.077,0.354-5.417c0-1.971-1.085-2.959-3.243-2.959c-1.201,0-2,0.454-2.459,1.313
c-1.296,2.44-1.95,10.893-1.95,25.322c0,11.26,3.005,16.579,9.194,16.579c3.259,0,5.983-1.663,8.098-4.995
c0.721-1.103,1.142-1.686,1.261-1.686c0.094,0,0.159,0.238,0.159,0.745C246.167,152.192,247.115,155.119,250.517,155.119
L250.517,155.119z M287.159,155.119c1.169,0,1.971-0.427,2.443-1.285c1.24-2.484,1.896-10.903,1.896-25.307
c0-3.435-0.259-6.275-0.772-8.619c-1.177-5.352-3.964-8.003-8.395-8.003c-3.664,0-6.572,1.928-8.708,5.772
c-0.281,0.551-0.521,0.778-0.659,0.778c-0.138,0-0.216-0.205-0.216-0.616c0-3.958-1.426-5.935-4.334-5.935
c-1.55,0-2.625,0.523-3.194,1.464c-0.532,0.912-0.796,2.506-0.796,4.779v30.598c0,1.054,0.07,2.063,0.21,3.02
c0.335,2.209,1.599,3.289,3.78,3.289c1.855,0,3.122-0.896,3.797-2.663c0.356-0.95,0.537-2.058,0.537-3.348v-7.928
c0-8.182,0.875-14.382,2.582-18.681c1.555-3.823,3.478-5.746,5.805-5.746c1.677,0,2.86,1.647,3.394,4.839
c0.333,1.923,0.476,4.315,0.476,7.178c-0.021,6.054-0.284,12.064-0.826,18.063c-0.232,2.274-0.354,4.078-0.354,5.4
c0,1.988,1.11,2.949,3.292,2.949H287.159z M316.507,128.123c0,2.808-0.21,5.719-0.634,8.748c-0.397,3.003-1.059,5.557-1.874,7.599
c-1.526,3.823-3.429,5.724-5.725,5.724c-2.935,0.141-3.85-6.475-3.85-13.512c0-4.784,1.439-19.679,8.284-19.679
c1.855,0,3.027,0.47,3.47,1.404c0.237,0.476,0.329,1.01,0.329,1.577V128.123z M324.837,105.268c0-3.094-0.146-6.264-3.964-6.264
c-3.362,0-4.366,2.916-4.366,5.983v7.177c0,0.54-0.064,0.848-0.235,0.848c-0.186,0-0.473-0.118-0.842-0.308
c-1.056-0.54-2.185-0.799-3.381-0.799c-4.525,0-8.065,2.608-10.606,7.793c-2.392,4.931-3.585,11.373-3.585,19.284
c0,8.517,3.121,16.212,9.221,16.072c3.284,0,5.979-1.696,8.139-5.05c0.656-1.031,1.01-1.566,1.123-1.566
c0.103,0,0.167,0.206,0.167,0.605c0,3.072,1.004,6.011,4.366,6.011c3.818,0,3.964-3.176,3.964-6.309V105.268z M354.839,155.055
c3.851,0.064,3.918-3.197,3.988-6.309v-30.565c-0.07-3.035-0.138-6.324-3.988-6.275c-1.307,0-2.317,0.405-2.935,1.198
c-0.205,0.266-0.467,0.405-0.796,0.405c-0.229,0-0.583-0.097-0.932-0.329c-1.434-0.82-2.841-1.274-4.229-1.274
c-4.528,0-8.047,2.608-10.601,7.793c-2.39,4.931-3.588,11.373-3.588,19.284c0,8.517,3.119,16.212,9.245,16.072
c3.653,0,6.589-2.021,8.768-6.033c0.257-0.469,0.448-0.701,0.567-0.701c0.094,0,0.156,0.254,0.156,0.724
C350.494,152.116,351.507,155.055,354.839,155.055L354.839,155.055z M342.175,150.193c-2.911,0.141-3.855-6.475-3.855-13.512
c0-4.784,1.437-19.679,8.284-19.679c2.605,0,3.891,0.935,3.891,2.813v9.947c0,1.831-0.2,4.197-0.626,7.107
c-0.445,2.938-1.083,5.486-1.971,7.599C346.396,148.293,344.495,150.193,342.175,150.193L342.175,150.193z M379.405,154.979
c2.762,0,5.02-0.75,6.802-2.252c1.785-1.507,3.024-3.461,3.64-5.881c0.114-0.324,0.138-0.572,0.138-0.751
c0-1.128-0.827-1.804-1.807-1.804c-0.821,0-1.434,0.416-1.809,1.329c-1.191,2.954-2.765,4.434-4.736,4.434
c-2.563,0-4.458-1.853-5.754-5.558c-0.843-2.419-1.264-5.146-1.264-8.273c0-7.544,1.013-12.961,3.027-16.266
c1.107-1.83,2.328-2.749,3.683-2.749c1.785,0,2.954,1.199,3.567,3.575c0.332,1.404,0.519,3.208,0.519,5.39
c0,0.988-0.068,1.923-0.262,2.911c-0.064,0.442-0.094,1.145-0.094,2.014c0,1.453,0.17,2.814,1.906,2.814c1.993,0,3-2.744,3-8.188
c0-9.191-3.151-13.793-9.378-13.793c-3.265,0-6.081,1.221-8.408,3.662c-4.01,4.223-6.027,11.098-6.027,20.629
c0,3.791,0.47,6.999,1.361,9.607c0.985,2.847,2.533,5.114,4.623,6.832C374.035,154.212,376.465,154.979,379.405,154.979
L379.405,154.979z M401.434,109.47c1.566,0,2.724-0.562,3.464-1.69c0.502-0.756,0.761-1.637,0.761-2.7
c0-1.14-0.378-2.225-1.158-3.181c-0.748-0.988-1.761-1.485-3-1.485c-2.465,0-4.174,2.111-4.174,5.136
C397.327,108.179,398.69,109.47,401.434,109.47L401.434,109.47z M401.263,155.055c2.917,0,4.396-2.021,4.396-6.011v-30.863
c0-4.649-1.083-6.275-3.969-6.275c-2.881,0-4.363,2.095-4.363,5.989v30.852c0,1.054,0.067,2.063,0.216,3.02
C397.861,153.975,399.084,155.055,401.263,155.055L401.263,155.055z M429.821,149.843c-2.89,0-5.047-1.712-6.475-5.093
c-1.245-2.997-1.855-7.053-1.855-12.215c0-10.531,3.024-15.846,9.051-15.846c2.778,0,4.763,1.739,6.032,5.195
c0.958,2.668,1.428,6.017,1.428,10.083c0,4.903-0.61,8.965-1.801,12.221C434.792,147.937,432.653,149.843,429.821,149.843
L429.821,149.843z M427.542,154.979c5.582,0,9.737-2.203,12.386-6.583c2.301-3.926,3.451-9.288,3.451-16.099
c0-5.368-0.821-9.813-2.527-13.252c-2.328-4.736-5.986-7.14-11.009-7.14c-5.773,0-10.088,2.214-12.926,6.643
c-2.511,3.845-3.775,9.104-3.775,15.764c0,5.659,1.004,10.255,3.019,13.819C418.728,152.705,422.527,154.979,427.542,154.979
L427.542,154.979z M425.924,108.67c1.288,0,3.213-0.799,5.773-2.349c2.549-1.545,3.869-3.116,3.869-4.661
c0-1.339-0.659-1.998-1.974-1.998c-1.239,0-3.051,1.129-5.395,3.402c-2.322,2.23-3.47,3.732-3.47,4.574
C424.728,108.319,425.122,108.67,425.924,108.67L425.924,108.67z M472.821,155.119c1.19,0,1.968-0.427,2.441-1.285
c1.239-2.484,1.898-10.903,1.898-25.307c0-3.435-0.259-6.275-0.756-8.619c-1.188-5.352-3.98-8.003-8.419-8.003
c-3.662,0-6.545,1.928-8.703,5.772c-0.278,0.551-0.491,0.778-0.629,0.778c-0.143,0-0.213-0.205-0.213-0.616
c0-3.958-1.458-5.935-4.364-5.935c-1.525,0-2.608,0.523-3.188,1.464c-0.545,0.912-0.799,2.506-0.799,4.779v30.598
c0,1.054,0.097,2.063,0.232,3.02c0.308,2.209,1.574,3.289,3.756,3.289c1.879,0,3.116-0.896,3.829-2.663
c0.343-0.95,0.535-2.058,0.535-3.348v-7.928c0-8.182,0.842-14.382,2.56-18.681c1.566-3.823,3.473-5.746,5.79-5.746
c1.717,0,2.886,1.647,3.429,4.839c0.327,1.923,0.464,4.315,0.464,7.178c-0.046,6.054-0.278,12.064-0.84,18.063
c-0.235,2.274-0.332,4.078-0.332,5.4c0,1.988,1.085,2.949,3.281,2.949H472.821z"/>
<g>
<path fill="#163F75" d="M206.898,156.113c3.626,0,4.701-3.09,4.701-6.249v-28.687c0-1.08,0.634-1.625,1.812-1.625l7.788,0.092
c1.807,0.092,2.806-0.908,2.806-2.085c0-1.086-0.362-1.814-1.094-2.263c-0.632-0.362-1.537-0.546-2.892-0.546
c-2.079,0-4.158,0.184-6.237,0.184c-1.456,0-2.182-0.453-2.182-2.711v-5.427c0-1.998,0.91-2.992,2.725-2.992
c0.996,0,2.352,0,3.523,0.098c1.094,0,8.689,0,9.502,0c2.714,0,3.988-1.27,3.988-2.452c0-1.62-1.091-2.533-3.076-2.803
c-0.913-0.184-1.636-0.184-2.362-0.184h-9.224h-8.238c-2.986,0-4.79,1.183-5.519,3.629c-0.27,1.172-0.448,2.532-0.448,4.158v43.252
c0,1.091,0.086,2.176,0.27,3.17C203.099,154.936,204.46,156.113,206.898,156.113L206.898,156.113z"/>
</g>
<g>
<defs>
<rect id="SVGID_23_" x="-476.587" y="-28.438" width="597.06" height="844.021"/>
</defs>
<clipPath id="SVGID_2_">
<use xlink:href="#SVGID_23_" overflow="visible"/>
</clipPath>
</g>
</svg>

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 798 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

View File

@@ -0,0 +1,109 @@
'use client'
import { useState } from 'react'
import type { BrandConfig } from '@/lib/types'
interface ConsentScreenProps {
brandConfig: BrandConfig | null
onAccept: (consentOperativo: boolean, consentMacroN1: boolean) => void
}
export function ConsentScreen({ brandConfig, onAccept }: ConsentScreenProps) {
const [operativo, setOperativo] = useState(false)
const [macroN1, setMacroN1] = useState(false)
const orgName = brandConfig?.org_name ?? 'tu empresa'
return (
<div className="consent-container" role="main">
<h1 className="consent-title">Antes de comenzar</h1>
<section className="consent-section" aria-labelledby="consent-intro-heading">
<h2 id="consent-intro-heading" className="consent-section-title">
¿Qué vamos a hacer con tus respuestas?
</h2>
<p>
Esta encuesta tiene dos propósitos que podés autorizar por separado:
</p>
<ol className="consent-list">
<li>
<strong>Diagnóstico interno de {orgName}:</strong> tus respuestas ayudan a la empresa
a entender la realidad de las personas que cuidan a familiares con discapacidad o adultos
mayores, para diseñar apoyos más adecuados. Solo se trabaja con{' '}
<strong>datos agregados</strong> nunca accede a respuestas individuales.
</li>
<li>
<strong>Estudio país (opcional):</strong> tus respuestas anonimizadas contribuyen a un
mapeo nacional sobre la economía del cuidado en Paraguay. Los datos se procesan de
forma irreversiblemente desvinculada de cualquier empresa o persona.
</li>
</ol>
</section>
{/* Párrafo OBLIGATORIO: anonimato y no-revocación (ADR-003) */}
<section className="consent-anon-box" role="note" aria-label="Sobre el anonimato">
<p>
<strong>Esta encuesta es completamente anónima.</strong> No guardamos ningún dato que
te identifique (nombre, número de documento, correo ni ningún otro identificador personal).
Por ser anónima, <strong>no es posible revocar ni eliminar tu respuesta una vez enviada</strong>,
ya que no habría forma de encontrarla entre las demás.
</p>
</section>
<section className="consent-checkboxes" aria-labelledby="consent-choices-heading">
<h2 id="consent-choices-heading" className="consent-section-title">
Tus decisiones
</h2>
{/* Checkbox 1: operativo — REQUERIDO */}
<label className="consent-checkbox-label" htmlFor="consent-operativo">
<input
type="checkbox"
id="consent-operativo"
checked={operativo}
onChange={(e) => setOperativo(e.target.checked)}
aria-required="true"
className="consent-checkbox-input"
/>
<span className="consent-checkbox-text">
<strong>Acepto</strong> que mis respuestas se usen para el diagnóstico interno de{' '}
{orgName} sobre cuidado y discapacidad.{' '}
<span className="consent-required-badge">Requerido para continuar</span>
</span>
</label>
{/* Checkbox 2: macro_n1 — OPCIONAL */}
<label className="consent-checkbox-label" htmlFor="consent-macro">
<input
type="checkbox"
id="consent-macro"
checked={macroN1}
onChange={(e) => setMacroN1(e.target.checked)}
className="consent-checkbox-input"
/>
<span className="consent-checkbox-text">
<strong>También acepto</strong> que mis respuestas anonimizadas contribuyan al estudio
país sobre economía del cuidado (sin identificarme en ningún caso).{' '}
<span className="consent-optional-badge">Opcional</span>
</span>
</label>
</section>
<div className="consent-footer">
<button
type="button"
disabled={!operativo}
onClick={() => onAccept(operativo, macroN1)}
className={`btn ${operativo ? 'btn-primary' : 'btn-primary btn-disabled'}`}
aria-disabled={!operativo}
>
Comenzar la encuesta
</button>
{!operativo && (
<p className="consent-required-hint" role="status" aria-live="polite">
Necesitás marcar el primer checkbox para continuar.
</p>
)}
</div>
</div>
)
}

View File

@@ -5,6 +5,7 @@ import { CheckboxGroup } from './widgets/checkbox-group'
import { RatingScale } from './widgets/rating-scale'
import { TextAreaField } from './widgets/text-area-field'
import { TextShortField } from './widgets/text-short-field'
import { GeoSelectWidget } from './widgets/geo-select-widget'
interface QuestionRendererProps {
question: Question
@@ -30,6 +31,22 @@ export function QuestionRenderer({
const { code, type, prompt, required, max_select, options } = question
const error = errors[code]
// A1 (Departamento) renders a combined geo widget that also handles A2 (Ciudad)
if (code === 'A1') {
return (
<GeoSelectWidget
departmentValue={(answers['A1'] as string) ?? ''}
cityValue={(answers['A2'] as string) ?? ''}
onDepartmentChange={(v) => onChange('A1', v)}
onCityChange={(v) => onChange('A2', v)}
departmentError={errors['A1']}
cityError={errors['A2']}
/>
)
}
// A2 is rendered inside the GeoSelectWidget above — skip here to avoid duplication
if (code === 'A2') return null
if (type === 'single_choice' && isArrayOptions(options)) {
return (
<RadioGroup

View File

@@ -1,14 +1,14 @@
'use client'
import { useCallback, useEffect, useRef, useState } from 'react'
import { useCallback, useEffect, useRef, useState, useTransition } from 'react'
import type { FormAnswers, Question, Survey } from '@/lib/types'
import { clearDraft, loadDraft, saveDraft } from '@/lib/storage'
import { getHiddenCodes, isQuestionVisible } from '@/lib/conditional'
import { submitSurvey } from '@/app/actions/submit-survey'
import { ConsentScreen } from './consent-screen'
import { ProgressBar } from './progress-bar'
import { QuestionRenderer } from './question-renderer'
import { SummaryScreen } from './summary-screen'
// Section metadata (code prefix → display title)
// Prefixes: 'A' for A1-A7, '1' for 1.1-1.16, '2' for 2.1-2.5, etc.
const SECTIONS: { prefix: string; title: string; sensitive?: boolean }[] = [
{ prefix: 'A', title: 'Datos Generales' },
{ prefix: '1', title: 'Prevalencia: cuidado y discapacidad', sensitive: true },
@@ -20,29 +20,29 @@ const SECTIONS: { prefix: string; title: string; sensitive?: boolean }[] = [
{ prefix: '7', title: 'Para cerrar' },
]
// Extracts the leading alpha or numeric segment from a question code.
// 'A1' → 'A', '1.1' → '1', '1.16' → '1', '6.4' → '6', '7.1' → '7'
function getSectionPrefix(code: string): string {
const m = code.match(/^([A-Za-z]+|\d+)/)
return m ? m[1] : code
}
type FormStage = 'consent' | 'form' | 'success' | 'error'
interface SurveyFormProps {
survey: Survey
questions: Question[]
}
export function SurveyForm({ survey, questions }: SurveyFormProps) {
const [stage, setStage] = useState<FormStage>('consent')
const [consentOperativo, setConsentOperativo] = useState(false)
const [consentMacroN1, setConsentMacroN1] = useState(false)
const [answers, setAnswers] = useState<FormAnswers>({})
const [errors, setErrors] = useState<Record<string, string>>({})
const [submitted, setSubmitted] = useState(false)
const [hydrated, setHydrated] = useState(false)
// Announce when conditional blocks appear/disappear
const [submitError, setSubmitError] = useState<string | null>(null)
const [isPending, startTransition] = useTransition()
const [a11yAnnounce, setA11yAnnounce] = useState('')
// Track which trigger codes had "Sí" on prev render to detect toggle
const prevVisibility = useRef<Record<string, boolean>>({})
const [hydrated, setHydrated] = useState(false)
const prevAnswers = useRef<FormAnswers>({})
// Hydrate from localStorage on mount
useEffect(() => {
@@ -51,43 +51,34 @@ export function SurveyForm({ survey, questions }: SurveyFormProps) {
setHydrated(true)
}, [survey.id])
// Persist to localStorage on every change (after hydration)
// Persist to localStorage after hydration
useEffect(() => {
if (!hydrated) return
saveDraft(survey.id, answers)
prevAnswers.current = answers
}, [answers, hydrated, survey.id])
const handleChange = useCallback(
(code: string, value: FormAnswers[string]) => {
setAnswers((prev) => {
const updated = { ...prev, [code]: value }
// Clear any dependent questions that become hidden
const toHide = getHiddenCodes(code, value, questions, prev)
for (const hiddenCode of toHide) {
updated[hiddenCode] = undefined as unknown as FormAnswers[string]
}
// Announce block visibility change to screen readers
if (toHide.length > 0) {
setA11yAnnounce('Se ocultaron preguntas relacionadas y se limpiaron sus respuestas.')
} else {
// Check if a conditional block just became visible
const appeared = questions.some(
(q) =>
q.conditional_rules?.some((r) => r.if_question === code) &&
isQuestionVisible(q, updated) &&
!isQuestionVisible(q, prev)
)
if (appeared) {
setA11yAnnounce('Aparecieron nuevas preguntas según tu respuesta.')
}
if (appeared) setA11yAnnounce('Aparecieron nuevas preguntas según tu respuesta.')
}
return updated
})
// Clear validation error for this field
setErrors((prev) => {
if (!prev[code]) return prev
const { [code]: _, ...rest } = prev
@@ -103,12 +94,7 @@ export function SurveyForm({ survey, questions }: SurveyFormProps) {
if (!q.required) continue
if (!isQuestionVisible(q, answers)) continue
const val = answers[q.code]
if (
val === null ||
val === undefined ||
val === '' ||
(Array.isArray(val) && val.length === 0)
) {
if (val === null || val === undefined || val === '' || (Array.isArray(val) && val.length === 0)) {
newErrors[q.code] = 'Este campo es obligatorio.'
}
}
@@ -118,82 +104,129 @@ export function SurveyForm({ survey, questions }: SurveyFormProps) {
function handleSubmit(e: React.FormEvent) {
e.preventDefault()
if (isPending) return
if (!validate()) {
// Move focus to first error
const firstErrorCode = Object.keys(errors)[0]
if (firstErrorCode) {
document.getElementById(firstErrorCode)?.focus()
}
if (firstErrorCode) document.getElementById(firstErrorCode)?.focus()
return
}
// 2A: no write to DB — just show summary
clearDraft(survey.id)
setSubmitted(true)
const questionMap = Object.fromEntries(questions.map((q) => [q.code, q.id]))
startTransition(async () => {
const result = await submitSurvey({
surveyId: survey.id,
answers: answers as Record<string, unknown>,
questionMap,
consentOperativo,
consentMacroN1,
})
if (result.success) {
clearDraft(survey.id)
setStage('success')
} else {
setSubmitError(result.error)
setStage('error')
}
})
}
function handleStartOver() {
setAnswers({})
setSubmitted(false)
setErrors({})
// ── Stage: consent ──────────────────────────────────────────
if (stage === 'consent') {
return (
<ConsentScreen
brandConfig={survey.brand_config}
onAccept={(op, macro) => {
setConsentOperativo(op)
setConsentMacroN1(macro)
setStage('form')
}}
/>
)
}
// Visible questions driven by conditional_rules
// ── Stage: success ──────────────────────────────────────────
if (stage === 'success') {
return (
<div className="survey-wrapper">
<div className="thank-you-container" role="main">
<h1 className="thank-you-title">¡Gracias por participar!</h1>
<p className="thank-you-body">
Tu respuesta fue registrada correctamente. Recordá que la encuesta es anónima: no hay
forma de vincular tus respuestas con tu identidad.
</p>
<p className="thank-you-body">
Los resultados agregados ayudarán a {survey.brand_config?.org_name ?? 'tu empresa'} a
diseñar mejores apoyos para las personas cuidadoras.
</p>
</div>
</div>
)
}
// ── Stage: error ────────────────────────────────────────────
if (stage === 'error') {
return (
<div className="survey-wrapper">
<div className="error-container" role="main">
<h1 className="error-title">No se pudo enviar la encuesta</h1>
<p>Hubo un error al guardar tus respuestas ({submitError}). Podés intentarlo de nuevo.</p>
<button
type="button"
className="btn btn-primary"
onClick={() => { setSubmitError(null); setStage('form') }}
>
Volver e intentar de nuevo
</button>
</div>
</div>
)
}
// ── Stage: form ─────────────────────────────────────────────
const visibleQuestions = questions.filter((q) => isQuestionVisible(q, answers))
const answeredCount = visibleQuestions.filter((q) => {
const v = answers[q.code]
return v !== null && v !== undefined && v !== '' && !(Array.isArray(v) && v.length === 0)
}).length
if (submitted) {
return (
<SummaryScreen
surveyTitle={survey.title}
questions={questions}
answers={answers}
onStartOver={handleStartOver}
/>
)
}
// Group visible questions by section prefix, in order
type Section = { prefix: string; title: string; sensitive?: boolean; questions: Question[] }
const sectionMap = new Map<string, Section>()
for (const q of visibleQuestions) {
const prefix = getSectionPrefix(q.code)
if (!sectionMap.has(prefix)) {
const meta = SECTIONS.find((s) => s.prefix === prefix)
sectionMap.set(prefix, {
prefix,
title: meta?.title ?? prefix,
sensitive: meta?.sensitive,
questions: [],
})
sectionMap.set(prefix, { prefix, title: meta?.title ?? prefix, sensitive: meta?.sensitive, questions: [] })
}
sectionMap.get(prefix)!.questions.push(q)
}
const bc = survey.brand_config
return (
<div className="survey-wrapper">
{/* Skip link for keyboard users */}
<a href="#survey-form" className="skip-link">
Ir al formulario
</a>
<a href="#survey-form" className="skip-link">Ir al formulario</a>
{/* Screen-reader live region for conditional announcements */}
<div
aria-live="polite"
aria-atomic="true"
className="sr-only"
role="status"
>
<div aria-live="polite" aria-atomic="true" className="sr-only" role="status">
{a11yAnnounce}
</div>
{/* Header contextual con org/branch si está configurado */}
{bc?.org_name && (
<div className="brand-header" role="note" aria-label="Información de la empresa">
<p className="brand-text">
Estás respondiendo esto porque pertenecés a <strong>{bc.org_name}</strong>
{bc.branch_name && (
<> y participás en las oficinas de <strong>{bc.branch_name}</strong>
{bc.branch_city && <> en <strong>{bc.branch_city}</strong></>}.</>
)}
</p>
</div>
)}
<header className="survey-header">
<h1 className="survey-title">{survey.title}</h1>
<p className="survey-anon-note">
Esta encuesta es anónima. Tus respuestas no te identifican.
</p>
<p className="survey-anon-note">Esta encuesta es anónima. Tus respuestas no te identifican.</p>
</header>
<div className="survey-progress-sticky" aria-label="Barra de progreso">
@@ -201,11 +234,7 @@ export function SurveyForm({ survey, questions }: SurveyFormProps) {
</div>
<main id="survey-form">
<form
onSubmit={handleSubmit}
noValidate
aria-label={`Encuesta: ${survey.title}`}
>
<form onSubmit={handleSubmit} noValidate aria-label={`Encuesta: ${survey.title}`}>
{Array.from(sectionMap.values()).map((section) => (
<section
key={section.prefix}
@@ -213,9 +242,7 @@ export function SurveyForm({ survey, questions }: SurveyFormProps) {
aria-labelledby={`section-${section.prefix}`}
>
<div className="section-header">
<h2 id={`section-${section.prefix}`} className="section-title">
{section.title}
</h2>
<h2 id={`section-${section.prefix}`} className="section-title">{section.title}</h2>
{section.sensitive && (
<p className="section-sensitive-note" role="note">
Esta sección contiene preguntas sensibles sobre salud o discapacidad.
@@ -223,13 +250,8 @@ export function SurveyForm({ survey, questions }: SurveyFormProps) {
</p>
)}
</div>
{section.questions.map((q) => (
<div
key={q.id}
className="question-wrapper"
data-code={q.code}
>
<div key={q.id} className="question-wrapper" data-code={q.code}>
<QuestionRenderer
question={q}
answers={answers}
@@ -242,8 +264,13 @@ export function SurveyForm({ survey, questions }: SurveyFormProps) {
))}
<div className="form-footer">
<button type="submit" className="btn btn-primary">
Ver resumen de respuestas
<button
type="submit"
className="btn btn-primary"
disabled={isPending}
aria-disabled={isPending}
>
{isPending ? 'Enviando…' : 'Enviar encuesta'}
</button>
</div>
</form>

View File

@@ -0,0 +1,90 @@
'use client'
import { DEPARTMENTS, getCities } from '@/lib/paraguay-geo'
interface GeoSelectWidgetProps {
departmentValue: string
cityValue: string
onDepartmentChange: (value: string) => void
onCityChange: (value: string) => void
departmentError?: string
cityError?: string
}
export function GeoSelectWidget({
departmentValue,
cityValue,
onDepartmentChange,
onCityChange,
departmentError,
cityError,
}: GeoSelectWidgetProps) {
const cities = departmentValue ? getCities(departmentValue) : []
const cityDisabled = !departmentValue
function handleDepartmentChange(val: string) {
onDepartmentChange(val)
onCityChange('') // limpiar ciudad al cambiar departamento
}
return (
<div className="geo-select-wrapper">
{/* Departamento */}
<div className="geo-select-group">
<label className="question-legend" htmlFor="A1">
Departamento
</label>
<select
id="A1"
name="A1"
value={departmentValue}
onChange={(e) => handleDepartmentChange(e.target.value)}
aria-invalid={!!departmentError}
aria-describedby={departmentError ? 'A1-error' : undefined}
className="geo-select"
>
<option value="">Seleccioná un departamento</option>
{DEPARTMENTS.map((dept) => (
<option key={dept} value={dept}>{dept}</option>
))}
</select>
{departmentError && (
<p role="alert" className="field-error" id="A1-error">{departmentError}</p>
)}
</div>
{/* Ciudad */}
<div className="geo-select-group">
<label
className={`question-legend${cityDisabled ? ' geo-label-disabled' : ''}`}
htmlFor="A2"
>
Ciudad
{cityDisabled && (
<span className="geo-disabled-hint"> (seleccioná un departamento primero)</span>
)}
</label>
<select
id="A2"
name="A2"
value={cityValue}
onChange={(e) => onCityChange(e.target.value)}
disabled={cityDisabled}
aria-disabled={cityDisabled}
aria-invalid={!!cityError}
aria-describedby={cityError ? 'A2-error' : undefined}
className={`geo-select${cityDisabled ? ' geo-select-disabled' : ''}`}
>
<option value="">
{cityDisabled ? 'Primero seleccioná el departamento' : 'Seleccioná una ciudad…'}
</option>
{cities.map((city) => (
<option key={city} value={city}>{city}</option>
))}
</select>
{cityError && (
<p role="alert" className="field-error" id="A2-error">{cityError}</p>
)}
</div>
</div>
)
}

84
lib/paraguay-geo.ts Normal file
View File

@@ -0,0 +1,84 @@
// Datos geográficos de Paraguay — departamentos y sus ciudades/municipios
// Fuente: INE Paraguay / Wikipedia. Actualizaciones: agregar al objeto GEO_DATA sin cambio de esquema.
export const GEO_DATA: Record<string, string[]> = {
'Asunción (Capital)': ['Asunción'],
'Alto Paraguay': ['Fuerte Olimpo', 'Bahía Negra', 'Carmelo Peralta', 'La Victoria'],
'Alto Paraná': [
'Ciudad del Este', 'Hernandarias', 'Minga Guazú', 'Presidente Franco',
'Minga Porã', 'Naranjal', 'Ñacunday', 'San Alberto', 'Santa Rita', 'Tavapy',
'Yguazú', "Juan E. O'Leary", 'San Cristóbal', 'Santa Fe del Paraná',
'Dr. Juan León Mallorquín', 'Itakyry', 'Domingo Martínez de Irala',
],
'Amambay': ['Pedro Juan Caballero', 'Bella Vista Norte', 'Capitán Bado', 'Zanja Pytã'],
'Boquerón': ['Filadelfia', 'Loma Plata', 'Mariscal Estigarribia', 'Neuland'],
'Caaguazú': [
'Coronel Oviedo', 'Caaguazú', 'Carayaó', 'Dr. Juan Manuel Frutos', 'Mbutuy',
'Nueva Londres', 'Raúl Arsenio Oviedo', 'Repatriación', 'San Joaquín',
'San José de los Arroyos', 'Simón Bolívar', 'Vaquería', 'Yhú',
'José Domingo Ocampos', '3 de Febrero', 'Mcal. Francisco Solano López', 'Los Cedrales',
],
'Caazapá': [
'Caazapá', 'Abai', 'Buena Vista', 'General Higinio Morínigo', 'Huber Duré',
'Maciel', 'San Juan Nepomuceno', 'Tavaí', 'Yegros', 'Yuty',
],
'Canindeyú': [
'Salto del Guairá', 'Corpus Christi', 'Curuguaty', 'General Francisco Caballero Álvarez',
'Itanará', 'Katueté', 'La Paloma', 'Nueva Esperanza', 'Yasy Kañy', 'Ypejhú',
],
'Central': [
'Areguá', 'Capiatá', 'Fernando de la Mora', 'Guarambaré', 'Itá', 'Itauguá',
'Juan Augusto Saldívar', 'Lambaré', 'Limpio', 'Luque', 'Mariano Roque Alonso',
'Nueva Italia', 'Ñemby', 'San Antonio', 'San Lorenzo', 'Villa Elisa', 'Villeta', 'Ypané', 'Ypacaraí',
],
'Concepción': [
'Concepción', 'Belén', 'Horqueta', 'Loreto', 'San Lázaro', 'San Carlos del Apa',
"Yby Yaú", "Azote'y", 'Sgto. José Félix López',
],
'Cordillera': [
'Caacupé', 'Altos', 'Arroyos y Esteros', 'Caraguatay', 'Emboscada', 'Eusebio Ayala',
'Isla Pucú', 'Itacurubí de la Cordillera', 'Juan de Mena', 'Loma Grande',
'Mbocayaty del Yhaguy', 'Nueva Colombia', 'Pirayú', 'Primero de Marzo', 'Tobatí', 'Valenzuela',
],
'Guairá': [
'Villarrica', 'Borja', 'Capitán Mauricio José Troche', 'Coronel Martínez',
'Félix Pérez Cardozo', 'General Eugenio A. Garay', 'Independencia', 'Itapé',
'Iturbe', 'José Fassardi', 'Mbocayaty', 'Natalicio Talavera', 'Ñumí', 'San Salvador', 'Yataity',
],
'Itapúa': [
'Encarnación', 'Alto Verá', 'Bella Vista', 'Cambyretá', 'Capitán Meza', 'Capitán Miranda',
'Carlos A. López', 'Carmen del Paraná', 'Coronel Bogado', 'Cosme', 'Edelira', 'Fram',
'General Artigas', 'Hohenau', 'Itapúa Poty', 'Jesús', 'La Paz', 'Leandro Oviedo',
'Mayor Otaño', 'Natalio', 'Nueva Alborada', 'Obligado', 'Pirapó', 'San Cosme y Damián',
'San Juan del Paraná', 'San Pedro del Paraná', 'San Rafael del Paraná',
'Trinidad', 'Tomás Romero Pereira',
],
'Misiones': [
'San Juan Bautista', 'Ayolas', 'San Ignacio', 'San Miguel', 'San Patricio',
'Santa María', 'Santa Rosa', 'Santiago', 'Villa Florida', 'Yabebyry',
],
'Ñeembucú': [
'Pilar', 'Alberdi', 'Cerrito', 'Desmochados', 'General José Eduvigis Díaz', 'Guazú Cuá',
'Humaitá', 'Isla Umbú', 'Laureles', 'Mayor José de J. Martínez', 'Paso de Patria',
'San Juan Bautista del Ñeembucú', 'Tacuaras', 'Villa Franca', 'Villa Oliva', 'Villalba',
],
'Paraguarí': [
'Paraguarí', 'Acahay', 'Carapeguá', 'Escobar', 'General Bernardino Caballero',
'La Colmena', 'Mbuyapey', 'Quiindy', 'Quyquyhó', 'San Roque González de Santa Cruz',
'Sapucaí', 'Tebicuarymí', 'Ybycuí', 'Ybytymí', 'Yaguarón',
],
'Presidente Hayes': [
'Villa Hayes', 'Benjamín Aceval', 'José Falcón', 'Nanawa', 'Nueva Asunción',
'Pozo Colorado', 'Puerto Pinasco', 'Teniente Primero Manuel Irala Fernández', 'Villa del Río',
],
'San Pedro': [
'San Pedro del Ycuamandiyú', 'Antequera', 'Choré', 'General Elizardo Aquino',
'Guayaibí', 'Itacurubí del Rosario', 'Lima', 'Nueva Germania', 'Río Verde',
'San Estanislao (Santaní)', 'Tacuatí', 'Unión', 'Villa del Rosario', 'Yataity del Norte',
],
}
export const DEPARTMENTS = Object.keys(GEO_DATA)
export const getCities = (department: string): string[] =>
GEO_DATA[department] ?? []

View File

@@ -39,12 +39,21 @@ export interface Question {
conditional_rules: ConditionalRule[] | null
}
export interface BrandConfig {
org_name?: string
branch_name?: string
branch_city?: string
}
export interface Survey {
id: string
org_id: string
title: string
status: string
is_anonymous: boolean
k_threshold: number
consent_version_id: string
brand_config: BrandConfig | null
questions: Question[]
}

View File

@@ -0,0 +1,258 @@
# ETAPA 2B — Consentimiento + persistencia real + dropdowns geográficos
> Leé: `CLAUDE.md`, `DATA_MODEL.md`, `SEED_SPEC.md`, `docs/adr/ADR-001`, `docs/adr/ADR-003`,
> `sprints/sprint-2/BRIEF.md` y este prompt. La app Next.js ya existe (Etapa 2A).
## 1. Objetivo
Cuatro cosas en una etapa:
1. **Geo dropdowns:** A1=Departamento, A2=Ciudad (dependiente de A1), A3=Barrio (texto, opcional).
2. **Header contextual:** mostrar organización y sucursal pre-configurados en la encuesta.
3. **URL por parámetro:** `?s=UUID` para cargar una encuesta específica.
4. **Persistencia real (2B):** pantalla de consentimiento + Server Action que escribe
`consent_record → response → answers` en Supabase Cloud.
## 2. Contexto previo
La app renderiza el formulario desde Supabase (anon key), tiene lógica condicional data-driven,
widget `text_short`, resiliencia lite. El esquema Sprint 1 tiene RLS, k-anonimato, consent inmutable.
`responses.consent_record_id` es `NOT NULL` → la escritura requiere consentimiento primero.
## 3. Decisiones ya tomadas
- **Geo:** A1=Departamento y A2=Ciudad son `single_choice` en el DB, renderizados con un widget
especial `GeoSelectWidget` (dos dropdowns enlazados). A3=Barrio es `text_short`, opcional.
Los datos geográficos viven en una constante TypeScript en el app (ver sección 5).
- **Header:** `survey.brand_config` tiene `{org_name, branch_name, branch_city}`. El formulario
lo muestra arriba: *"Estás respondiendo esto porque pertenecés a [org_name] y participás en las
oficinas de [branch_name] en [branch_city]."* — solo-lectura, no editable por el respondente.
- **URL:** `?s=<survey_id>` — la página lee `searchParams.s`. Si no hay parámetro, carga la primera
encuesta `live` (backwards compat para desarrollo).
- **Consentimiento:** pantalla ANTES del formulario. Checkbox 1 (requerido): acepta uso operativo.
Checkbox 2 (opcional): acepta macro anónimo. Sin checkbox 1, no puede avanzar. El texto debe ser
honesto sobre el anonimato y la NO revocación (ADR-003 — la encuesta es anónima; no hay forma de
revocar después). Los valores de ambos checkboxes se almacenan en `consent_record.granted_scopes`.
- **ip_hash:** se computa SERVER-SIDE en el Server Action con SHA-256 + `process.env.IP_HASH_SALT`
(variable server-only, **nunca** `NEXT_PUBLIC_`). Usar `x-forwarded-for` como IP (Traefik/Dokploy).
- **Orden de inserts:** consentimiento → response → answers, dentro del Server Action.
Si algo falla, el usuario ve un error y puede reintentar.
- **`service_role` NUNCA en el cliente.** Los inserts usan el cliente Supabase inicializado con la
`anon` key server-side (en el Server Action) — las RLS policies de INSERT lo permiten.
## 4. Tareas
### 4A — Seed: actualizar questions y brand_config
1. En `supabase/seed.sql`, actualizar:
- **A1** (Departamento): `type='single_choice'`, opciones = los 18 valores del listado geo (sección 5).
- **A2** (Ciudad): `type='single_choice'`, opciones = TODAS las ciudades del listado geo
concatenadas con el nombre de su departamento como prefijo para que la DB las almacene
correctamente (e.g. `{label:"Asunción", value:"Asunción"}`). El filtrado por departamento
es client-side en el widget.
- **A3** (Barrio): `type='text_short'`, prompt="¿En qué barrio vivís? (opcional)", required=false.
- **A4** (Área): agregar a las opciones existentes: `"Directorio"` y `"Gerencia"`.
- **1.3** (Elementos de apoyo): agregar opción `"Tecnología asistiva"`.
- **survey.brand_config**: actualizar el registro semilla con
`{"org_name": "Empresa Demo", "branch_name": "Oficina Central", "branch_city": "Asunción"}`.
(El director actualizará esto con los datos reales de la primera empresa directamente en
Supabase Studio antes de enviar el link.)
2. Aplicar a Cloud: `supabase db push --include-seed` o actualizar las questions directamente
via script SQL si el seed ya no es idempotente (usar ON CONFLICT UPDATE para questions).
### 4B — App: GeoSelectWidget + header + URL
3. Crear `components/widgets/geo-select-widget.tsx`:
- Primer dropdown: Departamento (opciones de A1).
- Segundo dropdown: Ciudad — opciones filtradas del `GEO_DATA` const según el departamento
seleccionado. Deshabilitado hasta que se seleccione departamento.
- Cuando cambia el departamento, limpiar la ciudad seleccionada.
- Ambos dropdowns son accesibles (label, aria, teclado).
4. En `question-renderer.tsx`: detectar `code === 'A1'` → renderizar `GeoSelectWidget` (que
maneja A1 y A2 juntos). Detectar `code === 'A2'` → skip (ya lo maneja el widget de A1).
5. En `app/page.tsx`:
- Leer `searchParams.s` como `surveyId`. Si existe, cargar esa encuesta por ID; si no, cargar
la primera `live`.
- Leer `survey.brand_config` y pasarlo al formulario.
6. Crear el **header contextual** (component o inline en `survey-form.tsx`): si `brand_config`
tiene `org_name`, mostrar el banner:
*"Estás respondiendo esto porque pertenecés a [org_name] y participás en las oficinas de
[branch_name] en [branch_city]."* — estilo discreto, no editable.
### 4C — Consentimiento (pantalla previa al formulario)
7. Crear `components/consent-screen.tsx`:
- Sección de explicación del tratamiento (qué se recolecta, para qué, que es anónimo).
- Párrafo OBLIGATORIO sobre anonimato: *"Esta encuesta es completamente anónima. No guardamos
ningún dato que te identifique. Por ser anónima, no es posible revocar ni eliminar tu
respuesta una vez enviada."*
- Checkbox 1 (required): *"Acepto que mis respuestas se usen para el diagnóstico interno de
[org_name] sobre cuidado y discapacidad."*
- Checkbox 2 (optional): *"También acepto que mis respuestas anonimizadas contribuyan al
estudio país sobre economía del cuidado (sin identificarme en ningún caso)."*
- Botón "Comenzar la encuesta" — deshabilitado hasta que checkbox 1 esté marcado.
- Al hacer clic en "Comenzar", guarda los valores de los checkboxes en el estado del formulario
y muestra el formulario (NO escribe en la base todavía — el insert va al enviar).
### 4D — Server Action: persistencia real
8. Crear `app/actions/submit-survey.ts` (Server Action):
```typescript
'use server'
import { headers } from 'next/headers'
import { createHash } from 'crypto'
import { createClient } from '@supabase/supabase-js'
export async function submitSurvey(payload: {
surveyId: string
answers: Record<string, unknown> // código → valor
questionMap: Record<string, string> // código → question_id (UUID)
consentOperativo: boolean
consentMacroN1: boolean
consentVersionId: string
}) {
// 1. IP hash (server-only)
const headersList = await headers()
const rawIp = headersList.get('x-forwarded-for')?.split(',')[0]?.trim() ?? 'unknown'
const salt = process.env.IP_HASH_SALT ?? ''
const ipHash = createHash('sha256').update(rawIp + salt).digest('hex')
// 2. Cliente Supabase con anon key (las RLS policies permiten INSERT a anon/authenticated)
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
// 3. INSERT consent_record
const { data: consent, error: cErr } = await supabase
.from('consent_records')
.insert({
consent_version_id: payload.consentVersionId,
granted_scopes: {
operativo: payload.consentOperativo,
macro_n1: payload.consentMacroN1
},
granted_at: new Date().toISOString()
})
.select('id')
.single()
if (cErr || !consent) return { success: false, error: 'consent_insert_failed' }
// 4. Extraer qi_* de las respuestas
const qi_age_bucket = String(payload.answers['A5'] ?? '')
const qi_sector = String(payload.answers['A4'] ?? '')
// 5. INSERT response
const { data: response, error: rErr } = await supabase
.from('responses')
.insert({
survey_id: payload.surveyId,
company_id: null, // se setea automáticamente por la survey.org_id en el trigger o app
respondent_id: null,
ip_hash: ipHash,
consent_record_id: consent.id,
qi_age_bucket: qi_age_bucket || null,
qi_sector: qi_sector || null,
qi_zone: null
})
.select('id')
.single()
if (rErr || !response) return { success: false, error: 'response_insert_failed' }
// 6. INSERT answers (bulk, excluir text_long/A2 si están vacíos, siempre excluir A2 separado
// ya que va incluido en A1 via GeoWidget)
const answerRows = Object.entries(payload.answers)
.filter(([code]) => code !== '__consent__') // filtrar meta-campos
.map(([code, value]) => ({
response_id: response.id,
question_id: payload.questionMap[code],
value: JSON.stringify(value)
}))
.filter(row => row.question_id && row.value !== 'null' && row.value !== '""' && row.value !== '[]')
const { error: aErr } = await supabase.from('answers').insert(answerRows)
if (aErr) return { success: false, error: 'answers_insert_failed' }
return { success: true }
}
```
9. En `survey-form.tsx`: al enviar, llamar `submitSurvey(...)`. Si success → mostrar pantalla de
agradecimiento/confirmación (reemplaza el resumen actual). Si error → mostrar mensaje de error
con opción de reintentar.
10. Agregar `IP_HASH_SALT` a `.env.example` (sin valor, solo el nombre).
## 5. Datos geográficos de Paraguay — constante TypeScript
Crear `lib/paraguay-geo.ts` con esta estructura y datos:
```typescript
export const GEO_DATA: Record<string, string[]> = {
"Asunción (Capital)": ["Asunción"],
"Alto Paraguay": ["Fuerte Olimpo","Bahía Negra","Carmelo Peralta","La Victoria"],
"Alto Paraná": ["Ciudad del Este","Hernandarias","Minga Guazú","Presidente Franco","Minga Porã","Naranjal","Ñacunday","San Alberto","Santa Rita","Tavapy","Yguazú","Juan E. O'Leary","San Cristóbal","Santa Fe del Paraná","Dr. Juan León Mallorquín","Itakyry","Domingo Martínez de Irala"],
"Amambay": ["Pedro Juan Caballero","Bella Vista Norte","Capitán Bado","Zanja Pytã"],
"Boquerón": ["Filadelfia","Loma Plata","Mariscal Estigarribia","Neuland"],
"Caaguazú": ["Coronel Oviedo","Caaguazú","Carayaó","Dr. Juan Manuel Frutos","Mbutuy","Nueva Londres","Raúl Arsenio Oviedo","Repatriación","San Joaquín","San José de los Arroyos","Simón Bolívar","Vaquería","Yhú","José Domingo Ocampos","3 de Febrero","Mcal. Francisco Solano López","Los Cedrales"],
"Caazapá": ["Caazapá","Abai","Buena Vista","General Higinio Morínigo","Huber Duré","Maciel","San Juan Nepomuceno","Tavaí","Yegros","Yuty"],
"Canindeyú": ["Salto del Guairá","Corpus Christi","Curuguaty","General Francisco Caballero Álvarez","Itanará","Katueté","La Paloma","Nueva Esperanza","Yasy Kañy","Ypejhú"],
"Central": ["Areguá","Capiatá","Fernando de la Mora","Guarambaré","Itá","Itauguá","Juan Augusto Saldívar","Lambaré","Limpio","Luque","Mariano Roque Alonso","Nueva Italia","Ñemby","San Antonio","San Lorenzo","Villa Elisa","Villeta","Ypané","Ypacaraí"],
"Concepción": ["Concepción","Belén","Horqueta","Loreto","San Lázaro","San Carlos del Apa","Yby Yaú","Azote'y","Sgto. José Félix López"],
"Cordillera": ["Caacupé","Altos","Arroyos y Esteros","Caraguatay","Emboscada","Eusebio Ayala","Isla Pucú","Itacurubí de la Cordillera","Juan de Mena","Loma Grande","Mbocayaty del Yhaguy","Nueva Colombia","Pirayú","Primero de Marzo","Tobatí","Valenzuela"],
"Guairá": ["Villarrica","Borja","Capitán Mauricio José Troche","Coronel Martínez","Félix Pérez Cardozo","General Eugenio A. Garay","Independencia","Itapé","Iturbe","José Fassardi","Mbocayaty","Natalicio Talavera","Ñumí","San Salvador","Yataity"],
"Itapúa": ["Encarnación","Alto Verá","Bella Vista","Cambyretá","Capitán Meza","Capitán Miranda","Carlos A. López","Carmen del Paraná","Coronel Bogado","Cosme","Edelira","Fram","General Artigas","Hohenau","Itapúa Poty","Jesús","La Paz","Leandro Oviedo","Mayor Otaño","Natalio","Nueva Alborada","Obligado","Pirapó","San Cosme y Damián","San Juan del Paraná","San Pedro del Paraná","San Rafael del Paraná","Trinidad","Tomás Romero Pereira"],
"Misiones": ["San Juan Bautista","Ayolas","San Ignacio","San Miguel","San Patricio","Santa María","Santa Rosa","Santiago","Villa Florida","Yabebyry"],
"Ñeembucú": ["Pilar","Alberdi","Cerrito","Desmochados","General José Eduvigis Díaz","Guazú Cuá","Humaitá","Isla Umbú","Laureles","Mayor José de J. Martínez","Paso de Patria","San Juan Bautista del Ñeembucú","Tacuaras","Villa Franca","Villa Oliva","Villalba"],
"Paraguarí": ["Paraguarí","Acahay","Carapeguá","Escobar","General Bernardino Caballero","La Colmena","Mbuyapey","Quiindy","Quyquyhó","San Roque González de Santa Cruz","Sapucaí","Tebicuarymí","Ybycuí","Ybytymí","Yaguarón"],
"Presidente Hayes": ["Villa Hayes","Benjamín Aceval","José Falcón","Nanawa","Nueva Asunción","Pozo Colorado","Puerto Pinasco","Teniente Primero Manuel Irala Fernández","Villa del Río"],
"San Pedro": ["San Pedro del Ycuamandiyú","Antequera","Choré","General Elizardo Aquino","Guayaibí","Itacurubí del Rosario","Lima","Nueva Germania","Río Verde","San Estanislao (Santaní)","Tacuatí","Unión","Villa del Rosario","Yataity del Norte"]
}
export const DEPARTMENTS = Object.keys(GEO_DATA).sort()
export const getCities = (department: string): string[] =>
(GEO_DATA[department] ?? []).sort()
```
Notas sobre los datos: lista basada en fuentes oficiales (INE Paraguay / Wikipedia). Si el director
identifica municipios faltantes, se agregan al objeto `GEO_DATA` sin cambio de esquema.
## 6. company_id en la response
El seed tiene `org_id` en la survey. En el Server Action, obtener el `org_id` de la survey para
setearlo como `company_id` en el `responses`:
```typescript
const { data: survey } = await supabase
.from('surveys')
.select('org_id, consent_version_id, brand_config')
.eq('id', payload.surveyId)
.single()
// Usar survey.org_id como company_id en el INSERT de responses
```
## 7. Definition of Done
- [ ] Dropdowns A1→A2 funcionan en el browser: seleccionar departamento filtra las ciudades.
- [ ] A3 (barrio) renderiza como campo de texto.
- [ ] A4 tiene opciones Directorio y Gerencia.
- [ ] 1.3 tiene opción Tecnología asistiva.
- [ ] Header muestra org_name/branch_name/branch_city de brand_config cuando existe.
- [ ] `?s=UUID` carga la encuesta correcta; sin parámetro carga la primera live.
- [ ] Pantalla de consentimiento aparece antes del formulario con texto honesto (anonimato + no revocación).
- [ ] Completar y enviar el formulario escribe en Supabase: 1 consent_record + 1 response + N answers.
- [ ] Verificar en Supabase Studio que los registros aparecen.
- [ ] `response.ip_hash` no es null ni la IP en texto plano (es el hash).
- [ ] `response.company_id` = el org_id de la survey.
- [ ] `response.consent_record_id` = el id del consent_record recién creado.
- [ ] `answers` tiene una fila por cada pregunta respondida.
- [ ] `npm run build` limpio.
- [ ] Sin `service_role` ni `IP_HASH_SALT` en código cliente ni en `NEXT_PUBLIC_*`.
- [ ] `git diff --name-only HEAD` solo con los archivos autorizados.
## 8. Validaciones mandatorias
- Enviar el formulario → verificar en Supabase Studio (Table Editor) que aparecen filas en
`consent_records`, `responses`, `answers`. Si alguna tabla queda vacía → error, no declarar lista.
- Enviar dos veces desde el mismo browser → verificar que `ip_hash` es el mismo (deduplicación visible).
- El texto del consentimiento menciona explícitamente que la encuesta es anónima y no se puede revocar.
- Si CUALQUIER validación falla: NO declarar lista. Reportar y esperar.
## 9. Qué reportar
- Verificado: captura de las filas escritas en consent_records + responses + answers (IDs concretos).
- Verificado: ip_hash no es null y es un hash (64 chars hex).
- Verificado: company_id del response = org_id de la survey.
- Asumidos, hallazgos, decisiones por iniciativa (con nivel).
- `git diff --name-only HEAD`.
## 10. Qué NO hacer
- NO exponer `IP_HASH_SALT` ni `service_role` al cliente.
- NO poner la IP en texto plano en la base.
- NO saltar la pantalla de consentimiento.
- NO escribir en la base si el checkbox 1 no fue marcado.
- NO modificar las migraciones 001007 ni las policies de RLS.
- NO hardcodear el survey_id en el código (siempre leer del parámetro URL).
- Ante conflicto entre restricción y "que funcione": detenerse y reportar.

View File

@@ -0,0 +1,8 @@
-- Migration 008: fix answers_insert policy
-- Root cause: WITH CHECK con EXISTS en responses
-- bloqueaba INSERT de anon porque anon no tiene SELECT en responses.
-- El FK response_id → responses(id) ya garantiza la integridad referencial.
DROP POLICY "answers_insert" ON public.answers;
CREATE POLICY "answers_insert" ON public.answers
FOR INSERT TO anon, authenticated
WITH CHECK (true);

View File

@@ -48,6 +48,11 @@ INSERT INTO public.surveys (
'20000000-0000-0000-0000-000000000001', 5
) ON CONFLICT (id) DO NOTHING;
-- brand_config: org demo (el director actualiza con datos reales antes de enviar el link)
UPDATE public.surveys
SET brand_config = '{"org_name":"Empresa Demo","branch_name":"Oficina Central","branch_city":"Asunción"}'::jsonb
WHERE id = '30000000-0000-0000-0000-000000000001';
-- ── Preguntas: DELETE + INSERT para idempotencia total ────────
DELETE FROM public.questions
WHERE survey_id = '30000000-0000-0000-0000-000000000001';
@@ -55,27 +60,69 @@ WHERE survey_id = '30000000-0000-0000-0000-000000000001';
-- ══════════════════════════════════════════════════════════════
-- SECCIÓN A — Datos Generales (top-level, cuasi-identificadores)
-- A1/A2/A3: text_short (texto libre, sin opciones)
-- qi_sector ← A4 · qi_age_bucket ← A5
-- qi_city/qi_country ← A2/A1: se agregan como columnas qi en Sprint 3
-- A1=Departamento (single_choice, GeoSelectWidget), A2=Ciudad (single_choice, filtrado client-side)
-- A3=Barrio (text_short, opcional)
-- qi_sector ← A4 · qi_age_bucket ← A5 · qi_city/qi_country ← Sprint 3
-- ══════════════════════════════════════════════════════════════
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required)
-- A1: Departamento (18 opciones — los 18 departamentos de Paraguay + Capital)
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
VALUES ('40000000-0000-0000-0000-000000000001','30000000-0000-0000-0000-000000000001',
'A1','text_short','País',1,false,false);
'A1','single_choice','Departamento',1,false,false,
'[{"value":"Asunción (Capital)","label":"Asunción (Capital)"},
{"value":"Alto Paraguay","label":"Alto Paraguay"},
{"value":"Alto Paraná","label":"Alto Paraná"},
{"value":"Amambay","label":"Amambay"},
{"value":"Boquerón","label":"Boquerón"},
{"value":"Caaguazú","label":"Caaguazú"},
{"value":"Caazapá","label":"Caazapá"},
{"value":"Canindeyú","label":"Canindeyú"},
{"value":"Central","label":"Central"},
{"value":"Concepción","label":"Concepción"},
{"value":"Cordillera","label":"Cordillera"},
{"value":"Guairá","label":"Guairá"},
{"value":"Itapúa","label":"Itapúa"},
{"value":"Misiones","label":"Misiones"},
{"value":"Ñeembucú","label":"Ñeembucú"},
{"value":"Paraguarí","label":"Paraguarí"},
{"value":"Presidente Hayes","label":"Presidente Hayes"},
{"value":"San Pedro","label":"San Pedro"}]'::jsonb);
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required)
-- A2: Ciudad (todas las ciudades; el GeoSelectWidget filtra client-side por departamento)
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
VALUES ('40000000-0000-0000-0000-000000000002','30000000-0000-0000-0000-000000000001',
'A2','text_short','Ciudad',2,false,false);
'A2','single_choice','Ciudad',2,false,false,
'[{"value":"Asunción","label":"Asunción"},
{"value":"Fuerte Olimpo","label":"Fuerte Olimpo"},{"value":"Bahía Negra","label":"Bahía Negra"},{"value":"Carmelo Peralta","label":"Carmelo Peralta"},{"value":"La Victoria","label":"La Victoria"},
{"value":"Ciudad del Este","label":"Ciudad del Este"},{"value":"Hernandarias","label":"Hernandarias"},{"value":"Minga Guazú","label":"Minga Guazú"},{"value":"Presidente Franco","label":"Presidente Franco"},{"value":"Minga Porã","label":"Minga Porã"},{"value":"Naranjal","label":"Naranjal"},{"value":"Ñacunday","label":"Ñacunday"},{"value":"San Alberto","label":"San Alberto"},{"value":"Santa Rita","label":"Santa Rita"},{"value":"Tavapy","label":"Tavapy"},{"value":"Yguazú","label":"Yguazú"},{"value":"Juan E. O''Leary","label":"Juan E. O''Leary"},{"value":"San Cristóbal","label":"San Cristóbal"},{"value":"Santa Fe del Paraná","label":"Santa Fe del Paraná"},{"value":"Dr. Juan León Mallorquín","label":"Dr. Juan León Mallorquín"},{"value":"Itakyry","label":"Itakyry"},{"value":"Domingo Martínez de Irala","label":"Domingo Martínez de Irala"},
{"value":"Pedro Juan Caballero","label":"Pedro Juan Caballero"},{"value":"Bella Vista Norte","label":"Bella Vista Norte"},{"value":"Capitán Bado","label":"Capitán Bado"},{"value":"Zanja Pytã","label":"Zanja Pytã"},
{"value":"Filadelfia","label":"Filadelfia"},{"value":"Loma Plata","label":"Loma Plata"},{"value":"Mariscal Estigarribia","label":"Mariscal Estigarribia"},{"value":"Neuland","label":"Neuland"},
{"value":"Coronel Oviedo","label":"Coronel Oviedo"},{"value":"Caaguazú","label":"Caaguazú"},{"value":"Carayaó","label":"Carayaó"},{"value":"Dr. Juan Manuel Frutos","label":"Dr. Juan Manuel Frutos"},{"value":"Mbutuy","label":"Mbutuy"},{"value":"Nueva Londres","label":"Nueva Londres"},{"value":"Raúl Arsenio Oviedo","label":"Raúl Arsenio Oviedo"},{"value":"Repatriación","label":"Repatriación"},{"value":"San Joaquín","label":"San Joaquín"},{"value":"San José de los Arroyos","label":"San José de los Arroyos"},{"value":"Simón Bolívar","label":"Simón Bolívar"},{"value":"Vaquería","label":"Vaquería"},{"value":"Yhú","label":"Yhú"},{"value":"José Domingo Ocampos","label":"José Domingo Ocampos"},{"value":"3 de Febrero","label":"3 de Febrero"},{"value":"Mcal. Francisco Solano López","label":"Mcal. Francisco Solano López"},{"value":"Los Cedrales","label":"Los Cedrales"},
{"value":"Caazapá","label":"Caazapá"},{"value":"Abai","label":"Abai"},{"value":"Buena Vista","label":"Buena Vista"},{"value":"General Higinio Morínigo","label":"General Higinio Morínigo"},{"value":"Huber Duré","label":"Huber Duré"},{"value":"Maciel","label":"Maciel"},{"value":"San Juan Nepomuceno","label":"San Juan Nepomuceno"},{"value":"Tavaí","label":"Tavaí"},{"value":"Yegros","label":"Yegros"},{"value":"Yuty","label":"Yuty"},
{"value":"Salto del Guairá","label":"Salto del Guairá"},{"value":"Corpus Christi","label":"Corpus Christi"},{"value":"Curuguaty","label":"Curuguaty"},{"value":"General Francisco Caballero Álvarez","label":"General Francisco Caballero Álvarez"},{"value":"Itanará","label":"Itanará"},{"value":"Katueté","label":"Katueté"},{"value":"La Paloma","label":"La Paloma"},{"value":"Nueva Esperanza","label":"Nueva Esperanza"},{"value":"Yasy Kañy","label":"Yasy Kañy"},{"value":"Ypejhú","label":"Ypejhú"},
{"value":"Areguá","label":"Areguá"},{"value":"Capiatá","label":"Capiatá"},{"value":"Fernando de la Mora","label":"Fernando de la Mora"},{"value":"Guarambaré","label":"Guarambaré"},{"value":"Itá","label":"Itá"},{"value":"Itauguá","label":"Itauguá"},{"value":"Juan Augusto Saldívar","label":"Juan Augusto Saldívar"},{"value":"Lambaré","label":"Lambaré"},{"value":"Limpio","label":"Limpio"},{"value":"Luque","label":"Luque"},{"value":"Mariano Roque Alonso","label":"Mariano Roque Alonso"},{"value":"Nueva Italia","label":"Nueva Italia"},{"value":"Ñemby","label":"Ñemby"},{"value":"San Antonio","label":"San Antonio"},{"value":"San Lorenzo","label":"San Lorenzo"},{"value":"Villa Elisa","label":"Villa Elisa"},{"value":"Villeta","label":"Villeta"},{"value":"Ypané","label":"Ypané"},{"value":"Ypacaraí","label":"Ypacaraí"},
{"value":"Concepción","label":"Concepción"},{"value":"Belén","label":"Belén"},{"value":"Horqueta","label":"Horqueta"},{"value":"Loreto","label":"Loreto"},{"value":"San Lázaro","label":"San Lázaro"},{"value":"San Carlos del Apa","label":"San Carlos del Apa"},{"value":"Yby Yaú","label":"Yby Yaú"},{"value":"Azote''y","label":"Azote''y"},{"value":"Sgto. José Félix López","label":"Sgto. José Félix López"},
{"value":"Caacupé","label":"Caacupé"},{"value":"Altos","label":"Altos"},{"value":"Arroyos y Esteros","label":"Arroyos y Esteros"},{"value":"Caraguatay","label":"Caraguatay"},{"value":"Emboscada","label":"Emboscada"},{"value":"Eusebio Ayala","label":"Eusebio Ayala"},{"value":"Isla Pucú","label":"Isla Pucú"},{"value":"Itacurubí de la Cordillera","label":"Itacurubí de la Cordillera"},{"value":"Juan de Mena","label":"Juan de Mena"},{"value":"Loma Grande","label":"Loma Grande"},{"value":"Mbocayaty del Yhaguy","label":"Mbocayaty del Yhaguy"},{"value":"Nueva Colombia","label":"Nueva Colombia"},{"value":"Pirayú","label":"Pirayú"},{"value":"Primero de Marzo","label":"Primero de Marzo"},{"value":"Tobatí","label":"Tobatí"},{"value":"Valenzuela","label":"Valenzuela"},
{"value":"Villarrica","label":"Villarrica"},{"value":"Borja","label":"Borja"},{"value":"Capitán Mauricio José Troche","label":"Capitán Mauricio José Troche"},{"value":"Coronel Martínez","label":"Coronel Martínez"},{"value":"Félix Pérez Cardozo","label":"Félix Pérez Cardozo"},{"value":"General Eugenio A. Garay","label":"General Eugenio A. Garay"},{"value":"Independencia","label":"Independencia"},{"value":"Itapé","label":"Itapé"},{"value":"Iturbe","label":"Iturbe"},{"value":"José Fassardi","label":"José Fassardi"},{"value":"Mbocayaty","label":"Mbocayaty"},{"value":"Natalicio Talavera","label":"Natalicio Talavera"},{"value":"Ñumí","label":"Ñumí"},{"value":"San Salvador","label":"San Salvador"},{"value":"Yataity","label":"Yataity"},
{"value":"Encarnación","label":"Encarnación"},{"value":"Alto Verá","label":"Alto Verá"},{"value":"Bella Vista","label":"Bella Vista"},{"value":"Cambyretá","label":"Cambyretá"},{"value":"Capitán Meza","label":"Capitán Meza"},{"value":"Capitán Miranda","label":"Capitán Miranda"},{"value":"Carlos A. López","label":"Carlos A. López"},{"value":"Carmen del Paraná","label":"Carmen del Paraná"},{"value":"Coronel Bogado","label":"Coronel Bogado"},{"value":"Cosme","label":"Cosme"},{"value":"Edelira","label":"Edelira"},{"value":"Fram","label":"Fram"},{"value":"General Artigas","label":"General Artigas"},{"value":"Hohenau","label":"Hohenau"},{"value":"Itapúa Poty","label":"Itapúa Poty"},{"value":"Jesús","label":"Jesús"},{"value":"La Paz","label":"La Paz"},{"value":"Leandro Oviedo","label":"Leandro Oviedo"},{"value":"Mayor Otaño","label":"Mayor Otaño"},{"value":"Natalio","label":"Natalio"},{"value":"Nueva Alborada","label":"Nueva Alborada"},{"value":"Obligado","label":"Obligado"},{"value":"Pirapó","label":"Pirapó"},{"value":"San Cosme y Damián","label":"San Cosme y Damián"},{"value":"San Juan del Paraná","label":"San Juan del Paraná"},{"value":"San Pedro del Paraná","label":"San Pedro del Paraná"},{"value":"San Rafael del Paraná","label":"San Rafael del Paraná"},{"value":"Trinidad","label":"Trinidad"},{"value":"Tomás Romero Pereira","label":"Tomás Romero Pereira"},
{"value":"San Juan Bautista","label":"San Juan Bautista"},{"value":"Ayolas","label":"Ayolas"},{"value":"San Ignacio","label":"San Ignacio"},{"value":"San Miguel","label":"San Miguel"},{"value":"San Patricio","label":"San Patricio"},{"value":"Santa María","label":"Santa María"},{"value":"Santa Rosa","label":"Santa Rosa"},{"value":"Santiago","label":"Santiago"},{"value":"Villa Florida","label":"Villa Florida"},{"value":"Yabebyry","label":"Yabebyry"},
{"value":"Pilar","label":"Pilar"},{"value":"Alberdi","label":"Alberdi"},{"value":"Cerrito","label":"Cerrito"},{"value":"Desmochados","label":"Desmochados"},{"value":"General José Eduvigis Díaz","label":"General José Eduvigis Díaz"},{"value":"Guazú Cuá","label":"Guazú Cuá"},{"value":"Humaitá","label":"Humaitá"},{"value":"Isla Umbú","label":"Isla Umbú"},{"value":"Laureles","label":"Laureles"},{"value":"Mayor José de J. Martínez","label":"Mayor José de J. Martínez"},{"value":"Paso de Patria","label":"Paso de Patria"},{"value":"San Juan Bautista del Ñeembucú","label":"San Juan Bautista del Ñeembucú"},{"value":"Tacuaras","label":"Tacuaras"},{"value":"Villa Franca","label":"Villa Franca"},{"value":"Villa Oliva","label":"Villa Oliva"},{"value":"Villalba","label":"Villalba"},
{"value":"Paraguarí","label":"Paraguarí"},{"value":"Acahay","label":"Acahay"},{"value":"Carapeguá","label":"Carapeguá"},{"value":"Escobar","label":"Escobar"},{"value":"General Bernardino Caballero","label":"General Bernardino Caballero"},{"value":"La Colmena","label":"La Colmena"},{"value":"Mbuyapey","label":"Mbuyapey"},{"value":"Quiindy","label":"Quiindy"},{"value":"Quyquyhó","label":"Quyquyhó"},{"value":"San Roque González de Santa Cruz","label":"San Roque González de Santa Cruz"},{"value":"Sapucaí","label":"Sapucaí"},{"value":"Tebicuarymí","label":"Tebicuarymí"},{"value":"Ybycuí","label":"Ybycuí"},{"value":"Ybytymí","label":"Ybytymí"},{"value":"Yaguarón","label":"Yaguarón"},
{"value":"Villa Hayes","label":"Villa Hayes"},{"value":"Benjamín Aceval","label":"Benjamín Aceval"},{"value":"José Falcón","label":"José Falcón"},{"value":"Nanawa","label":"Nanawa"},{"value":"Nueva Asunción","label":"Nueva Asunción"},{"value":"Pozo Colorado","label":"Pozo Colorado"},{"value":"Puerto Pinasco","label":"Puerto Pinasco"},{"value":"Teniente Primero Manuel Irala Fernández","label":"Teniente Primero Manuel Irala Fernández"},{"value":"Villa del Río","label":"Villa del Río"},
{"value":"San Pedro del Ycuamandiyú","label":"San Pedro del Ycuamandiyú"},{"value":"Antequera","label":"Antequera"},{"value":"Choré","label":"Choré"},{"value":"General Elizardo Aquino","label":"General Elizardo Aquino"},{"value":"Guayaibí","label":"Guayaibí"},{"value":"Itacurubí del Rosario","label":"Itacurubí del Rosario"},{"value":"Lima","label":"Lima"},{"value":"Nueva Germania","label":"Nueva Germania"},{"value":"Río Verde","label":"Río Verde"},{"value":"San Estanislao (Santaní)","label":"San Estanislao (Santaní)"},{"value":"Tacuatí","label":"Tacuatí"},{"value":"Unión","label":"Unión"},{"value":"Villa del Rosario","label":"Villa del Rosario"},{"value":"Yataity del Norte","label":"Yataity del Norte"}
]'::jsonb);
-- A3: Barrio (text_short, opcional — antes era "Sucursal o sede")
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required)
VALUES ('40000000-0000-0000-0000-000000000003','30000000-0000-0000-0000-000000000001',
'A3','text_short','Sucursal o sede',3,false,false);
'A3','text_short','¿En qué barrio vivís? (opcional)',3,false,false);
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
VALUES ('40000000-0000-0000-0000-000000000004','30000000-0000-0000-0000-000000000001',
'A4','single_choice','¿En qué área o gerencia trabajás?',4,false,false,
'[{"value":"Operaciones/Producción","label":"Operaciones/Producción"},
'[{"value":"Directorio","label":"Directorio"},
{"value":"Gerencia","label":"Gerencia"},
{"value":"Operaciones/Producción","label":"Operaciones/Producción"},
{"value":"Comercial/Ventas","label":"Comercial/Ventas"},
{"value":"Administración/Finanzas","label":"Administración/Finanzas"},
{"value":"Recursos Humanos/Cultura","label":"Recursos Humanos/Cultura"},
@@ -146,6 +193,7 @@ VALUES ('40000000-0000-0000-0000-000000000010','30000000-0000-0000-0000-00000000
{"value":"Andador","label":"Andador"},
{"value":"Muletas","label":"Muletas"},
{"value":"Prótesis","label":"Prótesis"},
{"value":"Tecnología asistiva","label":"Tecnología asistiva"},
{"value":"No utilizo","label":"No utilizo"}]'::jsonb,
'[{"if_question":"1.1","op":"eq","value":"Sí","action":"show"}]'::jsonb);