/*
 * Screen Time Machine — marketing site.
 *
 * Tokens mirror src/constants/theme.ts and the instrument materials mirror
 * src/constants/instrument.ts, so the site and the app are cut from the same glass and metal. The
 * instruments below are CSS recreations of real components: TimeDisplay, SegmentBar, LightStatus
 * and DialScale. The app ships a single light theme, so this does too: no dark mode, deliberately.
 *
 * DialScale is the one that differs: in the app it's a passive display, and here it's the page's
 * main interaction. See machine.js.
 */

@font-face {
  font-family: 'DSEG7Classic';
  src: url('fonts/DSEG7Classic-Bold.ttf') format('truetype');
  font-weight: 700;
  font-display: swap;
}

:root {
  /* surfaces */
  --bg: #ece0c9;
  --card: #f4ecd8;
  --card-hi: #fcf6e8;
  --card-lo: #e9ddc3;
  --card-edge: #dbcdae;
  --recess: #e1d4b8;
  --face: #f2e9d3;
  /* Ink printed onto an instrument face, darker than body ink is on cream (theme.ts faceInk). */
  --face-ink: #2a2015;
  /* ink */
  --ink: #221b12;
  --ink-soft: #6a5c44;
  /*
   * The old #9b8d72 came out at 2.5:1 on --bg, well under WCAG AA. This carries the same warm
   * grey-brown at 4.6:1. It lands close to --ink-soft on purpose: on a cream background there is
   * not much room below AA, so the muted/soft distinction is carried by size and weight (small,
   * uppercase, tracked) rather than by lightness.
   */
  --muted: #6f6249;
  /* espresso */
  --espresso: #3a2c1c;
  --espresso-2: #271c10;
  /* accent + amber */
  --accent: #cb4523;
  --accent-deep: #9a380f;
  --amber: #e08a2a;
  /* brass */
  --brass: #c9b084;
  --brass-hi: #e9d8b2;
  --brass-lo: #9a8259;
  /* warm shadow ladder */
  --shadow-soft: rgba(83, 61, 28, 0.25);
  --shadow: rgba(83, 61, 28, 0.3);
  --shadow-strong: rgba(58, 42, 24, 0.55);

  /* instrument materials (src/constants/instrument.ts) */
  --amber-on: #ffc24d;
  --amber-glow: #ff9e2c;
  --amber-ghost: rgba(255, 158, 44, 0.13);
  --screen-top: #39291a;
  --screen-bottom: #160e07;
  /* one bar-graph cell plus the gap after it — the pitch every segment meter runs on */
  --cell: 6px;
  --cell-pitch: 9px;

  --serif: 'Iowan Old Style', Palatino, 'Palatino Linotype', Georgia, 'Times New Roman', serif;
  --sans: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --radius: 16px;
  --maxw: 1040px;
}

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3 {
  font-family: var(--serif);
  font-weight: 600;
  line-height: 1.15;
  margin: 0;
}

a {
  color: var(--accent-deep);
}

a:hover {
  color: var(--accent);
}

img,
svg {
  max-width: 100%;
}

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 24px;
}

/* Keyboard users must be able to see where they are; the warm ring keeps it on-brand. */
:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

.skip {
  position: absolute;
  left: -9999px;
}

.skip:focus {
  left: 24px;
  top: 12px;
  z-index: 10;
  background: var(--card-hi);
  padding: 10px 16px;
  border-radius: 8px;
}

/*
 * Short copy that runs two sentences, one per line. Left to wrap freely, the second sentence
 * starts mid-line and breaks in the middle, so its tail reads as a crop rather than a second idea;
 * a line each keeps one idea per line. A sentence wider than the column still wraps inside its own
 * line, balanced so it can't drop a lone word. For paragraphs of three sentences or more, leave the
 * text to wrap — a line per sentence turns a paragraph into a ragged list.
 */
.sentences > span {
  display: block;
  text-wrap: balance;
}

/* ---------- top bar ---------- */

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 20px 0;
}

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--serif);
  font-size: 19px;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  letter-spacing: 0.01em;
}

/* The launcher icon itself, not a redrawing of it. Its own artwork carries the rounded square. */
.wordmark img {
  width: 30px;
  height: 30px;
  flex: none;
  border-radius: 7px;
}

.topbar nav {
  display: flex;
  gap: 22px;
  font-size: 15px;
}

.topbar nav a {
  color: var(--ink-soft);
  text-decoration: none;
}

.topbar nav a:hover {
  color: var(--ink);
  text-decoration: underline;
}

/* ---------- hero ---------- */

