/* =============================================================================
   The Light Lounge - ONE token file (WP-3, "One brand")
   =============================================================================
   WHY THIS FILE EXISTS
   Six live surfaces (public site, campaign pages, kiosk, member app, cockpit,
   office) each carried their own palette, their own type stack and their own
   spacing guesses. A member who booked on the public site, signed in to the
   member app and scanned the pod QR code saw three different companies. This
   file is the single place colour, type, space, radius, motion and focus are
   defined for all of them.

   THE THREE GROUNDS
     1. Arrival   - the guest light ground (cream paper, oxblood, bronze).
                    Declared on :root, so it is what a page gets by default.
     2. Nocturne  - the guest dark ground. Reached by html[data-theme="dark"]
                    (member app, cockpit, office), body[data-theme="dark"]
                    (kiosk, which flips by screen, not by preference) or an
                    explicit [data-ground="nocturne"].
     3. Studio    - the staff amber density. Reached by [data-ground="staff"].
                    Amber is not a second brand; it is the density staff work
                    in all day. Guest surfaces never resolve --ll-accent to it.

   HOW A SURFACE USES IT
     <link rel="stylesheet" href="/assets/tokens.css"> in the head, before the
     surface's own stylesheet, then read tokens by name. A surface may alias a
     token to its own local name (member-v2 maps --paper: var(--ll-ground)) but
     must never re-declare a --ll-* value: functions/brand-guard.test.js fails
     the build if it does, and fails on a new colour literal or an external
     font link in a guarded file.

   WHAT THIS FILE DOES NOT DO
     - It does not restyle the cockpit or office boards. Those pages load it for
       the fonts, the focus baseline and the Studio ground; remapping their own
       --amber/--ivory tokens onto --ll-* belongs to the staff package (WP-1).
     - It does not set page layout. No margins, no widths, no z-index stack
       beyond the two shared overlay components at the bottom of this file.
     - It does not ship a JavaScript theme switcher. Every surface already has
       its own, and they keep their own storage keys.

   ROLLBACK
     Delete the <link> from a page's head and that page falls back to whatever
     its own stylesheet declares. Nothing here is required for a page to boot.

   FONTS
     Every face below is served from this origin out of assets/fonts/ (latin
     subset, woff2, variable where the family offers it). No page may link
     fonts.googleapis.com or fonts.gstatic.com; the guard test enforces it.
     Brand faces are Fraunces and Inter. Cormorant Garamond and Manrope are the
     kiosk's documented pair. The rest are legacy campaign faces still named by
     lp/ pages and internal decks - they are self-hosted so no page reaches
     off-origin, and they retire as those pages move onto the brand pair (WP-9).
     Licences: all faces are SIL Open Font Licence 1.1 (see assets/fonts/OFL.md).
   ============================================================================= */

/* --- brand faces ---------------------------------------------------------- */
@font-face{font-family:'Fraunces';font-style:normal;font-weight:100 900;font-display:swap;src:url('/assets/fonts/fraunces-normal.woff2') format('woff2')}
@font-face{font-family:'Fraunces';font-style:italic;font-weight:100 900;font-display:swap;src:url('/assets/fonts/fraunces-italic.woff2') format('woff2')}
@font-face{font-family:'Inter';font-style:normal;font-weight:100 900;font-display:swap;src:url('/assets/fonts/inter-normal.woff2') format('woff2')}

/* --- kiosk pair ----------------------------------------------------------- */
@font-face{font-family:'Cormorant Garamond';font-style:normal;font-weight:300 700;font-display:swap;src:url('/assets/fonts/cormorant-garamond-normal.woff2') format('woff2')}
@font-face{font-family:'Cormorant Garamond';font-style:italic;font-weight:300 700;font-display:swap;src:url('/assets/fonts/cormorant-garamond-italic.woff2') format('woff2')}
@font-face{font-family:'Manrope';font-style:normal;font-weight:200 800;font-display:swap;src:url('/assets/fonts/manrope-normal.woff2') format('woff2')}

