/*
 * Tipatask marketing site — "Ink & Teal" design system.
 *
 * Source of truth: ai/product/website-style-guide.md. Every --tt-* token below is
 * transcribed from that guide's §15 token block and the design canvas it points to
 * (https://claude.ai/code/artifact/07a1fb9a-3aab-4ac0-8471-d38ff4229906 — TPT52).
 *
 * Namespace rule (guide §14): every custom property here is --tt-*. This file must
 * NEVER reference the app's --c-* tokens (api/web/src/styles.css) — those drive 19
 * switchable app themes, including the mauve/violet default this guide exists to
 * avoid. --tt-* tokens are static constants, defined once, here only.
 *
 * Type system (TPT77): exactly two faces, everywhere on the page —
 *   - Literata (serif) for every display and text role: headings, subhead, body,
 *     small, lead. Comfortable at body length; carries full Cyrillic coverage.
 *   - IBM Plex Mono for the technical layer: eyebrows, chips, tags, terminal
 *     panes, nav links, buttons, inputs, roadmap titles, card IDs.
 * The former third sans voice (IBM Plex Sans) and the decorative hand voice
 * (Architects Daughter, --tt-font-hand, .tt-hand) are retired — a third face
 * used only for body/UI text added noise without adding a role the mono face
 * couldn't already cover for technical content.
 *
 * Anti-trope bans enforced by this file (guide §13), most important first:
 *   - No purple/violet anywhere.
 *   - No smooth-blend gradients, no glassmorphism, no gradient-orb decoration.
 *     (The hatch and grain patterns below use CSS gradient() functions as a
 *     hard-edge repeating-pattern technique — every stop list resolves to exactly
 *     one non-transparent color, so nothing actually blends. That is not the
 *     decorative gradient this ban targets.)
 *   - No soft/blurred shadow — every shadow in this system has a 0 blur radius.
 *   - No prefers-color-scheme dark-mode switch — paper/ink bands are the answer to
 *     light/dark, not a toggle (see .tt-band--* below).
 *   - Banned fonts: Inter, Roboto, Arial, Fraunces.
 * website/tests/Feature/MarketingAssetsTest.php guards these mechanically.
 */

@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=Literata:wght@400;700;800&display=swap');

/* ---------------------------------------------------------------------------
 * Tokens — website-style-guide.md §15, two-face type system (TPT77).
 * ------------------------------------------------------------------------- */
:root {
  /* Ground */
  --tt-paper:        #F4F1EA;
  --tt-paper-deep:   #E9E4D8;
  --tt-ink:          #1A1A19;
  --tt-ink-soft:     #2A2A28;

  /* Text */
  --tt-ink-2:        #3E3E3A;
  --tt-ink-3:        #6B6B64;
  --tt-paper-2:      #B9B4A6;
  --tt-rule-soft:    #C9C3B4;

  /* Accent — teal is a fixed constant (website-spec.md §13); do not change */
  --tt-teal:         #14B8A6;
  --tt-teal-ink:     #0C7C6F;
  --tt-teal-deep:    #0E8377;
  --tt-teal-wash:    rgba(20, 184, 166, .14);
  --tt-sanguine:     #E08763;
  --tt-sanguine-ink: #9C4A28;

  /* Hero slider scrims (TPT79, paper pair added TPT116) — flat rgba() layers
   * over each photo slide, never a gradient(): style-guide.md §13 bans
   * gradient backgrounds, and MarketingAssetsTest's gradient guard only
   * tolerates a gradient() whose stop list resolves to exactly one
   * non-transparent colour. --tt-ink-scrim veils slide 0's dark canyon photo
   * for paper text. --tt-paper-scrim/-deep veil slides 1-2's light photos
   * for ink text — two strengths because the two source photos differ in
   * how much of their own tonal range needs damping to clear 4.5:1 at the
   * copy's on-image position: .30 for the whiteboard (already mostly light,
   * measured worst-case 8.37:1 on --tt-ink across 390-1920px), .62 for the
   * machine illustration (darker linework, measured worst-case 6.69:1). */
  --tt-ink-scrim:        rgba(26, 26, 25, .62);
  --tt-paper-scrim:      rgba(244, 241, 234, .30);
  --tt-paper-scrim-deep: rgba(244, 241, 234, .62);

  /* Type — two faces (TPT77): Literata for display+text, Plex Mono for label/code */
  --tt-font-display: 'Literata', Georgia, 'Times New Roman', serif;
  --tt-font-text:    'Literata', Georgia, 'Times New Roman', serif;
  --tt-font-mono:    'IBM Plex Mono', ui-monospace, 'SF Mono', Consolas, monospace;

  /* Drawn primitives */
  --tt-wobble-1: 255px 15px 225px 15px / 15px 225px 15px 255px;
  --tt-wobble-2: 12px 180px 18px 210px / 200px 16px 190px 14px;
  --tt-wobble-3: 200px 200px 20px 200px / 20px 200px 200px 20px;
  --tt-shadow-hard-paper: 6px 6px 0 var(--tt-ink);
  --tt-shadow-hard-ink:   6px 6px 0 var(--tt-teal);

  /* Layout */
  --tt-max-width: 1200px;
  --tt-gutter:    24px;
  --tt-band-pad-desktop: 96px;
  --tt-band-pad-mobile:  56px;

  /* Hero vertical rhythm (TPT86) — §6 spacing scale (4·8·12·16·24·32·48·64·
   * 96·128), replacing the hand-typed inline margins that used to live on
   * the blade markup. .tt-hero-copy's own top/bottom padding reuses
   * --tt-band-pad-desktop/-mobile below rather than adding a fourth token,
   * so the hero tracks the 128px band-padding step at >=1920px for free. */
  --tt-hero-gap-subhead: 32px;  /* headline -> subhead (was inline 16px) */
  --tt-hero-gap-actions: 64px;  /* subhead -> CTA row (was inline 40px)  */
  --tt-hero-cta-gap:     32px;  /* between the two CTAs (was 24px)       */
}

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

body {
  /* Default UA body margin (8px) was invisible everywhere pre-TPT79 — every
   * prior section's background matches the canvas-propagated body color, so
   * the inset never showed. The hero slider is the page's first full-bleed
   * element, which is what makes it visible: without this reset, the slider
   * (and any future full-bleed section) sits 8px short of the true viewport
   * edge on every side. */
  margin: 0;
  background: var(--tt-paper);
  color: var(--tt-ink);
  font-family: var(--tt-font-text);
}

a { color: var(--tt-teal-ink); }
a:hover { color: var(--tt-teal-deep); }

.tt-container { max-width: var(--tt-max-width); margin: 0 auto; }

/* ---------------------------------------------------------------------------
 * Type ramp — style-guide.md §4 table, 16px root.
 * ------------------------------------------------------------------------- */
