@charset "UTF-8";
/* ══════════════════════════════════════════════════════════════════════════════
   Aligned Hearts — the 2026 site

   The design is token-driven and otherwise styled inline, page by page. That is
   deliberate and it is how the comps were drawn: almost every rule in this file
   is either a custom property the inline styles read, a base reset, or a
   behaviour that cannot be expressed inline at all (hover, focus, breakpoints,
   reveal-on-scroll). Resist adding page styling here — it belongs next to the
   markup it dresses, where the comps put it.

   This file exists alongside the old site.css while pages are migrated one at a
   time. The layout picks which to load. When the last page moves, delete
   site.css, this file becomes site.css, and layouts/site.blade.php goes with it.

   Contents
     1  Tokens
     2  Base
     3  Hover and focus          — what inline styles cannot do
     4  Responsive               — the data-r contract
     5  Motion                   — reveal on scroll
     6  Forms
   ════════════════════════════════════════════════════════════════════════════ */

/* ── 1  Tokens ─────────────────────────────────────────────────────────────── */

:root {
  --ink:        #120C0A;
  --ink-soft:   #2A201C;
  --bone:       #F6F1EA;
  --bone-warm:  #EDE4D8;
  --ember:      #C4602E;
  --ember-deep: #8F3F1B;
  --sage:       #5C6B5A;
  --muted:      #8A7A70;
  --red:        #C8102E;

  /* The comps call for this on every solid-red hover but never defined it —
     the deep red is the one the "ways to work together" band is painted in. */
  --red-deep:   #9E0C24;

  --hair:       rgba(138, 122, 112, .22);
  --hair-dark:  rgba(246, 241, 234, .16);

  --display: 'Newsreader', Georgia, 'Times New Roman', serif;
  --body:    'Hanken Grotesk', Helvetica, Arial, sans-serif;

  --text:   clamp(17px, 16.6px + .15vw, 18px);
  --h1:     clamp(38px, 1.6rem + 3.4vw, 84px);
  --h2:     clamp(30px, 1.3rem + 2vw, 54px);
  --quote:  clamp(28px, 1.4rem + 1vw, 40px);
  --gutter: clamp(20px, 5vw, 72px);
  --sect:   clamp(72px, 40px + 5.5vw, 120px);

  --radius: 4px;
  --ease:   cubic-bezier(.22, 1, .36, 1);
}

/* ── 2  Base ───────────────────────────────────────────────────────────────── */

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bone);
  color: var(--ink);
  font-family: var(--body);
  font-size: var(--text);
  line-height: 1.6;
  font-feature-settings: "ss01";
}

h1, h2, h3, h4, p, figure { margin: 0; text-wrap: pretty; }

a {
  color: var(--red);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: color .15s ease, text-decoration-color .15s ease;
}
a:hover { color: var(--ember-deep); }

button { font: inherit; cursor: pointer; color: inherit; }

:focus-visible { outline: 2px solid var(--ember); outline-offset: 2px; }

img { display: block; max-width: 100%; }

/* The comps set display inline on nearly everything, and an inline
   display:grid outranks the user-agent rule for [hidden] — so a hidden
   element stays on screen. Anything toggled with the hidden attribute needs
   this or it never hides. */
[hidden] { display: none !important; }

/* Small caps labels must not break across lines. */
a[style*="text-transform:uppercase"],
button[style*="text-transform:uppercase"] { white-space: nowrap; }

table { border-collapse: collapse; }

/* The skip link, visible only once it has focus. */
.skip-link {
  position: absolute;
  left: 8px;
  top: -60px;
  z-index: 100;
  background: var(--bone);
  color: var(--ink);
  padding: 10px 14px;
  border-radius: var(--radius);
  text-decoration: none;
  transition: top .15s ease;
}
.skip-link:focus { top: 8px; }

/* ── 3  Hover and focus ────────────────────────────────────────────────────── */
/* The comps express hover with a style-hover attribute their tool understands.
   These classes are the standards-CSS equivalent, named for what they do. */

