/* ==========================================================================
   Tatreez Systems - the apex marketing page.

   This is the whole look of tatreezsystems.com's front door. Served at
   /marketing.css by seo.js (apex host only) and linked from the page that
   marketingPage.js renders. Edit this file and refresh the browser - there
   is no build step and nothing to restart.

   Read it in this order:
     1. TOKENS      - every colour, font and measure, in one place
     2. RESET       - the handful of global rules
     3. STATE       - :hover / :focus-visible / the no-JavaScript case
     4. LAYOUT      - page shell, section rhythm, the grids
     5. COMPONENTS  - header, hero, figures, steps, modules, swatches, cta,
                      footer
     6. OVERLAY     - the needle-and-thread intro curtain

   Two conventions worth knowing before you change anything:

   --k is a letter-spacing switch, not a size. The display face is tightened
   in English (--k:1) and left alone in Arabic (--k:0), because negative
   tracking breaks Arabic joining. Every negative letter-spacing here is
   written calc(var(--k) * -Npx) so the Arabic side stays correct. If you add
   tracking to a heading, do the same.

   Sizes are clamp(min, fluid, max) and that IS the responsive design - there
   are almost no media queries. To make something bigger on a phone, raise the
   first number; to cap it on a desktop, lower the third.
   ========================================================================== */


/* ==========================================================================
   1. TOKENS
   ========================================================================== */

.ts {
  /* Type. --disp and --body are rewritten by the language toggle: Bricolage
     leads in English, Reem Kufi leads in Arabic. */
  --disp: 'Bricolage Grotesque', 'Reem Kufi', Georgia, serif;
  --body: 'IBM Plex Sans', 'IBM Plex Sans Arabic', system-ui, sans-serif;
  --mono: 'IBM Plex Mono', monospace;
  --arabic: 'IBM Plex Sans Arabic', sans-serif;
  --k: 1;

  /* Paper and ink. */
  --linen: #F3EDE3;
  --paper: #FBF7F0;
  --paper-warm: rgba(251, 247, 240, .6);
  --paper-warmer: rgba(251, 247, 240, .7);
  --ink: #1A1714;
  --ink-soft: #4A433C;
  --ink-mute: #6E655B;
  --ink-light: #F7F3EC;

  /* Thread - the one accent, and the only red on the page. */
  --thread: #A81C25;
  --thread-deep: #6E1016;
  --thread-pale: #E0A0A4;
  --on-thread: #FBF7F0;

  /* Lines. */
  --line: #DCD2C2;
  --line-dash: #C9BDA9;
  --line-ghost: #B9AB95;
  --rule: #9C8F7D;

  /* The dark band. */
  --dark: #1A1714;
  --dark-hover: #231F1A;
  --dark-line: #3A342D;
  --dark-line-hover: #5A4F44;
  --dark-text: #BCB2A5;
  --dark-mute: #8A7F72;

  --live: #4A7A3E;

  --measure: 1240px;
  --measure-narrow: 900px;

  /* The graph-paper ground, three ways: on the linen, light-on-dark in the
     modules band, and coarser inside the embroidery hoop. Change the pitch
     (the 4px / 5px / 13px) to change the weave. */
  --weave: repeating-linear-gradient(0deg, rgba(26, 23, 20, .035) 0 1px, transparent 1px 4px),
           repeating-linear-gradient(90deg, rgba(26, 23, 20, .028) 0 1px, transparent 1px 4px);
  --weave-dark: repeating-linear-gradient(0deg, rgba(243, 237, 227, .045) 0 1px, transparent 1px 5px),
                repeating-linear-gradient(90deg, rgba(243, 237, 227, .035) 0 1px, transparent 1px 5px);
  --weave-chart: repeating-linear-gradient(0deg, rgba(26, 23, 20, .05) 0 1px, transparent 1px 13px),
                 repeating-linear-gradient(90deg, rgba(26, 23, 20, .05) 0 1px, transparent 1px 13px);

  /* Section padding, used by every band. */
  --band-y: clamp(40px, 7vw, 96px);
  --band-x: clamp(16px, 4vw, 52px);
}