/* --- legacy campaign faces (WP-9 retires these onto the brand pair) -------- */
@font-face{font-family:'Sora';font-style:normal;font-weight:100 800;font-display:swap;src:url('/assets/fonts/sora-normal.woff2') format('woff2')}
@font-face{font-family:'Anton';font-style:normal;font-weight:400;font-display:swap;src:url('/assets/fonts/anton-normal-400.woff2') format('woff2')}
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:300 700;font-display:swap;src:url('/assets/fonts/space-grotesk-normal.woff2') format('woff2')}
@font-face{font-family:'Archivo';font-style:normal;font-weight:100 900;font-display:swap;src:url('/assets/fonts/archivo-normal.woff2') format('woff2')}
@font-face{font-family:'Oswald';font-style:normal;font-weight:200 700;font-display:swap;src:url('/assets/fonts/oswald-normal.woff2') format('woff2')}
@font-face{font-family:'Newsreader';font-style:normal;font-weight:200 800;font-display:swap;src:url('/assets/fonts/newsreader-normal.woff2') format('woff2')}
@font-face{font-family:'Newsreader';font-style:italic;font-weight:200 800;font-display:swap;src:url('/assets/fonts/newsreader-italic.woff2') format('woff2')}
@font-face{font-family:'Spectral';font-style:normal;font-weight:400;font-display:swap;src:url('/assets/fonts/spectral-normal-400.woff2') format('woff2')}
@font-face{font-family:'Spectral';font-style:normal;font-weight:500;font-display:swap;src:url('/assets/fonts/spectral-normal-500.woff2') format('woff2')}
@font-face{font-family:'Spectral';font-style:normal;font-weight:600;font-display:swap;src:url('/assets/fonts/spectral-normal-600.woff2') format('woff2')}
@font-face{font-family:'Spectral';font-style:italic;font-weight:400;font-display:swap;src:url('/assets/fonts/spectral-italic-400.woff2') format('woff2')}
@font-face{font-family:'Spectral';font-style:italic;font-weight:500;font-display:swap;src:url('/assets/fonts/spectral-italic-500.woff2') format('woff2')}

/* =============================================================================
   GROUND 1 - Arrival (guest light). The default.
   ============================================================================= */