/*
 * Single column, centred. The machine used to sit in a 0.9fr side column, which left the dial about
 * 360px wide — not enough to set the hour axis without labels touching, and not the billing a page's
 * main interaction deserves. Copy on top, instrument beneath it at full width.
 */
.hero {
  padding: 48px 0 64px;
  text-align: center;
}

.hero-copy {
  max-width: 640px;
  margin: 0 auto;
}

/*
 * Smaller than the old fixed headline, because this one is a full sentence carrying two figures
 * that change as the visitor types. Balanced so the last line never strands a single word, and the
 * only thing that varies between the two states is a digit, so the line count holds and the grid
 * beneath it doesn't jump when the state flips.
 */
.hero h1 {
  font-size: clamp(34px, 5vw, 52px);
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.lede {
  font-size: 19px;
  color: var(--ink-soft);
  margin: 20px auto 0;
  max-width: 46ch;
}

.cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 32px;
}

/* Wide enough that the dial's face clears ~500px, where the hour axis sets cleanly. */
.panel {
  max-width: 560px;
  margin: 44px auto 0;
  text-align: center;
  background: var(--card);
  border-radius: var(--radius);
  padding: 22px;
  box-shadow: 0 1px 0 var(--card-hi) inset, 0 10px 28px var(--shadow-soft);
}

.cta-note {
  font-size: 14px;
  color: var(--muted);
}

.cta-sub {
  font-size: 14px;
  color: var(--muted);
  margin: 14px 0 0;
}

/* The one accent cap on the page — everything else stays cream, so the hierarchy reads at a glance. */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 600;
  text-decoration: none;
  padding: 14px 22px;
  border-radius: 12px;
  border: 1px solid var(--accent-deep);
  background: var(--accent);
  color: #fff;
  box-shadow: 0 2px 0 var(--accent-deep), 0 6px 14px var(--shadow-soft);
  transition: transform 90ms ease, box-shadow 90ms ease;
}

.btn:hover {
  color: #fff;
}

/* Press-in is quick, matching Motion.pressIn in the app. */
.btn:active {
  transform: translateY(2px);
  box-shadow: 0 0 0 var(--accent-deep), 0 3px 8px var(--shadow-soft);
}

.btn svg {
  width: 18px;
  height: 18px;
  flex: none;
}

/* ---------- TimeDisplay: an opening milled through the face, glass sunk in it ---------- */

/*
 * The ring is the metal the opening was cut through — thin, and lit upside down: shaded along its
 * top edge, catching light along its bottom. That inversion is the whole trick. A raised bezel is
 * bright on top and dark underneath, so running the same ring the other way up is what the eye
 * reads as a wall going into the surface rather than standing out of it, and the hairline of light
 * just outside it is the face the cut was made in.
 *
 * Ring and glass corners stay concentric by construction, exactly as the component does it: outer
 * radius = glass radius + ring width.
 */
.instrument {
  padding: 3px;
  border-radius: 17px;
  overflow: hidden;
  border: 1px solid rgba(40, 28, 12, 0.55);
  background: linear-gradient(180deg, var(--brass-lo), var(--brass), var(--brass-hi));
  box-shadow: inset 0 2px 3px rgba(30, 20, 8, 0.8), inset 0 -1.5px 2px rgba(255, 248, 228, 0.6),
    0 1px 0 rgba(255, 251, 241, 0.9);
}

/*
 * The glass runs dark at the top and lightens downward, which is a depth cue in its own right: the
 * upper lip overhangs the recess and the floor only brightens as it comes out from under it. Run
 * the convex way — light to dark, the way a face lit from above goes — and a sunk panel refuses to
 * look sunk however much inner shadow is piled on. For the same reason there is no sheen: a
 * highlight across the top of a recess reads as a dome.
 */
.glass {
  position: relative;
  padding: 12px 18px;
  border-radius: 14px;
  border: 1px solid #000;
  overflow: hidden;
  text-align: center;
  background: linear-gradient(180deg, var(--screen-bottom), var(--screen-top));
  box-shadow: inset 0 3px 8px 1px rgba(0, 0, 0, 0.92), inset 0 -2px 5px rgba(0, 0, 0, 0.55);
}

/* The lit row sizes the box; the ghost row overlays it exactly underneath. */
.readout {
  position: relative;
  display: inline-block;
}

.readout .lit,
.readout .ghost {
  display: flex;
  align-items: baseline;
  justify-content: center;
  font-family: 'DSEG7Classic', ui-monospace, Consolas, monospace;
}

.readout .ghost {
  position: absolute;
  inset: 0;
  color: var(--amber-ghost);
}