.tt-display-xl { font-family: var(--tt-font-display); font-weight: 800; font-size: clamp(44px, 6vw, 76px); line-height: 1.02; letter-spacing: -0.02em; margin: 0; }
.tt-display-l  { font-family: var(--tt-font-display); font-weight: 700; font-size: clamp(32px, 4vw, 46px); line-height: 1.08; letter-spacing: -0.01em; margin: 0; }
.tt-heading-m  { font-family: var(--tt-font-display); font-weight: 700; font-size: 28px; line-height: 1.2; margin: 0; }
.tt-subhead    { font-family: var(--tt-font-text); font-weight: 400; font-size: 21px; line-height: 1.55; margin: 0; }
.tt-body       { font-family: var(--tt-font-text); font-weight: 400; font-size: 19px; line-height: 1.7; max-width: 66ch; margin: 0; }
/* Lead — a larger .tt-body variant for a section's one standout paragraph
 * (TPT77, e.g. the L3 problem statement). Combine with .tt-body, declared
 * after it so it wins the size/line-height/width on source order. */
.tt-lead       { font-size: clamp(20px, 1.6vw, 23px); line-height: 1.6; max-width: 58ch; }
.tt-small      { font-family: var(--tt-font-text); font-weight: 400; font-size: 16px; line-height: 1.6; margin: 0; }
.tt-label      { font-family: var(--tt-font-mono); font-weight: 500; font-size: 13px; line-height: 1.3; letter-spacing: 0.12em; text-transform: uppercase; margin: 0; }
.tt-tag        { font-family: var(--tt-font-mono); font-weight: 400; font-size: 14px; line-height: 1.3; margin: 0; }
.tt-margin-note { font-size: 17px; line-height: 1.4; color: var(--tt-sanguine-ink); margin: 0; }

/* ---------------------------------------------------------------------------
 * Drawn primitives — style-guide.md §5.
 * ------------------------------------------------------------------------- */
.tt-wobble-1 { border-radius: var(--tt-wobble-1); }
.tt-wobble-2 { border-radius: var(--tt-wobble-2); }
.tt-wobble-3 { border-radius: var(--tt-wobble-3); }

.tt-hairline { border: 2px solid var(--tt-ink); }
.tt-band--ink .tt-hairline { border-color: var(--tt-paper-2); }

.tt-shadow { box-shadow: var(--tt-shadow-hard-paper); }
.tt-band--ink .tt-shadow { box-shadow: var(--tt-shadow-hard-ink); }

/* Cross-hatch fill — 45° hairlines at 6px pitch, ~35% opacity (§5). Built as a
 * hard-edge repeating-linear-gradient: every stop pairs the same color with
 * itself (an instant cutoff, not a blend), so this is a pattern of solid lines,
 * not the smooth-transition "gradient background" §13 bans. */
.tt-hatch { background-image: repeating-linear-gradient(45deg, rgba(26, 26, 25, .35) 0 1px, transparent 1px 6px); }
.tt-band--ink .tt-hatch { background-image: repeating-linear-gradient(45deg, rgba(185, 180, 166, .35) 0 1px, transparent 1px 6px); }

/* Paper grain — a tiled 2%-opacity ink dot mesh (§5 alternative to a global
 * feTurbulence filter). Apply once, at the page-background level, as an
 * absolutely-positioned overlay inside a position:relative ancestor:
 *   <div class="tt-grain" aria-hidden="true"></div>
 * Same hard-edge-gradient reasoning as .tt-hatch: single color, 1px cutoff. */
.tt-grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: .02;
  background-image: radial-gradient(var(--tt-ink) 1px, transparent 1px);
  background-size: 5px 5px;
}

/* Section rule — hand-drawn wavy line in place of <hr> (§5). */
.tt-rule {
  display: block;
  height: 10px;
  border: none;
  margin: 0;
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 10' preserveAspectRatio='none'%3E%3Cpath d='M0,5 Q150,1 300,5 T600,5 T900,5 T1200,5' fill='none' stroke='%23C9C3B4' stroke-width='2'/%3E%3C/svg%3E");
}
.tt-band--ink .tt-rule {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 10' preserveAspectRatio='none'%3E%3Cpath d='M0,5 Q150,1 300,5 T600,5 T900,5 T1200,5' fill='none' stroke='%23B9B4A6' stroke-width='2'/%3E%3C/svg%3E");
}

/* Emphasis marks — wobbly teal underline (SVG path, not text-decoration) for
 * inline emphasis, and a sanguine hand-drawn "circled" ellipse for a single
 * standout term per section (§5). Never more than one .tt-circled per section. */
.tt-emphasis {
  padding-bottom: 4px;
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 8px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 10' preserveAspectRatio='none'%3E%3Cpath d='M2,6 Q50,2 100,6 T198,5' fill='none' stroke='%2314B8A6' stroke-width='3' stroke-linecap='round'/%3E%3C/svg%3E");
}
.tt-circled {
  position: relative;
  display: inline-block;
  padding: 0 .3em;
  z-index: 0;
}
.tt-circled::before {
  content: "";
  position: absolute;
  inset: -.3em -.4em;
  z-index: -1;
  pointer-events: none;
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 80'%3E%3Cellipse cx='100' cy='40' rx='96' ry='34' fill='none' stroke='%23E08763' stroke-width='3'/%3E%3C/svg%3E");
}

/* ---------------------------------------------------------------------------
 * Band grounds — style-guide.md §8. An ink band is full-bleed on the section
 * element itself. Every ink-ground override above and below keys off
 * .tt-band--ink as the single scoping ancestor.
 * ------------------------------------------------------------------------- */
.tt-band { padding: var(--tt-band-pad-desktop) var(--tt-gutter); position: relative; }
.tt-band--paper      { background: var(--tt-paper); color: var(--tt-ink); }
.tt-band--paper-deep { background: var(--tt-paper-deep); color: var(--tt-ink); }
.tt-band--ink        { background: var(--tt-ink); color: var(--tt-paper-2); }
.tt-band--ink a      { color: var(--tt-teal); }
.tt-band--ink a:hover { color: var(--tt-teal); opacity: .85; }

/* ---------------------------------------------------------------------------
 * Components — style-guide.md §11, transcribed from the design canvas's
 * Components.dc.html (the guide's own pointer for "exact pattern markup").
 * ------------------------------------------------------------------------- */

/* Buttons */
.tt-btn {
  display: inline-block;
  font-family: var(--tt-font-mono);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: 0.02em;
  padding: 12px 22px;
  border: 2px solid var(--tt-ink);
  text-decoration: none;
  cursor: pointer;
}
.tt-band--ink .tt-btn { border-color: var(--tt-paper-2); }

.tt-btn-primary { background: var(--tt-ink); color: var(--tt-paper); box-shadow: var(--tt-shadow-hard-paper); }
.tt-btn-secondary { background: transparent; color: var(--tt-ink); box-shadow: var(--tt-shadow-hard-paper); }
.tt-btn-ghost { border: none; padding: 12px 4px; color: var(--tt-teal-ink); }
.tt-btn-ghost:hover { text-decoration: underline; text-decoration-style: wavy; text-decoration-color: currentColor; }

.tt-band--ink .tt-btn-primary { background: var(--tt-teal); color: var(--tt-ink); border-color: var(--tt-teal); box-shadow: var(--tt-shadow-hard-ink); }
.tt-band--ink .tt-btn-secondary { background: var(--tt-ink-soft); color: var(--tt-paper); border-color: var(--tt-paper-2); box-shadow: var(--tt-shadow-hard-ink); }
.tt-band--ink .tt-btn-ghost { color: var(--tt-teal); }