:root{
  /* type */
  --ll-font-display:'Fraunces',Georgia,serif;
  --ll-font-sans:'Inter',system-ui,-apple-system,'Segoe UI',sans-serif;
  --ll-font-kiosk-display:'Cormorant Garamond',Georgia,serif;
  --ll-font-kiosk-body:'Manrope',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  /* type scale - one ramp, in the sizes the surfaces actually use today */
  --ll-text-micro:9.5px;
  --ll-text-eyebrow:10.5px;
  --ll-text-xs:11.5px;
  --ll-text-sm:12.5px;
  --ll-text-btn:13.5px;
  --ll-text-body:15px;
  --ll-text-lg:17px;
  --ll-text-title:20px;
  --ll-text-display:26px;
  --ll-leading-tight:1.15;
  --ll-leading-body:1.5;
  --ll-tracking-eyebrow:.15em;
  /* space */
  --ll-space-1:4px; --ll-space-2:8px; --ll-space-3:12px; --ll-space-4:16px;
  --ll-space-5:24px; --ll-space-6:32px; --ll-space-7:48px;
  /* radius */
  --ll-radius-sm:11px; --ll-radius-md:14px; --ll-radius-lg:18px;
  --ll-radius-xl:22px; --ll-radius-pill:999px;
  /* motion */
  --ll-ease:cubic-bezier(.22,.61,.36,1);
  --ll-motion-fast:.16s; --ll-motion-standard:.25s; --ll-motion-slow:.34s;
  /* focus - one visible ring, every surface, keyboard only */
  --ll-focus-width:2px; --ll-focus-offset:2px;
  /* touch - the smallest a guest-facing control may be */
  --ll-tap-min:44px;
  /* the bottom stack: two real bar heights and one z-index order, for every surface that fixes
     something to the bottom of the viewport */
  --ll-stack-bar:calc(54px + env(safe-area-inset-bottom));
  --ll-stack-composer:calc(72px + env(safe-area-inset-bottom));
  /* home-screen fit: assets/standalone-fit.js sets this to the height iOS 26 leaves out of an installed
     app's layout viewport (62px on an 874px phone added under the black-translucent status-bar style).
     Only the member app's shell reads it (it grows by this much, which makes iOS extend the page to the
     whole screen); the bars below deliberately stay on the page bottom, so a phone that never extends
     the page keeps a visible bar with the old band under it rather than a bar pushed off the screen. */
  --ll-stack-drop:0px;
  --ll-stack-z-bar:20;
  --ll-stack-z-scrim:40;
  --ll-stack-z-sheet:50;
  --ll-stack-z-toast:60;

  /* ---------------------------------------------------------------------
     THE GUEST PALETTE, BOTH GROUNDS, ALWAYS RESOLVABLE.
     The kiosk paints a cream arrival screen and an espresso practice screen in
     the same session, so it needs both grounds at once and cannot rely on the
     active ground alone. These are the raw values; the ground tokens below
     point at them. Nothing outside this file may declare one.
     --------------------------------------------------------------------- */
  --ll-arrival-ink:#261d19;
  --ll-arrival-ink-soft:#624b3e;
  --ll-arrival-ground:#fbf7f0;
  --ll-arrival-ground-deep:#f1e9dc;
  --ll-arrival-raised:#fffaf5;
  --ll-arrival-surface:rgba(255,252,247,.94);
  --ll-arrival-surface-quiet:rgba(250,245,237,.88);
  --ll-arrival-line:#decbb4;
  --ll-arrival-line-strong:#bf976e;
  --ll-arrival-bronze:#9c5f30;
  --ll-arrival-bronze-bright:#bb7540;
  --ll-arrival-accent:#8f211f;
  --ll-arrival-accent-deep:#681713;
  --ll-arrival-accent-border:#a6453e;
  /* Aura: the blush that sits behind the dimensional membership pass and the arrival
     treatment. Added for the member app (LL-07); it is the one R4 colour with no
     production equivalent at any reasonable distance - nearest existing token is dE 23.8
     on arrival and 31.3 on nocturne, i.e. a different colour, not a rounding difference.
     Named for what it does, not for the draft it came from. */
  --ll-arrival-aura:#63233b;

  --ll-nocturne-ink:#fff8ef;
  --ll-nocturne-ink-soft:#d5c6b5;
  --ll-nocturne-ground:#0f0e0d;
  --ll-nocturne-ground-deep:#17140f;
  --ll-nocturne-raised:#28211c;
  --ll-nocturne-surface:rgba(22,19,15,.94);
  --ll-nocturne-surface-quiet:rgba(29,24,18,.88);
  --ll-nocturne-line:#654a31;
  --ll-nocturne-line-strong:#a87748;
  --ll-nocturne-bronze:#d7a06d;
  --ll-nocturne-bronze-bright:#ecc08f;
  --ll-nocturne-accent:#9d2926;
  --ll-nocturne-accent-deep:#681714;
  --ll-nocturne-accent-border:#ad4d45;
  --ll-nocturne-aura:#f0d3d6;
  --ll-nocturne-soft:#4a2a1d;
  --ll-nocturne-border:#5a493d;
  --ll-nocturne-gold-soft:#4a3a22;

  /* --- The eight goal categories (mp-14, 2026-09-05) -------------------------
     One colour per real category slug in functions/_lib/protocol-categories.js,
     and there are exactly eight because there are exactly eight categories - a
     ninth value here would be a category the studio does not have. Used by the
     member app's twelve-week practice calendar, where a member has to be able
     to tell Recover from Restore at 9px on a phone, which is why these are
     eight distinct hues rather than eight tints of the bronze. Both grounds are
     given real values: a chart legible on cream and mud on espresso is half a
     chart. Kept in one contiguous block, arrival then nocturne, so the whole
     palette can be read - and changed - in one place.
     ------------------------------------------------------------------------ */
  --ll-arrival-cat-perform:#9c5f30;
  --ll-arrival-cat-recover:#4f7a5c;
  --ll-arrival-cat-regenerate:#8f211f;
  --ll-arrival-cat-reset:#4a6480;
  --ll-arrival-cat-restore:#6d5a8c;
  --ll-arrival-cat-renew:#2f7c78;
  --ll-arrival-cat-glow:#b9843a;
  --ll-arrival-cat-lifestyle:#7a5c4a;

  --ll-nocturne-cat-perform:#c98549;
  --ll-nocturne-cat-recover:#79ab88;
  --ll-nocturne-cat-regenerate:#d1554f;
  --ll-nocturne-cat-reset:#7b9dc0;
  --ll-nocturne-cat-restore:#a08cc4;
  --ll-nocturne-cat-renew:#4fb3ad;
  --ll-nocturne-cat-glow:#e0ab5e;
  --ll-nocturne-cat-lifestyle:#b08b71;

  /* Shared with both grounds: the metals, the states, the text that sits on a
     rich fill. One value each - a guest never sees a second orange or a second
     green depending on which screen they are on. */
  --ll-gold:#a6864f;
  --ll-gold-soft:#e8dfc9;
  --ll-blush:#f3d9c4;
  --ll-limestone:#dfe0da;
  --ll-danger:#8a3226;
  --ll-danger-ground:#401814;
  --ll-positive:#456b59;
  --ll-success:#557a63;
  --ll-success-soft:#e7f0ea;
  --ll-success-tint:#8cb39b;
  --ll-success-deep-ground:#21372c;
  --ll-success-deep-ink:#d5e4da;
  --ll-info:#51718a;
  --ll-warn:#8a5a15;
  --ll-on-accent:#fffaf5;
  --ll-on-rich:#fff8ef;

  /* --- GROUND 1 - Arrival, the default --- */
  --ll-ink:var(--ll-arrival-ink);
  --ll-ink-soft:var(--ll-arrival-ink-soft);
  --ll-ground:var(--ll-arrival-ground);
  --ll-ground-deep:var(--ll-arrival-ground-deep);
  --ll-surface:var(--ll-arrival-surface);
  --ll-surface-quiet:var(--ll-arrival-surface-quiet);
  --ll-line:var(--ll-arrival-line);
  --ll-line-strong:var(--ll-arrival-line-strong);
  --ll-bronze:var(--ll-arrival-bronze);
  --ll-bronze-bright:var(--ll-arrival-bronze-bright);
  --ll-accent:var(--ll-arrival-accent);
  --ll-accent-deep:var(--ll-arrival-accent-deep);
  --ll-accent-border:var(--ll-arrival-accent-border);
  --ll-aura:var(--ll-arrival-aura);
  --ll-shadow:0 18px 48px rgba(67,42,27,.10);
  --ll-shadow-lift:0 -20px 50px -20px rgba(38,29,25,.42);
  --ll-scrim:rgba(20,13,8,.55);
  --ll-focus-ring:var(--ll-bronze);

  /* Translucent layers. These sit on top of photography or on the oxblood/rich
     fills, not on the ground, so they hold in both Arrival and Nocturne and are
     declared once. Named for the job they do, not the colour they are. */
  --ll-ink-veil:rgba(20,16,12,.55);
  --ll-nocturne-veil-top:rgba(15,14,13,.55);
  --ll-nocturne-veil-bottom:rgba(15,14,13,.68);
  --ll-rich-veil:rgba(255,250,245,.16);
  --ll-rich-fill:rgba(255,250,245,.94);
  --ll-rich-fill-quiet:rgba(255,250,245,.18);
  --ll-rich-line:rgba(255,250,245,.4);
  --ll-rich-line-soft:rgba(255,250,245,.28);
  --ll-rich-ring:rgba(255,250,245,.35);
  --ll-shadow-knob:0 1px 3px rgba(0,0,0,.3);
  --ll-shadow-chip:0 1px 2px rgba(0,0,0,.06);
  --ll-shadow-toast:0 14px 34px -14px rgba(0,0,0,.5);
  --ll-shadow-accent-lift:0 8px 20px -8px rgba(143,33,31,.5);
  --ll-rich-line-strong:rgba(255,250,245,.6);
  --ll-hairline:rgba(36,28,23,.13);
  --ll-hairline-soft:rgba(36,28,23,.12);
  --ll-hairline-inverse:rgba(255,255,255,.18);
  --ll-hairline-inverse-soft:rgba(255,255,255,.14);
  --ll-shadow-float:0 18px 44px rgba(0,0,0,.35);
  --ll-shadow-page:0 30px 70px -44px rgba(33,28,24,.45);
  --ll-shadow-card:0 1px 1px rgba(120,72,20,.05),0 10px 24px -10px rgba(120,72,20,.16),0 32px 56px -28px rgba(120,72,20,.24);
  --ll-shadow-card-dark:0 1px 2px rgba(0,0,0,.35),0 10px 24px -10px rgba(0,0,0,.4),0 32px 56px -28px rgba(0,0,0,.5);

  /* The rich espresso panel every guest QR and phone page opens with. One
     gradient, one glow, one text colour, shared by checkin, perk, protocol,
     partner and the printed placard. */
  --ll-rich-top:#2C2219;
  --ll-rich-bottom:#1A130E;
  --ll-rich-glow:rgba(224,168,94,.26);
  --ll-rich-ink:#F3E9DA;
  --ll-frame-line:rgba(42,29,15,.35);
  --ll-positive-pulse:rgba(79,160,107,.5);
  --ll-positive-pulse-out:rgba(79,160,107,0);
  /* The insignia's own flat amber. It is the mark, not a theme colour: it does
     not change with the ground, and the SVG carries it inline in markup. */
  --ll-mark:#FD7F2C;

  /* The eight categories, on the arrival ground. */
  --ll-cat-perform:var(--ll-arrival-cat-perform);
  --ll-cat-recover:var(--ll-arrival-cat-recover);
  --ll-cat-regenerate:var(--ll-arrival-cat-regenerate);
  --ll-cat-reset:var(--ll-arrival-cat-reset);
  --ll-cat-restore:var(--ll-arrival-cat-restore);
  --ll-cat-renew:var(--ll-arrival-cat-renew);
  --ll-cat-glow:var(--ll-arrival-cat-glow);
  --ll-cat-lifestyle:var(--ll-arrival-cat-lifestyle);
}