.readout .lit {
  position: relative;
  color: var(--amber-on);
  text-shadow: 0 0 8px var(--amber-glow);
}

/*
 * A readout whose figure climbs. The ghost takes over sizing the box and every value stacks on it,
 * each taking the glass in turn, so the digits move without the box resizing under them. Nothing is
 * lit until a step is handed the glass — see the handset's motion, which does the handing.
 */
.readout.stepped .ghost {
  position: relative;
}

.readout.stepped .lit {
  position: absolute;
  inset: 0;
  opacity: 0;
}

.readout .d {
  font-size: 36px;
  line-height: 44px;
  letter-spacing: 2px;
}

/* Units sit on the digits' baseline at UNIT_SCALE, the way an instrument silkscreens them small. */
.readout .u {
  font-size: 16px;
  line-height: 20px;
  letter-spacing: 1px;
}

.instrument-sm .readout .d {
  font-size: 22px;
  line-height: 28px;
  letter-spacing: 1px;
}

/* Same UNIT_SCALE against the smaller digits, so the units don't swell as the readout shrinks. */
.instrument-sm .readout .u {
  font-size: 10px;
  line-height: 13px;
}

/* The ring is one thickness at every size, so a smaller opening only takes its own radius down. */
.instrument-sm {
  padding: 3px;
  border-radius: 13px;
}

.instrument-sm .glass {
  padding: 7px 12px;
  border-radius: 10px;
}

.glass-caption {
  font-family: var(--sans);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: rgba(255, 178, 90, 0.55);
  margin-top: 6px;
}

/* ---------- SegmentBar: the amber bar-graph, ghost cells behind lit ones ---------- */

/*
 * Lit and unlit cells are two repeating gradients that both originate at the left edge, so they
 * stay registered without any per-cell markup. The fill clips its own copy of the gradient.
 */
.segbar {
  position: relative;
  height: 10px;
  margin-top: 6px;
  background: repeating-linear-gradient(
    90deg,
    var(--amber-ghost) 0 var(--cell),
    transparent var(--cell) var(--cell-pitch)
  );
}

.segbar-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 72%;
  overflow: hidden;
}

.segbar-fill::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 400px;
  background: repeating-linear-gradient(
    90deg,
    var(--amber-on) 0 var(--cell),
    transparent var(--cell) var(--cell-pitch)
  );
  filter: drop-shadow(0 0 4px var(--amber-glow));
}

/* ---------- LightStatus: a week of 1970s jewel pilot lamps ---------- */

.week {
  display: flex;
  align-items: center;
  margin-top: 22px;
}

.day {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 13px;
}

.day i {
  font-style: normal;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* The raised brass collar holding the glass jewel. */
.lamp {
  position: relative;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: linear-gradient(160deg, var(--brass-hi), var(--brass) 55%, var(--brass-lo));
  box-shadow: 0 1.5px 2.5px rgba(40, 24, 12, 0.28);
}

/*
 * The lens, recessed behind the collar's lip: the lip shades the top of the glass, a sliver of
 * light catches the bottom, and the radial stop is the specular glint of room light.
 */
.lamp::before {
  content: '';
  position: absolute;
  left: 3px;
  top: 3px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 1px solid rgba(20, 10, 4, 0.45);
  background: radial-gradient(ellipse 40% 22% at 32% 26%, rgba(255, 255, 255, 0.5), transparent 70%),
    linear-gradient(160deg, var(--ct), var(--eg));
  box-shadow: inset 0 1.5px 2px rgba(20, 10, 4, 0.55),
    inset 0 -1px 1.5px rgba(255, 248, 230, 0.25), 0 0 7px 1px var(--gl);
}

/* The incandescent hot core glowing behind the glass. */
.lamp::after {
  content: '';
  position: absolute;
  left: 6px;
  top: 6px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--hi);
  box-shadow: 0 0 4px 1px var(--hi);
}

/* Muted, warm jewel colours, never neon — the PILOT_PALETTES map in LightStatus.tsx. */
.lamp-healthy {
  --hi: #b1d978;
  --ct: #3b873b;
  --eg: #123d18;
  --gl: #8fcb5e;
}

.lamp-moderate {
  --hi: #ffe272;
  --ct: #e8aa08;
  --eg: #724500;
  --gl: #ffd33e;
}

.lamp-high {
  --hi: #ffb45a;
  --ct: #e96b0b;
  --eg: #762600;
  --gl: #ff8c1a;
}

.lamp-excessive {
  --hi: #ff8062;
  --ct: #d6351c;
  --eg: #641107;
  --gl: #f04a2a;
}

