/* Espace client — vocal-ia
 *
 * This wears the vocal-ia.ch charter: sand ground, cream cards floating on it with one
 * large soft shadow and no borders at all, brick red for the brand, rounded corners on
 * anything you touch. A client who leaves the marketing site and lands here must not feel
 * they changed supplier. The tokens below are the site's own, copied verbatim from
 * ../Website_v0.2/styles.css, so the two can be compared value by value.
 *
 * The thesis of the PAGE has not changed: it is a METER, not a dashboard. The product's
 * central artifact is a minute spent against an allowance, which is the oldest idea in
 * telephony, so the hero is one full-width horizontal meter that IS the month - not a grid
 * of stat cards.
 *
 * WHAT CHANGED, AND WHY, 28 Aug 2026. This file used to argue that overage must have no
 * colour of its own, and specifically that it must avoid brand red because "an overage is
 * an invoice, not a fault". The meter is now brand red, deliberately: an espace client has
 * to be recognisable before it is clever, and the marketing site's single accent is the
 * thing that makes it recognisable. Two parts of the old argument survive and are still
 * load-bearing:
 *
 *   - The overage is still HATCHED, in the same red. Hatching says "the same thing,
 *     continuing past the boundary", which is what actually happened; a second colour would
 *     say "a different thing", which is false.
 *   - Red now means two things - consumption and action - so they are separated by FORM,
 *     not hue. The meter is flat, square-cornered, unshadowed. The button is rounded at
 *     12px and carries a red glow. Errors keep the site's own #a00, never --primary.
 *
 * No web fonts, and this is not a divergence from the charter - the marketing site has none
 * either. Fetching a face from a third party sends every client's IP address to that third
 * party on every visit, which on a portal governed by the nLPD/GDPR is a processor to
 * declare in exchange for decoration. The site's stack, verbatim, is a system stack.
 */

:root {
    /* --- vocal-ia.ch, verbatim. Compare against ../Website_v0.2/styles.css --- */
    --bg:          #f6d19c;   /* the page: sand */
    --card:        #fff3e0;   /* every surface: cream */
    --ink:         #2b1d14;   /* body text - dark warm brown, never black */
    --ink-soft:    #4b3a32;   /* secondary prose (the site's .lead colour) */
    --ink-faint:   #6a4e42;   /* eyebrows, table heads, footer (the site's --muted) */
    --rule:        #d9c8b9;   /* every hairline and field border */
    --primary:     #d5443f;
    --primary-600: #b73632;
    --accent:      #f5b041;   /* the amber of the site's badge */

    --radius:      16px;                          /* cards */
    --radius-btn:  12px;                          /* buttons */
    --radius-in:   10px;                          /* fields */
    --shadow:      0 12px 40px rgba(0,0,0,.16);
    --shadow-btn:  0 6px 16px rgba(213,68,63,.28);
    --maxw:        1120px;

    /* --- extensions: things the marketing site never had to name --- */

    /* The meter's ink. One hue, two treatments: solid inside the allowance, hatched past
       it. See the header note for why this is now the brand red. */
    --meter: var(--primary);

    /* The trough, and the ground of .notice: cream pulled toward the sand behind it, so an
       unspent allowance reads as the page showing through rather than as a fourth colour. */
    --sunk: #f7e6cf;

    /* The site's only error colour (#form-err on its contact form). Deliberately not
       --primary: an error must not look like a call to action. */
    --danger: #a00;

    /* Tabular figures everywhere a quantity appears: durations, minutes, francs and phone
       numbers all want to line up in a column, and misaligned phone numbers are genuinely
       harder to compare. The marketing site has no data table, so it says nothing on the
       subject - this is an extension where the charter is silent, not a divergence. */
    --mono: ui-monospace, "SF Mono", "Cascadia Mono", "Segoe UI Mono", Consolas, monospace;
    --sans: system-ui, -apple-system, "Segoe UI", Roboto, Inter, Arial, sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

/* NB: the marketing site carries `html, body { overflow-x: hidden }` to clip the overhang of
   its scroll-reveal animations. It is deliberately NOT copied here - there is no reveal to
   clip, and overflow on the root element breaks `position: sticky` on the masthead. */

body {
    margin: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: var(--sans);
    font-size: 16px;
    line-height: 1.4;
}

/* Numbers are data. Give every one of them the same column discipline. */
.num, .meter__scale, .ledger td, .ledger th, .days__scale {
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* --primary is about 4.3:1 on cream, under AA for small text. The site gets away with it
   because it only ever sets red at size (1.6rem prices, buttons); a 0.875rem link is a
   different question. --primary-600 passes, and the pair still reads as one hue. */
a { color: var(--primary-600); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--primary); }

/* The site styles no focus state at all. Reproducing that omission on a login form would be
   an accessibility regression, not fidelity. */
:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

/* ---------------------------------------------------------------- shell */

.shell { width: min(92vw, var(--maxw)); margin-inline: auto; }

/* The site's header: full bleed, sticky, cream lightened toward white. The flat fallback is
   declared first on purpose - same pattern as the site, so a browser without color-mix gets
   the panel colour rather than a transparent bar over scrolling content. */
.masthead {
    position: sticky;
    top: 0;
    z-index: 50;
    background: var(--card);
    background: color-mix(in oklab, var(--card) 88%, white);
    border-bottom: 1px solid rgba(0,0,0,.06);
    backdrop-filter: saturate(130%) blur(6px);
}

.masthead__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.75rem 0;
    flex-wrap: wrap;
}

