/* ══════════════════════════════════════════════════════════════════════════
   TripFlair — design tokens
   ══════════════════════════════════════════════════════════════════════════

   One file. Loaded by index.html AND app.html, before any page CSS.

   WHY THIS EXISTS
   The site and the app had drifted into two dialects. Measured on the landing
   page alone: 29 distinct font-sizes, 14 distinct border-radii, 12 ad-hoc
   transition declarations. Nobody chose that — it accumulated. A shared token
   file is the only thing that holds a visual language together once more than
   one screen exists.

   HOW TO USE IT
   Reach for a token before you type a number. If no token fits, the right move
   is usually to add a token here, not a literal there. Page-level :root blocks
   still override these, which is deliberate — it makes migration incremental
   rather than a flag day.

   COLOUR is the Deep Water scheme shipped in flat_325. It is reproduced here
   unchanged so this file is the single source. The revert table lives in
   TF-COLOR-SCHEME.md.
   ══════════════════════════════════════════════════════════════════════════ */

:root{

  /* ── 1 · COLOUR ─────────────────────────────────────────────────────────
     Four ink steps, because a text navy is not a band navy. #255194 carries
     text at 7.3:1 on paper, but bright accents FAIL on it as a ground
     (teal 4.22, coral 4.05) — a full-bleed band needs --band.               */

  --ink:#00104F;            /* deepest navy — band ground and body ink       */
  --ink-2:#255194;          /* brand navy — structural                       */
  --ink-soft:#4C72AC;       /* secondary text · 4.66:1 on paper              */
  --muted:#556FA8;          /* tertiary text · 4.76:1 — used at 12px         */
  --band:#00104F;           /* full-bleed dark ground                        */
  --band-2:#0D3A7B;         /* lighter dark ground — the page has two voices */
  --on-band:#8EBFFF;        /* secondary text on --band · 9.31:1             */

  --paper:#F8FAFE;          /* cool uncoated stock                           */
  --paper-2:#EAF1FA;        /* second sheet — the mist band                  */
  --white:#FFFFFF;

  --teal:#33B5AB;
  --teal-ink:#007F77;       /* teal that can carry text · 4.67:1 on paper    */
  --teal-eyebrow:#0BA198;   /* large text only · 3.06:1                      */
  --teal-on-band:#53CEC4;   /* 9.26:1 on --band, 6.58:1 on --band-2          */

  --coral:#F39883;          /* never a ground for text                       */
  --coral-ink:#C9705B;      /* the button's shadow edge; text-safe coral     */
  --coral-on-band:#FEA28D;  /* 9.07:1 on --band, 6.21:1 on --band-2          */
  --cta-label:#00104F;      /* on coral · 8.11:1 — white would be 2.18:1     */

  --blush:#F8C3B6;
  --seafoam:#66BFAF;
  --seafoam-rule:#8CE5D4;

  /* Semantic aliases. Prefer these in new work — they survive a palette
     change, the literal names do not.                                       */
  --surface:var(--white);
  --surface-sunk:var(--paper);
  --surface-raised:var(--white);
  --surface-inverse:var(--band);
  --text:var(--ink);
  --text-2:var(--ink-soft);
  --text-3:var(--muted);
  --text-on-inverse:#FFFFFF;
  --text-2-on-inverse:var(--on-band);
  --accent:var(--coral);
  --accent-text:var(--coral-ink);
  --accent-quiet:var(--teal-ink);

  /* Press marks — rules and scores, never solid greys.                      */
  --rule:rgba(0,16,79,.13);
  --rule-soft:rgba(0,16,79,.07);
  --rule-strong:rgba(0,16,79,.22);
  --score:rgba(0,16,79,.22);

  /* State. Reserved — never reuse these as decorative colour.
     Two variants each, because a state colour that only works on paper will
     be used on a dark band anyway and quietly fail there.

     These were re-derived after design-system.html measured the first pass:
     the original --ok came out at 4.13:1 and --warn at 3.47:1 on paper, both
     under the 4.5 floor for small text. Hue and saturation held; lightness
     stepped until each cleared. That is the page doing its job.             */
  --ok:#0D8265;             /* 4.57:1 on paper                               */
  --warn:#9D671B;           /* 4.58:1 on paper                               */
  --alert:#C0492F;          /* 4.74:1 on paper                               */
  --ok-on-band:#13B98F;     /* 7.05:1 on --band                              */
  --warn-on-band:#DC942D;   /* 7.01:1 on --band                              */
  --alert-on-band:#DF8F7D;  /* 7.05:1 on --band                              */
  --ok-bg:rgba(13,130,101,.10);
  --warn-bg:rgba(157,103,27,.12);
  --alert-bg:rgba(192,73,47,.10);


  /* ── 2 · TYPE ───────────────────────────────────────────────────────────
     Three faces, three jobs, and they do not trade places.
       Fraunces — display and headings. The brand's voice.
       DM Sans  — everything a user reads to get something done.
       Syne     — eyebrows and labels ONLY, always uppercase + tracked.

     Eleven steps replacing 29 ad-hoc sizes. If a design needs a size that
     isn't here, the design is usually wrong — but add a step rather than a
     literal if it genuinely isn't.                                          */

  --font-display:'Fraunces',Georgia,'Times New Roman',serif;
  --font-ui:'DM Sans',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  --font-label:'Syne',var(--font-ui);
  --font-mono:ui-monospace,SFMono-Regular,'SF Mono',Menlo,monospace;

  --text-micro:11px;        /* eyebrows, stamps, legal                       */
  --text-caption:12px;      /* captions, metadata, tertiary                  */
  --text-sm:13px;           /* dense UI, table cells, chips                  */
  --text-base:14px;         /* default UI text                               */
  --text-body:15px;         /* reading text in the app                       */
  --text-lg:17px;           /* lede, emphasised body                         */
  --text-title-sm:20px;
  --text-title:24px;
  --text-display-sm:30px;
  --text-display:40px;
  --text-display-lg:52px;

  --leading-tight:1.06;     /* display only                                  */
  --leading-snug:1.22;      /* headings                                      */
  --leading-normal:1.5;     /* UI                                            */
  --leading-relaxed:1.66;   /* reading                                       */

  --tracking-display:-.02em;
  --tracking-tight:-.01em;
  --tracking-normal:0;
  --tracking-label:.16em;   /* Syne eyebrows — always with uppercase         */
  --tracking-wide:.2em;

  --weight-light:300;
  --weight-normal:400;
  --weight-medium:500;
  --weight-semi:600;
  --weight-bold:700;


  /* ── 3 · SPACE ──────────────────────────────────────────────────────────
     4px base. Use the token, not the number — it is the difference between
     a layout that has a rhythm and one that has 40 arbitrary gaps.          */

  --space-1:4px;   --space-2:8px;   --space-3:12px;  --space-4:16px;
  --space-5:20px;  --space-6:24px;  --space-8:32px;  --space-10:40px;
  --space-14:56px; --space-18:72px; --space-24:96px;

  --gutter:24px;            /* page side padding, desktop                    */
  --gutter-sm:18px;         /* page side padding, phone                      */
  --maxw:1180px;            /* page measure                                  */
  --maxw-read:70ch;         /* prose measure — never let text run wider      */


  /* ── 4 · SHAPE ──────────────────────────────────────────────────────────
     Six radii replacing 14. Roughly: marks, chips, controls, cards, panels,
     pills.                                                                  */

  --r-mark:2px;
  --r-xs:6px;
  --r-sm:10px;             /* buttons, inputs                                */
  --r-md:14px;             /* cards                                          */
  --r-lg:20px;             /* panels, sheets, modals                         */
  --r-pill:999px;

  --border:1px solid var(--rule);
  --border-soft:1px solid var(--rule-soft);


  /* ── 5 · ELEVATION ──────────────────────────────────────────────────────
     Four steps. Shadows are navy-tinted, never black — black shadows on a
     cool paper read as dirt.                                                */

  --shadow-flat:0 1px 2px rgba(0,16,79,.04);
  --shadow-raise:0 2px 8px rgba(0,16,79,.06), 0 1px 2px rgba(0,16,79,.04);
  --shadow-lift:0 22px 60px rgba(0,16,79,.10), 0 3px 12px rgba(0,16,79,.05);
  --shadow-float:0 32px 80px rgba(0,16,79,.18), 0 6px 20px rgba(0,16,79,.09);
  --shadow-press:0 2px 0 var(--coral-ink);   /* the CTA's printed edge       */


  /* ── 6 · MOTION ─────────────────────────────────────────────────────────
     THE RULE, and it is a rule rather than a preference:

       Functional motion  ≤ --dur-slow.  Fires on interaction. Invisible.
       Story motion       = --dur-story.  Fires ONLY on a milestone —
                            first itinerary generated, trip completed, trip
                            finished. Never on navigation, never on hover,
                            never on scroll.

     "Motion everywhere" and "Apple for simplicity" are incompatible. This is
     where that argument is settled: three or four set-pieces a user sees a
     handful of times, and everything else disappears into the interaction.

     Every animation must degrade under prefers-reduced-motion (below).       */

  --dur-instant:90ms;
  --dur-fast:150ms;         /* the default for anything interactive          */
  --dur-base:200ms;
  --dur-slow:320ms;         /* sheets, overlays, disclosure                  */
  --dur-story:1200ms;       /* milestone set-pieces ONLY                     */

  --ease-out:cubic-bezier(.2,.8,.2,1);       /* the default                  */
  --ease-in-out:cubic-bezier(.4,0,.2,1);
  --ease-spring:cubic-bezier(.34,1.4,.5,1);  /* lift on press — use sparingly*/

  --lift-hover:translateY(-1px);
  --lift-press:translateY(1px);


  /* ── 7 · PAPER ──────────────────────────────────────────────────────────
     The signature vocabulary, as tokens rather than as one-off CSS in
     whichever file needed it first. These are what make a surface read as
     printed rather than as a div.

     Zone rule: paper texture belongs to Front of House and the Keepsake.
     The Workshop (trip view, Day Studio, Budget) stays clean — texture on a
     screen someone opens at 11pm to check a ferry time is friction.          */

  --paper-grain:
    radial-gradient(circle at 17% 23%, rgba(0,16,79,.018) 0 1px, transparent 1px),
    radial-gradient(circle at 71% 61%, rgba(0,16,79,.014) 0 1px, transparent 1px),
    radial-gradient(circle at 43% 88%, rgba(0,16,79,.012) 0 1px, transparent 1px);
  --paper-grain-size:37px 37px, 53px 53px, 29px 29px;

  /* A fold crease: a soft valley with a highlight on one side.              */
  --fold-v:linear-gradient(90deg,
    transparent calc(50% - 9px), rgba(0,16,79,.05) calc(50% - 4px),
    rgba(0,16,79,.09) 50%, rgba(255,255,255,.55) calc(50% + 2px),
    transparent calc(50% + 9px));
  --fold-h:linear-gradient(180deg,
    transparent calc(50% - 9px), rgba(0,16,79,.05) calc(50% - 4px),
    rgba(0,16,79,.09) 50%, rgba(255,255,255,.55) calc(50% + 2px),
    transparent calc(50% + 9px));

  --tape:linear-gradient(135deg,
    rgba(255,255,255,.42), rgba(248,195,182,.30) 45%, rgba(255,255,255,.36));
  --tape-edge:1px dashed rgba(0,16,79,.10);

  --stamp-ink:var(--coral-ink);
  --stamp-border:2px solid var(--coral-ink);

  --photo-corner:rgba(0,16,79,.34);


  /* ── 8 · LAYERS ─────────────────────────────────────────────────────────
     Named, so nobody has to guess whether 9999 is enough.                   */

  --z-base:0;
  --z-raised:10;
  --z-sticky:100;
  --z-nav:200;
  --z-overlay:900;
  --z-modal:1000;
  --z-toast:1100;
}