/* =============================================================================
   GROUND 2 - Nocturne (guest dark).
   Three selectors because three surfaces already flip three different ways:
   html[data-theme] (member app, cockpit, office), body[data-theme] (kiosk,
   which flips per screen), and an explicit ground for anything new.
   ============================================================================= */
html[data-theme="dark"],
body[data-theme="dark"],
[data-ground="nocturne"]{
  --ll-ink:var(--ll-nocturne-ink);
  --ll-ink-soft:var(--ll-nocturne-ink-soft);
  --ll-ground:var(--ll-nocturne-ground);
  --ll-ground-deep:var(--ll-nocturne-ground-deep);
  --ll-surface:var(--ll-nocturne-surface);
  --ll-surface-quiet:var(--ll-nocturne-surface-quiet);
  --ll-line:var(--ll-nocturne-line);
  --ll-line-strong:var(--ll-nocturne-line-strong);
  --ll-bronze:var(--ll-nocturne-bronze);
  /* The eight categories, on the nocturne ground (mp-14). */
  --ll-cat-perform:var(--ll-nocturne-cat-perform);
  --ll-cat-recover:var(--ll-nocturne-cat-recover);
  --ll-cat-regenerate:var(--ll-nocturne-cat-regenerate);
  --ll-cat-reset:var(--ll-nocturne-cat-reset);
  --ll-cat-restore:var(--ll-nocturne-cat-restore);
  --ll-cat-renew:var(--ll-nocturne-cat-renew);
  --ll-cat-glow:var(--ll-nocturne-cat-glow);
  --ll-cat-lifestyle:var(--ll-nocturne-cat-lifestyle);
  --ll-bronze-bright:var(--ll-nocturne-bronze-bright);
  --ll-accent:var(--ll-nocturne-accent);
  --ll-accent-deep:var(--ll-nocturne-accent-deep);
  --ll-accent-border:var(--ll-nocturne-accent-border);
  --ll-aura:var(--ll-nocturne-aura);
  --ll-danger:#983a2d;
  --ll-positive:#83a996;
  --ll-warn:#e0a85e;
  --ll-shadow:0 24px 56px rgba(0,0,0,.32);
  --ll-shadow-lift:0 -20px 50px -20px rgba(0,0,0,.5);
  --ll-scrim:rgba(6,4,3,.62);
  --ll-focus-ring:var(--ll-bronze-bright);
}