.wordmark { display: inline-flex; align-items: center; text-decoration: none; }
.wordmark img { height: 56px; display: block; }

.masthead__who {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.9375rem;
    color: var(--ink-soft);
}

/* The site's nav idiom: a full pill that only shows its ground on hover. */
.pill {
    display: inline-block;
    padding: 0.5rem 0.8rem;
    border-radius: 999px;
    text-decoration: none;
    color: var(--ink);
    transition: background 0.2s ease;
}
.pill:hover { background: rgba(0,0,0,.06); color: var(--ink); }

/* An eyebrow only earns its place when it carries information. Here it is the billing
   period, which is the single fact that scopes every number below it. Same shape as the
   site's .kicker, kept at 0.75rem because .kicker inherits 16px and that is far too large
   for a label sitting above the figure it qualifies. */
.eyebrow {
    font-size: 0.75rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-faint);
    margin: 0 0 0.75rem;
    font-weight: 600;
}

/* Sections are the site's cards: cream on sand, one big soft shadow, and NO border. That
   shadow doing all the separation work is the charter's defining structural gesture.
   Padding is .hero .panel's, not .card's 1.1rem - a section holding a full-width meter is
   not a thumbnail. */
main.shell { padding-top: 1.5rem; padding-bottom: 1rem; }

section {
    background: var(--card);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: clamp(1.2rem, 2.5vw, 2rem);
    margin-bottom: clamp(1rem, 2vw, 1.5rem);
}

/* ---------------------------------------------------------------- the meter */

/* Square corners, inside a rounded card. The charter's rounding is for surfaces you touch -
   cards, buttons, pills; a measurement stays square. Two concrete reasons beyond taste: a
   2% fill under a 10px radius is unreadable, and the `overflow: hidden` that clipping a
   rounded fill would need also clips the boundary tick's overshoot below, which is the
   thing that makes it read as a graduation rather than a partition. */
.meter {
    position: relative;
    display: flex;
    height: 3.5rem;
    background: var(--sunk);
    border: 1px solid var(--rule);
}

.meter__used { background: var(--meter); }

/* Past the allowance: same ink, hatched. Not a second colour. */
.meter__over {
    background: repeating-linear-gradient(
        135deg,
        var(--meter) 0 5px,
        var(--sunk) 5px 10px
    );
}

/* The boundary itself, drawn as a hard rule rather than implied by a colour change. It
   overshoots the bar top and bottom so it reads as a tick, not an internal divider. */
.meter__bound {
    position: absolute;
    top: -0.375rem;
    bottom: -0.375rem;
    width: 2px;
    background: var(--ink);
}

/* The instrument draws itself, left to right, in the site's own 0.7s ease. A shutter that
 * retracts rightward, rather than scaling the bars: scaling would squash the 135deg hatch
 * while it ran. The inset overshoots by 1px horizontally and 0.5rem vertically so the
 * meter's own border and the boundary tick are covered too - nothing appears ahead of it.
 *
 * THE DIRECTION OF THE DEFAULT STATE IS LOAD-BEARING. The base is scaleX(0) - revealed -
 * and the keyframe starts from scaleX(1). Written the other way round (scaleX(1) base plus
 * `forwards`), the prefers-reduced-motion rule at the foot of this file, which kills all
 * animation, would freeze the shutter CLOSED and hide the meter permanently from exactly
 * the users who asked for less movement. */
.meter::after {
    content: "";
    position: absolute;
    inset: -0.5rem -1px;
    background: var(--card);
    transform: scaleX(0);
    transform-origin: right;
    animation: meter-reveal 0.7s ease;
}

@keyframes meter-reveal { from { transform: scaleX(1); } }

.meter__scale {
    display: flex;
    justify-content: space-between;
    font-size: 0.75rem;
    color: var(--ink-faint);
    margin-top: 0.5rem;
}

.readout {
    margin: 1.5rem 0 0;
    font-size: clamp(1.1875rem, 2vw, 1.375rem);
    line-height: 1.45;
    max-width: 34em;
}
.readout .num { font-weight: 700; }
.readout--over .over { white-space: nowrap; }

.footnote { margin: 0.625rem 0 0; font-size: 0.875rem; line-height: 1.55; color: var(--ink-soft); }

/* ---------------------------------------------------------------- daily bars */

/* The same bar language, turned ninety degrees. One column per day - which is why these
   take --meter and not a colour of their own: splitting the hue would break the parentage. */
.days {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    height: 5.5rem;
    border-bottom: 1px solid var(--rule);
}

