/* ════════════════════════════════════════════════════════════════════
   THE HOUSE — 2026-08-21.

   arroweb has four shells: `home/base.html`, `funnel/shell.html`,
   `brief/shell.html`, `brief/shell_product.html`. Four things are the same
   building in all four, and this file is those four:

     1. THE PALETTE      — the note, the action, the ground;
     2. THE MENU         — the launcher, the sheet, the way home;
     3. THE TILE GRAMMAR — how a destination is drawn;
     4. THE BAND + THE BUTTON — how every page after the front door is built.

   It exists because the funnel and the brief do NOT load `style.css`, and the
   day the menu partial started emitting tiles instead of rows, two of the four
   shells quietly lost their menu's stylesheet: they were still carrying a
   hand-copied version of the OLD nav CSS, whose `.nav-grid a` out-specified
   the tiles it no longer matched. A copy is not a shared definition. This is
   the shared definition.

   ⚠ LOAD IT FIRST, before the shell's own stylesheet — the palette has to be
   defined before anything reads `var(--note)`.
   ════════════════════════════════════════════════════════════════════ */

/* ════════════════════════════════════════════════════════════════════
   THE PALETTE — the pass that retired the gold.

   There used to be eight accent tokens. `--bordeaux`, `--bordeaux-bright`,
   `--rose`, `--sage` and `--w-gradient` all held the same #c8a15a, and not one
   of those names described it. That is how a palette dies: a name stops
   matching its value, so the next person reuses it for the next thing, until
   the site has five words for one colour and no word for what it MEANS.

   There are two now, and they mean something.
   ════════════════════════════════════════════════════════════════════ */