/* =============================================================================
   GROUND 3 - Studio (the staff ground). Never a guest ground.

   2026-09-07, the Office entrance. This ground was written as an amber density
   back when the staff surface was the old Operator Console, and nothing has ever
   rendered it. The staff app the studio actually uses today is Office V2, and
   Office V2 is oxblood on warm paper. So the seven values that decide how a staff
   surface reads - the accent, the deeper accent, the surface, the ink, the two
   line weights and the text that sits on the accent - are now Office V2's own
   light values, read straight off its stylesheet. The sign-in door at /ops/ is the
   first page ever to render this ground, and it now lands on the app instead of
   near it.
   ============================================================================= */
[data-ground="staff"]{
  --ll-ink:#211f1c;
  --ll-ink-soft:#564D43;
  --ll-ground:#F7F3ED;
  --ll-ground-deep:#EDE5D8;
  --ll-surface:#fffdfa;
  --ll-surface-quiet:#F1ECE2;
  --ll-line:#d8d1c8;
  --ll-line-strong:#a99e92;
  --ll-bronze:#8F5A1E;
  --ll-bronze-bright:#E0A85E;
  --ll-accent:#992e29;
  --ll-accent-deep:#79211d;
  --ll-accent-border:#F5DFB8;
  --ll-danger:#A8442C;
  --ll-positive:#2F6B45;
  --ll-warn:#8C7139;
  --ll-on-accent:#fffaf7;
  --ll-on-rich:#FFF;
  --ll-shadow:0 6px 20px -6px rgba(33,28,24,.12),0 2px 6px -2px rgba(33,28,24,.06);
  --ll-scrim:rgba(33,28,24,.5);
  --ll-focus-ring:var(--ll-accent-deep);
}
html[data-theme="dark"][data-ground="staff"],
[data-ground="staff"][data-theme="dark"]{
  --ll-ink:#f4ece3;
  --ll-ink-soft:#d9c9b2;
  --ll-ground:#16100c;
  --ll-ground-deep:#2b1f17;
  --ll-surface:#211711;
  --ll-surface-quiet:#2b1f17;
  --ll-line:#3a2a1f;
  --ll-line-strong:#3a2a1f;
  --ll-bronze:#f3c969;
  --ll-bronze-bright:#f0a23c;
  --ll-accent:#f0a23c;
  --ll-accent-deep:#f3c969;
  --ll-accent-border:#2b2013;
  --ll-danger:#e8694a;
  --ll-positive:#5fc98a;
  --ll-warn:#f0a23c;
  --ll-on-accent:#16100c;
  --ll-on-rich:#16100c;
  --ll-focus-ring:var(--ll-bronze);
}