.hv-ember:hover      { color: var(--ember); }
.hv-ember-deep:hover { color: var(--ember-deep); }
.hv-bone:hover       { color: var(--bone); }
.hv-blush:hover      { color: #F6D7DB; }
.hv-blush-pale:hover { color: #FBEEEF; }

.hv-fill-red:hover      { background: var(--red-deep); color: #FFFFFF; }
.hv-fill-ink:hover      { background: var(--ink-soft); }
.hv-fill-bone:hover     { background: var(--bone-warm); }
.hv-fill-ember:hover    { background: var(--ember-deep); }
.hv-fill-bone-faint:hover { background: rgba(246, 241, 234, .08); }
.hv-red-deep:hover      { color: var(--red-deep); }
.hv-border-ink:hover    { border-color: var(--ink); }
.hv-red-rule:hover      { color: var(--red); border-color: var(--red); }
.hv-red:hover           { color: var(--red); }

/* ── 3b  Legal prose ───────────────────────────────────────────────────────
   The eight legal pages are the one place the comps style plain elements
   rather than every node individually — the body of a policy is a list of
   paragraphs, lists and the odd table, and there are eighty sections of it.
   Scoped to .legal so nothing here leaks into a page that styles inline. */

/* The comps set a numbered list a touch tighter than a bulleted one. */
.legal ul,
.legal ol      { margin: 0; padding-left: 22px; display: grid; gap: 10px; }
.legal ol      { gap: 8px; }
.legal h3      { font-family: var(--display); font-weight: 500; font-size: 22px; line-height: 1.25; margin-top: 8px; }
.legal table   { width: 100%; border-collapse: collapse; font-size: 17px; }
.legal th      { text-align: left; font-weight: 600; font-size: 14px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); padding: 12px 16px 12px 0; border-bottom: 1px solid var(--muted); }
.legal td      { padding: 16px 16px 16px 0; border-bottom: 1px solid var(--hair); vertical-align: top; }
.legal td:first-child { font-weight: 600; }

/* A policy can hold a wide retention table; let it scroll rather than push
   the page sideways on a phone. */
.legal__scroll { overflow-x: auto; }

/* The two tinted panels the policies use to lift something out of the run of
   text. A note is an aside; an alert is the paragraph someone will be cross
   about having missed, so it takes the red edge and a full border. */
/* Block, not grid, and no gap: that is how the comps draw them, and with the
   reset zeroing paragraph margins a multi-paragraph panel runs together. Only
   one panel on the site has more than a single paragraph — the emergency
   numbers on the Safety page — and it is flagged in docs/BACKLOG.md rather
   than quietly given air the design does not have. */
.legal-note,
.legal-alert {
  background: #FAF7F3;
  border-radius: var(--radius);
  padding: clamp(20px, 3vw, 32px);
}
.legal-note  { border-left: 3px solid var(--ink); }
.legal-alert { border: 1px solid var(--muted); border-left: 3px solid var(--red); }

/* The statutory notices: the CCPA do-not-sell statement, the Texas DPSA
   sensitive-data notice, the arbitration and class-action waivers. Several of
   the statutes behind these require the disclosure to be conspicuous, so the
   caps and the weight are doing legal work, not visual work. Do not quieten
   them down because they shout. */
.legal-shout {
  font-size: 17px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .02em;
  line-height: 1.5;
}

/* ── 3a  Choice cards ──────────────────────────────────────────────────────
   The booking page's package and time choices. The comp draws them as
   aria-pressed buttons; here they are labels wrapping a radio, so the form
   still submits a value with no script running. That makes the chosen state a
   matter of :checked rather than a class some JavaScript remembered to add —
   which is why it survives a validation bounce with old() re-checked. */

.choice { position: relative; cursor: pointer; }
.choice input { position: absolute; opacity: 0; width: 0; height: 0; }
.choice:has(input:checked) { border-color: var(--ink); }
.choice input:checked ~ .choice__bar { background: var(--red); }
.choice input:focus-visible ~ .choice__bar { background: var(--ember); }

/* The focus ring has to come from the label: the input it belongs to is
   zero-sized, so an outline on it would be invisible. */
.choice:has(input:focus-visible) { outline: 2px solid var(--ember); outline-offset: 2px; }

.choice[data-taken="true"] { opacity: .4; pointer-events: none; }

/* ── 4  Responsive ─────────────────────────────────────────────────────────── */
/* The comps mark responsive intent with data-r on the element. Keeping that
   contract means the markup here and the markup in the comps stay comparable,
   which matters when a page is redrawn. */

[data-r="show-m"]       { display: none; }
[data-r="show-block-m"] { display: none; }

@media (max-width: 1023px) {
  [data-r="cols3"]  { grid-template-columns: 1fr !important; }
  [data-r="cols5"]  { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
  [data-r="hide-m"] { display: none !important; }
  [data-r="show-m"] { display: flex; }
  [data-r="show-block-m"] { display: block !important; }
  [data-r="cols"]   { grid-template-columns: 1fr !important; }
  [data-r="cols"] > * { grid-column: auto !important; }
  [data-r="col-m"]  { flex-direction: column !important; align-items: flex-start !important; }
  [data-r="span-m"] { grid-column: 1 / -1 !important; }
  [data-indent]     { margin-left: 0 !important; }

  /* Footer columns collapse to accordions below the desktop breakpoint. */
  [data-foot] [data-foot-body] { display: none !important; }
  [data-foot][data-open="true"] [data-foot-body] { display: grid !important; }
}

@media (min-width: 1024px) {
  [data-foot-head] { display: none !important; }
}

@media (max-width: 767px) {
  [data-r="cols4"]     { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
  [data-r="cols2"]     { grid-template-columns: 1fr !important; }
  [data-r="cols2"] > * { grid-column: auto !important; }
  [data-r="cell-note"] { display: none; }
  [data-r="pad-m"]     { padding-top: 24px !important; padding-bottom: 24px !important; }
}

/* ── 5  Motion ─────────────────────────────────────────────────────────────── */

[data-reveal] {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity .4s var(--ease), transform .4s var(--ease);
}
[data-reveal].in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
  [data-reveal] { opacity: 1; transform: none; }
}

/* ── 6  The Five Alignments ────────────────────────────────────────────────── */
/* The one hover in the comps that changes six things at once, so it could not
   be written as an inline style. Pure CSS rather than the mockup's mouse
   handlers: it then works for keyboard focus too, which the original did not. */

.five:hover,
.five:focus-within {
  background: rgba(246, 241, 234, .05);
  transform: translateY(-4px);
}
.five:hover .five__glyph,
.five:focus-within .five__glyph { transform: rotate(-6deg) scale(1.08); }

.five:hover .five__fill,
.five:focus-within .five__fill { background: var(--red); }

.five:hover .five__rule,
.five:focus-within .five__rule { width: 100%; }

.five:hover .five__body,
.five:focus-within .five__body { color: #F1E9DE; }

/* ── 7  Image placeholders ─────────────────────────────────────────────────── */
/* Where a photograph will go. Drawn the way the comps draw it: a dashed ring
   in currentColor at low opacity, a mark, and the art-direction brief in
   place, so the shot list travels with the build and every empty slot reads
   the same whether it sits on bone or on ink.
   The ring is a pseudo-element rather than a border on the figure so its
   opacity does not drag the caption down with it. */

.slot {
  position: relative;
  display: grid;
  place-items: center;
  align-content: center;
  gap: 10px;
  aspect-ratio: var(--slot-ratio, 3 / 2);
  padding: 16px;
  text-align: center;
  overflow: hidden;
  color: inherit;
}

.slot::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 1.5px dashed currentColor;
  border-radius: inherit;
  opacity: .35;
  pointer-events: none;
}

/* A picture mark: a frame with a sun and a horizon, at the comps' weight. */
.slot__mark {
  position: relative;
  width: 30px;
  height: 24px;
  border: 1.5px solid currentColor;
  border-radius: 3px;
  opacity: .45;
}
.slot__mark::before {
  content: "";
  position: absolute;
  left: 5px;
  top: 5px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  border: 1.5px solid currentColor;
}
.slot__mark::after {
  content: "";
  position: absolute;
  left: 2px;
  right: 2px;
  bottom: 3px;
  height: 8px;
  border-top: 1.5px solid currentColor;
  transform: skewY(-14deg);
  transform-origin: left;
}

.slot__brief {
  position: relative;
  max-width: 34ch;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 500;
  letter-spacing: .01em;
  opacity: .75;
}

/* Filled slots are a plain image; no ring, no brief. Block, not the grid the
   empty slot uses: in a grid the image kept its natural height and was
   centred, so a tall app screen showed its middle whatever object-position
   asked for. */
.slot--photo { display: block; padding: 0; }
.slot--photo::after { display: none; }
.slot--photo img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* An app screenshot, shown whole: the full height of the slot, centred, with
   a phone screen's corners and a lift off whatever panel it sits on. */
.slot--screen { display: flex; align-items: center; justify-content: center; padding: clamp(12px, 2vw, 24px); }
.slot--screen img {
  width: auto;
  max-width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: clamp(10px, 1.4vw, 18px);
  box-shadow: 0 1px 2px rgba(18, 12, 10, .12), 0 12px 32px rgba(18, 12, 10, .18);
}

/* A cut-out figure (transparent PNG/WebP): the whole person, feet — well,
   shoulders — on the bottom edge, over a warm bone-to-ember ground so the
   empty space reads as light rather than as a gap. */
.slot--cutout {
  background:
    radial-gradient(120% 80% at 50% 100%, rgba(196, 96, 46, .30), rgba(196, 96, 46, 0) 70%),
    linear-gradient(180deg, var(--bone) 0%, var(--bone-warm) 100%);
}
.slot--cutout img { object-fit: contain; object-position: center bottom; }

/* A slot asked to fill its parent has no ratio of its own. */
.slot[style*="height:100%"] { aspect-ratio: auto; }

/* ── 8  Disclosure ─────────────────────────────────────────────────────────── */
/* <details> carries the FAQ so it works without script. These only remove the
   browser's own marker — the comps draw their own + sign — and turn it when
   the panel opens. */

summary::-webkit-details-marker { display: none; }
summary::marker { content: ''; }

details[open] > summary span[aria-hidden] { transform: rotate(45deg); }
summary span[aria-hidden] {
  display: inline-block;
  transition: transform .2s var(--ease);
}

/* ── 9  Forms ──────────────────────────────────────────────────────────────── */
/* The comps draw inputs inline. These are the states they cannot: placeholder
   colour, invalid, and the disabled button while a form is in flight. */

input, textarea, select { font: inherit; color: inherit; }
input::placeholder, textarea::placeholder { color: var(--muted); opacity: 1; }

[data-invalid="true"] { border-color: #E8A07A !important; }

button[disabled], a[aria-disabled="true"] { opacity: .6; cursor: not-allowed; }

/* The honeypot field: present for robots, gone for everyone else. */
.hp-field {
  position: absolute !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