/* Hover/focus (TPT102, refined by bugfix): the `a.` element prefix wins by
 * specificity over the generic `a:hover`/`.tt-band--ink a:hover` rules (0,2,1
 * / 0,3,1 vs 0,1,1 / 0,2,1), not source order — that's what lets these two
 * rules differ by context instead of one blanket value.
 * Paper-context primaries (header nav, L14 plate, hero slide 2 — filled
 * --tt-ink, resting text --tt-paper): hover goes to --tt-teal, 7.0:1 on the
 * ink fill (the same ink-fill/teal-text pairing ink bands already use, see
 * .tt-band--ink a above). TPT102 originally pinned this case to --tt-paper
 * too, same as rest — a no-op (ΔE 0), silently killing the real, visible
 * --tt-teal-deep hover the plain `a:hover` rule gave these buttons pre-
 * TPT102. This restores that visible "turns teal" affordance, brighter/more
 * legible than the old --tt-teal-deep.
 * Ink-context primaries (hero slides 0/1 only — filled --tt-teal, resting
 * text --tt-ink): UNCHANGED, still pinned to --tt-paper. This is the real
 * disappearing-text case TPT102 exists to prevent — teal label on a teal
 * fill is 1:1, truly invisible, not just hard to notice. Do not "fix" this
 * one to match the paper-context rule above. */
a.tt-btn-primary:hover,
a.tt-btn-primary:focus-visible { color: var(--tt-teal); }
.tt-band--ink a.tt-btn-primary:hover,
.tt-band--ink a.tt-btn-primary:focus-visible { color: var(--tt-paper); }

/* Larger hero CTAs (TPT78, resized TPT86) — 20px/22x34. TPT78's original
 * 18px/18x26 was sized against the hero copy's since-removed .tt-col-7 cell
 * (~686px, TPT79 moved the hero copy to a full-width .tt-hero-copy.tt-
 * container instead); that width limit no longer applies. The binding case
 * is still the UK label pair ("Долучитися до тестування" / "Подивитися, як
 * це працює", 24 chars each) against .tt-hero-cta-gap (32px, > the 6px hard-
 * shadow offset so the shadows never touch) — at 20px/22x34 the pair runs
 * ~772px, comfortably inside the 1200px default container and every wider
 * step. Declared after .tt-btn (above) to win on source order at equal
 * specificity; the 640px step-down lives in the mobile media block below,
 * also after this rule. */
.tt-btn-lg { font-size: 20px; padding: 22px 34px; }

/* Tag chip */
.tt-chip {
  display: inline-block;
  font-family: var(--tt-font-mono);
  font-size: 14px;
  padding: 5px 12px;
  border: 2px solid var(--tt-ink);
  background: var(--tt-paper-deep);
}
.tt-band--ink .tt-chip { border-color: var(--tt-paper-2); background: var(--tt-ink-soft); color: var(--tt-paper); }

/* Task card */
.tt-card {
  background: var(--tt-paper-deep);
  border: 2px solid var(--tt-ink);
  box-shadow: var(--tt-shadow-hard-paper);
  border-radius: var(--tt-wobble-1);
  padding: 20px;
}
.tt-band--ink .tt-card { background: var(--tt-ink-soft); border-color: var(--tt-paper-2); box-shadow: var(--tt-shadow-hard-ink); }
.tt-card-id { font-family: var(--tt-font-mono); font-size: 11px; color: var(--tt-teal-ink); }
.tt-band--ink .tt-card-id { color: var(--tt-teal); }

/* Terminal pane — always an ink plate, on either ground (§11). Sized up
 * (TPT77) for comfortable reading at 100% zoom; steps back down at 640px so
 * the longest line doesn't wrap worse than before on mobile. */
.tt-terminal {
  background: var(--tt-ink);
  border: 2px solid var(--tt-ink);
  box-shadow: var(--tt-shadow-hard-paper);
  padding: 20px 24px;
  color: var(--tt-paper);
  font-family: var(--tt-font-mono);
  font-size: 16px;
  line-height: 1.55;
}
.tt-band--ink .tt-terminal { box-shadow: var(--tt-shadow-hard-ink); }
.tt-terminal-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--tt-teal); margin-right: 6px; }
.tt-terminal-line { margin: 10px 0; color: var(--tt-paper-2); }
.tt-terminal-prompt { color: var(--tt-teal); }

/* Nav — never on an ink band (§11). Reuse .tt-btn-primary for Join Beta. */
.tt-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--tt-paper);
  border-bottom: 2px solid var(--tt-ink);
  padding: 16px var(--tt-gutter);
}
.tt-nav-links { display: flex; gap: 26px; align-items: center; font-family: var(--tt-font-mono); font-size: 13px; color: var(--tt-ink-2); }
/* Header nav links only (TPT87) — scoped so the footer's reuse of the shared
 * .tt-nav-links class (landing.blade.php L15) doesn't also grow. */
.tt-nav .tt-nav-links { font-size: 16px; }
/* Header nav-link hover (bugfix) — the generic a:hover (--tt-teal-ink ->
 * --tt-teal-deep) is a ΔE~3 shift, imperceptible at this size and a hair
 * below the 4.5:1 body floor to boot (--tt-teal-deep on --tt-paper is
 * 4.1:1, UI/large-text only per style-guide §12). --tt-ink is unambiguous
 * and AAA (15.4:1). Scoped to .tt-nav (same precedent as the font-size rule
 * above) so it never reaches the footer's own .tt-nav-links — that one
 * already hovers correctly via .tt-band--ink a:hover below and would go
 * invisible (ink text on an ink ground) if this rule reached it too. */
.tt-nav .tt-nav-links a:hover { color: var(--tt-ink); }
/* Footer nav links (TPT93) — the shared class's 13px is a nav-bar size; in the
 * L15 footer's own column it reads as fine print. 18px is the same step
 * .tt-btn-lg already uses, not a new size. Scoped like the .tt-nav twin above
 * so neither sizes the other. */
.tt-footer .tt-nav-links { font-size: 18px; }

/* Footer — fixed ink (§8/§11). */
.tt-footer { background: var(--tt-ink); color: var(--tt-paper-2); padding: var(--tt-band-pad-desktop) var(--tt-gutter); }
.tt-footer a { color: var(--tt-paper-2); }
.tt-footer-signin { color: var(--tt-teal); }
/* Footer CTA (TPT93) — the page's last conversion link, previously an unstyled
 * 16px inherit, smaller than .tt-small. Display serif, sized per locale: EN's
 * "Join Beta →" is 11 chars, UK's "Долучитися до тестування →" is 26, and at the
 * desktop .tt-col-4 width (~268px just above the 900px breakpoint, the grid's
 * tightest point) one shared size cannot keep both on a single line — the same
 * EN/UK length split .tt-btn-lg resolved in TPT78. Color is deliberately not set
 * here: .tt-footer a.tt-footer-signin (0,2,1) owns it. */
.tt-footer-cta {
  display: inline-block;
  font-family: var(--tt-font-display);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.01em;
  max-width: 100%;
  font-size: clamp(16px, 1.6vw, 22px);
}
:lang(en) .tt-footer-cta { font-size: clamp(32px, 3vw, 40px); }