/* =============================================================================
   ACCESSIBILITY BASELINE - loaded with the tokens, so a surface cannot get the
   brand without it.
   ============================================================================= */

/* One visible focus ring, keyboard only, on every interactive element. Written
   with :focus-visible so a mouse press never paints a ring, and scoped off
   non-interactive focus anchors (the kiosk focuses its own h1 to announce a new
   screen - that must not paint a box a touch guest never asked for). */
:focus-visible{
  outline:var(--ll-focus-width) solid var(--ll-focus-ring);
  outline-offset:var(--ll-focus-offset);
}
[tabindex="-1"]:focus:not(:focus-visible){outline:none}

/* Honoured everywhere the token file is loaded. */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms!important;
    animation-iteration-count:1!important;
    transition-duration:.001ms!important;
    scroll-behavior:auto!important;
  }
}

/* Label text that only a screen reader needs. */
.ll-sr-only{
  position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}

/* =============================================================================
   COMPONENTS - one definition, reached by the class names each surface's markup
   already ships. The alias selectors are deliberate: the member app's markup is
   written by JavaScript owned by other packages this cycle, and the kiosk's by
   its own renderer, so renaming every call site would collide with work in
   flight. One rule, three hooks, no second definition anywhere.
   ============================================================================= */

/* --- one button grammar ---------------------------------------------------- */
.ll-btn,
.shell .btn,
.kiosk-shell .button{
  --ll-btn-bg:linear-gradient(135deg,var(--ll-accent),var(--ll-accent-deep));
  --ll-btn-fg:var(--ll-on-accent);
  --ll-btn-bd:var(--ll-accent-border);
  display:flex;
  width:100%;
  align-items:center;
  justify-content:center;
  gap:var(--ll-space-2);
  min-height:var(--ll-tap-min);
  padding:var(--ll-space-3) var(--ll-space-4);
  border:1px solid var(--ll-btn-bd);
  border-radius:var(--ll-radius-md);
  background:var(--ll-btn-bg);
  color:var(--ll-btn-fg);
  font-family:inherit;
  font-size:var(--ll-text-btn);
  font-weight:700;
  letter-spacing:.02em;
  line-height:1.25;
  text-align:center;
  cursor:pointer;
  transition:transform var(--ll-motion-fast) var(--ll-ease),opacity var(--ll-motion-fast) var(--ll-ease);
}
.ll-btn--secondary,
.shell .btn.ghost,
.kiosk-shell .button--secondary{
  --ll-btn-bg:transparent;
  --ll-btn-fg:var(--ll-ink);
  --ll-btn-bd:var(--ll-line-strong);
}
.ll-btn--quiet,
.kiosk-shell .button--quiet{
  --ll-btn-bg:var(--ll-ground-deep);
  --ll-btn-fg:var(--ll-ink);
  --ll-btn-bd:var(--ll-line);
}
.ll-btn--small,
.shell .btn.sm,
.kiosk-shell .button--small{
  display:inline-flex;
  width:auto;
  min-height:42px;
  padding:var(--ll-space-2) var(--ll-space-4);
  font-size:var(--ll-text-sm);
  border-radius:var(--ll-radius-sm);
}
.ll-btn--wide,
.kiosk-shell .button--wide{width:100%}
.ll-btn:disabled,
.shell .btn:disabled,
.kiosk-shell .button:disabled{opacity:.5}
.ll-btn:active,
.shell .btn:active,
.kiosk-shell .button:active{transform:translateY(1px)}