/* ==========================================================================
   2. RESET
   ========================================================================== */

* { box-sizing: border-box }
html { -webkit-text-size-adjust: 100% }

body {
  margin: 0;
  background: #F3EDE3;
  -webkit-font-smoothing: antialiased;
}

a { color: #A81C25; text-decoration: none }
::selection { background: #A81C25; color: #F7F3EC }


/* ==========================================================================
   3. STATE
   The rules an inline style attribute cannot carry.
   ========================================================================== */

.ts-pill:hover,
.ts-pill:focus-visible { color: var(--thread); border-color: var(--thread) }

.ts-btn--red:hover { background: var(--thread-deep); color: var(--on-thread) }
.ts-btn--ink:hover { background: var(--thread); color: var(--on-thread) }
.ts-btn--ghost:hover { border-color: var(--thread); color: var(--thread) }

.ts-module:hover { background: var(--dark-hover); border-color: var(--dark-line-hover) }

.ts-quiet:hover { color: var(--thread) }

a:focus-visible,
button:focus-visible { outline: 3px solid #A81C25; outline-offset: 3px }

/* The intro overlay is a curtain, and only the script that raises it knows
   how. Down by default would leave a browser that never ran the script - or a
   reader who has asked for less motion - staring at a blank screen with no way
   past it. */
#ts-overlay { display: none }
.ts-js #ts-overlay { display: flex }
@media (prefers-reduced-motion: reduce) { .ts-js #ts-overlay { display: none } }


/* ==========================================================================
   4. LAYOUT
   ========================================================================== */

/* The page shell. Everything else is inside this, which is also where the
   language toggle writes --disp / --body / --k and flips dir. */
.ts {
  position: relative;
  min-height: 100vh;
  overflow-x: hidden;
  color: var(--ink);
  font-family: var(--body);
  background-color: var(--linen);
  background-image: var(--weave);
}

/* A band of content, centred, with the standard vertical rhythm. */
.ts-band {
  max-width: var(--measure);
  margin: 0 auto;
  padding: var(--band-y) var(--band-x);
}

.ts-band--narrow {
  max-width: var(--measure-narrow);
  text-align: center;
}

/* The three card grids. Each collapses to one column when a card would go
   below its minimum - that number is the only thing deciding how many columns
   a phone gets. */
.ts-grid { display: grid; margin: 0; padding: 0 }
.ts-grid--steps { grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr)); gap: clamp(14px, 2.6vw, 30px) }
.ts-grid--modules { grid-template-columns: repeat(auto-fit, minmax(min(275px, 100%), 1fr)); gap: 12px }
.ts-grid--swatches { grid-template-columns: repeat(auto-fit, minmax(min(225px, 100%), 1fr)); gap: clamp(14px, 2.4vw, 26px) }

/* `[ 01 ]  Heading` */
.ts-sec-head {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}

.ts-sec-num {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 2px;
  color: var(--thread);
}

.ts-h2 {
  font-family: var(--disp);
  font-size: clamp(25px, 4.2vw, 42px);
  font-weight: 700;
  letter-spacing: calc(var(--k) * -.6px);
  margin: 0;
  text-wrap: pretty;
}

.ts-h2--big {
  font-size: clamp(27px, 5vw, 50px);
  letter-spacing: calc(var(--k) * -1px);
  margin: 0 0 14px;
  line-height: 1.15;
}

.ts-h3 {
  font-family: var(--disp);
  font-size: 21px;
  font-weight: 700;
  letter-spacing: calc(var(--k) * -.3px);
  margin: 0 0 10px;
  text-wrap: pretty;
}

/* The paragraph under a section heading. */
.ts-sub {
  font-size: 15.5px;
  line-height: 1.75;
  color: var(--ink-soft);
  max-width: 60ch;
  margin: 0 0 32px;
  text-wrap: pretty;
}

.ts-sub--wide { max-width: 62ch; margin-bottom: 30px }

.ts-body {
  font-size: 14.5px;
  line-height: 1.75;
  color: var(--ink-soft);
  margin: 0;
  text-wrap: pretty;
}


/* ==========================================================================
   5. COMPONENTS
   ========================================================================== */

/* --- Buttons -------------------------------------------------------------
   One base, three fills. Every one clears 42px so it is a real touch target.
   ------------------------------------------------------------------------- */

.ts-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  padding: 14px clamp(24px, 5vw, 30px);
  border-radius: 2px;
  font-weight: 600;
  font-size: 15.5px;
  white-space: nowrap;
}

.ts-btn--red { background: var(--thread); color: var(--on-thread) }
.ts-btn--ink { background: var(--ink); color: var(--ink-light) }

.ts-btn--ghost {
  background: transparent;
  color: var(--ink);
  padding: 14px clamp(22px, 5vw, 28px);
  border: 1.5px dashed var(--line-ghost);
}

/* The header's Get started: shorter, and sitting on a hairline of its own
   darker red so it reads as pressed into the paper. */
.ts-btn--sm {
  min-height: 42px;
  padding: 0 clamp(13px, 3.2vw, 22px);
  font-size: clamp(13px, 3.2vw, 14.5px);
  box-shadow: 0 1px 0 0 var(--thread-deep);
}

.ts-btn--cta { padding: 15px clamp(22px, 4vw, 32px); font-size: 16px }

/* A dashed round button: the language switch, Skip intro, Replay intro. */
.ts-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 1px dashed var(--line-dash);
  border-radius: 999px;
  color: var(--ink-mute);
  cursor: pointer;
  white-space: nowrap;
}