/* Language switcher */
.tt-lang-switch { display: flex; gap: 10px; align-items: center; font-family: var(--tt-font-mono); font-size: 13px; }
.tt-lang-switch a { color: inherit; text-decoration: none; opacity: .7; }
/* Found alongside the bugfix above: no hover rule existed at all here, so
 * these links gave zero feedback. Same opacity-based affordance the file
 * already uses elsewhere (.tt-band--ink a:hover, .is-active below). */
.tt-lang-switch a:hover { opacity: 1; }
.tt-lang-switch a.is-active { opacity: 1; border-bottom: 2px solid var(--tt-teal); padding-bottom: 2px; }

/* Input field */
.tt-input {
  background: var(--tt-paper);
  border: 2px solid var(--tt-ink);
  padding: 10px 12px;
  font-family: var(--tt-font-mono);
  font-size: 15px;
  color: var(--tt-ink);
}
.tt-band--ink .tt-input { background: var(--tt-ink-soft); border-color: var(--tt-paper-2); color: var(--tt-paper); }

/* Roadmap column (Now/Next/Later) — always ink, L13 (§11). */
.tt-roadmap-col { background: var(--tt-ink-soft); border: 2px solid var(--tt-paper-2); box-shadow: var(--tt-shadow-hard-ink); padding: 16px; }
.tt-roadmap-title { font-family: var(--tt-font-mono); color: var(--tt-teal); font-size: 13px; letter-spacing: .1em; text-transform: uppercase; margin: 0 0 10px; }
.tt-roadmap-col p { color: var(--tt-paper-2); font-size: 15px; line-height: 1.55; margin: 0; }

/* ---------------------------------------------------------------------------
 * Insignia — style-guide.md §7 and §9. Markup lives in
 * resources/views/partials/insignia.blade.php; this is the color + motion
 * contract it renders against.
 * ------------------------------------------------------------------------- */
.tt-insignia { display: inline-block; color: var(--tt-teal); line-height: 0; }
.tt-insignia--reversed { color: var(--tt-paper); }
.tt-insignia svg { display: block; }

/* Static by default (fully drawn) — the §7 rule is ONE motion moment in the
 * whole system, so only the hero instance opts into .tt-insignia--animate. */
.tt-insignia path { stroke-dasharray: 200; stroke-dashoffset: 0; }
.tt-insignia--animate path {
  stroke-dashoffset: 200;
  animation: tt-draw 900ms ease-out .1s forwards;
}
@keyframes tt-draw {
  to { stroke-dashoffset: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .tt-insignia--animate path {
    animation: none;
    stroke-dashoffset: 0;
  }
}

/* ---------------------------------------------------------------------------
 * Accessibility — style-guide.md §12.
 * ------------------------------------------------------------------------- */
:focus-visible { outline: 3px solid var(--tt-teal-ink); outline-offset: 2px; }
.tt-band--ink :focus-visible { outline-color: var(--tt-teal); }

/* ---------------------------------------------------------------------------
 * Responsive — style-guide.md §6. Every section must also be checked at 390px.
 * ------------------------------------------------------------------------- */
@media (max-width: 640px) {
  .tt-band, .tt-footer { padding: var(--tt-band-pad-mobile) var(--tt-gutter); }
}

/* ===========================================================================
 * Landing page layout — TPT68, style-guide.md §6, plus a11y/visibility
 * fixes to existing components the landing page is the first to exercise.
 * No new hex literals anywhere below — every value resolves through a
 * --tt-* token already declared in :root above (style-guide.md §14).
 * ========================================================================= */

/* .tt-nav is full-bleed flex; its content needs the 1200px cap too. */
.tt-nav .tt-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  gap: 24px;
}

/* Nav right-hand cluster (TPT69): links + language switcher + Join Beta.
 * .tt-nav .tt-container is a space-between row — grouping the three keeps
 * the wordmark-left / cluster-right split the style guide §11 nav specifies
 * instead of spreading four children across the bar. */
.tt-nav-right { display: flex; align-items: center; gap: 24px; }

/* 12-column grid, 24px gutter (§6). */
.tt-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--tt-gutter);
  align-items: start;
}
.tt-col-3 { grid-column: span 3; }
.tt-col-4 { grid-column: span 4; }
.tt-col-5 { grid-column: span 5; }
.tt-col-6 { grid-column: span 6; }
.tt-col-7 { grid-column: span 7; }
.tt-col-12 { grid-column: span 12; }
/* Copy-before-vignette on mirrored feature bands (e.g. L7). */
.tt-order-first { order: -1; }

.tt-stack > * + * { margin-top: 16px; }
.tt-stack-md > * + * { margin-top: 32px; }
.tt-section-head { margin-bottom: 48px; }
/* Same no-max-width gap as .tt-plate above — caps the L4/L10/L12/L13 section
 * headings so they don't run as one long line at the container ramp below. */
.tt-section-head .tt-display-l { max-width: 28ch; }
.tt-chip-row { display: flex; flex-wrap: wrap; gap: 8px; }

/* Hero subhead (TPT86) — was an inline style="margin-top: 16px; max-width:
 * 52ch;" on the blade markup; now a named rule reading --tt-hero-gap-subhead.
 * (Slide 2's reversed insignia, and the matching .tt-hero-copy .tt-insignia
 * margin rule that once shared this token, were removed in TPT116 — see the
 * hero markup's own comment.) */
.tt-hero-subhead { margin-top: var(--tt-hero-gap-subhead); max-width: 52ch; }