/* A day with no data yet: the same collar holding dark unlit glass. */
.lamp-off {
  --ct: #453a2e;
  --eg: #191310;
  --gl: transparent;
}

.lamp-off::after {
  display: none;
}

/* ---------- the life grid ---------- */

/*
 * Eighty squares, one a year, ten to a row so a row is a decade and the age opening each row says
 * where on it you already are. Only ever one quantity is drawn: the years the phone takes.
 *
 * Laid out in two blocks and wider than a stock panel: the picture, and the instruments that drive
 * it. Stacked, the panel ran past 700px and the reading at the top was never on screen with the
 * grid at the bottom. Side by side the whole thing is one glance.
 *
 * Spacing is all gap rather than margins on the pieces, so the two columns can't drift apart as
 * copy changes length.
 */
.lifegrid {
  /* The hot band off LightStatus's `excessive` lamp, flattened from a jewel to a fill. */
  --year-phone: #d6351c;

  display: grid;
  gap: 20px;
  max-width: 780px;
  text-align: left;
}

.lifegrid-plot,
.lifegrid-controls {
  display: flex;
  flex-direction: column;
  gap: 14px;
  /* Without this a grid child refuses to shrink below its content, and the squares overflow. */
  min-width: 0;
}

@media (min-width: 820px) {
  .lifegrid {
    grid-template-columns: minmax(0, 1fr) 296px;
    gap: 26px;
    align-items: start;
  }

  /*
   * Side by side the column is too narrow for two instruments abreast, and stacking them is what
   * buys the width that keeps the squares big enough to count.
   */
  .dials {
    flex-direction: column;
    align-items: flex-start;
  }
}

.years {
  display: grid;
  grid-template-columns: 2.4em repeat(10, 1fr);
  gap: 6px;
  align-items: center;
}

.decade {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  text-align: right;
  padding-right: 2px;
}

.year {
  aspect-ratio: 1;
  border-radius: 3px;
  background: var(--recess);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35);
  /* Colour only. The arrival is a Web Animation, deliberately out of reach of the blanket
     `transition: none` this sheet applies under reduced motion. */
  transition: background-color 300ms ease;
}

/*
 * Holds the grid empty between load and the moment it is scrolled into view. From there machine.js
 * takes over: it drops this class and starts the per-square animations in the same tick, and their
 * backwards fill keeps each square hidden until its turn.
 *
 * Scoped to .years rather than the panel because only machine.js ever puts squares in there. With
 * JS off there is nothing inside to hide.
 */
.years:not(.is-revealed) .year {
  opacity: 0;
}

.year.is-yours {
  background: var(--brass);
}

.year.is-phone {
  background: var(--year-phone);
}

.year-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  font-size: 13px;
  color: var(--ink-soft);
}

.year-legend span {
  display: flex;
  align-items: center;
  gap: 7px;
}

.year-legend i {
  width: 11px;
  height: 11px;
  border-radius: 2px;
  flex: none;
}

.swatch-lived {
  background: var(--recess);
  box-shadow: inset 0 0 0 1px var(--card-edge);
}

.swatch-yours {
  background: var(--brass);
}

.swatch-phone {
  background: var(--year-phone);
}

/* Two lines of headroom, so switching states doesn't shunt the chips up and down the panel. */
.lifegrid-maths {
  margin: 0;
  font-size: 13px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  min-height: 2.8em;
}

.lifegrid-caveat {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--muted);
}

/*
 * The nudge keys either side of a readout: the hard-edged keycap the dial's cap chips wore, cut
 * down to a single glyph. The chips came off with the cap comparison, so this is all that wears it.
 */