/* --- Header --------------------------------------------------------------- */

.ts-head {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: nowrap;
  gap: clamp(8px, 2vw, 24px);
  padding: 9px clamp(12px, 4vw, 52px);
  background: rgba(243, 237, 227, .93);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}

.ts-brand {
  display: flex;
  align-items: center;
  gap: clamp(8px, 1.6vw, 11px);
  min-width: 0;
  flex: 0 1 auto;
  color: inherit;
}

/* The mark is the same gear chart as the hero, stitched at n=34. */
.ts-mark {
  width: clamp(30px, 7vw, 36px);
  height: clamp(30px, 7vw, 36px);
  flex: 0 0 auto;
}

.ts-brand-text {
  display: flex;
  flex-direction: column;
  line-height: 1.1;
  min-width: 0;
}

.ts-brand-name {
  font-family: var(--disp);
  font-size: clamp(15px, 3.6vw, 20px);
  font-weight: 700;
  letter-spacing: calc(var(--k) * -.2px);
}

.ts-brand-sub {
  font-family: var(--mono);
  font-size: clamp(8px, 1.9vw, 9px);
  letter-spacing: 1.5px;
  color: var(--ink-mute);
}

/* Both brand lines truncate rather than wrap - the header is one row at every
   width, and a wrapped brand would push the buttons off a small phone. */