/* Hero action row (TPT78/TPT86, pinned TPT114) — larger gap than
 * .tt-chip-row; no align-items, so flex's default stretch keeps both
 * buttons the same height (their hard 6px shadows need matching baselines
 * — centering would let unequal-height buttons offset their shadows, a
 * visible flaw in a zero-blur system).
 *
 * TPT114: this used to render once per slide, inside .tt-hero-copy, and
 * slide with the track. It's now a single instance, a sibling of
 * [data-tt-hero-track] (landing.blade.php), pinned with position: absolute
 * over the track so it never translates and is never inside a
 * [data-tt-hero-slide] the script can toggle `inert` on. Kept as a
 * .tt-container (in the markup) so it reuses that class's max-width +
 * margin: 0 auto centering against left/right: 0 below — the standard
 * "centered max-width box, positioned absolutely" pattern.
 *
 * Positioned from the slide's vertical CENTER (top: 50% + transform), not
 * its top edge — deliberately. `.tt-hero-slide` centers its own content
 * (align-items: center) inside a min-height that is NOT always the
 * clamp(460px, 62vh, 760px) it looks like at a glance: a later `@media
 * (min-width: 1600px)` rule replaces it with a flat, uncapped `62vh`, so on
 * a wide-and-tall window this box can end up far taller than any slide's
 * actual content, with the slack split above and below the centered copy.
 * A fixed `top` (measured from the slide's top edge) drifts by however
 * much that slack is — real, confirmed by measurement, and different on
 * every monitor. The offset from the slide's CENTER to slide 0's subhead
 * is unaffected by that slack (centering preserves the relationship
 * between the center and the content around it), so anchoring here instead
 * makes the row's position independent of viewport height, leaving only
 * viewport WIDTH (which changes wrap counts) to calibrate against.
 *
 * `top: 50%` itself resolves against this element's containing block —
 * `#hero`/.tt-hero-slider, the nearest positioned ancestor — not against
 * the individual .tt-hero-slide, since .tt-hero-actions is a sibling of
 * the track, not a descendant of one slide (can't be, it has to render
 * identically across all of them). .tt-hero-slider's own height is the
 * track (= the slide height, via the track's default flex stretch) PLUS
 * .tt-hero-controls below it, so 50% overshoots the slide's true center by
 * half of .tt-hero-controls' own height. That height is fixed per
 * breakpoint (padding + the arrow buttons' size, never content- or
 * width-dependent), so it's subtracted back out of the translateY literal
 * below instead of left as an approximation — 74px desktop / 70px mobile,
 * i.e. 37px / 35px subtracted from what the slide-center offset alone
 * would need.
 *
 * `translateY`/`.tt-hero-copy`'s padding-bottom below are measured
 * literals, not derived from content flow — content height varies by
 * slide/locale/width in a genuinely non-monotonic way (h1 hits an awkward
 * 3-line wrap around 1280-1400px container width before dropping back to 2
 * lines at 1440+). Measured against slide 0 (the page's only
 * .tt-display-xl slide, always the tallest) by rendering the real page at
 * a dense sweep of widths AND viewport heights, in both locales, taking
 * the worst case in each of the two --tt-band-pad-desktop brackets, with a
 * margin on top for this row's own further, otherwise-unrelated copy
 * edits — see ai/architecture/tt-website-laravel.md's Hero Slider entry
 * for the numbers. Slides 1-2's shorter .tt-display-l content only gains
 * clearance, never loses it. */
.tt-hero-actions {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(calc(123px + var(--tt-hero-gap-actions)));
  z-index: 2;
  padding-inline: var(--tt-gutter);
  display: flex;
  flex-wrap: wrap;
  gap: var(--tt-hero-cta-gap);
}

/* Ground-independent button treatment + own hover/focus rules (TPT114) —
 * the row no longer sits inside any slide, so it has no .tt-band--ink
 * ancestor to inherit ink-band colors/hover from (marketing.css Buttons
 * block above), and must read on all three current grounds (dark photo+ink
 * scrim on slide 0, light photo+paper scrim on slides 1-2, TPT116) with no
 * per-slide styling hook. Primary reuses the same teal-fill/ink-text pairing
 * the ink-band slide already uses (7.0:1); secondary is ink-fill/paper-text
 * (15.4:1) — both fills are opaque, so their own contrast holds regardless
 * of which photo sits behind the row. Both also get an ink border so the
 * row stays legible by outline alone anywhere a ground is marginal. Hover text mirrors
 * the equivalent ink-band cases (a.tt-btn-primary:hover rules above) since
 * the generic .tt-band--ink a:hover fallbacks can't reach this row either.
 * Focus ring is pinned to --tt-teal — the page default --tt-teal-ink is
 * near-invisible on a dark photo/ink ground. */
.tt-hero-actions .tt-btn-primary {
  background: var(--tt-teal);
  color: var(--tt-ink);
  border-color: var(--tt-ink);
  box-shadow: var(--tt-shadow-hard-paper);
}
.tt-hero-actions .tt-btn-secondary {
  background: var(--tt-ink);
  color: var(--tt-paper);
  border-color: var(--tt-paper);
  box-shadow: var(--tt-shadow-hard-paper);
}
.tt-hero-actions a.tt-btn-primary:hover,
.tt-hero-actions a.tt-btn-primary:focus-visible { color: var(--tt-paper); }
.tt-hero-actions a.tt-btn-secondary:hover,
.tt-hero-actions a.tt-btn-secondary:focus-visible { color: var(--tt-teal); }
.tt-hero-actions :focus-visible { outline-color: var(--tt-teal); }

/* Steps rail (L4, TPT78) — the section head and the rail share one centred
 * 68ch column so the heading's left edge lines up with the first card's,
 * instead of a centred rail sitting under a full-width left-aligned head (an
 * axis break that grows wider as the container ramp below opens up). Wrap
 * both the section head and the step stack in this class in the markup. */
.tt-steps { max-width: 68ch; margin-inline: auto; }

/* Vertical centering for two-column vignette bands (TPT78) — apply only to
 * bands whose vignette is comparable in height to its copy column (L6, L7,
 * L9). Not L5/L8: their vignette is a single short card / a 3-row list,
 * roughly a third the copy column's height, and centering would drop it
 * clear of the heading it illustrates, opening a large empty rectangle. */
.tt-grid--middle { align-items: center; }

/* Eyebrow = the section's spec §17 title string. --tt-ink-2, not
 * --tt-ink-3/--tt-teal-ink — both fail the 4.5:1 body floor on the
 * --tt-paper-deep bands (L5/L8/L11) per style-guide.md §12. */
.tt-eyebrow { color: var(--tt-ink-2); margin-bottom: 12px; }
.tt-band--ink .tt-eyebrow { color: var(--tt-teal); }

/* Wordmark — style-guide.md §9 specifies .tt-brand-delta; it was never
 * added to this file. */
.tt-wordmark {
  font-family: var(--tt-font-display);
  font-weight: 800;
  font-size: 28px;
  /* Fixed length, not a unitless multiplier (TPT87): unitless line-height
   * inherits as the bare number and re-multiplies against the larger
   * .tt-brand-delta span's own font-size below, inflating this element's
   * line box and knocking it off-center in the flex-centered nav row. A
   * length value inherits as its computed px, so the delta span can't
   * re-scale it. */
  line-height: 28px;
  letter-spacing: -0.01em;
  text-decoration: none;
  color: inherit;
}
/* Plain inline text, not a flex container — with only text content (no
 * separate icon child) a flex layout would treat "Tip", this span, and
 * "Task" as three anonymous flex items, and `vertical-align` (used below)
 * has no effect on a flex item, so it would silently do nothing. */
.tt-brand-delta {
  color: var(--tt-teal);
  font-style: italic;
  font-size: 1.35em;
  margin: 0 0.06em;
  vertical-align: -0.05em;
}

/* L14 "paper + teal plate" (§8). Ink text on --tt-teal is 7.0:1 AAA. */
.tt-plate {
  background: var(--tt-teal);
  color: var(--tt-ink);
  border: 2px solid var(--tt-ink);
  box-shadow: var(--tt-shadow-hard-paper);
  border-radius: var(--tt-wobble-2);
  padding: 56px var(--tt-gutter);
  text-align: center;
}
/* .tt-display-l carries no max-width of its own (.tt-body is capped at 66ch,
 * the display ramp isn't) — on the plate, centered text with no cap would run
 * the full container width at the L4-min-width TPT78 container ramp below. */
.tt-plate .tt-display-l { max-width: 24ch; margin-inline: auto; }
/* The global focus-ring color is --tt-teal-ink — invisible on a solid teal
 * plate (the ring itself paints on the plate's own background, outside
 * the focused element's box). Text color is deliberately NOT overridden
 * here: .tt-btn-primary already sets its own ink-on-paper-band contrast
 * (ink fill, paper text), and a blanket `.tt-plate a { color: ink }` would
 * repaint that paper text to ink — invisible on the button's own ink
 * fill. Style any future plain (non-.tt-btn) link on the plate explicitly. */
