# Quov web pages: instructions for AI agents

Use this file when building or editing a Quov web page: the marketing site at `quov.io` (Astro and Tailwind CSS 4) or any other public page. Load `quov-brand.en.md` first (https://quov.io/design-system/quov-brand.en.md); this file applies the brand to the screen and never overrides it.

Logo files are listed in the brand file and served from `https://quov.io/design-system/logo/` (`quov-mark-dark.svg`, `quov-mark-light.svg`, `quov-letters.svg`, plus PNG at 32 to 1024 px). Never redraw the mark.

## Stance

The page reads like a datasheet from a serious supplier: ruled structure, data set as data, plain statements of what is delivered. It is a brand surface: it communicates, it does not sell. A visitor should leave knowing who Quov is, the four ways it serves a company, and how to start a conversation.

The signature idea: the mark is four letters in a 2×2 grid, and Quov offers four things, so the hero carries a ruled 2×2 index of the four lines of business. The logo's structure becomes the page's structure. Every section after it is built differently (a ledger, a sequence, a spec list), so the page never becomes a grid of cards.

## Tokens

In the Quov site every token lives in `src/styles/globals.css`, with the same names as the product apps. Components use the Tailwind names, never a literal color. Outside the site, start from this block (Tailwind CSS 4):

```css
@import 'tailwindcss';
@import '@fontsource/aoboshi-one/latin-400.css';
@import '@fontsource-variable/geist';
@import '@fontsource-variable/geist-mono';

/* The paper theme applies when <html> carries data-theme="light". */
@custom-variant light (&:where([data-theme='light'], [data-theme='light'] *));

@theme inline {
  --font-heading: 'Aoboshi One', ui-serif, Georgia, serif;
  --font-sans: 'Geist Variable', 'Geist', ui-sans-serif, system-ui, sans-serif;
  --font-mono: 'Geist Mono Variable', 'Geist Mono', ui-monospace, Menlo, monospace;

  --radius-sm: calc(var(--radius) * 0.6);
  --radius-md: calc(var(--radius) * 0.8);
  --radius-lg: var(--radius);

  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-card: var(--card);
  --color-card-foreground: var(--card-foreground);
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  --color-secondary: var(--secondary);
  --color-secondary-foreground: var(--secondary-foreground);
  --color-muted: var(--muted);
  --color-muted-foreground: var(--muted-foreground);
  --color-border: var(--border);
  --color-input: var(--input);
  --color-ring: var(--ring);
  --color-mark: var(--mark);
}

@theme {
  --ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);
}

/* Dark (default): cold slate, hue 260. */
:root {
  color-scheme: dark;
  --radius: 0.375rem;
  --background: oklch(0.11 0.01 260);
  --foreground: oklch(0.93 0.01 260);
  --card: oklch(0.15 0.01 260);
  --card-foreground: oklch(0.93 0.01 260);
  --primary: oklch(0.93 0 0);
  --primary-foreground: oklch(0.13 0 0);
  --secondary: oklch(0.2 0.01 260);
  --secondary-foreground: oklch(0.85 0.01 260);
  --muted: oklch(0.2 0.01 260);
  --muted-foreground: oklch(0.64 0.01 260);
  --border: oklch(1 0 0 / 10%);
  --input: oklch(1 0 0 / 12%);
  --ring: oklch(0.55 0.01 260);
  --mark: oklch(0.06 0.005 260);
}

/* Light: sugar-cane paper, hue 75. */
:root[data-theme='light'] {
  color-scheme: light;
  --background: oklch(0.95 0.02 75);
  --foreground: oklch(0.18 0.01 75);
  --card: oklch(0.98 0.015 75);
  --card-foreground: oklch(0.18 0.01 75);
  --primary: oklch(0.18 0 0);
  --primary-foreground: oklch(0.95 0.02 75);
  --secondary: oklch(0.91 0.02 75);
  --secondary-foreground: oklch(0.25 0.01 75);
  --muted: oklch(0.91 0.02 75);
  --muted-foreground: oklch(0.48 0.01 75);
  --border: oklch(0 0 0 / 10%);
  --input: oklch(0 0 0 / 8%);
  --ring: oklch(0.48 0.02 75);
  --mark: oklch(0.995 0.005 75);
}

@layer base {
  * {
    border-color: var(--color-border);
  }
  html {
    scroll-behavior: smooth;
    scroll-padding-top: 5rem;
  }
  body {
    background-color: var(--color-background);
    color: var(--color-foreground);
    font-family: var(--font-sans);
    font-size: 1.0625rem;
    line-height: 1.65;
  }
  [data-theme='light'] body {
    line-height: 1.6;
  }
  h1,
  h2 {
    font-family: var(--font-heading);
    font-weight: 400;
    text-wrap: balance;
  }
  :focus-visible {
    outline: 2px solid var(--color-ring);
    outline-offset: 3px;
  }
}
```

| Tailwind                             | Use                                                                               |
| ------------------------------------ | --------------------------------------------------------------------------------- |
| `bg-background`                      | The page. The only page background: sections do not alternate bands.              |
| `bg-card`                            | One step of elevation: a screenshot mat, code, an open sheet.                     |
| `bg-secondary`                       | Subtle fills: hover on a ghost control, a tag.                                    |
| `text-foreground`                    | Text, the current navigation item, the letters of the mark.                       |
| `text-muted-foreground`              | Leads, captions, metadata, inactive navigation.                                   |
| `bg-primary text-primary-foreground` | The primary button. One per view.                                                 |
| `border-border`                      | Every hairline, rule and frame.                                                   |
| `font-heading`                       | Aoboshi One. `h1` and `h2` get it from the base layer.                            |
| `font-sans`                          | Geist, the default.                                                               |
| `font-mono`                          | Geist Mono, for data only. Add `tabular-nums` to figures.                         |
| `rounded-lg`                         | `0.375rem`, controls and frames. `rounded-md` and `rounded-sm` for smaller parts. |
| `ease-out-quint`                     | The only easing.                                                                  |
| `light:`                             | Variant for the paper theme.                                                      |

## Type scale

In `apps/website` the fluid steps are Tailwind theme sizes defined in `src/styles/globals.css`; each one carries its own line height and tracking.

| Level    | Classes                                        | Value                                                    | Where                                                  |
| -------- | ---------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------ |
| Display  | `font-heading text-display`                    | `clamp(2.25rem, 1.2rem + 3.4vw, 4.5rem)`, 1.06, -0.015em | The hero statement, once per page                      |
| Title    | `font-heading text-title` (h2 default font)    | `clamp(1.75rem, 1.3rem + 1.8vw, 3rem)`, 1.1, -0.01em     | Section titles, the contact title                      |
| Subtitle | `font-heading text-subtitle`                   | `clamp(1.375rem, 1.25rem + 0.5vw, 1.625rem)`, 1.25       | Product names, step titles, the reference project name |
| Lead     | `text-lead`                                    | `clamp(1.125rem, 1.07rem + 0.25vw, 1.25rem)`, 1.6        | The paragraph under a section title                    |
| Body     | default                                        | `1.0625rem`, 1.65 on slate, 1.6 on paper, `max-w-[65ch]` | Running text                                           |
| Label    | `text-xs font-medium uppercase tracking-wider` | `0.75rem`                                                | Table header cells, small labels                       |
| Data     | `font-mono text-[0.8125rem] tabular-nums`      | `0.8125rem`                                              | Indexes, statuses, domains, the language switch        |

Heading steps keep at least a 1.25 ratio at every width. Body text never goes below 16 px.

## Layout

- **Container:** the `container-page` utility: `max-width: 76rem`, centered, gutters of 1rem on phones, 1.5rem from 40rem wide, 2rem from 64rem.
- **Section rhythm:** the `section-y` utility, `padding-block: clamp(4rem, 2.75rem + 5vw, 7.5rem)`. Sections sit on the page background and are separated by one hairline (`border-t border-border`). Generous space between sections, tight grouping inside them.
- **Section head:** a mono index (`01` to `04`) in `text-muted-foreground`, the title in Aoboshi One, then a lead in `text-muted-foreground` under 65 characters.
- **Composition:** asymmetric two columns from `lg` (the head on the narrow side, the content on the wide side), a single column on phones.
- **Depth:** borders only. No shadows, no nested containers.
- **Anchors:** the header is fixed, so anchored sections keep `scroll-padding-top: 5rem`.

## Components

Before building something new, use one of these.

- **Header:** fixed, on `bg-background`; a bottom hairline appears once the page scrolls. Left: the mark and the "Quov" wordmark, linking home. Then four anchor links (Products, Software, Infrastructure, Devices; in Spanish: Productos, Software a la medida, Infraestructura, Dispositivos), the EN / ES switch in mono, the theme toggle (an icon button), and one primary button, "Schedule a call" ("Agendar una llamada"). Below `lg`, the anchors, the switch and the toggle move into a side sheet opened by a menu button.
- **Hero:** left, the statement in Display ("From the first line of code to the last device." / "De la primera línea de código al último dispositivo."), a short lead on what Quov is to a company (one provider that designs, builds and keeps the technology running), never a list of the four lines, which the index already carries, and two actions: the primary "Schedule a call" and `contact@quov.io` as a mono mailto link. Right (below on phones), the 2×2 index.
- **2×2 index:** a square-cornered ruled grid of four cells (`grid grid-cols-2 border-t border-l`, each cell `border-r border-b`). Each whole cell is a link to its section and holds a mono index (`01`) with a small down-right arrow, the line's name in Aoboshi One, and one short line in `text-muted-foreground`. Hover tints the cell with `bg-card`. The cells enter once, staggered.
- **Ledger table:** for products. Columns: name (Aoboshi One), what it does, who it is for, status (mono, for example "By invitation" / "Por invitación"), link (mono, with an up-right arrow). Header cells in mono `text-xs text-muted-foreground` over a hairline; hairlines between rows. On phones each row stacks. A row without a link shows nothing in that cell, never a disabled-looking control. A note may sit under the table in Small.
- **Spec list:** a two-column ruled list (term, description) for capabilities: `dl` with one row per item, the term in `font-medium`, the description in `text-muted-foreground`. Never cards.
- **Numbered sequence:** for steps that happen in order, and only then. Each step: a mono index, a title in Aoboshi One, one line. Four columns from `lg` under one rule; a ruled list on phones.
- **Framed screenshot:** a real page, captured 1600 px wide, in grayscale (`grayscale`), inside a `rounded-md border` frame whose top bar shows the domain in mono over a hairline. The link sits beside it in mono. Alt text in each language says what the image shows. Under the products ledger, one framed screen per product sits three across (stacked on phones), in the ledger's order, with the product name as caption.
- **Reference project:** shipped work as proof, placed under the line of business it proves (a tailored build under Tailored software, an infrastructure build under Infrastructure). A label, the project name in Subtitle, a one-sentence summary in Lead, a short body, a ruled facts list (Client, with the client's official name; Delivered; Site) and its framed screenshot. Consecutive references put the screenshot on alternating sides.
- **Contact block:** the title "Schedule a call" / "Agenda una llamada" in Aoboshi One, a short lead inviting the visitor to say what they need and stating that the first call defines scope and next steps, the booking link as the primary action, and `contact@quov.io` as the secondary one.
- **Footer:** the mark and wordmark, one line on what Quov does, the four anchors, the language switch, a "Design system" link, `contact@quov.io`, and `© <year> Quov S.A.S.`. No identification number.
- **Buttons and links:** primary `rounded-md bg-primary font-medium text-primary-foreground hover:bg-primary/90`, `h-12 px-6 text-base` with a trailing arrow in page sections and `h-9 px-4 text-sm` in the header; secondary `rounded-md border border-border font-medium hover:bg-secondary` at the same sizes. Text links use the `link-rule` utility: a 1px underline at 40% of the text color, offset 0.25em, that turns solid on hover. Data links (domains, email addresses) are mono. External links add a small up-right arrow (lucide `ArrowUpRight`).
- **Icons:** lucide only, 16 px, beside a label. Never an inline hand-drawn SVG icon, never a row of decorative icons.

Never build an identical grid of icon cards, a hero metric block, a logo wall, a testimonial carousel or a pricing table.

## Motion

Quiet: two moments in the whole site.

- **Entrance:** the hero's 2×2 index only. Each cell fades in and rises a few pixels, staggered, with `ease-out-quint`. Opacity and transform only.
- **Theme switch:** a 300 ms crossfade of `color`, `background-color` and `border-color`.
- **Never:** scroll-triggered reveals, parallax, hover lifts, bounce or elastic easing, animated layout properties.
- `prefers-reduced-motion: reduce` collapses every animation and transition to an instant change.

## Languages

- English at `/`, Spanish under `/es`. The same page exists in both, complete. A new string ships in both languages at once.
- `<html lang="en">` and `<html lang="es-CO">`. `og:locale` `en_US` and `es_CO`, each with the other as `og:locale:alternate`. `<link rel="alternate" hreflang="en|es|x-default">` on both, and a canonical per locale.
- Routes, URL segments and anchor ids stay English in both languages: `#products`, `#software`, `#infrastructure`, `#devices`, `#contact`.
- The EN / ES switch, in mono, links to the same page in the other language and marks the current one with `aria-current`.
- Copy lives in one typed dictionary per locale; the Spanish dictionary is typed from the English one, so a missing key fails the build.
- Register: English without contractions; Spanish with _tú_.
- "Schedule a call" points to the booking page. Until one exists, every such control is a `mailto:contact@quov.io` link with a subject in the page's language.

## Themes

- Dark is the default for every first visit. The operating system preference is not consulted.
- A header icon button switches themes. Its accessible label is in the page's language and names the target ("Switch to light theme" / "Cambiar a tema claro"), and it carries `aria-pressed`.
- The choice is stored in `localStorage` under `quov-theme`, every access wrapped in `try/catch`. Without storage the site stays dark and still works.
- No flash: a small inline script in `<head>` applies the stored theme before the first paint.
- `<meta name="theme-color">` carries both theme backgrounds, and the toggle updates it.

```html
<script>
  try {
    if (localStorage.getItem('quov-theme') === 'light') {
      document.documentElement.dataset.theme = 'light';
    }
  } catch {
    /* No storage: the page stays dark. */
  }
</script>
```

## Accessibility

- WCAG 2.2 AA in both themes, checked with a contrast computation, not assumed. The brand file lists the ratios of every token pair.
- Focus is always visible: 2 px `--ring` outline, 3 px offset.
- The header and the sheet are reachable and operable by keyboard.
- One `h1` per page, `h2` per section, `h3` for items. Decorative SVG carries `aria-hidden="true"`.

## Copy

- Statements, not slogans. Leads say what the visitor gets, in one or two sentences.
- No em dashes, no superlatives, no prices, no competitor names, no invented figures, no people.
- English without contractions, Spanish with _tú_.

## Before you finish

1. View the page at 375 px and 1440 px wide, in both themes and both languages.
2. Reload after switching to paper: the theme persists with no flash, and the page still works with storage blocked.
3. Confirm every color is a token, every heading is Aoboshi One, and mono appears only on data.
4. Re-read both languages for em dashes, contractions, _usted_, superlatives and invented figures.