.ts-brand-name,
.ts-brand-sub {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ts-nav {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: clamp(6px, 1.6vw, 12px);
  flex: 0 0 auto;
}

/* Square, so it reads as a glyph and not a word. The script rewrites its
   font-family and size when it flips to EN. */
.ts-lang {
  font-family: var(--arabic);
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
  border-style: solid;
  width: 42px;
  height: 42px;
  padding: 0;
  flex: 0 0 auto;
}


/* --- Hero ----------------------------------------------------------------- */

.ts-hero {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: clamp(26px, 5vw, 64px);
  align-items: center;
  max-width: var(--measure);
  margin: 0 auto;
  padding: clamp(26px, 6vw, 84px) var(--band-x) clamp(24px, 4vw, 56px);
}

/* Without this a grid child refuses to shrink below its content and the page
   scrolls sideways on a phone. */
.ts-hero > * { min-width: 0 }

.ts-badge {
  display: flex;
  width: fit-content;
  max-width: 100%;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 8px;
  font-family: var(--mono);
  font-size: clamp(9.5px, 1.1vw, 11px);
  line-height: 1.5;
  letter-spacing: 1.8px;
  color: var(--ink-mute);
  border: 1px dashed var(--line-dash);
  border-radius: 18px;
  padding: 8px 14px;
  margin-bottom: 20px;
}

.ts-h1 {
  font-family: var(--disp);
  font-weight: 700;
  font-size: clamp(34px, 7vw, 72px);
  line-height: 1.08;
  margin: 0 0 18px;
  letter-spacing: calc(var(--k) * -1.4px);
  text-wrap: pretty;
}

.ts-h1 > span { display: block }
.ts-h1 .ts-accent { display: inline; color: var(--thread) }

.ts-lede {
  font-size: clamp(15px, 1.5vw, 18.5px);
  line-height: 1.8;
  color: var(--ink-soft);
  max-width: 52ch;
  margin: 0 0 26px;
  text-wrap: pretty;
}

.ts-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 22px }
.ts-actions--center { justify-content: center; margin-bottom: 0 }

.ts-status {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 12px;
  font-family: var(--mono);
  font-size: clamp(10px, 1.1vw, 11.5px);
  letter-spacing: 1.3px;
  color: var(--ink-mute);
}

.ts-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--live);
}

.ts-pipe { color: var(--rule) }

.ts-chart-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

/* The hoop: a square of graph paper with the chart stitched onto it. */
.ts-chart {
  position: relative;
  width: 100%;
  max-width: 470px;
  aspect-ratio: 1;
  background: var(--paper);
  border: 1px solid var(--line);
  box-shadow: 0 22px 50px -34px rgba(26, 23, 20, .45);
  background-image: var(--weave-chart);
}

.ts-chart svg { position: absolute; inset: 0; width: 100%; height: 100% }

.ts-chart-cap {
  width: 100%;
  max-width: 470px;
  text-align: start;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 1.5px;
  color: var(--ink-mute);
}


/* --- Figures band --------------------------------------------------------- */

.ts-figures {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  background: var(--paper-warm);
}

.ts-figures-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(168px, 45%), 1fr));
  max-width: var(--measure);
  margin: 0 auto;
}

.ts-figure {
  padding: 22px clamp(14px, 3vw, 32px);
  border-inline-end: 1px dashed var(--line);
}

.ts-figure:last-child { border-inline-end: 0 }

.ts-figure-n {
  font-family: var(--disp);
  font-size: clamp(28px, 4.4vw, 36px);
  font-weight: 700;
  color: var(--thread);
  line-height: 1;
}

.ts-figure-label {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink-mute);
  margin-top: 6px;
}


/* --- Steps ---------------------------------------------------------------- */

.ts-step {
  position: relative;
  background: var(--paper);
  border: 1px solid var(--line);
  padding: 28px 24px 26px;
  list-style: none;
}

.ts-step-n {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 2px;
  color: var(--ink-mute);
  margin-bottom: 14px;
}

/* The running stitch along the bottom edge of a card. */
.ts-rule {
  position: absolute;
  bottom: 0;
  inset-inline: 0;
  width: 100%;
  height: 8px;
}

/* ==========================================================================
   Swipe tracks

   On a phone the six steps and the six modules are a swipe, not a column.
   Stacked, each of those sections runs close to three screensful, and a
   visitor has to scroll the entire workflow to reach anything below it. One
   card at a time with the next one peeking in is the same gesture as any
   photo carousel, and it is plain scroll-snap: no script, no library, and the
   cards are the same markup they are on a desktop.

   The margin/padding pair is what makes it feel native. The negative margin
   bleeds the track to both screen edges so a card can scroll right off them;
   the matching padding puts the first card back under the heading, and
   scroll-padding makes every card snap to that same line instead of the
   screen edge. All three are logical properties, so Arabic gets it mirrored
   for free.

   The breakpoint is where these grids would otherwise fall to one column.
   To make a fourth grid swipe, add its selector to all four rules below and
   give its container tabindex="0" in marketingPage.js.
   ========================================================================== */