.day { flex: 1 1 0; min-width: 3px; background: var(--meter); opacity: 0.85; transition: opacity 0.2s ease; }
/* The !important beats the inline height:0% the template writes, so a day with no call
   still shows a 1px baseline tick rather than vanishing. Load-bearing; do not strip it. */
.day--empty { background: var(--rule); height: 1px !important; opacity: 1; }
.day:hover { opacity: 1; }

.days__scale {
    display: flex;
    justify-content: space-between;
    font-size: 0.75rem;
    color: var(--ink-faint);
    margin-top: 0.5rem;
}

/* ---------------------------------------------------------------- the ledger */

.ledger { width: 100%; border-collapse: collapse; font-size: 0.9375rem; }

.ledger th {
    text-align: left;
    font-weight: 600;
    font-size: 0.75rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-faint);
    padding: 0 0 0.625rem;
    border-bottom: 1px solid var(--rule);
}

.ledger td { padding: 0.6875rem 0; border-bottom: 1px solid var(--rule); }
.ledger tr:last-child td { border-bottom: 0; }
.ledger .r { text-align: right; }
.ledger .muted { color: var(--ink-faint); }

.pager {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    margin-top: 1.25rem;
    font-size: 0.875rem;
    color: var(--ink-soft);
}

/* ---------------------------------------------------------------- forms */

/* Flex column, not grid. With `display: grid; place-content: center` the tracks size to
   their content, so the card's `width: 100%` and the track width define each other in a
   circle as soon as the logo sits beside it. A column flex resolves the card against the
   container and lets max-width do the capping. */
.gate {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 2rem 1.5rem;
}

.gate__logo { height: 56px; display: block; margin: 0 auto 1.5rem; }

.gate__card {
    width: 100%;
    max-width: 24rem;
    background: var(--card);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: clamp(1.5rem, 3vw, 2rem);
}

.gate h1 {
    font-size: 1.5rem;
    margin: 0 0 0.375rem;
    font-weight: 800;
    line-height: 1.2;
}

.gate p { margin: 0 0 1.75rem; color: var(--ink-soft); font-size: 0.9375rem; line-height: 1.55; }

.gate__foot { margin-top: 1.25rem; margin-bottom: 0; }

label {
    display: block;
    font-size: 0.8125rem;
    font-weight: 600;
    margin-bottom: 0.375rem;
    color: var(--ink);
}

input[type="email"], input[type="password"] {
    width: 100%;
    padding: 0.7rem;
    font: inherit;
    color: var(--ink);
    background: #FFF;
    border: 1px solid var(--rule);
    border-radius: var(--radius-in);
    margin-bottom: 1rem;
}
input:focus-visible { border-color: var(--primary); }

/* The site's button, verbatim, plus a transition it does not have on .btn but does have on
   its 404 page - and which the motion vocabulary chosen here justifies. The 2px border is
   the same colour as the fill, so it reads as extra padding rather than an outline. */
.btn {
    width: 100%;
    padding: 0.9rem 1.1rem;
    font: inherit;
    font-weight: 700;
    color: #FFF;
    background: var(--primary);
    border: 2px solid var(--primary);
    border-radius: var(--radius-btn);
    box-shadow: var(--shadow-btn);
    cursor: pointer;
    transition: background 0.2s ease, border-color 0.2s ease;
}
.btn:hover { background: var(--primary-600); border-color: var(--primary-600); }

/* Errors state what happened and what to do. They do not apologise and are never vague.
   --danger, never --primary: the button beside it is the brand red, and an error that
   borrows the call-to-action's colour is telling the reader to press it. */
.notice {
    padding: 0.7rem 0.875rem;
    margin-bottom: 1.25rem;
    font-size: 0.875rem;
    line-height: 1.5;
    border-left: 3px solid var(--danger);
    border-radius: var(--radius-in);
    background: var(--sunk);
}

.empty { color: var(--ink-soft); font-size: 0.9375rem; line-height: 1.55; margin: 0; }

/* ---------------------------------------------------------------- footer */

/* Mirrors the masthead, exactly as the site's footer mirrors its header: same tint, same
   hairline, no shadow. */
.siteftr {
    margin-top: 3rem;
    background: var(--card);
    background: color-mix(in oklab, var(--card) 88%, white);
    border-top: 1px solid rgba(0,0,0,.06);
    padding: 1.5rem 0;
    font-size: 0.875rem;
    line-height: 1.55;
    color: var(--ink-faint);
}
.siteftr p { margin: 0 0 0.35rem; }
.siteftr p:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------- responsive */

@media (max-width: 40rem) {
    .wordmark img, .gate__logo { height: 40px; }
    .readout { font-size: 1.1875rem; }
    .meter { height: 2.75rem; }
    /* The Heure column is the first thing to go: on a phone, the day and the duration are
       what a caller's record is for. */
    .ledger .drop { display: none; }
}

/* The meter shutter's base state is scaleX(0), so killing animation here leaves the meter
   fully visible. See the note on .meter::after - the inverse spelling would hide it. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { animation: none !important; transition: none !important; }
}