/* ── 9 · REDUCED MOTION ───────────────────────────────────────────────────
   Not a nicety. Someone has told their operating system that motion makes
   them unwell, and a travel brand that ignores that is not premium.

   Story motion stops entirely. Functional motion collapses to near-instant
   rather than to zero, so state changes are still legible.                  */

@media (prefers-reduced-motion:reduce){
  :root{
    --dur-instant:1ms; --dur-fast:1ms; --dur-base:1ms;
    --dur-slow:1ms;    --dur-story:1ms;
    --lift-hover:none; --lift-press:none;
  }
  *,*::before,*::after{
    animation-duration:1ms !important;
    animation-iteration-count:1 !important;
    transition-duration:1ms !important;
    scroll-behavior:auto !important;
  }
}


/* ── 10 · PRIMITIVES ──────────────────────────────────────────────────────
   The handful of classes worth sharing between the site and the app. Kept
   deliberately small — a token file that turns into a framework stops being
   read.                                                                     */

.tf-eyebrow{
  font-family:var(--font-label); font-weight:var(--weight-bold);
  font-size:var(--text-micro); letter-spacing:var(--tracking-label);
  text-transform:uppercase; color:var(--accent-quiet);
}

.tf-display{
  font-family:var(--font-display); font-weight:var(--weight-bold);
  line-height:var(--leading-tight); letter-spacing:var(--tracking-display);
}