@media (max-width: 699px) {
  .ts-grid--steps,
  .ts-grid--modules,
  .ts-grid--swatches {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: min(82%, 340px);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    margin-inline: calc(var(--band-x) * -1);
    padding-inline: var(--band-x);
    scroll-padding-inline: var(--band-x);
    scrollbar-width: none;
  }

  /* The peeking card is the affordance; a scrollbar under it is just noise. */
  .ts-grid--steps::-webkit-scrollbar,
  .ts-grid--modules::-webkit-scrollbar,
  .ts-grid--swatches::-webkit-scrollbar { display: none }

  .ts-grid--steps > *,
  .ts-grid--modules > *,
  .ts-grid--swatches > * { scroll-snap-align: start }
}

/* A track takes tabindex so it can be scrolled by keyboard - a scrollable
   region reachable only by touch is unreachable to anyone using a keyboard. */
.ts-grid--steps:focus-visible,
.ts-grid--modules:focus-visible,
.ts-grid--swatches:focus-visible { outline: 3px solid var(--thread); outline-offset: 3px }


/* --- Modules (the dark band) ---------------------------------------------- */

.ts-dark {
  background: var(--dark);
  color: var(--linen);
  background-image: var(--weave-dark);
}

.ts-dark .ts-sec-num { color: var(--thread-pale) }
.ts-dark .ts-sub { color: var(--dark-text); margin-bottom: 34px }

.ts-module {
  background: var(--dark);
  border: 1px solid var(--dark-line);
  padding: 28px 24px;
  list-style: none;
}

.ts-module .ts-h3 { font-size: 20px }

.ts-module-tag {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 1.8px;
  color: var(--dark-mute);
}

.ts-module-x { color: var(--thread); font-size: 18px }

.ts-module .ts-body { font-size: 14px; color: var(--dark-text) }


/* --- Swatches ------------------------------------------------------------- */
/* One menu row, worked in four palettes. Each card carries its own colours as
   --sw-bg / --sw-thread / --sw-linen, written inline from the SWATCHES table
   in marketingPage.js - those are real values the owner panel can save, so
   change the palettes there, not here. */

.ts-swatch {
  margin: 0;
  background: var(--paper);
  border: 1px solid var(--line);
  padding: 12px;
}

.ts-swatch-card {
  position: relative;
  aspect-ratio: 4/5;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  background: var(--sw-bg);
}

/* The stitch itself: two diagonals crossing on a grid, faded out towards the
   corner so the dish name stays readable on top of it. */