.tt-plate :focus-visible { outline-color: var(--tt-ink); }

/* Fixes to existing components, needed the moment a real page uses them:
 * - .tt-card/.tt-chip both default-fill --tt-paper-deep, which is invisible
 *   on the --tt-paper-deep bands (L5/L8/L11), and a chip nested in a card
 *   was always the same color as the card regardless of band.
 * - .tt-terminal's border is --tt-ink, invisible on the --tt-band--ink
 *   bands (L6/L9) this page actually puts terminal vignettes on.
 * - .tt-margin-note hardcodes --tt-sanguine-ink, ~2:1 on --tt-ink.
 * - .tt-band--ink defaults text to --tt-paper-2; heading text wants the
 *   higher-contrast --tt-paper per style-guide.md §8's implementer note.
 * - .tt-wobble-2/-3 share .tt-card's specificity and lose on source order,
 *   so "tt-card tt-wobble-2" was previously a no-op.
 * - .tt-card-id is 11px --tt-teal-ink, 4.01:1 on --tt-paper-deep — below
 *   the 4.5:1 body floor. §12's own escape hatch is ">=18.5px/bold".
 */
.tt-band--paper-deep .tt-card,
.tt-band--paper-deep .tt-chip {
  background: var(--tt-paper);
}
.tt-card .tt-chip { background: var(--tt-paper); }
.tt-band--ink .tt-terminal { border-color: var(--tt-paper-2); }
.tt-band--ink .tt-margin-note { color: var(--tt-sanguine); }
.tt-band--ink .tt-display-xl,
.tt-band--ink .tt-display-l,
.tt-band--ink .tt-heading-m {
  color: var(--tt-paper);
}
.tt-card.tt-wobble-2 { border-radius: var(--tt-wobble-2); }
.tt-card.tt-wobble-3 { border-radius: var(--tt-wobble-3); }
.tt-card-id { font-size: 19px; font-weight: 600; }
/* .tt-footer a (0,0,1,1) is more specific than .tt-footer-signin alone
 * (0,0,1,0) and silently wins regardless of source order, so the intended
 * teal Join Beta link renders paper-2 instead. L15 is the first real
 * consumer of this class — fix with a selector that actually outranks it. */
.tt-footer a.tt-footer-signin { color: var(--tt-teal); }

/* Product vignettes standing in for the still-uncaptured website-spec.md
 * §18 screenshots, framed exactly as style-guide.md §10 specifies the real
 * captures will be — swapping one in later is a markup-only change. */
.tt-vignette { display: grid; gap: 12px; }
.tt-shot {
  border: 2px solid var(--tt-ink);
  box-shadow: 8px 8px 0 var(--tt-ink);
  display: block;
  max-width: 100%;
}
.tt-band--ink .tt-shot {
  border-color: var(--tt-paper-2);
  box-shadow: 8px 8px 0 var(--tt-teal);
}

/* Keyboard skip link — 15 bands with a nav at the top, none existed. */
.tt-skip-link { position: absolute; left: -9999px; }
.tt-skip-link:focus {
  left: var(--tt-gutter);
  top: 12px;
  z-index: 3;
  background: var(--tt-paper);
  color: var(--tt-ink);
  padding: 10px 16px;
  border: 2px solid var(--tt-ink);
}

/* --- Breakpoints (§6: 1200 / 900 / 640; every section also checked at
 * 390px). ------------------------------------------------------------- */
@media (max-width: 900px) {
  .tt-grid { grid-template-columns: repeat(6, 1fr); }
  .tt-col-3 { grid-column: span 3; }
  .tt-col-4,
  .tt-col-5,
  .tt-col-6,
  .tt-col-7,
  .tt-col-12 {
    grid-column: span 6;
  }
  .tt-order-first { order: 0; }
  .tt-section-head { margin-bottom: 32px; }
}
@media (max-width: 640px) {
  .tt-grid { grid-template-columns: 1fr; }
  .tt-col-3,
  .tt-col-4,
  .tt-col-5,
  .tt-col-6,
  .tt-col-7,
  .tt-col-12 {
    grid-column: span 1;
  }
  .tt-nav .tt-container { flex-wrap: wrap; gap: 12px; }
  .tt-nav-right { flex-wrap: wrap; gap: 12px; }
  .tt-plate { padding: 40px var(--tt-gutter); }
  .tt-terminal { font-size: 14px; padding: 16px 18px; }
  /* Hero rhythm step-down (TPT86) — .tt-hero-actions' own gap reads the
   * tokens redeclared here, same pattern as --tt-max-width/
   * --tt-band-pad-desktop below at the large-viewport end of the ramp. */
  :root {
    --tt-hero-gap-subhead: 16px;
    --tt-hero-gap-actions: 32px;
    --tt-hero-cta-gap:     16px;
  }
  .tt-btn-lg { font-size: 17px; padding: 16px 26px; }
  /* TPT114: mobile pin — center-anchored (see .tt-hero-actions' main
   * comment above), one shared value for both locales since the
   * center-relative offset needed less locale-specific margin than the
   * old top-relative one did. The matching .tt-hero-copy padding-bottom
   * for this bracket is set in the second max-width: 640px block further
   * down (with padding-top), not here — this block precedes the
   * unconditional .tt-hero-copy padding-bottom declaration below in
   * source order, so setting it here would just get silently overridden
   * by that later, always-matching rule (same trap as the >=1920px
   * block's own comment describes). */
  .tt-hero-actions { transform: translateY(calc(105px + var(--tt-hero-gap-actions))); }
}

/* ---------------------------------------------------------------------------
 * Large-viewport container ramp (TPT78) — this file's first min-width
 * queries. Order matters: media queries add no specificity, so these two
 * blocks win purely on being declared last, and the 1920px block must follow
 * the 1440px block or 1400px would win at 1920px too. --tt-gutter
 * deliberately does not grow at either step — it is also the grid gap, the
 * band side padding, and .tt-plate's padding, so widening it is extra blast
 * radius for no gain. 1560px caps the ramp; at 3840px that leaves ~1140px of
 * margin per side, well within style-guide.md §6's "reasonable margin up to
 * 4k". .tt-body stays capped at 66ch regardless of container width; the
 * display-size headings have their own measure caps added above, since
 * .tt-display-l carries none of its own.
 * ------------------------------------------------------------------------- */
@media (min-width: 1440px) {
  :root { --tt-max-width: 1400px; }
}
@media (min-width: 1920px) {
  :root { --tt-max-width: 1560px; --tt-band-pad-desktop: 128px; }
}

/* ===========================================================================
 * Hero slider (TPT79) — L2, three manually-navigated slides. Full-bleed on
 * the section itself (not a .tt-band): each slide's own ground spans the
 * viewport past the .tt-container cap above, out to 4k, per the task's
 * "background must span beyond current content width" direction. Copy stays
 * inside .tt-hero-copy (max-width: var(--tt-max-width)) while the ground
 * behind it runs edge to edge. See ai/architecture/tt-website-laravel.md §
 * Hero Slider for the style-guide.md §7/§15 departure this section is.
 * ========================================================================= */