.key {
  font-family: var(--sans);
  font-size: 19px;
  font-weight: 700;
  line-height: 1;
  min-width: 42px;
  padding: 11px 0;
  border-radius: 10px;
  cursor: pointer;
  color: var(--ink);
  border: 1px solid rgba(40, 28, 12, 0.35);
  background: linear-gradient(180deg, #fbf4e4, var(--card));
  box-shadow: 0 2px 0 rgba(40, 28, 12, 0.3), 0 5px 10px var(--shadow-soft);
  transition: transform 90ms ease, box-shadow 90ms ease;
}

.key:active {
  transform: translateY(2px);
  box-shadow: 0 0 0 rgba(40, 28, 12, 0.3), 0 2px 6px var(--shadow-soft);
}

/* A key at the end of its range says so rather than clicking to no effect. */
.key:disabled {
  opacity: 0.38;
  cursor: default;
  transform: none;
  box-shadow: 0 2px 0 rgba(40, 28, 12, 0.3);
}

.dials {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 22px;
}

.dial-set {
  display: flex;
  align-items: center;
  gap: 10px;
}

/*
 * Focus lands on the glass, which is the spinbutton. The ring is amber so it reads as part of the
 * instrument, and offset far enough to clear the brass bezel instead of disappearing under it.
 */
.readout[role='spinbutton']:focus-visible {
  outline: 2px solid var(--amber-on);
  outline-offset: 7px;
  border-radius: 4px;
}

/* ---------- what you get ---------- */

section {
  padding: 56px 0;
}

/*
 * The handset and the three features, side by side. The phone is the smaller column: it's evidence,
 * not the argument, and at this size the panels inside it still read.
 */
.showcase {
  display: grid;
  grid-template-columns: 0.8fr 1.2fr;
  gap: 56px;
  align-items: center;
}

.showcase-head {
  font-size: clamp(26px, 3.2vw, 34px);
  margin-bottom: 34px;
}

.features {
  display: grid;
  gap: 30px;
}

/*
 * A feature, a name, one line. The hairline does the separating so three of these don't read as
 * cards, and on the one the handset is showing it goes accent — the picture and the words light
 * together, so neither has to be matched to the other by hand.
 */
.feature {
  border-top: 2px solid var(--ink);
  padding-top: 14px;
  transition: border-color 260ms ease;
}

.feature .eyebrow {
  transition: color 260ms ease;
}

/*
 * Tapping a feature plays it on the phone. Offered only once machine.js is running, which is what
 * puts the attribute on the section: a pointer here would otherwise promise something a page with
 * no JS can't do. Hovering lights the name, which is what the tap then keeps lit.
 */
[data-showing] .feature {
  cursor: pointer;
}

[data-showing] .feature:hover .eyebrow {
  color: var(--accent);
}

.feature.is-active {
  border-top-color: var(--accent);
}

.feature.is-active .eyebrow {
  color: var(--accent);
}

.feature h3 {
  font-size: 21px;
  margin-bottom: 6px;
}

.feature p {
  color: var(--ink-soft);
  margin: 0;
  font-size: 15px;
  max-width: 52ch;
}

/* ---------- the handset ---------- */

/*
 * A phone in a bezel cut like the object it is: espresso, because a handset is dark and a cream frame
 * around a cream screen would read as one shape.
 *
 * It shows the TOP of the home screen and fades out at the bottom rather than standing the full
 * 9:19.5. Two reasons: a whole screen's worth of console would have to invent the app rows below it,
 * and a fade says "it continues" where an empty lower half says "that's all there is".
 */
/* The phone and, under it, what the screen on show does to the apps you picked. */
.handset {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.device {
  width: 100%;
  max-width: 300px;
  padding: 8px 8px 0;
  border-radius: 36px 36px 0 0;
  background: linear-gradient(180deg, var(--espresso), var(--espresso-2));
  box-shadow: inset 0 1.5px 2px rgba(255, 248, 228, 0.14), 0 16px 36px var(--shadow-soft);
  -webkit-mask-image: linear-gradient(180deg, #000 74%, transparent);
  mask-image: linear-gradient(180deg, #000 74%, transparent);
}

.device-screen {
  position: relative;
  aspect-ratio: 9 / 11;
  border-radius: 29px 29px 0 0;
  background: var(--bg);
  overflow: hidden;
}

/*
 * The screens, stacked in the one frame. Only the lit screen runs its animations: dropping the
 * class parks a screen back at its still, so each one starts from the top when its turn comes
 * round again.
 *
 * Out is quick and in is slow, so the screen leaving is gone before it re-parks rather than
 * snapping back in full view.
 */
.screen {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 22px 18px 0;
  opacity: 0;
  transition: opacity 140ms ease-out;
}

.screen.is-active {
  opacity: 1;
  transition: opacity 420ms ease-in;
}

/* The screen's name, in the app's own centred serif. */
.device-label {
  font-family: var(--serif);
  font-size: 15px;
  font-weight: 600;
  color: var(--ink-soft);
  margin: 0;
  text-align: center;
}

/* In the app the week strip rides the console's face above the glass, so it sits tight to it here. */
.device .week {
  margin-top: 0;
}

.device .day {
  gap: 8px;
}

.device .day i {
  font-size: 9px;
}

.device .lamp {
  width: 14px;
  height: 14px;
}

/* The lens and its hot core are absolutely placed off the collar's 18px, so a smaller lamp needs both
   inset again rather than scaled — a transform would soften the glass edge. */
.device .lamp::before {
  left: 2px;
  top: 2px;
  width: 10px;
  height: 10px;
}

.device .lamp::after {
  left: 4.5px;
  top: 4.5px;
  width: 5px;
  height: 5px;
}

/*
 * The app's push-toggle, at the size a row of seven sets it: a pill knob seated in a recessed
 * socket, portrait. The knob never travels — off is a grey pill, on is bakelite orange, and the two
 * faces are stacked rather than interpolated so the colour can't pass through mud on the way.
 */
.sw {
  position: relative;
  width: 15px;
  height: 22px;
  border-radius: 5px;
  background: #6d6d6d;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5);
}

.sw::before,
.sw::after {
  content: '';
  position: absolute;
  inset: 2px;
  border-radius: 3.5px;
}

.sw::before {
  background: linear-gradient(180deg, #8a8a8a, #a1a1a1, #b4b4b4, #bababa);
  box-shadow: 0 1px 2px rgba(20, 12, 4, 0.45);
}

.sw::after {
  opacity: 0;
  background: linear-gradient(180deg, #e94714, #e85617, #ff7324, #ff844f);
  box-shadow: 0 0 3px rgba(233, 71, 20, 0.9);
}

.sw-on::after {
  opacity: 1;
}

/* A day that's in, named in the accent its switch is lit in. */
.day-on i {
  color: var(--accent);
}

/* Start and end abreast. Two clock faces on a 284px screen leave the digits less room than the
   small instrument assumes, so they come down a size rather than out to the glass's edge. */
.times {
  display: flex;
  gap: 10px;
}

.times .instrument {
  flex: 1;
  min-width: 0;
}

.times .readout .d {
  font-size: 18px;
  line-height: 24px;
}

/* What a panel adds up to, on the recessed plate the app prints it on. */
.summary {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin: 0;
  padding: 6px 10px;
  border-radius: 10px;
  border: 1px solid var(--card-edge);
  background: var(--recess);
  font-size: 11px;
  color: var(--ink-soft);
}

.summary svg {
  width: 13px;
  height: 13px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/*
 * The master lever: the one control you throw rather than tap. A brass plate carrying a caption
 * strip over a machined channel, with the grip seated at the top of its travel until it goes down.
 */
.lever {
  padding: 7px;
  border-radius: 12px;
  border: 1px solid rgba(40, 28, 12, 0.55);
  background: linear-gradient(180deg, var(--brass-hi), var(--brass), var(--brass-lo));
  box-shadow: inset 0 1.5px 2px rgba(255, 248, 228, 0.75), inset 0 -2px 3px rgba(30, 20, 8, 0.55),
    0 4px 10px rgba(0, 0, 0, 0.3);
}

.lever-cap {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  margin: 0 0 5px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--face-ink);
}

/* Both captions ride the one cell, so the strip can't change width when the lever lands. */
.caps {
  position: relative;
  white-space: nowrap;
}

.cap-live {
  position: absolute;
  inset: 0;
  opacity: 0;
}

/* The pilot lamp on the plate: dark glass until a session is live, red for as long as it runs. */
.lamp-pair {
  position: relative;
  width: 14px;
  height: 14px;
  flex: none;
}

.lamp-pair .lamp {
  position: absolute;
  inset: 0;
}

.lamp-live {
  opacity: 0;
}

.channel {
  position: relative;
  height: 44px;
  border-radius: 8px;
  background: linear-gradient(180deg, var(--espresso-2), var(--espresso));
  box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.8);
}

.grip {
  position: absolute;
  top: 4px;
  left: 4px;
  right: 4px;
  height: 20px;
  border-radius: 6px;
  background: repeating-linear-gradient(180deg, rgba(40, 28, 12, 0.18) 0 1px, transparent 1px 4px),
    linear-gradient(180deg, var(--brass-hi), var(--brass) 55%, var(--brass-lo));
  box-shadow: 0 2px 4px rgba(20, 12, 4, 0.55);
}

/*
 * The apps under the phone: three tiles that go dark, and the word for what happened to them. It
 * sits low enough to be clear of the frame's fade without opening a gap the eye has to cross.
 */
.blocked {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 16px;
  font-size: 13px;
  color: var(--ink-soft);
}

.tiles {
  display: flex;
  gap: 8px;
}

/* A tracked app. Any of them: the glyph is the generic launcher icon, never a brand's own. */
.tile {
  position: relative;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  border: 1px solid var(--card-edge);
  background: linear-gradient(180deg, var(--card-hi), var(--card-lo));
  box-shadow: 0 2px 5px var(--shadow-soft);
  color: var(--ink-soft);
}

.tile svg {
  width: 15px;
  height: 15px;
}

/* Blocked: the face goes dark, with the app still faintly under it — shut, not deleted. */
.tile::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 7px;
  background: linear-gradient(180deg, var(--espresso), var(--espresso-2));
  opacity: 0.93;
}

.blocked svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The longer of the two words holds the width; both sit centred in it, so the strip stays put
   under the phone whichever one it's showing. */
.blocked .caps {
  text-align: center;
}

.blocked .cap-live {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  opacity: 1;
}

.blocked .cap-live svg {
  width: 14px;
  height: 14px;
}

.blocked .cap-idle {
  opacity: 0;
}

.eyebrow {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 10px;
}

/* ---------- the handset, in motion ---------- */

/*
 * Each screen plays the thing its feature does: the days coming on, the day filling the cap, the
 * lever going down. Every delay clears the screen's fade-in first, so nothing has already happened
 * by the time the screen is legible.
 *
 * Which fill a piece uses follows from its still. A piece the screen holds lit runs `backwards`, so
 * the fill hides it until its turn and it lands on the state that's already in the sheet; a piece
 * that only ends up lit runs `forwards` onto it. Either way a screen with its animations off — the
 * reduced-motion case below — still reads as a panel someone has set.
 */
@keyframes fade-up {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
}

@keyframes lit-in {
  from {
    opacity: 0;
  }
}

@keyframes lit-on {
  to {
    opacity: 1;
  }
}

@keyframes lit-off {
  to {
    opacity: 0;
  }
}

/* One step's turn on the glass: lit for the beat, dark the instant the next one takes over. */
@keyframes lcd-hold {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

/* The step that keeps the glass: lit for its beat and, on the forwards fill, for good after it. */
@keyframes lcd-take {
  from,
  to {
    opacity: 1;
  }
}

@keyframes meter-fill {
  from {
    width: 0;
  }
}

@keyframes lever-throw {
  to {
    transform: translateY(16px);
  }
}

/* Schedule: the days come on one after another, then what the window adds up to. */
.screen.is-active .sw-on::after {
  animation: lit-in 240ms ease-out 420ms backwards;
}

.screen.is-active .day:nth-child(2) .sw-on::after {
  animation-delay: 510ms;
}

.screen.is-active .day:nth-child(3) .sw-on::after {
  animation-delay: 600ms;
}

.screen.is-active .day:nth-child(4) .sw-on::after {
  animation-delay: 690ms;
}

.screen.is-active .day:nth-child(5) .sw-on::after {
  animation-delay: 780ms;
}

.screen.is-active .summary {
  animation: fade-up 320ms ease-out 1000ms backwards;
}

/*
 * Daily limit: the day's figure climbs the glass while the meter fills under it, both landing on
 * the cap together. The plate follows a beat later — it's the consequence, not a caption.
 */
.screen.is-active .segbar-fill {
  animation: meter-fill 1400ms linear 420ms backwards;
}

.screen.is-active .stepped .lit {
  animation: lcd-hold 700ms steps(1, end) 420ms forwards;
}

.screen.is-active .stepped .lit:nth-child(3) {
  animation-delay: 1120ms;
}

/* The figure it settles on, so this one takes the glass and doesn't give it back. */
.screen.is-active .stepped .lit:last-child {
  animation: lcd-take 700ms 1820ms forwards;
}

/*
 * Focus: the duration is lit from the off, the lever goes down, and the glass drops a minute the
 * moment the session is running — a readout that never moves is a readout nobody believes.
 */
[data-screen='focus'].is-active .stepped .lit {
  animation: lcd-hold 1400ms steps(1, end) forwards;
}

[data-screen='focus'].is-active .stepped .lit:last-child {
  animation: lcd-take 700ms 1400ms forwards;
}

.screen.is-active .grip {
  animation: lever-throw 380ms cubic-bezier(0.55, 0, 0.15, 1) 700ms forwards;
}

.screen.is-active .lamp-live,
.screen.is-active .cap-live {
  animation: lit-on 160ms ease-out 1040ms forwards;
}

.screen.is-active .cap-idle {
  animation: lit-off 160ms ease-out 1040ms forwards;
}

/*
 * The apps under the phone go dark on the beat the screen above them reaches them: a window coming
 * round, a cap filling, a lever seating. That beat is the one thing each screen has to say about
 * them, so it's all the screen sets — the strip below plays the same way whichever it is.
 */
.showcase {
  --block-at: 1200ms;
}

[data-showing='limit'] {
  --block-at: 1900ms;
}

[data-showing='focus'] {
  --block-at: 1150ms;
}

.blocked.is-active .tile::after {
  animation: lit-in 260ms ease-out var(--block-at) backwards;
}

.blocked.is-active .tile:nth-child(2)::after {
  animation-delay: calc(var(--block-at) + 70ms);
}

.blocked.is-active .tile:nth-child(3)::after {
  animation-delay: calc(var(--block-at) + 140ms);
}

/* The word for it holds while they're still open, and hands over once the last one is shut. */
.blocked.is-active .cap-idle {
  animation: lcd-hold calc(var(--block-at) + 200ms) steps(1, end) forwards;
}

.blocked.is-active .cap-live {
  animation: lit-in 220ms ease-out calc(var(--block-at) + 200ms) backwards;
}

/* ---------- closing CTA ---------- */

/*
 * The reader who got this far is the most convinced one on the page, and until now the only Play
 * button was in the hero, three screens up.
 */
.closer {
  text-align: center;
  padding: 72px 0 24px;
}

.closer h2 {
  font-size: clamp(28px, 3.6vw, 40px);
  max-width: 20ch;
  margin: 0 auto;
}

.closer-sub {
  color: var(--ink-soft);
  max-width: 46ch;
  margin: 18px auto 0;
}

.closer .cta {
  justify-content: center;
  margin-top: 28px;
}

/* ---------- cards (legal pages) ---------- */

.card {
  background: var(--card);
  border-radius: var(--radius);
  padding: 28px;
  box-shadow: 0 1px 0 var(--card-hi) inset, 0 6px 18px var(--shadow-soft);
}

.card h3 {
  font-size: 21px;
  margin-bottom: 8px;
}

.card p {
  color: var(--ink-soft);
  margin: 0;
  font-size: 16px;
}

.tag {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  background: var(--recess);
  border-radius: 999px;
  padding: 3px 10px;
  margin-left: 8px;
  vertical-align: 3px;
}

/* ---------- footer ---------- */

footer {
  border-top: 1px solid var(--card-edge);
  margin-top: 40px;
  padding: 32px 0 48px;
  font-size: 14px;
  color: var(--muted);
}

.footer-row {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
}

.footer-row nav {
  display: flex;
  gap: 20px;
}

footer a {
  color: var(--ink-soft);
  text-decoration: none;
}

footer a:hover {
  text-decoration: underline;
}

/* ---------- legal pages ---------- */

.legal {
  max-width: 720px;
  margin: 0 auto;
  padding: 32px 0 64px;
}

.legal h1 {
  font-size: clamp(32px, 4.4vw, 44px);
}

.legal .updated {
  color: var(--muted);
  font-size: 14px;
  margin: 12px 0 40px;
}

.legal h2 {
  font-size: 24px;
  margin: 40px 0 12px;
}

.legal h3 {
  font-size: 18px;
  margin: 26px 0 8px;
}

.legal p,
.legal li {
  color: var(--ink-soft);
}

.legal li {
  margin-bottom: 8px;
}

.legal ul {
  padding-left: 22px;
}

.legal strong {
  color: var(--ink);
}

.legal .card {
  padding: 24px 28px;
  margin: 28px 0;
}

.legal .card p:first-child {
  margin-top: 0;
}

.legal .card p:last-child {
  margin-bottom: 0;
}

/* ---------- responsive ---------- */

@media (max-width: 900px) {
  .hero {
    padding: 32px 0 48px;
  }

  /* The handset goes on top: it's the first proof of what the app is, and stacked under the rules it
     would sit below the fold on every phone. */
  .showcase {
    grid-template-columns: 1fr;
    gap: 40px;
  }
}

@media (max-width: 680px) {
  body {
    font-size: 16px;
  }

  .topbar nav {
    gap: 16px;
  }

  .panel {
    padding: 16px;
  }

  /* Ten columns hold all the way down; the gutter and the decade label give up the room instead. */
  .years {
    grid-template-columns: 1.9em repeat(10, 1fr);
    gap: 4px;
  }

  .closer {
    padding-top: 48px;
  }
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
  }

  /* The blanket rule above can't touch an animation. The handset holds whichever screen it's on
     still: machine.js leaves the rotation parked under this preference, so the phone shows the
     screen the markup opens on — or, once a feature is tapped, that one — at its settled state. */
  .screen *,
  .blocked * {
    animation: none !important;
  }

  /* Nothing hands the glass on with the animations off, so the figure a readout settles on keeps
     it — otherwise a tapped screen arrives with dead digits. */
  .stepped .lit:last-child {
    opacity: 1;
  }
}