.tf-heading{
  font-family:var(--font-display); font-weight:var(--weight-semi);
  line-height:var(--leading-snug); letter-spacing:var(--tracking-tight);
}

/* The one filled button on a screen. If there are two, one of them is wrong. */
.tf-cta{
  font-family:var(--font-ui); font-weight:var(--weight-bold);
  font-size:var(--text-base); color:var(--cta-label);
  background:var(--accent); border:0; border-radius:var(--r-sm);
  padding:var(--space-3) var(--space-5); min-height:44px; cursor:pointer;
  box-shadow:var(--shadow-press);
  transition:transform var(--dur-fast) var(--ease-out),
             box-shadow var(--dur-fast) var(--ease-out);
}
.tf-cta:hover{transform:var(--lift-hover);}
.tf-cta:active{transform:var(--lift-press); box-shadow:0 0 0 var(--coral-ink);}

.tf-ghost{
  font-family:var(--font-ui); font-weight:var(--weight-medium);
  font-size:var(--text-sm); color:var(--text-2);
  background:var(--surface); border:var(--border); border-radius:var(--r-sm);
  padding:var(--space-2) var(--space-4); min-height:44px; cursor:pointer;
  transition:border-color var(--dur-fast) var(--ease-out),
             color var(--dur-fast) var(--ease-out);
}
.tf-ghost:hover{border-color:var(--text-2); color:var(--text);}

/* Every interactive element clears 44px. Measured: 29 of 31 controls on the
   app's first screen did not. This is the floor, not the target.            */
.tf-tap{min-height:44px; min-width:44px;}

/* Focus. One ring, everywhere, and it is never removed without a replacement.*/
.tf-focus:focus-visible,
button:focus-visible, a:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible{
  outline:2px solid var(--teal-ink); outline-offset:2px; border-radius:var(--r-xs);
}

/* Front of House / Keepsake only — see the zone rule in §7.                 */
.tf-paper{
  background-color:var(--surface);
  background-image:var(--paper-grain);
  background-size:var(--paper-grain-size);
}
.tf-fold-v{position:relative;}
.tf-fold-v::after{
  content:''; position:absolute; inset:0; pointer-events:none;
  background:var(--fold-v);
}