.ts-swatch-stitch {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(45deg, transparent 43%, var(--sw-thread) 43%, var(--sw-thread) 57%, transparent 57%),
    linear-gradient(-45deg, transparent 43%, var(--sw-thread) 43%, var(--sw-thread) 57%, transparent 57%);
  background-size: 19px 19px;
  opacity: .9;
  -webkit-mask-image: linear-gradient(160deg, #000 0%, rgba(0, 0, 0, .45) 62%, transparent 92%);
  mask-image: linear-gradient(160deg, #000 0%, rgba(0, 0, 0, .45) 62%, transparent 92%);
}

.ts-swatch-face {
  position: relative;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  width: 100%;
  padding: .9rem;
}

.ts-swatch-dish { font-weight: 700; font-size: .95rem; color: var(--sw-linen) }
.ts-swatch-price { font-weight: 800; font-size: 1.05rem; color: var(--sw-thread) }

.ts-swatch-cap {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  margin-top: 11px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 1.1px;
  color: var(--ink-mute);
}

.ts-swatch-cap .ts-accent { color: var(--thread) }


/* --- Call to action ------------------------------------------------------- */

.ts-cta {
  border-top: 1px solid var(--line);
  background: var(--paper-warmer);
}

.ts-cta-rule { width: min(240px, 60%); height: 10px; margin-bottom: 24px }

.ts-cta .ts-sub {
  font-size: 16px;
  line-height: 1.8;
  max-width: 52ch;
  margin: 0 auto 26px;
}


/* --- Footer --------------------------------------------------------------- */

.ts-foot {
  border-top: 1px solid var(--line);
  padding: 26px var(--band-x);
  display: flex;
  flex-wrap: wrap;
  gap: 12px 16px;
  align-items: center;
  justify-content: space-between;
  max-width: var(--measure);
  margin: 0 auto;
}

.ts-foot-note {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 1.5px;
  color: var(--ink-mute);
}

.ts-foot-side { display: flex; align-items: center; gap: 16px; flex-wrap: wrap }

.ts-quiet { font-size: 13.5px; color: var(--ink-mute) }

.ts-replay {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 1.2px;
  padding: 9px 14px;
  min-height: 38px;
}


/* ==========================================================================
   6. OVERLAY - the intro curtain
   Laid out here; animated by marketingIntro.js, which writes opacity and
   transform on #ts-title, #ts-overlay and the SVG groups.
   ========================================================================== */

.ts-overlay {
  position: fixed;
  inset: 0;
  z-index: 90;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(6px, 1.6vh, 22px);
  padding: clamp(10px, 2.4vh, 30px) 14px;
  overflow: hidden;
  background-color: var(--linen);
  background-image: var(--weave);
}

.ts-overlay-vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(circle at 50% 44%, rgba(243, 237, 227, 0) 38%, rgba(202, 189, 170, .5) 100%);
}

/* vmin keeps the hoop square against a phone's width; the 58vh cap stops it
   pushing the title and the skip button off a short landscape screen. */
.ts-overlay-stage {
  position: relative;
  width: min(70vmin, 480px, 58vh);
  min-height: 0;
  flex: 0 1 auto;
  aspect-ratio: 1;
}

/* overflow:visible - the needle starts well outside the viewBox and flies in. */
.ts-overlay-stage svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.ts-overlay-title {
  position: relative;
  min-height: 0;
  text-align: center;
  opacity: 0;
}

.ts-overlay-name {
  font-family: var(--disp);
  font-size: min(clamp(26px, 6vw, 56px), 7vh);
  font-weight: 700;
  letter-spacing: calc(var(--k) * -1px);
  line-height: 1.1;
}

.ts-overlay-tag {
  font-family: var(--mono);
  font-size: clamp(9px, 1.4vw, 11.5px);
  letter-spacing: 4px;
  color: var(--ink-mute);
  margin-top: clamp(4px, 1vh, 10px);
}

.ts-counter {
  position: relative;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 2.2px;
  color: var(--ink-mute);
}

.ts-skip {
  position: relative;
  flex: 0 0 auto;
  margin-top: clamp(4px, 1.4vh, 16px);
  font-family: var(--body);
  font-size: 13px;
  line-height: 1;
  padding: 12px 22px;
  min-height: 42px;
}


/* ==========================================================================
   7. LOGIN MODAL & PORTAL
   ========================================================================== */

.ts-login-open {
  cursor: pointer;
}

.ts-modal-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(26, 23, 20, .72);
  backdrop-filter: blur(8px);
  padding: 16px;
  overflow-y: auto;
  align-items: center;
  justify-content: center;
}

.ts-modal-backdrop.ts-modal--open {
  display: flex;
}

.ts-modal-card {
  position: relative;
  width: 100%;
  max-width: 440px;
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 4px;
  box-shadow: 0 24px 56px rgba(26, 23, 20, .32);
  padding: clamp(20px, 5vw, 32px);
  color: var(--ink);
  animation: tsModalIn .2s cubic-bezier(.16, 1, .3, 1);
}