.tt-hero-slider { position: relative; overflow: hidden; }

.tt-hero-track {
  display: flex;
  transition: transform 420ms ease;
}
@media (prefers-reduced-motion: reduce) {
  .tt-hero-track { transition: none; }
}

.tt-hero-slide {
  position: relative;
  flex: 0 0 100%;
  display: flex;
  align-items: center;
  min-height: clamp(460px, 62vh, 760px);
}
@media (min-width: 1600px) {
  .tt-hero-slide { min-height: 62vh; }
}

/* Photo ground (slide 0) — a flat rgba() scrim (--tt-ink-scrim above), not a
 * gradient overlay, keeps paper text readable over the dark canyon panorama
 * without touching the §13 gradient ban. Declared after .tt-band--ink so
 * this background wins at equal specificity (slide 0 also carries
 * .tt-band--ink for its text/button contrast — see the blade comment at the
 * hero markup). --ink/--teal below keep their original class names (TPT79
 * ground names) even though TPT116 turned both into photo grounds too —
 * renaming them would only churn the blade $ground array for no reader
 * benefit. */
.tt-hero-slide--photo {
  background: var(--tt-ink) url('../images/hero-bg.jpg') center / cover no-repeat;
}
.tt-hero-slide--photo::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--tt-ink-scrim);
}

/* Slide 1 (TPT116) — the whiteboard photo is light everywhere the copy sits,
 * so this ground takes ink text and a light --tt-paper-scrim veil instead of
 * .tt-band--ink; the position offset (25% instead of center) keeps the
 * board's darker right-hand figure clear of the copy column at every
 * viewport width the copy's own measure can reach — center crops that
 * figure in behind the text below ~900px and the text drops under 3:1. */
.tt-hero-slide--ink {
  background: var(--tt-paper) url('../images/hero-bg-2.jpg') 25% center / cover no-repeat;
}
.tt-hero-slide--ink::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--tt-paper-scrim);
}

/* Slide 2 (TPT116) — the machine illustration runs darker than slide 1's
 * whiteboard (ink linework down to L 0.02), so it takes the deeper
 * --tt-paper-scrim-deep veil to clear 4.5:1 at center position; no
 * .tt-band--ink, matching how L14's .tt-plate handles a light ground. */
.tt-hero-slide--teal {
  background: var(--tt-paper) url('../images/hero-bg-3.jpg') center / cover no-repeat;
}
.tt-hero-slide--teal::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--tt-paper-scrim-deep);
}
.tt-hero-slide--teal :focus-visible { outline-color: var(--tt-ink); }

/* TPT86: padding-block reuses --tt-band-pad-desktop instead of its own 64px
 * constant — every other band on the page pads 96px top/bottom, and the
 * hero previously read shorter/denser than the bands beneath it. Also picks
 * up the 128px step at >=1920px (§ Large-viewport container ramp) for free.
 * padding-inline is new: .tt-hero-copy is a bare .tt-container with no side
 * padding of its own — every other section gets its --tt-gutter side inset
 * from .tt-band on the *section* element, which the full-bleed hero
 * deliberately isn't, so this was the one place nothing supplied it. Below
 * --tt-max-width (roughly <=770px once the larger TPT86 CTAs are in play)
 * the copy ran edge-to-edge, out of alignment with the nav wordmark above
 * and every band below. */
/* TPT114: padding-bottom is split off from the padding-block shorthand and
 * pinned to a measured literal (410px, the 641-1919px bracket's worst case)
 * instead of tracking --tt-band-pad-desktop — it reserves space for the
 * now-absolutely-positioned .tt-hero-actions row (see that rule's comment
 * for the exact worst-case derivation) so it neither overlaps slide text
 * nor gets cut off by .tt-hero-slider's overflow: hidden. The >=1920px
 * bracket gets its own smaller override below (that width range never
 * wraps the CTA row to two lines), not the page's normal band rhythm. */
.tt-hero-copy {
  position: relative;
  padding-top: var(--tt-band-pad-desktop);
  padding-bottom: 410px;
  padding-inline: var(--tt-gutter);
}

/* TPT116 — bumping slides 1-2's heading to .tt-display-xl (same size as
 * slide 0) pairs with slide 1-2's own longer UK titles to overflow a single
 * long word (e.g. "Перетворює", "відстежувану") past .tt-hero-copy's own
 * padding at narrow mobile widths, past .tt-hero-slider's overflow: hidden
 * — silently clipping it, not just wrapping oddly. Slide 0's own title never
 * hit this (its longest word still fits at 390px), so this wasn't needed
 * before. Standard fallback: only a word that doesn't fit breaks; every
 * other heading on the page wraps exactly as before. */
.tt-hero-copy h1,
.tt-hero-copy h2 { overflow-wrap: break-word; }

/* Controls sit in their own paper bar under the track, so they have one
 * contrast story regardless of which slide is showing — never overlaid on
 * the image/ink/teal grounds themselves. Hidden until the slider script
 * marks it ready (a no-JS visitor gets slide 0 with no dead controls). */
.tt-hero-controls { background: var(--tt-paper); border-top: 2px solid var(--tt-ink); }
.tt-hero-slider:not(.is-ready) .tt-hero-controls { display: none; }
.tt-hero-controls-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 24px;
  padding-block: 16px;
}

.tt-hero-arrow {
  font-family: var(--tt-font-mono);
  font-size: 20px;
  line-height: 1;
  width: 40px;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--tt-paper);
  color: var(--tt-ink);
  border: 2px solid var(--tt-ink);
  box-shadow: var(--tt-shadow-hard-paper);
  cursor: pointer;
}

.tt-hero-dots { display: flex; gap: 12px; }
.tt-hero-dot {
  width: 14px;
  height: 14px;
  padding: 0;
  border-radius: 50%;
  border: 2px solid var(--tt-ink);
  background: var(--tt-paper);
  cursor: pointer;
}
.tt-hero-dot[aria-current="true"] { background: var(--tt-teal); }

@media (max-width: 640px) {
  .tt-hero-slide { min-height: 420px; }
  /* Both properties set explicitly (TPT114) rather than a padding-block
   * shorthand — this rule needs to be the one that wins for padding-bottom
   * (it comes after the unconditional 641px+ declaration above in source
   * order; the earlier max-width: 640px block, which sets
   * .tt-hero-actions' mobile `top`, comes before that unconditional rule
   * and would have its own padding-bottom silently overridden by it — see
   * that block's comment). */
  .tt-hero-copy {
    padding-top: var(--tt-band-pad-mobile);
    /* TPT114: worst case measured across the full 280-640px sweep, not
     * just at the 375px checkpoint — content height (hence how far the
     * centered copy's own box extends past the pinned row) varies enough
     * across that range, in both locales, that the 375px-only figure
     * undersized this badly. Placed here rather than the earlier
     * max-width: 640px block: see this block's own note below.
     */
    padding-bottom: 500px;
  }
  .tt-hero-controls-row { gap: 16px; }
  .tt-hero-arrow { width: 36px; height: 36px; font-size: 18px; }
}