/* The kiosk is a wall-mounted iPad at arm's length: same grammar, one size up. */
.kiosk-shell .button{
  min-height:50px;
  border-radius:var(--ll-radius-pill);
  padding:var(--ll-space-3) var(--ll-space-5);
  font-size:clamp(13px,1.5vw,16px);
}
.kiosk-shell .button--small{min-height:42px;font-size:12px;border-radius:var(--ll-radius-pill)}

/* --- one eyebrow grammar --------------------------------------------------- */
.ll-eyebrow,
.shell .sec,
.kiosk-shell .eyebrow{
  display:flex;
  align-items:center;
  gap:var(--ll-space-2);
  font-family:inherit;
  font-size:var(--ll-text-eyebrow);
  font-weight:700;
  letter-spacing:var(--ll-tracking-eyebrow);
  line-height:1.3;
  text-transform:uppercase;
  color:var(--ll-bronze);
}
.ll-eyebrow--accent,
.kiosk-shell .eyebrow--orange{color:var(--ll-accent)}
.ll-eyebrow--inverse,
.kiosk-shell .eyebrow--inverse{color:var(--ll-on-rich)}
.ll-eyebrow .ln,
.shell .sec .ln{flex:1;height:1px;background:var(--ll-line)}

/* --- one sheet component --------------------------------------------------- */
.ll-scrim,
.shell .scrim{
  position:absolute;
  inset:0;
  z-index:var(--ll-stack-z-scrim);
  background:var(--ll-scrim);
  backdrop-filter:blur(2px);
  opacity:0;
  pointer-events:none;
  transition:opacity var(--ll-motion-standard) var(--ll-ease);
}
.ll-scrim.show,
.shell .scrim.show{opacity:1;pointer-events:auto}
.ll-sheet,
.shell .sheet{
  position:absolute;
  left:0;right:0;bottom:0;
  z-index:var(--ll-stack-z-sheet);
  max-height:82%;
  overflow-y:auto;
  padding:var(--ll-space-4) var(--ll-space-5) calc(env(safe-area-inset-bottom) + var(--ll-space-5));
  border-top:1px solid var(--ll-line-strong);
  border-radius:var(--ll-radius-xl) var(--ll-radius-xl) 0 0;
  background:var(--ll-ground);
  box-shadow:var(--ll-shadow-lift);
  transform:translateY(105%);
  transition:transform var(--ll-motion-slow) var(--ll-ease);
}
.ll-sheet.show,
.shell .sheet.show{transform:none}
.ll-sheet .grip,
.shell .sheet .grip{
  width:38px;height:4px;margin:0 auto var(--ll-space-4);
  border-radius:4px;background:var(--ll-line-strong);
}
.ll-sheet-close,
.shell .sheetx{
  position:absolute;top:var(--ll-space-2);right:10px;
  display:flex;align-items:center;justify-content:center;
  width:36px;height:36px;
  border:1px solid var(--ll-line);
  border-radius:50%;
  background:var(--ll-surface);
  color:var(--ll-ink-soft);
  font-size:22px;line-height:1;cursor:pointer;
}