@keyframes tsModalIn {
  from { opacity: 0; transform: translateY(12px) scale(.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

.ts-modal-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 20px;
}

.ts-modal-title-group {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.ts-modal-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 1.5px;
  color: var(--thread);
  text-transform: uppercase;
  font-weight: 600;
}

.ts-modal-stitch {
  font-size: 10px;
}

.ts-modal-h2 {
  font-family: var(--disp);
  font-size: clamp(22px, 3.5vw, 26px);
  font-weight: 700;
  color: var(--ink);
  margin: 0;
  line-height: 1.2;
  letter-spacing: calc(var(--k) * -0.5px);
}

.ts-modal-sub {
  font-family: var(--body);
  font-size: 13px;
  color: var(--ink-mute);
  margin: 0;
  line-height: 1.4;
}

.ts-modal-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 1px dashed var(--line-dash);
  border-radius: 50%;
  width: 34px;
  height: 34px;
  color: var(--ink-mute);
  cursor: pointer;
  font-size: 13px;
  flex-shrink: 0;
  transition: color .2s ease, border-color .2s ease;
}

.ts-modal-close:hover,
.ts-modal-close:focus-visible {
  color: var(--thread);
  border-color: var(--thread);
}

.ts-tabs {
  display: flex;
  gap: 8px;
  border-bottom: 1.5px solid var(--line);
  margin-bottom: 20px;
}

.ts-tab {
  flex: 1;
  padding: 10px 14px;
  background: none;
  border: none;
  border-bottom: 2.5px solid transparent;
  font-family: var(--body);
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-mute);
  cursor: pointer;
  text-align: center;
  transition: color .2s ease, border-color .2s ease;
  margin-bottom: -1.5px;
}

.ts-tab:hover {
  color: var(--ink);
}

.ts-tab--active {
  color: var(--thread);
  border-bottom-color: var(--thread);
}

.ts-subtabs {
  display: flex;
  gap: 6px;
  background: rgba(26, 23, 20, .05);
  padding: 4px;
  border-radius: 3px;
  margin-bottom: 16px;
  border: 1px solid var(--line);
}

.ts-subtab {
  flex: 1;
  padding: 7px 10px;
  background: none;
  border: none;
  border-radius: 2px;
  font-family: var(--body);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink-mute);
  cursor: pointer;
  transition: background .2s ease, color .2s ease;
}

.ts-subtab--active {
  background: #FFFFFF;
  color: var(--ink);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .08);
}

.ts-alert {
  padding: 11px 14px;
  border-radius: 3px;
  font-size: 13px;
  margin-bottom: 16px;
  line-height: 1.4;
  font-family: var(--body);
}

.ts-alert--error {
  background: #FDE8E9;
  border: 1px solid var(--thread-pale);
  color: var(--thread-deep);
}

.ts-alert--success {
  background: #EAF4E8;
  border: 1px solid #B8D8B2;
  color: #2E5824;
}

.ts-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.ts-field {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.ts-label {
  font-family: var(--body);
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-soft);
  text-transform: uppercase;
  letter-spacing: .5px;
}

.ts-input {
  width: 100%;
  padding: 11px 13px;
  font-family: var(--body);
  font-size: 14.5px;
  color: var(--ink);
  background: #FFFFFF;
  border: 1.5px solid var(--line);
  border-radius: 2px;
  outline: none;
  transition: border-color .2s ease, box-shadow .2s ease;
}

.ts-input:focus {
  border-color: var(--thread);
  box-shadow: 0 0 0 3px rgba(168, 28, 37, .12);
}

.ts-form-footer {
  margin-top: 6px;
}

.ts-btn--block {
  width: 100%;
  min-height: 46px;
  cursor: pointer;
  border: none;
  font-family: var(--body);
  font-size: 14.5px;
  font-weight: 600;
}

.ts-btn-text {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.ts-hint {
  font-family: var(--body);
  font-size: 12px;
  color: var(--ink-mute);
  margin: 6px 0 0 0;
  text-align: center;
  line-height: 1.4;
}