:root {
    /* ── The ground ──────────────────────────────────────────────── */
    --bg-base: #0c0e13;
    --bg-deep: #060410;
    --text-primary: #f3ecf0;
    --text-secondary: #c5b8c0;
    --text-muted: #968a92;

    /* ── THE NOTE — the colour of WHERE YOU ARE ───────────────────
       One per page, sampled from the Arrow spectrum exactly as the front
       door's categories are, and it carries that page's section labels,
       icons, edges and glows. Colour CLASSIFIES on this site; it does not
       decorate.

       Two forms of one colour, because CSS cannot take an alpha off a hex:
       `--note` to paint with, `--note-rgb` to compose with —
       `rgb(var(--note-rgb) / 0.35)`.

       The default is steel — the neutral the lockup's own halo is lit with —
       so a page that has not declared its group reads sober rather than
       wrong. */
    --note: #9aa8c2;
    --note-rgb: 154 168 194;

    /* ── THE ACTION — her pink, and it never varies ───────────────
       The note says where you are. The action says what happens if you press.
       It is the pink the ROSE half of the lockup ends on, it is the same on
       every page, and nothing that is not an action wears it — which is what
       makes it readable at a glance. `--act-ink` is what goes on top when the
       pink is a fill instead of an edge. */
    --act: #cf7f9c;
    --act-rgb: 207 127 156;
    --act-ink: #180a11;

    /* The Arrow spectrum, whole. It belongs to the MARK and to nothing else —
       the launcher's glow, the lockup's halo. A rainbow behind content is
       noise; behind the logo it is the logo. */
    --logo-gradient: linear-gradient(100deg, #7b2ff7 0%, #d81b8c 21%, #e8451e 40%, #f2a800 57%, #4fb03a 76%, #1ca9e0 100%);

    /* ── The glass ───────────────────────────────────────────────── */
    --surface: rgba(255,255,255,0.045);
    --surface-hover: rgba(255,255,255,0.075);
    --border-soft: rgba(255,255,255,0.10);
    --border-medium: rgba(255,255,255,0.20);
    --shadow-card: 0 18px 44px -22px rgba(0,0,0,0.72);
    --glass-blur: blur(16px) saturate(140%);
    --font: 'Plus Jakarta Sans', sans-serif;
}

/* ── THE FOUR NOTES ───────────────────────────────────────────────────
   The same four the front door groups its destinations by, and the meanings
   are kept over the sequence: money is green, things to read are blue, and
   CONTATTI takes the pink the lockup ends on — which is why a contact page's
   note and its action are the same colour. On a contact page everything IS
   the action.

   Two selectors, one declaration, on purpose:
     · `body.n-*` tints a whole page — set it with `{% block body_note %}`;
     · `.lp-cat--*` tints one category inside a page, which is how the front
       door and the menu sheet paint groups in one document.
   The inner one wins inside its own subtree, which is exactly right. */
body.n-prodotti, .lp-cat--prodotti { --note: #a87ae8; --note-rgb: 168 122 232; }  /* the spectrum's violet end */
body.n-bandi,    .lp-cat--bandi    { --note: #6fae7a; --note-rgb: 111 174 122; }  /* public money */
body.n-studio,   .lp-cat--studio   { --note: #6f9fd0; --note-rgb: 111 159 208; }  /* things to read */
body.n-contatti, .lp-cat--contatti { --note: #cf7f9c; --note-rgb: 207 127 156; }  /* her pink */

/* ── THE WALK — ten notes, and a page uses SEVERAL ────────────────────
   ⚠ READ THIS BEFORE PUTTING A SECOND BAND ON A PAGE.

   Nicolas, twice now: *"on the pages there should NOT be only one colour
   accent. The colours go on the icons and around the tile borders, and they
   have to DIFFER, so it's easy to understand that we're going from section 1
   to section 2 to section 3. Not ONLY PURPLE. Each section in the same page
   with different colours, and even in a section tiles can have different
   colour accents."*

   THE FOUR NOTES ABOVE ARE A PAGE'S STARTING POINT, NOT ITS CEILING. `body.n-*`
   says which GROUP a page belongs to and tints anything that has not said
   otherwise. It was never meant to be the only colour on the page, and reading
   it that way is what produced a wall of violet on the request pages — while
   /web-apps/, one page over, had been walking the spectrum band by band since
   the eleven-doors pass.

   So: **a band declares its own note, and the colour is how you know you have
   moved on a section.** These ten are the Arrow spectrum sampled in reading
   order — coral, rose, orchid, violet, periwinkle, blue, cyan, teal, green,
   olive — the same sweep the eleven archetype tiles use, so a colour means the
   same distance along the wheel wherever it appears.

   ⚠ A NOTE CLASS SETS `--note` ON WHATEVER YOU PUT IT ON. On a `.band` it
   colours that section's kicker, edges and icons; on a single `.band-card` or
   `.lp-tile` it colours just that tile — which is how a set of cards inside
   one band can each carry their own.

   ⚠ THE AMBER SIXTH OF THE WHEEL IS SKIPPED, here as everywhere. That is where
   the retired gold lived, and one band wearing it would read as the gold
   coming back rather than as one note among ten.

   ⚠ THE ACTION'S PINK IS NOT IN THIS WALK. `--act` never varies: the note says
   which section you are in, the action says what happens if you press. `note-2`
   is close to it on purpose — it is the section colour nearest her pink, not
   her pink. */
.note-1  { --note: #d08468; --note-rgb: 208 132 104; }   /* coral      */
.note-2  { --note: #cf7f9c; --note-rgb: 207 127 156; }   /* rose       */
.note-3  { --note: #c583c6; --note-rgb: 197 131 198; }   /* orchid     */
.note-4  { --note: #a87ae8; --note-rgb: 168 122 232; }   /* violet     */
.note-5  { --note: #8b91de; --note-rgb: 139 145 222; }   /* periwinkle */
.note-6  { --note: #6f9fd0; --note-rgb: 111 159 208; }   /* blue       */
.note-7  { --note: #5fb0c6; --note-rgb:  95 176 198; }   /* cyan       */
.note-8  { --note: #5cb0a6; --note-rgb:  92 176 166; }   /* teal       */
.note-9  { --note: #6fae7a; --note-rgb: 111 174 122; }   /* green      */
.note-10 { --note: #8ab86f; --note-rgb: 138 184 111; }   /* olive      */

/* ════════════════════════════════════════════════════════════════════
   THE CROSSING — how one page becomes the next. 2026-08-21.

   Nicolas: *"all across the site I find the transitions very hard between the
   pages — but I don't want the pages to take time either because of animations.
   It's very fast, I don't know... it would be nice to have a smooth website."*

   It is not a feeling and it is not slowness. Three things were happening:

   1. `home/base.html` boosts every link with htmx and swaps the WHOLE BODY's
      innerHTML. The new document is painted in ONE frame with nothing in
      between — which at 40ms reads as a flicker, not as speed. The eye needs
      something continuous to know it is the same site; a hard cut says
      "something went wrong" even when nothing did.
   2. `scroll-behavior: smooth` is on `html` for anchor links — and htmx's
      scroll-to-top after a boosted swap OBEYS IT. So the new page painted,
      and THEN the viewport slid up through it. That is the "glitchy" one.
   3. The two request shells do not boost at all, so /pacchetto-…/ arrived with
      a full document load while everything else soft-swapped. Two different
      motions inside one site read as a fault in the site.

   The fix costs ZERO milliseconds, which was the condition. A view transition
   is not an animation played BEFORE the new page: the browser has already
   painted it and is cross-fading two snapshots on the compositor. The page is
   interactive the whole time. 140ms is a little under the ~150ms where a
   transition stops feeling instant.

     · `@view-transition { navigation: auto; }` covers real navigations — the
       request shells, any hard load, the back button.
     · `<meta name="htmx-config" content='{"globalViewTransitions":true}'>` in
       `home/base.html` covers the boosted ones. It is a meta tag and not a
       script so it cannot lose a race with htmx's own boot.
     · the launcher and the sheet are NAMED, so they are held still and do not
       blink out and back on every page. The chrome stays; the content crosses.

   ⚠ Firefox has no view transitions yet: it simply gets today's behaviour,
   which is the hard cut. Nothing breaks and nothing is slower.
   ⚠ Anything named here must be UNIQUE in the document. `_menu.html` renders
   once per page, which is the reason it was made one partial.
   ════════════════════════════════════════════════════════════════════ */
@view-transition { navigation: auto; }

::view-transition-old(root) { animation: house-out 0.14s ease both; }
::view-transition-new(root) { animation: house-in  0.14s ease both; }
@keyframes house-out { to   { opacity: 0; } }
@keyframes house-in  { from { opacity: 0; } }

/* ⚠ THE CHROME IS NOT NAMED, AND IT WAS. `view-transition-name` on the
   launcher, the sheet and the backdrop was meant to hold them still while the
   content crossed. What it actually did was give each of them ITS OWN SNAPSHOT
   — and all three are `backdrop-filter: blur(14px)` objects, which is a filter
   applied to whatever is BEHIND the element. Lift such an element into a
   separate layer and there is nothing behind it any more, so the blur is
   computed against the wrong thing for the length of the transition and pops
   back when it ends.

   Nicolas: *"the blur animation is a bit weird at page transition."* It was.
   The root crossfade already carries the whole page, chrome included; naming
   the chrome bought nothing and cost exactly this. */

@media (prefers-reduced-motion: reduce) {
    ::view-transition-old(root),
    ::view-transition-new(root) { animation: none; }
}

/* ⚠ AND THE SCROLL DOES NOT ANIMATE ON A NAVIGATION. `scroll-behavior: smooth`
   below is there for in-page anchors — `/come-funziona/#q-prezzo` from the
   front door's question tiles. It must NOT apply while a page is being
   replaced, or the jump to the top of the new page becomes a visible slide
   through content the reader has never seen. `html:active-view-transition`
   is set for exactly the length of a transition, which is exactly the window
   in which htmx and the browser reset the scroll. */
html:active-view-transition { scroll-behavior: auto; }

/* ════════════════════════════════════════════════════════════════════
   THE GROUND, AND THE TYPE — moved out of style.css 2026-08-21.

   These were in `style.css`, which the two request shells do NOT load, so
   /pacchetto-…/ was painting its own flat navy radial and declaring its own
   three weights of Plus Jakarta Sans. Two consequences, both visible:

     · the note-tinted vignette that carries WHICH GROUP a page belongs to
       stopped at the request pages — they were the only dark pages in the
       site with no colour in the air;
     · weight 300 was never declared there, so every `.band-sub` and every
       hint on those pages was synthesised by the browser from 400.

   A copy is not a shared definition. This is the shared definition, and it
   sits with the palette because it IS the palette, applied to the page.
   ════════════════════════════════════════════════════════════════════ */
@font-face {
    font-family: 'Plus Jakarta Sans';
    src: url("../fonts/plus-jakarta-sans-v12-latin-300.aa96939d511b.woff2") format('woff2');
    font-weight: 300; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Plus Jakarta Sans';
    src: url("../fonts/plus-jakarta-sans-v12-latin-regular.503e7cbdb484.woff2") format('woff2');
    font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Plus Jakarta Sans';
    src: url("../fonts/plus-jakarta-sans-v12-latin-600.79e62f3332cd.woff2") format('woff2');
    font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Plus Jakarta Sans';
    src: url("../fonts/plus-jakarta-sans-v12-latin-700.5b629bd8abb4.woff2") format('woff2');
    font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Plus Jakarta Sans';
    src: url("../fonts/plus-jakarta-sans-v12-latin-800.408ecc6630e8.woff2") format('woff2');
    font-weight: 800; font-style: normal; font-display: swap;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
/* No page should ever scroll horizontally — clip (not hidden, so sticky and
   fixed elements still work). */
html, body { overflow-x: clip; }

html {
    background-color: var(--bg-base);
    scroll-behavior: smooth;
}
body {
    font-family: var(--font);
    background-color: transparent;
    color: var(--text-primary);
    font-size: 17px;
    line-height: 1.7;
    text-align: center;
    -webkit-font-smoothing: antialiased;
}
body::before {
    content: '';
    position: fixed;
    top: 0; left: 0;
    width: 100%; height: 100%;
    z-index: -2;
    background-color: var(--bg-base);
    /* One vignette, lit from the page's own note and held at 6% — the
       atmosphere carries the group before a word of it is read, and at that
       strength it never competes with the content sitting on it. */
    background-image:
        radial-gradient(1200px 760px at 50% 26%, rgb(var(--note-rgb) / 0.06), transparent 68%),
        radial-gradient(1200px 760px at 50% 30%, #1a2030 0%, #0c0e13 62%);
    background-repeat: no-repeat;
}

/* ════════════════════════════════════════════════════════════════════
   THE MENU — one launcher, one sheet, four shells
   ════════════════════════════════════════════════════════════════════ */

/* ── THE FOOT OF THE PANEL — the way home, and the language ───────────
   One row, two ends. Nicolas: *"in the panel, the languages on the right side,
   as they are but on the right side, and on the left a little home tile — even
   if the logo is touchable it's not obvious either."*

   ⚠ The lockup at the top of the sheet has ALWAYS been a home link, and the
   partial's own comment used to give that as the reason there was no Home
   tile. A title that happens to be a link is not an affordance anybody can
   see. Both exist now; only one of them is findable, and that is the point. */
.sheet-foot {
    display: flex;
    align-items: center;
    /* Right-aligned as a group (langs, then HOME rightmost): the open
       button owns the bottom-LEFT corner, so nothing here can ever sit
       under it. 2026-08-23, his call. */
    justify-content: flex-end;
    flex-wrap: wrap;
    row-gap: 0.6rem;
    /* clearance for the open/close button parked in the bottom-LEFT corner */
    padding-left: 5.6rem;
    gap: 1rem;
    margin-top: 1.4rem;
    padding-top: 1.1rem;
    border-top: 1px solid var(--border-soft);
}
.sheet-home {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.9rem;
    border-radius: 10px;
    border: 1px solid var(--border-soft);
    background: var(--surface);
    color: var(--text-secondary);
    font-size: 0.74rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    text-decoration: none;
    transition: border-color 0.16s, background 0.16s, color 0.16s;
}
.sheet-home svg { width: 1rem; height: 1rem; flex: 0 0 auto; color: var(--act); }
.sheet-home:hover { border-color: var(--act); background: var(--surface-hover); color: var(--text-primary); }

/* Language switch — the right end of that row */
.sheet-lang { display: none; gap: 0.6rem; }
.sheet-lang a {
    text-decoration: none;
    color: var(--text-secondary);
    background: var(--surface);
    border: 1px solid var(--border-soft);
    font-size: 0.74rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    padding: 0.5rem 1rem;
    border-radius: 8px;
}
.sheet-lang a.active { color: var(--act-ink); background: var(--note); border-color: transparent; }

.nav-launcher,
.nav-backdrop,
.nav-sheet { display: none; }

/* The glass sheet that slides up from the bottom */
.nav-sheet {
    position: fixed;
    left: 0; right: 0; bottom: 0; top: auto;
    z-index: 130;
    flex-direction: column;
    align-items: center;
    gap: 0.35rem;
    /* Grows with its content up to most of the screen (Rose-style) - a
       fixed half-height band read as a squeezed sandwich on long menus and
       forced scrolling where none was needed. 2026-08-23, his report. */
    height: auto;
    max-height: 88dvh;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    padding: 0.9rem 1.4rem calc(1.4rem + env(safe-area-inset-bottom));
    display: flex; flex-direction: column; gap: 0.9rem;
    background: #0c0816;
    border-top: 1px solid var(--border-soft);
    border-radius: 22px 22px 0 0;
    box-shadow: 0 22px 54px -26px rgba(0,0,0,0.7);
    transform: translateY(100%);
    will-change: transform;
    transition: transform 0.32s cubic-bezier(0.32,0.72,0,1);
}
.nav-sheet::before { content: none; }
/* The grab handle sits at the TOP of the panel and stays put while the list
   scrolls under it. */
.nav-grab {
    /* First in the DOM now - sticky + flex order disagreed on mobile and
       painted the bar mid-list as a second line. 2026-08-23.
       Full-width strip: the handle is the ONLY close gesture now, so its
       hit area is generous - the bar stays small, the finger target is not. */
    position: sticky;
    top: 0;
    align-self: stretch;
    flex-shrink: 0;
    width: auto; height: 34px;
    margin: 0 0 0.2rem;
    cursor: grab;
    touch-action: none;
    display: flex; align-items: center; justify-content: center;
}
.nav-grab::after {
    content: '';
    width: 46px; height: 5px;
    border-radius: 3px;
    background: rgba(255,255,255,0.28);
}
/* THE WAY HOME. It is the panel's title AND its home link, so it is centred
   at the top and sized to be read. */
.nav-sheet-logo {
    /* order dropped 2026-08-23: the grab handle is first in the DOM now and
       must PAINT first - the bar under the lockup read as a second big line. */
    flex: none;
    position: relative;
    display: block;
    text-align: center;
    line-height: 0;
    margin: 0.2rem 0 0.9rem;
}
.nav-sheet-logo img { position: relative; height: 46px; width: auto; max-width: 86%; }
.nav-sheet-logo::before {
    content: '';
    position: absolute;
    top: 50%; left: 50%;
    width: 150%; height: 280%;
    transform: translate(-50%, -50%);
    background: radial-gradient(closest-side,
        rgba(207, 127, 156, 0.30) 0%, rgba(170, 185, 210, 0.16) 55%, transparent 78%);
    filter: blur(22px);
    opacity: 0.9;
    border-radius: 50%;
    pointer-events: none;
}
.nav-sheet.open { transform: translateY(0); }

.nav-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(6,4,12,0.55);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    z-index: 110;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    will-change: opacity;
    transition: opacity 0.32s cubic-bezier(0.32,0.72,0,1), visibility 0.32s;
}
.nav-backdrop.open { opacity: 1; visibility: visible; pointer-events: auto; }

/* ════════════════════════════════════════════════════════════════════
   THE LAUNCHER — a button, not a bar.

   It was a full-width band pinned to the top of every page. Nicolas: "get rid
   of the top sticky bar and use the same buttons as we have for neorhei,
   adapted in colours." neorhei's proportions, from Respira's pair: 6rem, 5rem
   on a phone. Adapted for a dark ground — neorhei is a light site with a solid
   white button; here it is glass with a light glyph, and the presence comes
   from the shadow rather than from a blur over live content.
   ════════════════════════════════════════════════════════════════════ */
.nav-launcher {
    position: fixed;
    top: auto;
    right: auto;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 1.5rem);
    left:   calc(env(safe-area-inset-left,   0px) + 1.5rem);
    z-index: 140;
    width: 6rem;
    height: 6rem;
    padding: 0;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, 0.14);
    background: rgba(16, 19, 28, 0.92);
    -webkit-backdrop-filter: blur(14px) saturate(1.2);
            backdrop-filter: blur(14px) saturate(1.2);
    box-shadow: 0 18px 40px -14px rgba(0, 0, 0, 0.85);
    cursor: pointer;
    overflow: visible;
    transition: transform 0.18s, border-color 0.18s, bottom 0.32s cubic-bezier(0.32,0.72,0,1);
}
.nav-launcher:hover { transform: translateY(-2px); border-color: rgba(255, 255, 255, 0.28); }
/* Open, it IS the close button — so it rides up with the panel instead of
   floating over the panel's own bottom-left tile. */
/* The sheet grows to content now (no fixed 55dvh), so the open button no
   longer floats above a known edge - it stays home in its corner, over the
   sheet, where the thumb already knows it. 2026-08-23. */
.nav-launcher.open { bottom: 1.1rem; z-index: 140; }
@media (max-width: 640px) {
    .nav-launcher.open { bottom: 0.9rem; z-index: 140; }
}
/* ⚠ THE PANEL WINS OVER ALL. `_sticky_cta.html` is `position: fixed` at
   z-index 140 — the launcher's level, and above the sheet's 130 — so the
   page's action floated over the open menu. Nicolas: *"when active, to me, the
   panel wins over all."* Two things, deliberately: it is dropped BELOW the
   sheet so it can never overlap even mid-transition, and it retreats entirely
   while the sheet is open. `body.nav-open` is set by the menu's own setOpen().
   The specificity here (0,2,1) beats `.rs-sticky-cta.show` (0,2,0) wherever
   the two files load in relation to each other. */
.rs-sticky-cta { z-index: 120; }
body.nav-open .rs-sticky-cta {
    opacity: 0;
    transform: translateY(14px);
    pointer-events: none;
}

.nav-launcher::before { content: none; }
.nav-launcher img { display: none; }      /* markup is shared; the glyph is the burger */
.nav-launcher-glow {
    position: absolute;
    inset: -18%;
    background: radial-gradient(closest-side,
        rgba(168, 122, 232, 0.30) 0%, rgba(207, 127, 156, 0.14) 55%, transparent 78%);
    filter: blur(10px);
    opacity: 0.9;
    pointer-events: none;
    transition: opacity 0.25s;
}
@media (max-width: 640px) {
    .nav-launcher { width: 5rem; height: 5rem;
        bottom: calc(env(safe-area-inset-bottom, 0px) + 1.1rem);
        left:   calc(env(safe-area-inset-left,   0px) + 1.1rem); }
}

.nav-burger {
    position: relative;
    height: 26px;
    width: 30px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    pointer-events: none;
}
.nav-burger span {
    display: block;
    height: 2px;
    width: 100%;
    border-radius: 2px;
    background: var(--text-primary);
    opacity: 0.85;
    transform-origin: center;
    transition: transform 0.28s cubic-bezier(0.32,0.72,0,1), opacity 0.2s;
}
.nav-launcher.open .nav-burger span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-launcher.open .nav-burger span:nth-child(2) { opacity: 0; transform: scaleX(0.3); }
.nav-launcher.open .nav-burger span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* The launcher pair is on every viewport; there is no top bar to clear. */
.site-header { display: none; }
.nav-launcher { display: flex; }
.nav-backdrop { display: block; }
.nav-sheet    { display: flex; }
.sheet-lang   { display: flex; justify-content: flex-end; }
body { padding-top: 0; }
.back-to-top { display: none; }

/* The column that stacks the categories — the ONLY thing in the sheet that
   scrolls: the handle and the wordmark stay put above it. */
.nav-grid {
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 1180px;
    margin: 0 auto;
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* ── THE SAME TILES, AT PANEL DENSITY ─────────────────────────────────
   Two corrections, and the second undoes half the first.

   1. THE WIDTH. *"Fix the panel width, look at the Rose one — it is nice, and
      the arroweb one is a bit weird."* It was: the grid was capped at 1180 and
      centred inside a full-width sheet, so the panel had empty margins its own
      edges did not explain. Rose's launcher fills its sheet. This one does too.

   2. THE RULE. *"In the panel the same rule from the landing applies for the
      tiles."* The first fix had also swapped the landing's flex rule for
      Rose's auto-fit grid, which put all five PRODOTTI in one row — a
      different shape from the same partial on the front door. Wrong: one
      definition, two surfaces means the RULE travels too.

   What stays panel-specific is only the SIZE: a fixed short height instead of
   the page's tall one, so the categories fit in a sheet. */
.nav-sheet .nav-grid { max-width: none; }
.nav-sheet .lp-cat { margin-bottom: 0.95rem; }
.nav-sheet .lp-cat-label { font-size: 0.62rem; margin-bottom: 0.5rem; }
.nav-sheet .lp-tile {
    min-height: 0;
    height: 4.6rem;
    padding: 0.5rem 0.45rem;
    gap: 0.38rem;
    border-radius: 0.8rem;
}
.nav-sheet .lp-tile svg { width: 1.25rem; height: 1.25rem; }
.nav-sheet .lp-tile span { font-size: 0.68rem; letter-spacing: 0.015em; }
@media (max-width: 520px) {
    .nav-sheet .lp-tile { height: 4.1rem; }
    .nav-sheet .lp-tile span { font-size: 0.62rem; }
}

/* ── NO SCROLLBAR ─────────────────────────────────────────────────────
   *"If there is a way to make that big white scrollbar disappear, that is an
   anxiety win for me."* There is: the sheet is glass on a dark ground and
   Windows draws its native bar in the light theme, which put a bright grey
   slab down the right-hand edge. It is a 3px thread in the panel's own
   colours now — present enough to say the list continues, quiet enough to
   stop being furniture. */
.nav-sheet,
.nav-sheet .nav-grid {
    scrollbar-width: thin;
    scrollbar-color: rgba(255,255,255,0.16) transparent;
}
.nav-sheet::-webkit-scrollbar,
.nav-sheet .nav-grid::-webkit-scrollbar { width: 3px; }
.nav-sheet::-webkit-scrollbar-track,
.nav-sheet .nav-grid::-webkit-scrollbar-track { background: transparent; }
.nav-sheet::-webkit-scrollbar-thumb,
.nav-sheet .nav-grid::-webkit-scrollbar-thumb {
    background: rgba(255,255,255,0.16);
    border-radius: 3px;
}

/* ════════════════════════════════════════════════════════════════════
   THE TILE GRAMMAR — the "access, not marketing" pass.

   Written for the front door and kept here, because the MENU SHEET renders the
   same tiles on every page from the same partial (`home/_nav_links.html`). One
   definition, two surfaces.

   THE RULE, ported from Rose's ui-consistency.css so the two houses cannot
   drift:
     · three tiles per row, MAXIMUM;
     · a short last row STRETCHES to fill the width — five products read as
       three, then two half-width tiles landing on the same edge as a two-tile
       category below them;
     · ⚠ except a last row of exactly ONE tile, which keeps a tile's width and
       centres. That one is the "three tiles and another giant one underneath"
       this rule exists to kill;
     · counts that would otherwise leave an orphan (4, 6) drop to two a row, so
       four reads as a 2x2.
   The count is read in CSS, so adding a destination re-picks the layout on its
   own — and it holds in three languages, where Italian shows five products and
   en/fr show two.
   ════════════════════════════════════════════════════════════════════ */
/* ── A category ──────────────────────────────────────────────────── */
.lp-cat { margin-bottom: clamp(1.6rem, 4vw, 2.4rem); }
.lp-cat-label {
    display: block;
    font-size: 0.68rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    /* The label wears its group's colour, like the icons under it — so a group
       reads as one thing before a single word is read. */
    color: var(--note);
    margin: 0 0 0.75rem 0.15rem;
}

/* ── The grid, and the rule ──────────────────────────────────────── */
.lp-grid {
    --tile-cols: 3;
    --tile-gap: clamp(0.45rem, 1vw, 0.85rem);
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--tile-gap);
}
.lp-grid > * {
    /* GROW. A short last row stretches to fill the width, so every row ends on
       the same edge. */
    flex: 1 1 calc((100% - (var(--tile-cols) - 1) * var(--tile-gap)) / var(--tile-cols));
    min-width: 0;
}
.lp-grid:has(> :first-child:nth-last-child(2)),
.lp-grid:has(> :first-child:nth-last-child(4)),
.lp-grid:has(> :first-child:nth-last-child(6)) { --tile-cols: 2; }

/* ⚠ THE ONE EXCEPTION, and it is the whole reason the rule exists: a last row
   holding exactly ONE tile must NOT stretch. It keeps a tile's width and
   centres instead. Counts that end that way at three per row: */
.lp-grid:has(> :first-child:nth-last-child(7))  > :last-child,
.lp-grid:has(> :first-child:nth-last-child(10)) > :last-child,
.lp-grid:has(> :first-child:nth-last-child(13)) > :last-child { flex-grow: 0; }

/* A group with a single tile is that same case at n=1 — half width, centred,
   never a full-width band. */
.lp-grid:has(> :first-child:nth-last-child(1)) > * {
    flex: 0 0 calc((100% - var(--tile-gap)) / 2);
}

/* ── A tile — the whole thing is the link ────────────────────────── */
.lp-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.55rem;
    min-height: clamp(84px, 11vw, 132px);
    padding: 0.9rem 0.7rem;
    border-radius: 0.9rem;
    /* The edge is the group's colour too, held well back — enough to bind a
       row together, not enough to shout. */
    border: 1px solid color-mix(in srgb, var(--note) 30%, transparent);
    background: var(--surface);
    color: var(--text-primary);
    text-decoration: none;
    text-align: center;
    transition: border-color 0.16s, background 0.16s, transform 0.16s;
    /* The tile is the query container for its own contents, so the icon and
       the label size off the TILE's real width rather than the viewport's —
       vw lies the moment a rail or a zoom level makes the row narrower. */
    container-type: inline-size;
}
.lp-tile:hover,
.lp-tile:focus-visible {
    border-color: color-mix(in srgb, var(--note) 70%, transparent);
    background: color-mix(in srgb, var(--note) 9%, var(--surface-hover));
    transform: translateY(-2px);
    outline: none;
}
.lp-tile svg {
    width: clamp(20px, 16cqw, 30px);
    height: clamp(20px, 16cqw, 30px);
    color: var(--note);
}
.lp-tile span {
    font-size: clamp(0.62rem, 9cqw, 0.86rem);
    font-weight: 600;
    letter-spacing: 0.02em;
    line-height: 1.25;
    overflow-wrap: anywhere;
}
/* Under ~90px of tile — five across on a phone — the tracking is the
   difference between a word and a broken word. Buy it back there. */
@container (max-width: 90px) {
    .lp-tile span { letter-spacing: 0; }
}

/* ── The four notes ──────────────────────────────────────────────────
   ⚠ THE VALUES ARE AT THE TOP OF THIS FILE, on `body.n-*, .lp-cat--*`
   together: a whole page and a single category want the same four colours,
   and there is no reason for the site to hold two copies. */

/* ════════════════════════════════════════════════════════════════════
   THE BAND — how every page after the front door is built.

   Written for /web-apps/ and moved here the same day, because four more pages
   wanted exactly it and a copy is not a shared definition.

   It replaces `style.css`'s generic `section`, which capped prose at 680px
   under galleries running at 1180 and set it in 0.86rem muted grey. Nicolas:
   *"the text in between is a bit weird, like it is made not to be read"* and
   *"it needs to take space, not apologise for being there."*

       .bands          the wrapper: one width for the whole page, and the
                       counter. Put it around every band on the page.
       .band           a step. `.band--plain` opts out of the numbering.
       .band-head      kicker + headline + at most ONE paragraph
       .band-kicker    the label object, in the band's note, carrying its
                       number — counted in CSS, so inserting a band anywhere
                       renumbers the page and nobody has to remember
       .band-h         the headline
       .band-sub       one paragraph. If a band needs two, it is two bands.
       .band-cards     explanations: icon in a tinted square, title, body
       .band-rows      DESTINATIONS: the whole row is the link (rule 2)

   ⚠ A band takes its colour by setting `--note` on itself — that is all a
   colour is here. *"Colours for sections and icons, white text."*
   ════════════════════════════════════════════════════════════════════ */
.bands {
    max-width: 1180px;
    margin: 0 auto;
    padding: clamp(2.4rem, 6vw, 4rem) clamp(1rem, 4vw, 2rem) 0;
    counter-reset: band;
}
.band-head { text-align: center; margin-bottom: clamp(1.8rem, 4vw, 2.6rem); }
.band-head h1 {
    font-size: clamp(1.6rem, 3.6vw, 2.5rem);
    font-weight: 800;
    line-height: 1.12;
    letter-spacing: -0.015em;
    color: var(--text-primary);
    margin: 0;
}
.band { margin-top: clamp(3.4rem, 8vw, 5.5rem); counter-increment: band; }
.band:first-child { margin-top: 0; }   /* .bands already pads the top */

/* ⚠ THE STACK INSIDE A BAND — one rule, so no template writes an inline
   margin again. Nicolas: *"it just needs a little bit more work and care and
   attention to detail, like the spacing between «tre cose…» and the tiles
   beneath — those are the little things we need to care for now."*

   He was looking at a band whose kicker, headline and lede were DIRECT
   children of `.band` instead of being wrapped in `.band-head`, so
   `.band-head`'s bottom margin never applied and the tiles started right under
   the sentence. Adjacent-sibling margins collapse to the larger of the two, so
   a head still gets its bigger gap and everything else gets this one. */
.band > * + * { margin-top: clamp(1.1rem, 2.6vw, 1.7rem); }
.band-kicker {
    display: inline-flex;
    align-items: baseline;
    gap: 0.6rem;
    font-size: 0.76rem;
    font-weight: 700;
    letter-spacing: 0.26em;
    text-transform: uppercase;
    color: var(--note);
    margin-bottom: 0.9rem;
}
.band-kicker::before {
    content: counter(band, decimal-leading-zero);
    font-size: 0.72rem;
    letter-spacing: 0.08em;
    opacity: 0.55;
    padding-right: 0.55rem;
    border-right: 1px solid rgb(var(--note-rgb) / 0.35);
}
.band-h {
    font-size: clamp(1.35rem, 2.8vw, 2rem);
    font-weight: 800;
    line-height: 1.18;
    letter-spacing: -0.012em;
    color: var(--text-primary);
    margin: 0;
}
.band-sub {
    max-width: 62ch;
    margin: 1rem auto 0;
    font-size: clamp(1rem, 1.25vw, 1.12rem);
    font-weight: 300;
    line-height: 1.7;
    color: var(--text-secondary);
}

/* A band that is not part of the walk — no number. */
.band--plain { counter-increment: none; }
.band--plain .band-kicker::before { content: none; border-right: 0; padding-right: 0; }
/* A kicker OUTSIDE any band — the page's own head. The counter is still zero
   there, so without this the label opens with a literal «00». */
.band-kicker--plain::before { content: none; border-right: 0; padding-right: 0; }

/* ── .band-cards — an explanation, said properly ──────────────────────
   Icon in a tinted square, title, body. The body is NOT optional: a card with
   a title and nothing under it is a page telling you a word and leaving you to
   guess — which /web-apps/ did for eight features whose sentences were sitting
   unrendered in `i18n.py` the whole time. */
.band-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(17.5rem, 1fr));
    gap: clamp(0.6rem, 1.4vw, 0.95rem);
    text-align: left;
}
.band-cards--wide { grid-template-columns: repeat(auto-fit, minmax(24rem, 1fr)); }
.band-card {
    display: flex;
    gap: 1rem;
    padding: 1.3rem 1.35rem;
    border-radius: 0.95rem;
    border: 1px solid rgb(var(--note-rgb) / 0.24);
    background: var(--surface);
    transition: border-color 0.16s, background 0.16s;
}
.band-card:hover { border-color: rgb(var(--note-rgb) / 0.5); background: var(--surface-hover); }
.band-card-ico {
    flex: 0 0 auto;
    width: 2.7rem; height: 2.7rem;
    border-radius: 0.8rem;
    display: grid; place-items: center;
    color: var(--note);
    background: rgb(var(--note-rgb) / 0.12);
    border: 1px solid rgb(var(--note-rgb) / 0.3);
}
.band-card-ico svg { width: 1.4rem; height: 1.4rem; }
.band-card-body { min-width: 0; }
.band-card-body b {
    display: block;
    font-size: 1.02rem; font-weight: 700; line-height: 1.3;
    color: var(--text-primary);
    margin-bottom: 0.35rem;
}
.band-card-body p {
    font-size: 0.96rem; font-weight: 300; line-height: 1.68;
    color: var(--text-secondary);
    margin: 0;
}
.band-card-body p + p { margin-top: 0.6rem; }
.band-card-body a { color: var(--text-primary); border-bottom: 1px solid rgb(var(--note-rgb) / 0.5); text-decoration: none; }
.band-card-body a:hover { border-bottom-color: var(--note); }

/* ── .band-rows — a list of destinations ──────────────────────────────
   THE WHOLE ROW IS THE LINK. Rule 2, and the rule the site's list pages broke
   hardest: a card with a "Leggi →" in the corner has one clickable inch and an
   arrow doing the work a whole row should do. */
.band-rows { display: grid; gap: 0.6rem; text-align: left; }
.band-row {
    display: block;
    padding: 1.3rem 1.4rem;
    border-radius: 0.95rem;
    border: 1px solid rgb(var(--note-rgb) / 0.2);
    background: var(--surface);
    text-decoration: none;
    color: var(--text-primary);
    transition: border-color 0.16s, background 0.16s, transform 0.16s;
}
.band-row:hover, .band-row:focus-visible {
    border-color: rgb(var(--note-rgb) / 0.6);
    background: color-mix(in srgb, var(--note) 7%, var(--surface-hover));
    transform: translateY(-2px);
    outline: none;
}
.band-row:active { transform: translateY(0); transition-duration: 0.06s; }
.band-row-meta {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem 0.9rem;
    font-size: 0.72rem; font-weight: 700;
    letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--note);
    margin-bottom: 0.5rem;
}
.band-row-meta time { color: var(--text-muted); letter-spacing: 0.06em; }
.band-row-title {
    display: block;
    font-size: clamp(1.05rem, 1.6vw, 1.25rem);
    font-weight: 700; line-height: 1.3;
    color: var(--text-primary);
    margin-bottom: 0.4rem;
}
.band-row-body {
    display: block;
    font-size: 0.95rem; font-weight: 300; line-height: 1.68;
    color: var(--text-secondary);
}

/* ── A quiet, honest empty state ─────────────────────────────────── */
.band-empty {
    padding: 2.4rem 1.4rem;
    border: 1px dashed rgb(var(--note-rgb) / 0.28);
    border-radius: 0.95rem;
    text-align: center;
    font-size: 0.95rem;
    color: var(--text-muted);
}

/* ── The tail: one honest line, under a rule, at the END of a page ────
   Rule 4 lives here. A price, a licence, a limit — disclosed, never sold. */
.band-tail {
    max-width: 1180px;
    margin: clamp(3rem, 7vw, 4.5rem) auto 0;
    padding: 1.6rem clamp(1rem, 4vw, 2rem) 0;
    border-top: 1px solid var(--border-soft);
    text-align: center;
}
.band-tail p {
    max-width: 66ch;
    margin: 0 auto;
    font-size: 0.9rem; line-height: 1.75;
    color: var(--text-muted);
}
.band-tail b { color: var(--text-secondary); font-weight: 700; }
.band-tail a { color: var(--text-secondary); border-bottom: 1px solid rgb(var(--note-rgb) / 0.45); text-decoration: none; }
.band-tail a:hover { color: var(--text-primary); border-bottom-color: var(--note); }

/* ════════════════════════════════════════════════════════════════════
   THE BUTTON

   *"The newsletter button is a rule — where there is the pink button, it is
   across the site."*

   `--act` has meant "what happens if you press" since the palette pass. It was
   still wearing three costumes: a 2px edge under a glass pill on /web-apps/, a
   solid gradient slab on /nidi-jtf/, and a glass pill with a FOUR-LAYER
   coloured glow as `.cta-button`. Same meaning, three objects, so the meaning
   did not carry. One object now:

       .btn          the action. Filled in her pink, dark ink, no glow.
       .btn--big     the same, at page-CTA size
       .btn--quiet   the OTHER option. Glass, the page's note on its edge.

   ⚠ ONE `.btn` PER VIEW. If a band offers two things, the second is
   `.btn--quiet`. Two pink buttons side by side is two answers to "what happens
   if I press", which is none.

   ⚠ THE COMPATIBILITY LIST carries the legacy class names. It is a bridge, not
   the design, and it should SHRINK: when a template is next touched, change
   its class to `.btn` and drop the name from the list.
   ════════════════════════════════════════════════════════════════════ */
.btn,
.nl-btn,
.cta-button,
.nidi-cta-btn,
.nidi-submit-btn,
.btn-prenota,
.home-band-demo,
form button[type="submit"] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    font-family: var(--font);
    font-size: 0.88rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: none;
    text-decoration: none;
    padding: 0.72rem 1.5rem;
    border: 0;
    border-radius: 10px;
    cursor: pointer;
    color: var(--act-ink);
    background: var(--act);
    box-shadow: none;                     /* the glow was the gold era */
    transition: background 0.16s, transform 0.12s;
}
.btn:hover, .btn:focus-visible,
.nl-btn:hover, .nl-btn:focus-visible,
.cta-button:hover, .cta-button:focus-visible,
.nidi-cta-btn:hover, .nidi-submit-btn:hover, .btn-prenota:hover,
.home-band-demo:hover,
form button[type="submit"]:hover {
    /* a LIGHTER rose, not a brightness filter: `brightness()` washes the ink
       out with the fill and the label goes grey with it. */
    background: color-mix(in srgb, var(--act) 68%, #ffffff);
    color: var(--act-ink);
    transform: none;
    box-shadow: none;
    outline: none;
}
.btn:active,
.nl-btn:active,
.cta-button:active,
.nidi-cta-btn:active, .nidi-submit-btn:active, .btn-prenota:active,
.home-band-demo:active,
form button[type="submit"]:active { transform: translateY(1px); }

.btn--big, .cta-button.big { font-size: 0.95rem; padding: 0.9rem 2rem; }
.btn svg, .cta-button svg, .home-band-demo svg { width: 1.1rem; height: 1.1rem; flex: 0 0 auto; }

/* ── THE OTHER OPTION ─────────────────────────────────────────────────
   Glass, the page's note on the edge, never pink. It is a destination, not an
   action — which is exactly the difference the colour is carrying. */
.btn--quiet,
.cta-button.secondary,
.inline-link {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    font-family: var(--font);
    font-size: 0.86rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: none;
    text-decoration: none;
    padding: 0.7rem 1.4rem;
    border-radius: 10px;
    border: 1px solid rgb(var(--note-rgb) / 0.45);
    background: var(--surface);
    color: var(--text-primary);
    box-shadow: none;
    cursor: pointer;
    transition: border-color 0.16s, background 0.16s;
}
.btn--quiet:hover, .cta-button.secondary:hover, .inline-link:hover {
    border-color: var(--note);
    background: color-mix(in srgb, var(--note) 9%, var(--surface-hover));
    color: var(--text-primary);
    transform: none;
    box-shadow: none;
}

/* A row of actions: the pink one first, the quiet one beside it. */
.btn-row {
    display: flex; flex-wrap: wrap;
    gap: 0.7rem;
    justify-content: center;
    margin-top: 1.6rem;
}



/* ── .band-cards--flat — cards with no icon ─────────────────────
   Some sets are facts rather than features: a source, a method, a
   measurement. They get a title, a body and a METRIC — the one line that
   says how the fact is checkable — and no icon, because inventing eleven
   glyphs for six data sources is decoration pretending to be information. */
.band-cards--flat .band-card { display: block; }
.band-card-metric {
    display: block;
    margin-top: 0.6rem;
    padding-top: 0.6rem;
    border-top: 1px solid rgb(var(--note-rgb) / 0.22);
    font-size: 0.82rem;
    font-weight: 600;
    line-height: 1.5;
    color: var(--note);
}
.band-card-metric a { color: inherit; border-bottom: 1px solid rgb(var(--note-rgb) / 0.5); text-decoration: none; }

/* ── .band-shot — one picture, framed like every other picture ──────
   ⚠ The ratio is fixed and the image is `contain`, not `cover`: a screenshot
   of somebody's real site must never be cropped to fit a box. If it does not
   fit, THE PICTURE gets remade — rule 6. Contain plus a dark mat is the
   honest version of that until the picture is recut. */
.band-shot {
    margin: 0 0 clamp(1.4rem, 3vw, 2rem);
    border-radius: 1rem;
    overflow: hidden;
    border: 1px solid rgb(var(--note-rgb) / 0.3);
    background: #0b0d13;
    box-shadow: 0 18px 40px -24px rgba(0,0,0,0.9);
}
.band-shot img { display: block; width: 100%; height: auto; }
.band-shot figcaption {
    padding: 0.7rem 1rem;
    border-top: 1px solid var(--border-soft);
    font-size: 0.78rem; font-weight: 700;
    letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--note);
}

/* ── The icon square, on the two product landings ──────────────────
   `.rs-pillar .ico` and `.cm-pillar .ico` used to hold an EMOJI at 1.2rem, so
   the rule only had to size a glyph. They hold a line mark now, which makes
   them the same object as `.band-card-ico` and `.point-ico`: a tinted square
   in the section's note, drawn rather than typed. */
.rs-pillar .ico,
.cm-pillar .ico {
    display: grid; place-items: center;
    width: 2.7rem; height: 2.7rem;
    border-radius: 0.8rem;
    margin-bottom: 0.85rem;
    font-size: 0;                       /* no glyph can sneak back in */
    color: var(--note);
    background: rgb(var(--note-rgb) / 0.12);
    border: 1px solid rgb(var(--note-rgb) / 0.3);
}
.rs-pillar .ico svg,
.cm-pillar .ico svg { width: 1.4rem; height: 1.4rem; }

/* ════════════════════════════════════════════════════════════════════
   THE HALO ON A HEADLINE

   Nicolas: *"there are lots of white titles everywhere and it's fine, but
   wouldn't we add that colouring the Arrow has — it has some rose glow to
   it? Only the section white titles."*

   The lockup on the front door is lit from behind by a pink-and-steel halo.
   This is that halo, at a whisper, on every white headline in the site: two
   text-shadows in the ACTION's pink, wide and low-alpha, so the letters stay
   white and only the air around them warms.

   ⚠ It is `--act`, not `--note` — CONSTANT, like the mark. The note says
   which section you are in; the halo says whose site it is. If it took the
   note it would just be the section colour again, twice.

   ⚠ A headline carries it at full strength. The line under it carries a third
   of it — see the block right below. Nothing below that. */
.band-h,
.band-head h1,
.hero-title,
.stage-head h2,
.section-headline {
    text-shadow:
        0 0 24px rgb(var(--act-rgb) / 0.20),
        0 0 64px rgb(var(--act-rgb) / 0.12);
}

/* ── AND, AT A THIRD OF IT, ON THE LINE UNDER ───────────────────
   Nicolas: *"bring the rose glow from the Arrow Rose logo that we have on the
   titles also on the subtitles, so it lives a bit more."*

   The rule here used to read "headlines only — on body text a glow is a blur",
   and that is still true AT THE HEADLINE'S STRENGTH: 0.20 alpha at 24px behind
   a 1rem 300-weight line does soften the letters. So the lede takes the SAME
   colour at a THIRD of the alpha and nearly double the radius — 0.07 at 40px —
   which puts warm air behind the paragraph without touching the edges of the
   glyphs. The NEAR shadow is dropped entirely; that is the one that blurs. A
   headline and its lede now read as one lit object instead of a lit line with
   a grey caption under it.

   ⚠ Still nothing below the lede. A `.band-card` body is body text and stays
   flat — three cards each glowing is a page with fog on it. */
.band-sub,
.hero-sub,
.hero-promise,
.band-head > p {
    text-shadow: 0 0 40px rgb(var(--act-rgb) / 0.07);
}

/* ── .band-chips — a filter you can SEE ───────────────────────────────
   The blog's category and tag filters were two <select>s that submitted on
   change. Same fault as /web-apps/'s retired dropdown, one page over: a list
   you have to open is a list you cannot compare, and a crawler reads none of
   it. Chips are the tile grammar at label size. */
.band-chips {
    display: flex; flex-wrap: wrap;
    gap: 0.4rem;
    justify-content: center;
    margin: 0 0 clamp(1.4rem, 3vw, 2rem);
}
.band-chip {
    display: inline-flex; align-items: center;
    padding: 0.42rem 0.85rem;
    border-radius: 999px;
    border: 1px solid rgb(var(--note-rgb) / 0.3);
    background: var(--surface);
    color: var(--text-secondary);
    font-size: 0.8rem; font-weight: 600; letter-spacing: 0.02em;
    text-decoration: none;
    transition: border-color 0.16s, background 0.16s, color 0.16s;
}
.band-chip:hover { border-color: var(--note); color: var(--text-primary); background: var(--surface-hover); }
.band-chip[aria-current="true"] {
    background: var(--note); border-color: var(--note);
    color: var(--act-ink);
}

/* ── THE SEVEN QUESTIONS ───────────────────────────────────────────────
   /come-funziona/, and the tiles under the front door. `home/questions.py`
   holds the rule these were written under; this is only how they look. */
.band--q-intro { --note: #9aa8c2; --note-rgb: 154 168 194; }
.band--q-ask   { --note: #cf7f9c; --note-rgb: 207 127 156; }

/* ⚠ THE COIN IS GONE (2026-08-21). Each question's number used to be a filled
   2rem DISC — the kicker with its counter suppressed, a bare digit inside a
   coloured circle. Nicolas: *"the dots for the number on the come-funziona page
   are kinda ridiculous — I'm sure there's a way to structure it like the
   beautiful 01 | LE DOMANDE on top."* He is right, and the fix is not a new
   object: it is the object the whole rest of the site already uses. A question
   band is now `01 │ DOMANDA` like every other band on every other page, and the
   number comes back from the CSS counter — so inserting a question anywhere
   renumbers the page and nobody has to remember.

   The intro band opts OUT of the count instead: it is the page's head, not its
   first question, and with it counting the seven questions read 02–08. */
.band--q-intro { counter-increment: none; }
.band--q-intro .band-kicker::before { content: none; border-right: 0; padding-right: 0; }
/* An answer is not a caption: it is the point of the band, so it is set at
   reading size and left-aligned rather than centred like a lede. */
/* max-width without auto margins anchored the whole head LEFT while its
   text centred inside itself - every question hung left of the page axis
   (his screenshots, 2026-08-23). */
.q-band .band-head { max-width: 68ch; margin-inline: auto; }
.q-band .band-h { font-size: clamp(1.25rem, 2.4vw, 1.75rem); }
.q-band .band-sub { font-size: 1.04rem; color: var(--text-secondary); }

/* The four figures on the price question. */
.q-fig {
    display: block;
    margin: 0.15rem 0 0.5rem;
    font-size: 1.5rem; font-weight: 800; letter-spacing: -0.01em;
    color: var(--text-primary);
}
.q-fig small { display: block; font-size: 0.82rem; font-weight: 400; color: var(--text-muted); letter-spacing: 0; }

/* ── The question tiles on the front door ────────────────────────────
   The same tile, holding a SENTENCE instead of a word — so it is taller,
   its text is left-aligned and it does not shout in caps. */
.lp-cat--domande { --note: #9aa8c2; --note-rgb: 154 168 194; }
.lp-grid--q { --tile-cols: 3; }
.lp-tile--q {
    min-height: 0;
    padding: 0.95rem 1.05rem;
    align-items: flex-start;
    justify-content: center;
    text-align: left;
}
.lp-tile--q span {
    font-size: clamp(0.8rem, 6cqw, 0.95rem);
    font-weight: 600;
    letter-spacing: 0;
    line-height: 1.35;
    overflow-wrap: normal;
}

/* The "it becomes yours" band, and the two product leads. */
.band--yours   { --note: #cf7f9c; --note-rgb: 207 127 156; }
.band--cm-lead { --note: #d08468; --note-rgb: 208 132 104; }
.band--rs-lead { --note: #63b4d4; --note-rgb:  99 180 212; }

/* ════════════════════════════════════════════════════════════════════
   THE FIELD — the fifth object, 2026-08-21.

   Until today the house had four objects and NO WAY TO ASK A QUESTION, so
   every page that needed one grew its own: `brief.css` answered with white
   email-style panels on the dark ground and `funnel.css` with white tiles —
   a second visual language inside one site, on exactly the pages where a
   stranger decides whether to write to us or leave.

   Nicolas, on the request pages: "the form I find it horrible really, it's
   really off when compared to the rest of the site... the white background
   does a lot to make it uncomfortable too. More tiley once again, more sober,
   and way more clear — text and input fields should really be clear."

   So a question is asked in the same glass everything else is made of:

       .form          the form: it carries the grammar for everything inside
       .form-panel    ONE GROUP OF QUESTIONS, in glass. The panel is the unit
                      a person reads — the six fields the contract needs, or
                      the ones that change the demo. Never one panel per field.
       .form-legend   the group's label, in the page's note
       .f             one field: the question, then the control under it
       .f-cap         the question   ·   .f-hint  the line that explains it
       .f-grid        two questions side by side, one on a phone
       .f-check       a checkbox and its sentence
       .f-slots/.f-slot   an upload, drawn as a tile you can press anywhere on
       .f-callout     a boxed fact inside a panel (a promise, a warning)
       .f-note        the quiet line under the button
       .f-error / .f-invalid / .f-field-error   what went wrong, in ROSE's red

   ⚠ THE CONTROL IS THE LOUDEST THING IN A PANEL. On the white version the
   caption was 12.5px semibold and the field a pale lilac box, so the form read
   as a document to be filed. Here the caption is 0.92rem, the control sits at
   reading size on a lit ground, and the only saturated colour in the whole
   form is the ONE pink submit button.

   ⚠ 1rem = 16px on every control, deliberately: iOS Safari zooms the page in
   on focus for anything smaller, and never zooms back out.

   ⚠ ONE `.btn` PER FORM. The four "Scegli file" pills used to be pink as well,
   which put five answers to "what happens if I press" on one screen. They are
   quiet glass now — rule 5.
   ════════════════════════════════════════════════════════════════════ */
/* ⚠ NO CARD, NO GREY. The panel was `background: var(--surface)` — white at
   4.5% — which on the navy reads as a grey card, and five of them stacked read
   as a form to be filed. Nicolas: *"can't we just get rid of the grey fond,
   and make the fields and titles sensefully big, like small caps, not
   necessarily bold but bright white on the navy fond?"*

   So a group of questions is separated by SPACE and by a rule in the section's
   note — the colour on the edge, the words in white, which is the site's own
   rule 5 applied to a form. Nothing is filled except the controls themselves,
   because a control is the one thing here that has to look pressable. */
.form { text-align: left; }
.form-panel {
    border: 0;
    border-top: 1px solid rgb(var(--note-rgb) / 0.4);
    border-radius: 0;
    background: none;
    padding: clamp(1.4rem, 3vw, 1.8rem) 0 0;
    margin: 0;
}
.form-panel + .form-panel { margin-top: clamp(2.2rem, 5vw, 3.2rem); }
.form-legend {
    display: block;
    width: 100%;
    padding: 0;
    margin: 0 0 1.3rem;
    font-size: 1.02rem;
    font-weight: 600;
    font-variant-caps: all-small-caps;
    letter-spacing: 0.14em;
    text-transform: none;
    color: var(--text-primary);
}
.form-legend .opt {
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: none;
    color: var(--text-muted);
}
/* A panel may open with one sentence of context. It is not a caption: it is
   the reason the questions under it are being asked at all. */
.form-lead {
    margin: -0.5rem 0 1.5rem;
    font-size: 0.96rem;
    font-weight: 300;
    line-height: 1.65;
    color: var(--text-secondary);
}

/* ── One field ─────────────────────────────────────────────────────── */
.f { display: flex; flex-direction: column; }
.f + .f, .f-grid + .f, .f + .f-grid, .f-grid + .f-grid,
.f + .f-slots, .f-grid + .f-slots, .f + fieldset, .f-grid + fieldset { margin-top: 1.6rem; }
/* ⚠ THE QUESTION IS READ, NOT SCANNED. It was 0.92rem semibold over a pale
   box; somebody filling this in is reading a sentence, so it is set at reading
   size in the brightest ink on the page. */
.f-cap {
    display: block;
    font-size: 1.02rem;
    font-weight: 600;
    line-height: 1.45;
    color: var(--text-primary);
    margin-bottom: 0.55rem;
}
/* The hint sits on its OWN line under the question. Inline, it competed with
   the question for the same line and wrapped the field out of alignment. */
.f-hint {
    display: block;
    margin-top: 0.3rem;
    font-size: 0.86rem;
    font-weight: 300;
    line-height: 1.5;
    color: var(--text-muted);
}
/* The required marker, wherever it stands — in a caption, or at the end of a
   consent sentence. It is the ACTION's pink because a required field is part
   of what happens when you press. */
.req { color: var(--act); font-weight: 700; }

.f-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 1.6rem 1.4rem; }
/* In a two-up row the questions wrap to different heights; anchoring the
   controls to the bottom of the cell keeps both fields on one line. */
.f-grid .f > input, .f-grid .f > select, .f-grid .f > textarea { margin-top: auto; }

/* ── The controls ──────────────────────────────────────────────────── */
.form input[type=text], .form input[type=email], .form input[type=url],
.form input[type=tel], .form input[type=number], .form input[type=date],
.form textarea, .form select {
    width: 100%;
    font-family: var(--font);
    font-size: 1rem;
    font-weight: 400;
    line-height: 1.45;
    color: var(--text-primary);
    background: rgba(255,255,255,0.055);
    border: 1px solid var(--border-medium);
    border-radius: 10px;
    padding: 0.85rem 1rem;
    transition: border-color 0.16s, box-shadow 0.16s, background 0.16s;
}
.form input::placeholder, .form textarea::placeholder { color: var(--text-muted); opacity: 1; }
.form input:focus, .form textarea:focus, .form select:focus {
    outline: none;
    border-color: var(--act);
    background: rgba(255,255,255,0.08);
    box-shadow: 0 0 0 3px rgb(var(--act-rgb) / 0.18);
}
.form textarea { min-height: 7rem; resize: vertical; }
/* The chevron is drawn here rather than left to the platform: a native select
   on a dark ground renders a light-grey arrow on a light-grey plate. */
.form select {
    appearance: none; -webkit-appearance: none;
    padding-right: 2.4rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23c5b8c0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.95rem center;
    background-size: 0.7rem;
}
/* ⚠ The OPEN dropdown is painted by the operating system, not by this file:
   without this line Chrome on Windows draws white text on a white list. */
.form select option { background: #141821; color: var(--text-primary); }

/* ── A checkbox and its sentence ───────────────────────────────────── */
.f-check {
    display: flex;
    align-items: flex-start;
    gap: 0.85rem;
    font-size: 0.98rem;
    font-weight: 300;
    line-height: 1.55;
    color: var(--text-secondary);
    cursor: pointer;
}
.f-check + .f-check { margin-top: 0.95rem; }
.f-check a { color: var(--text-primary); border-bottom: 1px solid rgb(var(--act-rgb) / 0.55); text-decoration: none; }
.f-check a:hover { border-bottom-color: var(--act); }
/* ⚠ A RECTANGLE, AND BIG ENOUGH TO HIT. *"Even the tick boxes — let's make
   them nice rectangles."* It was a 1.15rem rounded square, which is under the
   44px touch target every phone guideline asks for and reads as a bullet. */
.f-check input[type=checkbox] {
    flex: 0 0 auto;
    appearance: none; -webkit-appearance: none;
    width: 1.4rem; height: 1.4rem;
    margin: 0.1rem 0 0;
    border: 1.5px solid var(--border-medium);
    border-radius: 5px;
    background: rgba(255,255,255,0.05);
    display: grid; place-content: center;
    cursor: pointer;
    transition: background 0.14s, border-color 0.14s;
}
.f-check:hover input[type=checkbox] { border-color: rgb(var(--note-rgb) / 0.8); }
.f-check input[type=checkbox]::before {
    content: "";
    width: 0.85rem; height: 0.85rem;
    transform: scale(0);
    transition: transform 0.14s;
    background: var(--act-ink);
    clip-path: polygon(14% 47%, 0 60%, 40% 100%, 100% 22%, 86% 8%, 39% 70%);
}
.f-check input[type=checkbox]:checked { background: var(--act); border-color: var(--act); }
.f-check input[type=checkbox]:checked::before { transform: scale(1); }
.f-check input[type=checkbox]:focus-visible { outline: 2px solid var(--act); outline-offset: 2px; }
.f-checks { margin-top: 1.3rem; }
.form fieldset { border: 0; padding: 0; margin: 0; }

/* ── An upload, drawn as a tile ────────────────────────────────────────
   Rule 2 all the way down: the whole tile is the control, not a pill at the
   end of a line. Dashed while it is empty and solid once it holds something —
   the one place in this site where an edge carries a state. */
.f-slots { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 0.9rem; }
.f-slot {
    position: relative;
    display: block;
    padding: 1rem 1.1rem;
    border: 1px dashed rgb(var(--note-rgb) / 0.38);
    border-radius: 0.9rem;
    background: rgba(255,255,255,0.028);
    cursor: pointer;
    transition: border-color 0.16s, background 0.16s;
}
.f-slot:hover { border-color: rgb(var(--note-rgb) / 0.7); background: rgba(255,255,255,0.05); }
.f-slot:focus-within { border-color: var(--act); box-shadow: 0 0 0 3px rgb(var(--act-rgb) / 0.16); }
.f-slot-t { display: block; font-size: 0.95rem; font-weight: 700; line-height: 1.35; color: var(--text-primary); }
.f-slot-h { display: block; margin: 0.25rem 0 0.8rem; font-size: 0.82rem; font-weight: 300; line-height: 1.5; color: var(--text-muted); }
/* Hidden but focusable — opacity + zero size, NOT clip-path, which double-fires
   the picker on some WebKit builds. */
.f-file { position: absolute; top: 0; left: 0; width: 0.1px; height: 0.1px; opacity: 0; overflow: hidden; z-index: -1; }
.f-file-row { display: flex; align-items: center; gap: 0.7rem; }
.f-file-btn {
    flex: 0 0 auto;
    display: inline-flex; align-items: center;
    padding: 0.5rem 0.95rem;
    border-radius: 8px;
    border: 1px solid rgb(var(--note-rgb) / 0.45);
    background: var(--surface);
    font-size: 0.82rem; font-weight: 700; line-height: 1;
    color: var(--text-primary);
    white-space: nowrap;
}
.f-slot:hover .f-file-btn { border-color: var(--note); background: var(--surface-hover); }
.f-file:focus-visible + .f-file-row .f-file-btn { outline: 2px solid var(--act); outline-offset: 2px; }
.f-file-name {
    min-width: 0; flex: 1 1 auto;
    font-size: 0.82rem; font-weight: 300;
    color: var(--text-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.f-file.has-files ~ .f-file-row .f-file-name { color: var(--text-primary); font-weight: 600; }
.f-slot:has(.f-file.has-files) { border-style: solid; border-color: rgb(var(--note-rgb) / 0.6); }

/* ── A boxed fact inside a panel ───────────────────────────────────── */
.f-callout {
    margin-top: 1.2rem;
    padding: 0.95rem 1.1rem;
    border-radius: 0.8rem;
    border: 1px solid rgb(var(--note-rgb) / 0.28);
    border-left: 3px solid var(--note);
    background: rgb(var(--note-rgb) / 0.07);
    font-size: 0.9rem; font-weight: 300; line-height: 1.65;
    color: var(--text-secondary);
}
.f-callout b { color: var(--text-primary); font-weight: 700; }
.f-callout--warn { border-color: rgb(var(--act-rgb) / 0.45); border-left-color: var(--act); background: rgb(var(--act-rgb) / 0.08); }

/* ── The end of a form ─────────────────────────────────────────────── */
.f-actions { margin-top: 1.8rem; }
.f-submit { width: 100%; }
.f-note {
    margin: 0.9rem 0 0;
    font-size: 0.82rem; font-weight: 300; line-height: 1.6;
    color: var(--text-muted);
    text-align: center;
}

/* ── What went wrong ───────────────────────────────────────────────────
   ROSE's red: the action's pink pushed towards a warning, so an error still
   reads as part of this site rather than a browser alert dropped into it. */
.f-error, .f-field-error, .form ul.errorlist,
/* ⚠ COMPATIBILITY. `rs-form-error` is written from Python in three apps
   (comanda/mondrian/reams views, the htmx inquiry + demo endpoints) and lands
   inside a panel on the request pages. It is a bridge, not a design: when one
   of those views is next touched, make it emit `f-error` and drop this line. */
.rs-form-error {
    display: block;
    margin: 0.5rem 0 0;
    padding: 0;
    list-style: none;
    font-size: 0.84rem; font-weight: 600; line-height: 1.5;
    color: #ff9db0;
}
.f-field-error:empty { display: none; }
.f-errors {
    margin: 0 0 1.1rem;
    padding: 0.85rem 1rem;
    border-radius: 0.7rem;
    border: 1px solid rgba(255,157,176,0.35);
    background: rgba(255,157,176,0.09);
}
.f-errors p { margin: 0; font-size: 0.88rem; font-weight: 600; color: #ff9db0; }
.f-errors p + p { margin-top: 0.35rem; }
.form input.f-invalid, .form textarea.f-invalid, .form select.f-invalid {
    border-color: rgba(255,157,176,0.7);
    background: rgba(255,157,176,0.07);
}
.form input.f-invalid:focus, .form textarea.f-invalid:focus {
    border-color: #ff9db0;
    box-shadow: 0 0 0 3px rgba(255,157,176,0.18);
}

/* ── What a form says when it worked ──────────────────────────────────
   It replaces the form in place — the thing you pressed becomes the answer to
   pressing it — so it is drawn at the same size, in the same panel. */
.f-done, .rs-form-success { text-align: center; padding: 0.5rem 0 0.2rem; }
.f-done h3, .rs-form-success h3 {
    margin: 0 0 0.45rem;
    font-size: 1.1rem; font-weight: 800; line-height: 1.3;
    color: var(--text-primary);
}
.f-done p, .rs-form-success p {
    margin: 0;
    font-size: 0.95rem; font-weight: 300; line-height: 1.65;
    color: var(--text-secondary);
}
.f-done p + p, .rs-form-success p + p { margin-top: 0.65rem; }
.f-done b, .f-done strong { color: var(--text-primary); font-weight: 700; }

/* ── WHILE IT IS WORKING ───────────────────────────────────────────────
   Two objects, moved out of `booking.css` when that file was retired.

   THE LOADER replaces the submit button while the request is in flight: the
   Arrow mark wiping left to right. It is not a spinner because a spinner says
   "something is happening somewhere"; this says "your thing is being sent",
   which is the only thing a person waiting on a form wants to know.

   THE TOAST is what a form says when it worked and the form itself stays on
   the page (the appointment request, which resets rather than navigating). A
   form that gives way to a confirmation uses `.f-done` instead. */
.arrow-loader { display: none; text-align: center; padding: 1rem 0; min-height: 3.5rem; }
.arrow-loader-logo {
    width: 90px; height: auto; display: inline-block;
    animation: arrow-dust 1.4s ease-in-out infinite alternate;
}
@keyframes arrow-dust {
    0%   { clip-path: inset(0 100% 0 0); opacity: 0.3; }
    100% { clip-path: inset(0 0% 0 0);   opacity: 1; }
}
form.htmx-request .arrow-loader,
form.is-submitting .arrow-loader { display: block; }
form.htmx-request  button[type="submit"],
form.is-submitting button[type="submit"] { display: none; }
@media (prefers-reduced-motion: reduce) { .arrow-loader-logo { animation: none; opacity: 1; } }

.booking-toast {
    position: fixed;
    left: 50%; bottom: 2rem;
    transform: translateX(-50%) translateY(12px);
    z-index: 999;
    max-width: min(28rem, calc(100vw - 2rem));
    padding: 0.85rem 1.5rem;
    border-radius: 999px;
    border: 1px solid rgb(var(--act-rgb) / 0.5);
    background: rgba(16, 19, 28, 0.94);
    -webkit-backdrop-filter: blur(14px) saturate(1.2);
            backdrop-filter: blur(14px) saturate(1.2);
    box-shadow: 0 18px 40px -14px rgba(0,0,0,0.85);
    color: var(--text-primary);
    font-size: 0.9rem; font-weight: 600; text-align: center;
    opacity: 0; pointer-events: none;
    transition: opacity 0.35s ease, transform 0.35s ease;
}
.booking-toast.visible { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ── A page that is mostly a form is narrower than a page of tiles ────
   1180px is the width of a gallery. A form read at that width turns every
   two-up row into a reach across the desk. */
.bands--ask { max-width: 52rem; }

/* A numbered card — the same object as .band-card with a figure in the square
   instead of a glyph, for a sequence that really is ordered. */
.band-card-ico--n { font-size: 1.05rem; font-weight: 800; letter-spacing: -0.01em; }

/* ════════════════════════════════════════════════════════════════════
   THE PICKER — a day and an hour, chosen without a native widget.
   2026-08-21, and it belongs to THE FIELD above.

   Nicolas: *"I need the hour and the date selectors to be native to arroweb
   and nicely styled and highly functional on all devices, popping at the
   centre. There is an example in the restaurant archetype — but obviously
   adapted for arroweb so everything feels native, nothing weird from any
   device."*

   WHAT WAS THERE: `<input type="date">` and `<input type="time">`, which are
   not one control but five — Chrome on Windows drew `mm/dd/yyyy` on an Italian
   page, Safari drew a grey wheel, Firefox drew a text box, and the AM/PM
   suffix appeared or did not depending on the OS locale rather than on the
   page's. A form asking an Italian shopkeeper for a day cannot render the day
   in American order because of a setting they have never seen.

   So the day and the hour are drawn here:

       .pick-grid / .pick-btn   the two fields — a label and the chosen value,
                                the same glass as every other control
       .pick-back / .pick-pop   the backdrop and the sheet, centred
       .cal-*                   one month, seven columns
       .pick-times / .pick-time the hours, as chips

   ⚠ THE HOUR IS A GRID OF CHIPS, NOT A WHEEL. The restaurant archetype uses a
   scroll-snap wheel and it is lovely on a phone; on a desktop with a mouse it
   is a scroll target you have to fight, and a scroll-snap column inside a
   scroll-locked dialog is exactly the kind of thing that behaves differently
   on four browsers. Twenty-three chips are one tap, readable at a glance,
   reachable by keyboard, and identical everywhere — which is what
   "nothing weird from any device" actually asks for.

   ⚠ THE REAL VALUES ARE TWO HIDDEN INPUTS, `slot_date` (YYYY-MM-DD) and
   `slot_time` (HH:MM). The server contract in booking/views.py does not change
   by one character, and with JS off the page still posts — the pickers are the
   only way to fill them, so the button says so.
   ════════════════════════════════════════════════════════════════════ */
.pick-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: 1.15rem; }
.pick-btn {
    display: flex; flex-direction: column; align-items: flex-start; gap: 0.3rem;
    width: 100%;
    padding: 0.7rem 0.9rem;
    font-family: var(--font);
    text-align: left;
    border: 1px solid var(--border-medium);
    border-radius: 10px;
    background: rgba(255,255,255,0.055);
    cursor: pointer;
    transition: border-color 0.16s, background 0.16s, box-shadow 0.16s;
}
.pick-btn:hover { border-color: rgb(var(--note-rgb) / 0.7); background: rgba(255,255,255,0.08); }
.pick-btn:focus-visible { outline: none; border-color: var(--act); box-shadow: 0 0 0 3px rgb(var(--act-rgb) / 0.18); }
.pick-lbl { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--note); }
.pick-val { font-size: 1rem; font-weight: 600; line-height: 1.3; color: var(--text-primary); }
.pick-val.empty { font-weight: 400; color: var(--text-muted); }

/* ── The sheet ─────────────────────────────────────────────────────── */
.pick-back {
    position: fixed; inset: 0; z-index: 200;
    background: rgba(6, 4, 16, 0.72);
    -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.pick-pop {
    position: fixed; z-index: 201;
    left: 50%; top: 50%; transform: translate(-50%, -50%);
    width: min(23rem, 92vw);
    max-height: 88dvh; overflow-y: auto;
    padding: 1.2rem;
    border-radius: 1.1rem;
    border: 1px solid rgb(var(--note-rgb) / 0.45);
    background: #12151d;
    box-shadow: 0 30px 80px -20px rgba(0,0,0,0.9);
    text-align: left;
}
body.pick-open { overflow: hidden; }
.pick-pop-h {
    display: flex; align-items: center; justify-content: space-between; gap: 0.8rem;
    margin-bottom: 1rem;
}
.pick-pop-h b { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--note); }
.pick-close {
    flex: 0 0 auto;
    width: 2rem; height: 2rem;
    display: grid; place-items: center;
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    background: transparent;
    color: var(--text-secondary);
    font-size: 1.1rem; line-height: 1;
    cursor: pointer;
}
.pick-close:hover { border-color: var(--border-medium); color: var(--text-primary); }

/* ── One month ─────────────────────────────────────────────────────── */
.cal-head { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; margin-bottom: 0.9rem; }
.cal-head span { font-size: 0.98rem; font-weight: 700; color: var(--text-primary); text-transform: capitalize; }
.cal-nav {
    width: 2.2rem; height: 2.2rem;
    display: grid; place-items: center;
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    background: transparent;
    color: var(--text-secondary);
    font-size: 1.1rem; line-height: 1;
    cursor: pointer;
}
.cal-nav:hover:not(:disabled) { border-color: var(--note); color: var(--text-primary); }
.cal-nav:disabled { opacity: 0.28; cursor: default; }
.cal-dow { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.2rem; margin-bottom: 0.4rem; }
.cal-dow span { text-align: center; font-size: 0.68rem; font-weight: 700; letter-spacing: 0.08em; color: var(--text-muted); }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.2rem; }
.cal-cell {
    aspect-ratio: 1;
    display: grid; place-items: center;
    border: 1px solid transparent;
    border-radius: 8px;
    background: transparent;
    font-family: var(--font); font-size: 0.9rem; font-weight: 500;
    color: var(--text-secondary);
    cursor: pointer;
    transition: border-color 0.12s, background 0.12s, color 0.12s;
}
.cal-cell:hover { border-color: rgb(var(--note-rgb) / 0.7); color: var(--text-primary); }
.cal-cell:focus-visible { outline: 2px solid var(--act); outline-offset: 1px; }
.cal-cell.out { visibility: hidden; }
.cal-cell.dis { color: var(--text-muted); opacity: 0.3; pointer-events: none; }
.cal-cell.today { border-color: rgb(var(--note-rgb) / 0.45); }
.cal-cell.sel { background: var(--act); border-color: var(--act); color: var(--act-ink); font-weight: 700; }

/* ── The hours ─────────────────────────────────────────────────────── */
.pick-times { display: grid; grid-template-columns: repeat(auto-fit, minmax(4.2rem, 1fr)); gap: 0.35rem; }
.pick-time {
    padding: 0.6rem 0.2rem;
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    background: rgba(255,255,255,0.03);
    font-family: var(--font); font-size: 0.9rem; font-weight: 600;
    color: var(--text-secondary);
    cursor: pointer;
    transition: border-color 0.12s, background 0.12s, color 0.12s;
}
.pick-time:hover { border-color: rgb(var(--note-rgb) / 0.7); color: var(--text-primary); }
.pick-time:focus-visible { outline: 2px solid var(--act); outline-offset: 1px; }
.pick-time.sel { background: var(--act); border-color: var(--act); color: var(--act-ink); }
.pick-note { margin: 0.9rem 0 0; font-size: 0.8rem; font-weight: 300; line-height: 1.55; color: var(--text-muted); }

/* ── WhatsApp, outlined ────────────────────────────────────────────────
   Nicolas: *"cut the full green background on the button, it hurts — borders
   and icon coloured green are fine."* He is right twice: a saturated fill is
   the loudest thing on a dark page, and on this site a FILL means "this is THE
   action" — a colour reserved for one pink button per view. WhatsApp is a
   destination, so it is `.btn--quiet` wearing its own edge and glyph. */
.btn--wa { border-color: rgba(37, 211, 102, 0.55); }
.btn--wa:hover { border-color: rgba(37, 211, 102, 0.9); background: rgba(37, 211, 102, 0.1); }
.btn--wa svg { width: 1.15rem; height: 1.15rem; flex: 0 0 auto; color: #4ade80; }

/* ════════════════════════════════════════════════════════════════════
   THE SEARCH — 2026-08-21. The front door's one field, and what it
   turns the front door into.

   The map has carried this since the front-door session: *"a full search would
   be nice too — but design first."* The design has settled, so here it is.

   Nicolas: *"I want the whole landing page emptied (except the footer), and
   the landing page becomes the search results tiles — with the colour-coded
   borders and icons, and small title with content preview, in nice structures,
   2×X tiles full width. Three characters minimum for searches, and very
   important, it needs to be reactive too: when I go under 3 chars the landing
   page fades back in."*

   So this is not a search PAGE. The front door has two states and one of them
   is the search: the destinations move aside while there is a query, and come
   back the moment there is not. Nothing navigates, nothing loads, the field
   never loses focus.

       .sr-field   the field: a magnifier, an input, and a clear
       .sr-out     where the results land (htmx swaps into it)
       .sr-grid    TWO across, full width, one on a phone
       .sr-tile    the whole tile is the link — rule 2 — and it wears the
                   note of the group the result belongs to
       .lp-body    the front door itself, which steps aside and comes back

   ⚠ EVERY TILE CARRIES ITS KIND, IN WORDS AND IN COLOUR. A result list where
   an article, a photo and a request form look identical is a list you have to
   read twice. `home/search.py` KINDS maps each kind to one of the front door's
   four groups, and the tile takes that group's `.lp-cat--*` class — so a
   result is drawn in exactly the colour the destination tile for the same
   thing is drawn in, one screen up.
   ════════════════════════════════════════════════════════════════════ */
.sr-field {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    max-width: 34rem;
    margin: 0 auto clamp(1.6rem, 4vw, 2.4rem);
    padding: 0.2rem 0.4rem 0.2rem 0.9rem;
    border: 1px solid var(--border-medium);
    border-radius: 12px;
    background: rgba(255,255,255,0.045);
    transition: border-color 0.16s, box-shadow 0.16s, background 0.16s;
}
.sr-field:focus-within {
    border-color: var(--act);
    background: rgba(255,255,255,0.07);
    box-shadow: 0 0 0 3px rgb(var(--act-rgb) / 0.16);
}
.sr-field > svg { flex: 0 0 auto; width: 1.1rem; height: 1.1rem; color: var(--text-muted); }
.sr-field:focus-within > svg { color: var(--act); }
.sr-input {
    flex: 1 1 auto; min-width: 0;
    border: 0; outline: none; background: transparent;
    padding: 0.8rem 0;
    font-family: var(--font);
    /* 1rem = 16px: below that iOS Safari zooms the page in on focus and never
       zooms back out — and this is the first thing a phone touches. */
    font-size: 1rem; font-weight: 400;
    color: var(--text-primary);
    text-align: left;
}
.sr-input::placeholder { color: var(--text-muted); opacity: 1; }
.sr-input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.sr-clear {
    flex: 0 0 auto;
    width: 2rem; height: 2rem;
    display: grid; place-items: center;
    border: 0; border-radius: 8px;
    background: transparent;
    color: var(--text-muted);
    font-size: 1.2rem; line-height: 1;
    cursor: pointer;
}
.sr-clear:hover { color: var(--text-primary); background: var(--surface-hover); }
.sr-clear[hidden] { display: none; }

/* ── The front door steps aside ────────────────────────────────────────
   Taken OUT OF FLOW rather than hidden, so the results start at the top of
   the page instead of under a hole — and put back with a fade, which is the
   half Nicolas actually asked for ("the landing page fades back in"). */
.lp-body { transition: opacity 0.22s ease; }
.lp.is-searching .lp-body {
    opacity: 0;
    pointer-events: none;
    position: absolute;
    left: -9999px;
    top: 0;
}

/* ── The results ───────────────────────────────────────────────────── */
.sr { animation: sr-in 0.2s ease both; text-align: left; }
@keyframes sr-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
    .sr { animation: none; }
    .lp-body { transition: none; }
}
.sr-count {
    margin: 0 0 clamp(0.9rem, 2vw, 1.2rem);
    font-size: 0.74rem; font-weight: 700;
    letter-spacing: 0.16em; text-transform: uppercase;
    color: var(--text-muted);
    text-align: center;
}

/* TWO ACROSS, FULL WIDTH — and exactly one on a phone, where two would make
   both the title and the preview unreadable. */
.sr-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.7rem; }
@media (max-width: 720px) { .sr-grid { grid-template-columns: 1fr; } }

.sr-tile {
    display: flex;
    gap: 0.9rem;
    padding: 1.05rem 1.15rem;
    border-radius: 0.95rem;
    border: 1px solid rgb(var(--note-rgb) / 0.28);
    background: var(--surface);
    text-decoration: none;
    color: var(--text-primary);
    transition: border-color 0.16s, background 0.16s, transform 0.16s;
}
.sr-tile:hover, .sr-tile:focus-visible {
    border-color: rgb(var(--note-rgb) / 0.75);
    background: color-mix(in srgb, var(--note) 7%, var(--surface-hover));
    transform: translateY(-2px);
    outline: none;
}
.sr-tile:active { transform: translateY(0); transition-duration: 0.06s; }
.sr-ico {
    flex: 0 0 auto;
    width: 2.4rem; height: 2.4rem;
    display: grid; place-items: center;
    border-radius: 0.7rem;
    color: var(--note);
    background: rgb(var(--note-rgb) / 0.12);
    border: 1px solid rgb(var(--note-rgb) / 0.3);
}
.sr-ico svg { width: 1.25rem; height: 1.25rem; }
.sr-body { min-width: 0; display: block; }
.sr-kind {
    display: block;
    font-size: 0.66rem; font-weight: 700;
    letter-spacing: 0.16em; text-transform: uppercase;
    color: var(--note);
    margin-bottom: 0.25rem;
}
.sr-title {
    display: block;
    font-size: 1rem; font-weight: 700; line-height: 1.3;
    color: var(--text-primary);
    margin-bottom: 0.3rem;
}
.sr-text {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
    overflow: hidden;
    font-size: 0.88rem; font-weight: 300; line-height: 1.6;
    color: var(--text-secondary);
}

/* ── Nothing found, said without blaming the reader ─────────────────── */
.sr-empty {
    padding: clamp(2rem, 6vw, 3rem) 1.4rem;
    border: 1px dashed rgb(var(--note-rgb) / 0.28);
    border-radius: 0.95rem;
    text-align: center;
}
.sr-empty p { margin: 0; font-size: 1rem; color: var(--text-secondary); }
.sr-empty-n { margin-top: 0.6rem !important; font-size: 0.9rem !important; color: var(--text-muted) !important; }
.sr-empty a { color: var(--text-primary); border-bottom: 1px solid rgb(var(--act-rgb) / 0.5); text-decoration: none; }
.sr-empty a:hover { border-bottom-color: var(--act); }