/* --- one bottom stack ------------------------------------------------------ */
/* Everything a guest surface fixes to the bottom of the viewport stacks here, in this order, so a
   tab bar, a composer, a sheet and a toast can never fight over the same pixels or the same
   z-index again. The two heights are measured off the real rendered bars at
   safe-area-inset-bottom:0 (54px and 72px) and carry the env() term so a notched phone is right
   without any JavaScript. The member app's tab bar and Concierge composer are the hooks; a new
   surface uses the class names. */
.ll-bottom-stack__bar,
.shell .tabbar{
  position:fixed;left:0;right:0;bottom:0;
  margin:0 auto;
  z-index:var(--ll-stack-z-bar);
}
.ll-bottom-stack__composer,
.shell .composer{
  position:fixed;left:0;right:0;bottom:var(--ll-stack-bar);
  margin:0 auto;
  z-index:var(--ll-stack-z-bar);
}
.ll-bottom-stack__toast{
  position:fixed;left:50%;bottom:calc(var(--ll-stack-bar) + var(--ll-space-4));
  transform:translateX(-50%);
  z-index:var(--ll-stack-z-toast);
}

/* =============================================================================
   MARQUEE - the marketing home page's own editorial expression of the Nocturne ground.
   assets/ll.css (the home page, index.html) reads every colour it paints through these
   forty-one names and declares none of its own - WP-3 moved its literals here so the
   brand guard could hold the whole site to one file. They were referenced by that
   rewrite but never written down here, which left the home page with no ground and
   black ink on the live site for most of 2026-09-05 until the deploy that carries this
   block. functions/tokens-resolve.test.js now fails the build if any shipped stylesheet
   reads a --ll-* name this file does not define. Values are the pre-WP-3 literals,
   recovered line for line from assets/ll.css at f590c2f^ - nothing about the page's look
   is new. ============================================================================ */
:root{
  --ll-marquee-blush:#ff6f91;
  --ll-marquee-blush-chip:rgba(255,111,145,.1);
  --ll-marquee-blush-glow:rgba(255,111,145,.34);
  --ll-marquee-card:#20160f;
  --ll-marquee-card-2:#271b12;
  --ll-marquee-deep-shadow:rgba(0,0,0,.8);
  --ll-marquee-fade-1:rgba(22,16,12,.72);
  --ll-marquee-fade-2:rgba(22,16,12,.28);
  --ll-marquee-fade-3:rgba(22,16,12,.55);
  --ll-marquee-fade-4:rgba(22,16,12,.2);
  --ll-marquee-flare:#ff8a3d;
  --ll-marquee-flare-chip:rgba(255,138,61,.16);
  --ll-marquee-flare-glow:rgba(255,138,61,.5);
  --ll-marquee-flare-line:rgba(255,138,61,.4);
  --ll-marquee-flare-wash:rgba(255,138,61,.06);
  --ll-marquee-flare-wash-2:rgba(255,138,61,.1);
  --ll-marquee-flare-wash-3:rgba(255,138,61,.12);
  --ll-marquee-glow:rgba(255,138,61,.3);
  --ll-marquee-gold:#e7b366;
  --ll-marquee-gold-core:rgba(231,179,102,.5);
  --ll-marquee-gold-line:rgba(231,179,102,.35);
  --ll-marquee-gold-wash:rgba(231,179,102,.28);
  --ll-marquee-ground:#16100c;
  --ll-marquee-ground-2:#1d150f;
  --ll-marquee-ink:#f8efe6;
  --ll-marquee-ink-soft:#cdb3a2;
  --ll-marquee-label:#aa9388;
  --ll-marquee-line:#33241a;
  --ll-marquee-muted:#9c8073;
  --ll-marquee-on-flare:#241009;
  --ll-marquee-phone:#1a110b;
  --ll-marquee-phone-shadow:rgba(0,0,0,.85);
  --ll-marquee-plan-muted:#a08a7c;
  --ll-marquee-pod-bottom:#160d09;
  --ll-marquee-pod-ember:#ffe6bf;
  --ll-marquee-pod-glow:rgba(255,138,61,.25);
  --ll-marquee-pod-line:#43291a;
  --ll-marquee-pod-top:#2a1c12;
  --ll-marquee-quote-veil:rgba(15,10,7,.62);
  --ll-marquee-veil:rgba(22,16,12,.82);
  --ll-marquee-veil-strong:rgba(20,14,10,.99);
}