/* TPT114 — >=1920px pin. Placed here (after every unconditional
 * .tt-hero-actions/.tt-hero-copy declaration above), not inside the
 * existing >=1920px --tt-max-width block near the container-ramp section:
 * that block sits EARLIER in the file, and since a @media block adds no
 * specificity, an unconditional rule declared later always wins over an
 * earlier-declared one at any width where both match — putting this
 * override there would have been silently discarded.
 * --tt-max-width stops growing past this point, so slide 0's subhead never
 * wraps more than it does right at 1920px — a different, separately-
 * measured translateY than the 641-1919px bracket above needs (see that
 * rule's main comment for why this is center- not top-anchored). */
@media (min-width: 1920px) {
  .tt-hero-actions { transform: translateY(calc(193px + var(--tt-hero-gap-actions))); }
  .tt-hero-copy { padding-bottom: 350px; }
}

/* ===========================================================================
 * Testimonials band (TPT71/TPT101/TPT104) — L12a, a standalone section
 * between L12 (who-its-for) and L13 (roadmap). Six paper speech-bubble tiles
 * — a 2px ink hairline, no `aspect-ratio` (height follows content, ~2.4:1
 * once wrapped) — each topped by a centered 5-star rating and a quote.
 * `--tt-ink-scrim` stays defined for the hero slider; the tile's own former
 * ink ground + `.tt-hatch` texture + unused `--photo` hook are gone with it.
 * See ai/architecture/tt-website-laravel.md § Testimonials for the
 * website-spec.md §11 claim-register note this section carries.
 * ========================================================================= */
.tt-testimonials {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 1fr; /* every row matches its tallest tile (longest quote wraps to 2-3 lines depending on locale) */
  gap: 40px var(--tt-gutter); /* taller row gap than --tt-gutter alone so the tail below doesn't crowd the next row */
}

.tt-testimonial {
  margin: 0;
  position: relative;
  border: 2px solid var(--tt-ink);
  /* Flat 16px radius, not a --tt-wobble-* token: at this tile's ~2.4:1
   * proportions the wobble radii (tuned for near-square cards) clamp down
   * and swallow the whole left/right edge into a lozenge (the same trap
   * §L4's .tt-card comment already documents). */
  border-radius: 16px;
  background: var(--tt-paper);
  /* filter: drop-shadow(...), not box-shadow — deliberate departure from the
   * §5 box-shadow primitive. box-shadow only traces the border box, so the
   * ::after tail (a sibling paint layer) would punch a notch through it;
   * drop-shadow traces the element's full rendered silhouette, tail
   * included, at the same zero-blur 6px/6px/ink offset as
   * --tt-shadow-hard-paper. Written as literal px, not
   * drop-shadow(var(--tt-shadow-hard-paper)), to keep the value unambiguous
   * to parse. */
  filter: drop-shadow(6px 6px 0 var(--tt-ink));
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  padding: 16px 22px;
}

/* Comic speech tail — one 45°-rotated square with two ink borders, not two
 * stacked border-triangles: the 2px hairline is then applied perpendicular
 * to the edge by construction (no outline-thickness math to get wrong).
 * The rotated bottom/right edges become the tail's two visible slants; the
 * hidden upper half sits over the tile's own bottom border and breaks it,
 * the classic comic-panel tail notch. Fixed `left`, not centered — a
 * center-bottom tail reads as a thought bubble instead of a speech bubble. */
.tt-testimonial::after {
  content: "";
  position: absolute;
  left: 34px;
  bottom: -9px;
  width: 18px;
  height: 18px;
  background: var(--tt-paper);
  border-right: 2px solid var(--tt-ink);
  border-bottom: 2px solid var(--tt-ink);
  transform: rotate(45deg);
}
.tt-testimonial > * { position: relative; } /* paint above the tail */

.tt-star-row { display: flex; justify-content: center; gap: 6px; margin-bottom: 10px; }
.tt-star { width: 36px; height: 36px; flex: none; }
/* --tt-ink-3, not --tt-paper-2 — that was the right stroke for the old ink
 * ground, invisible on this tile's now-paper one. */
.tt-star--empty { stroke: var(--tt-ink-3); stroke-width: 12; fill: none; }

.tt-testimonial-quote {
  font-family: var(--tt-font-display);
  font-weight: 700;
  font-size: 17px;
  line-height: 1.4;
  text-wrap: balance;
  color: var(--tt-ink);
  margin: 0;
}
.tt-testimonial-attr {
  font-family: var(--tt-font-mono);
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* --tt-teal-ink, the style guide's sanctioned teal-as-text pairing
   * (4.51:1) — legal specifically because the tile itself is --tt-paper,
   * not this band's own --tt-paper-deep ground (where the same pairing
   * drops to ~4.0:1 and fails body-text contrast). */
  color: var(--tt-teal-ink);
  margin-top: 12px;
}

@media (max-width: 1100px) {
  /* 900px (this file's usual 3→2 breakpoint) leaves a ~268px 3-col tile at
   * vw 901 — narrow enough that a long quote wraps to 3 lines and the tile
   * goes back to ~1.5:1, square again. 1100px keeps the narrowest 2-col
   * column above ~500px instead. */
  .tt-testimonials { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .tt-testimonials { grid-template-columns: 1fr; }
  /* Capped, not full-width — an uncapped single column runs ~590px wide at
   * this breakpoint and even a two-line quote reads as a thin letterboxed
   * strip rather than a bubble. */
  .tt-testimonial { max-width: 420px; margin-inline: auto; }
}

/* ── L14 Join Beta inline form (TPT96) — renders inside .tt-plate only in
 * beta mode (config('site.beta_mode'), see landing.blade.php). .tt-input's
 * existing paper-on-teal contrast needs no new variant here — the plate's
 * own ground is teal, not ink, so the default (non .tt-band--ink) .tt-input
 * rule already reads correctly against it. */
.tt-beta-form {
  max-width: 420px;
  margin: 24px auto 0;
  text-align: left;
}
.tt-beta-field {
  margin-bottom: 16px;
}
.tt-beta-field label {
  display: block;
  font-family: var(--tt-font-mono);
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 6px;
}
.tt-beta-field .tt-input {
  width: 100%;
  box-sizing: border-box;
}
.tt-beta-form .tt-btn {
  width: 100%;
}
/* Honeypot — a real visitor never sees or fills this; a bot filling every
 * field on the page does. Off-canvas, not display:none/visibility:hidden —
 * some crawlers skip fields those two properties hide but still fill an
 * off-canvas one. */
.tt-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
/* Success/error panel after a Join Beta submit, and the ?beta=required
 * notice banner shown above the form when a rejected sign-in bounces back
 * here (api/src/routes/auth.js). */
.tt-alert {
  border: 2px solid var(--tt-ink);
  padding: 14px 16px;
  margin: 0 auto 16px;
  max-width: 420px;
  font-family: var(--tt-font-text);
  font-size: 15px;
  text-align: left;
}
.tt-alert--ok {
  background: var(--tt-paper);
  color: var(--tt-ink);
}
.tt-alert--error {
  background: var(--tt-paper);
  color: var(--tt-sanguine-ink);
  border-color: var(--tt-sanguine-ink);
}
