/* THE TIMELINE ROOM (view-timeline) — its stylesheet.
 *
 * Linked right after app.css (see the room-css markers in index.html). Holds every rule
 * only this room's elements use: the page controls, the spine and its pins, the list,
 * the ring, the Lately strip (tly-), the river of days (tlr-) and the day view (tl-day-).
 * What stays in app.css is shared: .tl-row, .tl-openable, .tl-chev and the tlc-/tlf-/tlk-/tlw-
 * rules belong to the contact and company timelines.
 *
 * Moved from app.css in the 15 Oct rebuild, rule for rule and in the same order.
 */


  /* THE LIFE TIMELINE.
     A spine down the left with the years on it. The gaps are drawn as loudly as
     the entries — see renderTimeline() — because a timeline with four things in
     it looks broken, and the same four with the empty years named between them
     looks like something being built. */
  /* ==========================================================
     C17 — THE SPINE
     ==========================================================
     "a timeline that moves canonizing major events, (child born, trip to
     Antigua) as well as future events, (John's wedding, Grateful Dead
     concert)."

     A horizontal line, scaled at a fixed 84px a year rather than fitted to the
     entries — so a dense recent decade LOOKS dense and a quiet stretch looks
     quiet. See renderTimelineSpine() for why that scale is the whole decision.

     Three states a pin can be in, and each is a different fact:
       plain      something that happened
       .is-land   a landmark — his own mark, drawn large, always labelled
       .is-ahead  it has not happened yet — past the Today marker, dashed */
  .tl-controls{ display:flex; align-items:flex-start; justify-content:space-between;
    gap:var(--space-4); flex-wrap:wrap; margin-bottom:var(--space-4); }
  .tl-shape{ flex:none; }

  .tl-spine-head{ display:flex; align-items:center; gap:var(--space-2); flex-wrap:wrap; margin-bottom:var(--space-3); }
  .tl-spine-hint{ font-size:var(--type-body); color:var(--text-faint); }

  /* THE RAIL SCROLLS; THE PAGE DOES NOT.
     overscroll-behavior-x:contain stops reaching the end of a life from
     handing the gesture to the browser's back-navigation, which on a trackpad
     is a very expensive way to look at 1974. */
  .tl-rail{
    position:relative; overflow-x:auto; overflow-y:hidden; overscroll-behavior-x:contain;
    padding:0; border-radius:var(--radius-card); border:1px solid var(--glass-border);
    background:rgba(120,120,140,.05);
    cursor:grab; scrollbar-width:thin;
    /* Room for three rows of stacked labels above and two below. */
    min-height:330px;
  }
  .tl-rail:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
  .tl-rail.is-dragging{ cursor:grabbing; scroll-behavior:auto; }
  .tl-rail::-webkit-scrollbar{ height:8px; }
  .tl-rail::-webkit-scrollbar-thumb{ background:rgba(120,120,140,.28); border-radius:var(--radius-tight); }
  .tl-track{ position:relative; height:330px; padding:0 var(--space-16); }

  /* The line itself sits at the vertical middle, so pins have somewhere to go
     in both directions. */
  .tl-line{ position:absolute; left:0; right:0; top:50%; height:2px;
    background:linear-gradient(90deg, transparent, var(--glass-border-hi) 6%, var(--glass-border-hi) 94%, transparent); }
  /* Everything after today, dashed and dimmer. Same line, not a second one. */
  .tl-future{ position:absolute; right:0; top:50%; height:2px; transform:translateY(-1px);
    background-image:repeating-linear-gradient(90deg,
      color-mix(in srgb, var(--accent) 55%, transparent) 0 8px, transparent 8px 16px);
    opacity:.7; }

  .tl-tick{ position:absolute; top:50%; transform:translateX(-50%); pointer-events:none; }
  .tl-tick i{ position:absolute; left:50%; top:-9px; width:1px; height:18px;
    background:var(--glass-border-hi); }
  .tl-tick span{ position:absolute; left:50%; top:14px; transform:translateX(-50%);
    font-family:var(--font-mono); font-size:var(--type-label); color:var(--text-faint); }

  /* WHERE TODAY IS. The one mark on the line that is not an entry, and it has
     to read as a different kind of thing — hence the accent and the label. */
  .tl-now{ position:absolute; top:50%; transform:translateX(-50%); z-index:3; pointer-events:none; }
  .tl-now i{ position:absolute; left:50%; top:-118px; width:2px; height:236px;
    background:linear-gradient(180deg, transparent, var(--accent) 22%, var(--accent) 78%, transparent);
    opacity:.5; }
  .tl-now span{ position:absolute; left:50%; top:-140px; transform:translateX(-50%);
    font-size:var(--type-label); font-weight:700; letter-spacing:.09em; text-transform:uppercase;
    color:var(--accent); white-space:nowrap; }

  .tl-pin{
    position:absolute; top:50%; transform:translateX(-50%);
    background:none; border:none; padding:0; cursor:pointer; z-index:2;
    color:inherit; font-family:inherit; text-align:left;
  }
  .tl-pin-stem{ position:absolute; left:50%; width:1px; background:var(--tl-c, var(--accent)); opacity:.45; }
  .tl-pin.up .tl-pin-stem{ bottom:0; height:var(--tl-lift, 26px); }
  .tl-pin.down .tl-pin-stem{ top:0; height:var(--tl-lift, 26px); }
  .tl-pin-dot{
    position:absolute; left:50%; top:0; transform:translate(-50%, -50%);
    width:9px; height:9px; border-radius:var(--radius-round);
    background:var(--tl-c, var(--accent));
    box-shadow:0 0 0 3px var(--bg-deep, #0b0e18);
    transition:width var(--dur-fast) var(--ease-out), height var(--dur-fast) var(--ease-out);
  }
  .tl-pin-label{
    position:absolute; left:50%; transform:translateX(-50%);
    width:132px; text-align:center; pointer-events:none;
  }
  .tl-pin.up .tl-pin-label{ bottom:var(--tl-lift, 26px); margin-bottom:var(--space-2); }
  .tl-pin.down .tl-pin-label{ top:var(--tl-lift, 26px); margin-top:var(--space-2); }
  .tl-pin-t{ font-size:var(--type-body); font-weight:600; line-height:1.3; color:var(--text);
    /* Two lines and then an ellipsis. A pin is a way in, not the entry. */
    display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
  .tl-pin-w{ display:block; font-family:var(--font-mono); font-size:var(--type-label);
    color:var(--text-faint); margin-top:var(--space-hair); }
  .tl-pin:hover .tl-pin-dot{ width:13px; height:13px; }
  .tl-pin:hover .tl-pin-t{ color:var(--tl-c, var(--accent)); }
  .tl-pin:focus-visible{ outline:2px solid var(--accent); outline-offset:4px; border-radius:var(--radius-control); }

  /* A LANDMARK. Larger dot, a ring around it, and its title at heading weight —
     it should be findable while scrubbing past at speed without reading a word. */
  .tl-pin.is-land .tl-pin-dot{
    width:15px; height:15px;
    box-shadow:0 0 0 3px var(--bg-deep, #0b0e18), 0 0 0 5px color-mix(in srgb, var(--tl-c, var(--accent)) 55%, transparent),
               0 0 20px 2px color-mix(in srgb, var(--tl-c, var(--accent)) 45%, transparent);
  }
  .tl-pin.is-land:hover .tl-pin-dot{ width:18px; height:18px; }
  .tl-pin.is-land .tl-pin-label{ width:164px; }
  .tl-pin.is-land .tl-pin-t{ font-family:var(--font-display); font-size:var(--type-lead); font-weight:600;
    -webkit-line-clamp:3; }
  .tl-pin.is-land .tl-pin-stem{ opacity:.8; width:2px; }

  /* NOT YET. Hollow rather than filled — the difference between a thing that
     happened and a thing that is going to is worth being able to see from the
     other end of the line. */
  .tl-pin.is-ahead .tl-pin-dot{
    background:var(--bg-deep, #0b0e18);
    box-shadow:0 0 0 2px var(--tl-c, var(--accent)), 0 0 0 4px var(--bg-deep, #0b0e18);
  }
  .tl-pin.is-ahead.is-land .tl-pin-dot{
    box-shadow:0 0 0 3px var(--tl-c, var(--accent)), 0 0 0 6px var(--bg-deep, #0b0e18),
               0 0 20px 2px color-mix(in srgb, var(--tl-c, var(--accent)) 40%, transparent);
  }
  .tl-pin.is-ahead .tl-pin-stem{ opacity:.3; }
  .tl-pin.is-ahead .tl-pin-t{ color:var(--text-dim); }

  /* On paper the dot's knockout ring must be paper, not ink. */
  :root[data-mode="light"] .tl-pin-dot{ box-shadow:0 0 0 3px var(--bg, #fff); }
  :root[data-mode="light"] .tl-pin.is-land .tl-pin-dot{
    box-shadow:0 0 0 3px var(--bg, #fff), 0 0 0 5px color-mix(in srgb, var(--tl-c, var(--accent)) 55%, transparent); }
  :root[data-mode="light"] .tl-pin.is-ahead .tl-pin-dot{
    background:var(--bg, #fff); box-shadow:0 0 0 2px var(--tl-c, var(--accent)), 0 0 0 4px var(--bg, #fff); }
  :root[data-mode="light"] .tl-now i{ opacity:.35; }

  /* A phone has no room for a 132px label either side of a 9px dot, and a spine
     that has to be scrubbed with a thumb through overlapping text is worse than
     a list. The rail still works; it just gets tighter. */
  @media(max-width:700px){
    .tl-rail, .tl-track{ min-height:280px; height:auto; }
    .tl-track{ height:280px; padding:0 var(--space-10); }
    .tl-pin-label{ width:104px; }
    .tl-pin.is-land .tl-pin-label{ width:124px; }
    .tl-pin.is-land .tl-pin-t{ font-size:var(--type-body); }
  }

  /* The landmark checkbox in the add/edit card. */
  .tl-land-check{ display:flex; align-items:flex-start; gap:var(--space-3); margin:var(--space-3) 0 var(--space-1);
    font-size:var(--type-body); color:var(--text-dim); line-height:1.5; cursor:pointer; }
  .tl-land-check input{ flex:none; width:16px; height:16px; margin-top:1px;
    accent-color:var(--accent); cursor:pointer; }
  .tl-land-check b{ color:var(--text); }

  /* THE DATE COLUMN'S WIDTH, IN ONE PLACE. Three rules need it: the column
     itself, the year heading that has to line up with it, and the "six years
     pass" row that has to clear it. It was 74, 74 and 88. */
  :root{ --tl-spine-w:74px; }
  .tl-year{ display:flex; align-items:baseline; gap:var(--space-4); margin:var(--space-6) 0 var(--space-3); }
  .tl-year-n{ font-family:var(--font-display); font-size:var(--type-title); font-weight:600; color:var(--text);
      min-width:var(--tl-spine-w); }
  .tl-year-rule{ flex:1; height:1px; background:var(--glass-border); }
  .tl-spine{ width:var(--tl-spine-w); flex:none; text-align:right; font-size:var(--type-body); color:var(--text-faint);
      padding-top:var(--space-1); }
  .tl-dot{ width:11px; height:11px; border-radius:var(--radius-round); flex:none; margin-top:var(--space-2);
      background:var(--tl-c, var(--accent)); box-shadow:0 0 10px var(--tl-g, var(--accent-glow)); }
  .tl-body{ min-width:0; flex:1; }
  .tl-t{ font-size:var(--type-lead); font-weight:600; color:var(--text); }
  .tl-w{ font-size:var(--type-body); color:var(--text-dim); margin-top:var(--space-hair); }
  .tl-guess{ font-size:var(--type-label); font-weight:700; letter-spacing:.05em; text-transform:uppercase;
      color:var(--orange); margin-left:var(--space-2); }
  .tl-acts{ display:flex; gap:var(--space-2); align-items:center; flex:none; opacity:0; transition:opacity var(--dur-fast); }
  .tl-row:hover .tl-acts{ opacity:1; }
  /* "Six years pass" sits under the rows it separates, indented to clear the
     date column so it starts where the dots do. That indent was 88px, which was
     nothing in particular: the column beside it is .tl-spine's 74 plus the row's
     own --space-4 gap, which is 90. Two pixels is not visible; a number that is
     nearly the width of the thing it is clearing, and cannot follow it if that
     width changes, is the fault the scale exists to stop. --tl-spine-w is
     declared five rules up, beside the column it describes. */
  .tl-gap{ display:flex; align-items:center; gap:var(--space-4);
      margin:var(--space-3) 0 var(--space-3) calc(var(--tl-spine-w) + var(--space-4));
      font-size:var(--type-body); color:var(--text-faint); font-style:italic; }
  .tl-gap i{ display:block; width:34px; height:1px; background:var(--glass-border);
      font-style:normal; }

  /* ==========================================================
     THE YEAR CARDS.

     "timeline redesign with translucents from image, snapshot,
      each year has a card or pin…click it and there is 1
      picture, one message, one something to mark time"
                                    (Matt, 1 September.)

     The photograph is BEHIND the words rather than beside them.
     A thumbnail in a corner is decoration; a picture the text
     sits on is the year having a colour. That is what the
     "translucents from image" was asking for.

     A year with no photo takes a wash of the category colour
     instead, so a row of years reads as a row of years rather
     than as a row of holes.
     ========================================================== */
  .tly-strip{ display:flex; gap:var(--space-3); overflow-x:auto; padding:var(--space-hair) var(--space-hair) var(--space-3);
    scroll-snap-type:x proximity; }
  /* ONE LINE OF CARDS, ENDING ON THE PAGE'S OWN RIGHT EDGE.
     =====================================================
     "Fix the size and width of timeline. One line of cards against the right
     spine."  (Matt, 23 September.)

     flex:0 0 168px was a card that is 168px wide whatever the screen is. Seven
     years in a 1450px page therefore measured 1260px and stopped 200px short
     of the right-hand edge, with the page carrying on past it — a line of
     cards that does not reach the side it is supposed to sit against.

     flex:1 0 168px changes one number and both halves of that sentence:

       GROW, so the row divides the width it is given and the last card ends
       flush with the page column. That is the "against the right spine" half.

       DO NOT SHRINK, and keep 168px as the basis, so a life with thirty years
       in it does not squeeze thirty unreadable slivers onto one screen — the
       strip overflows and scrolls, which is what .tly-strip already does.

     The ceiling is --tile-ideal, the same width a card is allowed to be
     everywhere else in Lucid. Without it three years on a wide monitor would
     each be 470px, which is a banner rather than a card. */
  .tly-card{
    position:relative; flex:1 0 168px; max-width:var(--tile-ideal);
    min-height:104px; scroll-snap-align:start;
    display:flex; flex-direction:column; justify-content:flex-end; gap:var(--space-hair);
    text-align:left; padding:var(--space-3) var(--space-3); border-radius:var(--radius-card); cursor:pointer;
    border:1px solid var(--glass-border); background:var(--glass-bg);
    color:var(--text); overflow:hidden; isolation:isolate;
    transition:border-color var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
  }
  .tly-card:hover{ border-color:var(--tly-c); transform:translateY(-2px); }
  /* The wash, for the years with no picture. */
  .tly-card::before{
    content:''; position:absolute; inset:0; z-index:-2;
    background:linear-gradient(160deg,
      color-mix(in srgb, var(--tly-c) 22%, transparent) 0%,
      transparent 62%);
  }
  /* And the picture, when there is one. Translucent, and darkened towards the
     bottom so the words on top of it stay readable whatever the photo is —
     white text on a bright sky is the failure mode of every design like this. */
  .tly-img{
    position:absolute; inset:0; z-index:-1;
    background-image:var(--tly-img); background-size:cover; background-position:center;
    opacity:.42;
    -webkit-mask-image:linear-gradient(to bottom, rgba(0,0,0,.55) 0%, rgba(0,0,0,1) 100%);
    mask-image:linear-gradient(to bottom, rgba(0,0,0,.55) 0%, rgba(0,0,0,1) 100%);
  }
  .tly-card::after{
    content:''; position:absolute; inset:0; z-index:-1; pointer-events:none;
    background:linear-gradient(to top, rgba(0,0,0,.55) 0%, transparent 70%);
  }
  .tly-year{ font-size:var(--type-title); font-weight:600; line-height:1; font-variant-numeric:tabular-nums; }
  .tly-what{ font-size:var(--type-body); line-height:1.35;
    display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
  .tly-more{ font-size:var(--type-label); opacity:.7; }
  /* A year he marked as a landmark carries its colour on the edge. */
  .tly-card.is-land{ border-left:3px solid var(--tly-c); }
  /* Years that have not happened yet are drawn quieter, like the pins are. */
  .tly-card.is-ahead{ opacity:.62; border-style:dashed; }
  .tl-year-flash{ outline:2px solid var(--orb-accent, var(--accent)); outline-offset:3px;
    border-radius:var(--radius-control); }
  @media (prefers-reduced-motion: reduce){
    .tly-card:hover{ transform:none; }
  }

  /* ==========================================================
     THE RING — ONE YEAR OF THE TIMELINE, DRAWN ROUND.
     ==========================================================
     "making G our centerpiece on the timeline page. Straight
      timeline shows my whole life. But the circle graph shows
      each year on the timeline represented by the events on
      the circle graph."                    (Matt, on treatment G.)

     NOT ONE NEW COLOUR. Every value below resolves to a token
     the thirteen themes already carry — the category colours
     the pins and the rows already wear, --accent for today and
     for a recurrence, --brass/--blue/--green/--orange for the
     four seasons washed into the band. A ring that needed its
     own palette would need thirteen of them.

     The drawing itself is in renderTimelineRing() in app.js,
     and so is the reasoning: why a lived year fills a ring
     evenly where a forward horizon clumps, why the other years
     sit ghosted inside it, and what a year with two things in
     it does instead of looking broken. */
  .tl-ring-wrap{ margin:0 0 var(--space-6); }

  .tl-ring-head{ display:flex; align-items:center; gap:var(--space-2); flex-wrap:wrap; margin-bottom:var(--space-3); }
  .tl-ring-y{ font-family:var(--font-display); font-size:var(--type-page); font-weight:600; color:var(--text);
    font-variant-numeric:tabular-nums; letter-spacing:-.01em; min-width:70px; text-align:center; }
  .tl-ring-hint{ font-size:var(--type-body); color:var(--text-faint); }
  .tl-ring-opts{ margin-bottom:0; }
  /* A STEPPER THAT HAS RUN OUT SAYS SO. The button is disabled and reads
     "Earliest" rather than staying live and doing nothing — item on never
     shipping a control that looks like it works and does not. */
  .tl-ring-head .btn[disabled]{ opacity:.42; cursor:default; }

  .tl-ring{ display:flex; gap:var(--space-8); align-items:flex-start; }
  /* A CAP ON THE FIGURE. Left to grow the ring took nine hundred pixels on a
     wide monitor and the drawing stopped being a thing you can take in at once.
     min-width:0 because a flex child with an SVG in it will otherwise refuse to
     shrink below the SVG's intrinsic width. */
  .tl-ring-fig{ position:relative; flex:1 1 620px; min-width:0; max-width:880px; }
  .tl-ring-fig svg{ display:block; width:100%; height:auto; }

  /* THE MIDDLE OF THE RING IS A GAUGE, NOT A DECORATION, and it is HTML rather
     than SVG text so the numeral can be genuinely large and the sentence under
     it can wrap. The biggest thing on this page is a number and the number is
     about the year the ring is drawing. */
  .tl-ring-gauge{ position:absolute; inset:0; display:flex; flex-direction:column;
    align-items:center; justify-content:center; text-align:center; pointer-events:none; }
  /* 25 PER CENT, AND IT IS MEASURED RATHER THAN CHOSEN. The month letters ride
     at radius 146 in a 1000-wide viewBox, so anything wider than 29% of the
     figure prints through them — which is exactly what the first draft did to
     the F of February. */
  .tl-ring-gauge .in{ width:25%; }
  .tl-ring-alarm{ font-family:var(--font-mono); font-size:var(--type-label); letter-spacing:.12em;
    text-transform:uppercase; line-height:1.6; color:var(--accent); margin:0 0 var(--space-3); }
  .tl-ring-alarm b{ font-weight:700; }
  .tl-ring-cap{ font-family:var(--font-mono); font-size:var(--type-label); letter-spacing:.18em;
    color:var(--text-faint); margin:0 0 var(--space-1); font-variant-numeric:tabular-nums; }
  .tl-ring-big{ font-family:var(--font-display); font-size:var(--type-fluid-3); line-height:.94;
    font-weight:600; letter-spacing:-.03em; color:var(--accent); margin:0;
    font-variant-numeric:tabular-nums; }
  /* A YEAR WITH NOTHING IN IT GETS A RULE WHERE THE NUMERAL GOES. A large
     nought is a score, and this page is not marking him. */
  .tl-ring-rule{ display:block; width:46px; height:2px; margin:var(--space-6) auto var(--space-6);
    background:var(--text-faint); opacity:.5; }
  .tl-ring-unit{ font-family:var(--font-mono); font-size:var(--type-label); letter-spacing:.14em;
    text-transform:uppercase; color:var(--text-dim); margin:var(--space-2) 0 0; }
  .tl-ring-from{ font-size:var(--type-body); line-height:1.5; color:var(--text-dim); margin:var(--space-2) 0 0; }
  .tl-ring-from b{ color:var(--text); font-weight:600; }

  .tl-ring-read{ flex:0 0 296px; min-width:0; padding-top:var(--space-1); }
  .tl-ring-lede{ font-family:var(--font-display); font-size:var(--type-title); line-height:1.44; font-weight:600;
    letter-spacing:-.01em; color:var(--text-dim); margin:0 0 var(--space-5); }
  .tl-ring-lede b{ color:var(--text); font-weight:700; }
  .tl-rg{ margin:0 0 var(--space-4); padding-left:var(--space-3); border-left:2px solid var(--glass-border); }
  .tl-rg.c-1{ border-left-color:color-mix(in srgb, var(--teal) 60%, transparent); }
  .tl-rg.c-2{ border-left-color:color-mix(in srgb, var(--text-dim) 45%, transparent); }
  .tl-rg.c-3{ border-left-color:color-mix(in srgb, var(--accent) 65%, transparent); }
  .tl-rg h4{ font-family:var(--font-mono); font-size:var(--type-label); letter-spacing:.13em;
    text-transform:uppercase; color:var(--text-faint); margin:0 0 var(--space-2); font-weight:500; }
  .tl-rg p{ font-size:var(--type-body); line-height:1.56; color:var(--text-dim); margin:0; }
  .tl-rg p b{ color:var(--text); font-weight:600; }

  /* THE KEY IS A LEGEND AND NOT A CONTROL. The category filters are the chip
     row at the top of the page; a second set of switches that looked the same
     and toggled the same thing would be two places to be out of step. */
  /* TWO FIXED COLUMNS RATHER THAN A WRAPPING ROW. Wrapped, the seventh key
     landed a few pixels over the edge of a 296px column and "Travel 2" was cut
     off mid-word — a legend that lies about a category by clipping its count is
     worse than no legend. A grid cannot overflow the track it is given. */
  .tl-ring-keys{ display:grid; grid-template-columns:repeat(2, minmax(0, 1fr));
    gap:var(--space-2) var(--space-4); margin-top:var(--space-5); padding-top:var(--space-4);
    border-top:1px solid var(--glass-border); }
  .tl-ring-key{ display:flex; align-items:center; gap:var(--space-2); min-width:0;
    font-size:var(--type-body); color:var(--text-dim); }
  .tl-ring-key span{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .tl-ring-key i{ width:8px; height:8px; border-radius:var(--radius-round); flex:none; }
  .tl-ring-key b{ font-family:var(--font-mono); font-size:var(--type-label); font-weight:500;
    color:var(--text-faint); font-variant-numeric:tabular-nums; }

  .tl-ring-note{ font-size:var(--type-body); line-height:1.6; color:var(--text-faint);
    margin:var(--space-4) 0 0; max-width:80ch; }

  /* ---- the marks on the ring ---- */
  .tl-ring-mo{ font-family:var(--font-mono); font-size:var(--type-body); letter-spacing:.06em;
    fill:var(--text-faint); opacity:.68; }
  .tl-ring-season{ font-family:var(--font-mono); font-size:var(--type-label); letter-spacing:.19em;
    opacity:.85; paint-order:stroke; stroke:var(--bg-base); stroke-width:3.5px; }
  .tl-ring-today{ font-family:var(--font-mono); font-size:var(--type-label); letter-spacing:.17em;
    fill:var(--accent); opacity:.92; paint-order:stroke; stroke:var(--bg-base); stroke-width:4px; }
  .tl-ring-label{ font-size:var(--type-body); fill:var(--text-dim);
    paint-order:stroke; stroke:var(--bg-base); stroke-width:4px; }
  /* A landmark keeps its name at heading weight, on the ring as on the line. */
  .tl-ring-label.is-land{ font-family:var(--font-display); font-size:var(--type-body); font-weight:600; fill:var(--text); }
  .tl-ring-sub{ font-family:var(--font-mono); font-size:var(--type-label); letter-spacing:.05em;
    fill:var(--text-faint); paint-order:stroke; stroke:var(--bg-base); stroke-width:4px; }
  .tl-ring-spoke{ stroke:var(--accent); stroke-width:1.2; opacity:.5; stroke-dasharray:3 3; }
  /* THE SEASON WASH. Its weight lives here rather than inline because paper
     needs more of it: on a cream ground a sixteen-per-cent tint of anything is
     a smudge, and the four seasons read as one colour. */
  .tl-ring-wash{ opacity:.17; }
  :root[data-mode="light"] .tl-ring-wash{ opacity:.30; }
  /* The dot is a way into the entry, so it says so with the cursor. */
  .tl-ring-dot, .tl-ring-label{ cursor:pointer; }
  .tl-ring-dot:hover{ stroke-width:3; }
  .tl-ring-label:hover{ text-decoration:underline; }
  /* On paper the knockout behind a label has to be paper. --bg-base is the top
     of the page gradient in every theme, so this is one rule and not thirteen. */
  :root[data-mode="light"] .tl-ring-label,
  :root[data-mode="light"] .tl-ring-sub,
  :root[data-mode="light"] .tl-ring-season{ stroke:var(--bg-base); }

  /* A THIN YEAR IS A LESSER VERSION THAT STILL WORKS.
     The band is already thicker and the dots already larger — that is done in
     the drawing, because it is geometry. What is left here is the type: on two
     things there is room to say both of them properly, so the sentence under
     the numeral is set at reading size rather than as a caption. */
  .tl-ring.is-thin .tl-ring-from{ font-size:var(--type-body); line-height:1.62; }
  .tl-ring.is-bare .tl-ring-from{ color:var(--text-faint); }

  /* ---- a read that failed ---- */
  /* NOT AN EMPTY YEAR, AND IT MUST NOT LOOK LIKE ONE. No ring is drawn here at
     all: the drawing is what makes the claim, and a network error has no claim
     to make. The mark is the only place on this page that wears the warm
     category red, so it cannot be mistaken for a quiet year. */
  .tl-ring-failed{ display:flex; gap:var(--space-4); align-items:flex-start;
    padding:var(--space-5) var(--space-5); border-radius:var(--radius-card);
    border:1px solid color-mix(in srgb, var(--cat-red-2) 45%, transparent);
    background:color-mix(in srgb, var(--cat-red) 9%, transparent); }
  .tl-ring-failed-mark{ flex:none; width:3px; align-self:stretch; border-radius:var(--radius-tight);
    background:var(--cat-red-2); }
  .tl-ring-failed-body{ min-width:0; }
  .tl-ring-failed-t{ font-family:var(--font-display); font-size:var(--type-lead); font-weight:600;
    color:var(--text); margin-bottom:var(--space-2); }
  .tl-ring-wait{ padding:var(--space-6) var(--space-5); border-radius:var(--radius-card); border:1px solid var(--glass-border);
    background:rgba(120,120,140,.05); font-size:var(--type-body); color:var(--text-faint); }

  /* ==========================================================
     MOTION — three movements, each of which means something.
     ==========================================================
       THE YEAR TURNS. Changing the year swings the marks in
       by six degrees rather than cutting to them, because the
       thing that changed is a rotation and cutting makes it
       look like a different picture rather than the same ring
       pointed somewhere else.
       THE OTHER YEARS FADE IN BEHIND. They are behind, so
       they arrive behind.
       TODAY BREATHES. It is the one mark on this ring that
       will not be here tomorrow. */
  @keyframes tlRingTurn{ from{ opacity:0; transform:rotate(-6deg); } to{ opacity:1; transform:none; } }
  @keyframes tlRingGhostIn{ from{ opacity:0; } to{ opacity:1; } }
  @keyframes tlRingBreathe{ 0%,100%{ opacity:.16 } 50%{ opacity:.44 } }
  /* The origin is the ring's own centre in viewBox units, so the year turns
     about its middle rather than about the top left of the figure. It has to
     match TL_RING_CX/TL_RING_CY in app.js. */
  .tl-ring-marks{ transform-box:view-box; transform-origin:500px 345px;
    animation:tlRingTurn 620ms var(--ease-out) both; }
  .tl-ring-ghosts{ animation:tlRingGhostIn 900ms var(--ease-out) both; }
  .tl-ring-breathe{ animation:tlRingBreathe 4s var(--ease-in-out) infinite; opacity:.16; }

  /* ---- THE DAY, ASSEMBLED -------------------------------------------------

     Matched to the approved page (sports-and-timeline-options.html, Timeline A)
     rather than redesigned. The photograph sits BEHIND the words rather than
     beside them — the same decision already made on the year cards, and for the
     same reason: a thumbnail in a corner is decoration, a photograph the words
     sit on gives the day a colour.

     THE THREE STATES THAT ARE NOT "read" ARE STYLED TO BE TOLD APART ACROSS THE
     ROOM. A failed slice is the only thing on this page that gets a warm edge
     and a mark, because a section that could not be read is the one thing on
     the screen that must not be mistaken for a quiet afternoon. */

  .tl-day-wrap{ margin-bottom:var(--space-6); }
  .tl-day-head{ display:flex; gap:var(--space-2); align-items:center; flex-wrap:wrap;
    margin-bottom:var(--space-3); }
  .tl-day-wait{ padding:var(--space-8) var(--space-6); text-align:center; color:var(--text-faint);
    border:1px dashed var(--glass-border); border-radius:var(--radius-card); }

  .tl-day{ border:1px solid var(--glass-border); border-radius:var(--radius-card);
    background:linear-gradient(170deg, rgba(28,40,86,.30), rgba(255,255,255,.012) 54%);
    overflow:hidden; }

  /* No photograph is not a broken photograph: the wash is the same one the year
     cards fall back to, so a day with nothing to show still has a colour. */
  .tl-day-photo{ height:210px; position:relative; background-size:cover; background-position:center;
    background-image:linear-gradient(150deg, #2A4A6B 0%, #7C6A4E 42%, #C08A52 74%, #2B2237 100%); }
  .tl-day-photo::after{ content:''; position:absolute; inset:0;
    background:linear-gradient(180deg, rgba(5,7,16,.22), rgba(5,7,16,.92)); }
  .tl-day-photo .cap{ position:absolute; left:var(--space-5); right:var(--space-5);
    bottom:var(--space-4); z-index:2; }
  .tl-day-photo .cap h3{ font-family:var(--font-display); font-size:var(--type-figure);
    font-weight:600; margin:0 0 2px; line-height:1.05; }
  .tl-day-photo .cap p{ margin:0; color:var(--text-dim); font-family:'IBM Plex Mono', monospace;
    font-size:var(--type-label); letter-spacing:.12em; text-transform:uppercase; }

  .tl-day-body{ padding:var(--space-5) var(--space-6) var(--space-6); }
  .tl-day-sec{ padding:var(--space-4) 0; border-top:1px solid rgba(255,255,255,.055); }
  .tl-day-sec:first-child{ border-top:0; padding-top:0; }
  .tl-day-sec > h5{ font-family:'IBM Plex Mono', monospace; font-size:10px; font-weight:600; letter-spacing:.16em;
    text-transform:uppercase; color:var(--text-faint); margin:0 0 var(--space-3); }

  .tl-day-p{ display:flex; align-items:flex-start; gap:var(--space-3); padding:var(--space-2) 0; }
  .tl-day-p .g{ min-width:0; flex:1; }
  .tl-day-p b{ font-weight:600; }
  .tl-day-p .sub{ display:block; color:var(--text-faint); font-size:var(--type-label); }
  .tl-day-av{ flex:none; width:30px; height:30px; border-radius:50%; display:flex;
    align-items:center; justify-content:center; font-family:'IBM Plex Mono', monospace; font-size:10px;
    font-weight:600; letter-spacing:.04em; background:var(--wash-hover); color:var(--text-dim);
    border:1px solid var(--glass-border); }
  .tl-day-av.is-met{ color:var(--accent); }
  .tl-day-av.is-body{ color:var(--green-2); }

  /* The one line that gives him the small shock, so it is the one line here
     that is allowed a colour. */
  .tl-day-gap{ display:block; color:var(--orange-2); font-weight:600;
    font-size:var(--type-label); margin-top:1px; }

  .tl-day-thumbs{ display:flex; gap:var(--space-2); flex-wrap:wrap; }
  .tl-day-thumb{ width:58px; height:58px; border-radius:var(--radius-tight); display:block;
    object-fit:cover; background:var(--wash-hover); }

  .tl-day-num{ display:flex; gap:var(--space-6); flex-wrap:wrap; }
  .tl-day-num div{ min-width:96px; }
  .tl-day-num b{ display:block; font-family:var(--font-display);
    font-size:var(--type-title); font-weight:600; }
  .tl-day-num span{ font-family:'IBM Plex Mono', monospace; font-size:10px; letter-spacing:.12em;
    text-transform:uppercase; color:var(--text-faint); }
  .tl-day-rows{ margin-top:var(--space-3); }
  .tl-day-row{ display:flex; justify-content:space-between; gap:var(--space-4);
    padding:var(--space-1) 0; font-size:var(--type-label); color:var(--text-dim); }
  .tl-day-row b{ font-variant-numeric:tabular-nums; color:var(--text); }

  .tl-day-next{ font-family:var(--font-display); font-style:normal; font-weight:500;
    font-size:var(--type-lead); color:var(--text-dim); margin:0 0 var(--space-2); }
  .tl-day-next a{ color:var(--text); }
  .tl-day-quiet{ font-family:var(--font-display); font-style:normal; font-weight:500;
    color:var(--text-dim); margin:0; }
  .tl-day-foot{ color:var(--text-faint); font-size:var(--type-label); margin:var(--space-2) 0 0; }
  .tl-day-prov{ margin-top:var(--space-4); }

  .tl-day-write{ border:1px dashed color-mix(in srgb, var(--brass) 40%, transparent);
    border-radius:var(--radius-control); background:rgba(200,164,93,.04);
    padding:var(--space-3) var(--space-4); }
  .tl-day-write p{ margin:0 0 var(--space-2); color:var(--text-faint); font-style:normal; font-weight:500;
    font-family:var(--font-display); }
  .tl-day-write input{ width:100%; background:rgba(0,0,0,.24); border:1px solid var(--glass-border);
    border-radius:var(--radius-control); color:var(--text); font-family:inherit;
    font-size:var(--type-body); padding:var(--space-2) var(--space-3); }

  /* ---- A READ THAT FAILED -------------------------------------------------
     House rule 211, made visible. This is the only warm edge on the day, and it
     is deliberately louder than anything around it. */
  .tl-day-alarm{ border:1px solid color-mix(in srgb, var(--orange-2) 45%, transparent);
    border-left-width:3px; border-radius:var(--radius-control);
    background:color-mix(in srgb, var(--orange-2) 8%, transparent);
    padding:var(--space-3) var(--space-4); margin-bottom:var(--space-4); }
  .tl-day-alarm b{ display:block; color:var(--orange-2); margin-bottom:2px; }
  .tl-day-alarm span{ display:block; color:var(--text-dim); font-size:var(--type-label); }

  .tl-day-sec.is-failed{ }
  .tl-day-cant{ display:flex; gap:var(--space-3); align-items:flex-start;
    border:1px solid color-mix(in srgb, var(--orange-2) 35%, transparent);
    border-radius:var(--radius-control);
    background:color-mix(in srgb, var(--orange-2) 6%, transparent);
    padding:var(--space-3) var(--space-4); }
  .tl-day-cant.is-whole{ padding:var(--space-6); }
  .tl-day-cant-mark{ flex:none; width:10px; height:10px; margin-top:5px; border-radius:50%;
    background:var(--orange-2); }
  .tl-day-cant b{ display:block; color:var(--orange-2); margin-bottom:2px; }
  .tl-day-cant span{ display:block; color:var(--text-dim); font-size:var(--type-label); }
  .tl-day-cant .btn{ margin-top:var(--space-3); }
  .tl-day-why{ font-family:'IBM Plex Mono', monospace; font-size:10px; color:var(--text-faint);
    margin-top:var(--space-2); word-break:break-word; }

  /* ---- A THING LUCID NEVER HELD ------------------------------------------
     Quieter than a failure and still not silent. Nothing broke; it was simply
     not being kept, and saying so is the only true sentence available. */
  .tl-day-never{ margin:0; color:var(--text-faint); font-size:var(--type-label);
    border-left:2px solid var(--glass-border); padding-left:var(--space-3); }

  @media(max-width:700px){
    .tl-day-body{ padding:var(--space-4); }
    .tl-day-photo{ height:160px; }
    .tl-day-photo .cap h3{ font-size:var(--type-page); }
    .tl-day-photo .cap{ left:var(--space-4); right:var(--space-4); }
    .tl-day-num{ gap:var(--space-4); }
  }

  @media (prefers-reduced-motion: reduce){
    .tl-ring-marks, .tl-ring-ghosts{ animation:none; opacity:1; transform:none; }
    .tl-ring-breathe{ animation:none; opacity:.3; }
  }

  /* ---- narrow ----
     THE READING STACKS UNDER THE RING, and the figure has to be told to
     stretch: in a column flex container align-items:flex-start sizes a child to
     its content, and an <svg width:100%> inside a content-sized box collapses to
     nothing at all. */
  @media(max-width:1080px){
    .tl-ring{ flex-direction:column; gap:var(--space-6); align-items:stretch; }
    .tl-ring-fig{ flex:0 0 auto; width:100%; }
    .tl-ring-read{ flex:0 0 auto; width:100%; }
    .tl-ring-gauge .in{ width:34%; }
  }
  @media(max-width:700px){
    .tl-ring-hint{ display:none; }
    .tl-ring-label{ font-size:var(--type-lead); }
    .tl-ring-sub{ font-size:var(--type-label); }
    .tl-ring-mo{ font-size:var(--type-body); }
  }


/* THE DAYS ON THE TIMELINE. 15 October.
   "We have emails and text and pictures and memories and nothing on the
   timeline." A strip of day cards, newest first, and under it whatever line
   he opened — see renderTimelineRiver() in app.js. Existing tokens only: the
   kind colours are marks, never fills, and the type is the room's own pair
   (Outfit for the names of things, Instrument Sans for everything read). */
.tlr{ margin-bottom:var(--space-6); }
.tlr-head{ display:flex; align-items:baseline; gap:var(--space-3); flex-wrap:wrap; margin-bottom:var(--space-3); }
.tlr-title{ font-family:var(--font-display); font-size:var(--type-title); font-weight:600; margin:0; }
.tlr-hint{ margin:0; color:var(--text-faint); font-size:var(--type-label); }
.tlr-alarm{ margin-bottom:var(--space-3); }

.tlr-strip{ display:flex; gap:var(--space-3); overflow-x:auto; overscroll-behavior-x:contain;
  scroll-snap-type:x proximity; padding-bottom:var(--space-2); align-items:flex-start; }
.tlr-day{ flex:0 0 300px; scroll-snap-align:start; display:flex; flex-direction:column; gap:var(--space-2);
  padding:var(--space-3); border-radius:var(--radius-card); border:1px solid var(--glass-border);
  background:var(--glass-bg); color:var(--text); min-width:0; }
.tlr-day.is-open{ border-color:color-mix(in srgb, var(--accent) 55%, var(--glass-border)); }
.tlr-day.is-unread{ border-style:dashed; }
.tlr-dh{ display:flex; align-items:center; justify-content:space-between; gap:var(--space-2); }
.tlr-dname{ all:unset; cursor:pointer; display:flex; flex-direction:column; gap:var(--space-hair); min-width:0; }
.tlr-dname .n{ font-family:var(--font-display); font-size:var(--type-lead); font-weight:600; line-height:1.1; }
.tlr-dname .d{ font-size:var(--type-label); color:var(--text-faint); }
.tlr-dname:hover .n, .tlr-dname:focus-visible .n{ text-decoration:underline; text-underline-offset:3px; }
.tlr-dname:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; border-radius:var(--radius-tight); }
.tlr-ppl{ display:flex; flex:none; }
.tlr-ppl .tlr-av + .tlr-av{ margin-left:calc(var(--space-1) * -1); }

.avatar.tlr-av{ width:32px; height:32px; font-size:var(--type-label); flex:none; overflow:hidden; }
.avatar.tlr-av.is-sm{ width:24px; height:24px; font-size:var(--type-label); }

.tlr-photos{ all:unset; cursor:pointer; display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-1); }
.tlr-thumb{ width:62px; height:62px; border-radius:var(--radius-tight); object-fit:cover; display:block;
  background:var(--wash-hover); }
.tlr-thumb.is-more{ display:flex; align-items:center; justify-content:center; font-weight:600;
  color:var(--text-dim); font-size:var(--type-body); }
.tlr-phone{ font-size:var(--type-label); color:var(--text-dim); padding:var(--space-1) var(--space-2);
  border-radius:var(--radius-pill); border:1px solid var(--glass-border); }

.tlr-lines{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; }
.tlr-line{ all:unset; box-sizing:border-box; width:100%; cursor:pointer; display:flex; align-items:flex-start;
  gap:var(--space-2); padding:var(--space-2) var(--space-1); border-radius:var(--radius-control);
  font-size:var(--type-body); line-height:1.35; }
.tlr-line:hover, .tlr-line:focus-visible{ background:var(--wash-hover); }
.tlr-line:focus-visible{ outline:2px solid var(--accent); outline-offset:-2px; }
.tlr-line.is-sel{ background:color-mix(in srgb, var(--tlr-c) 14%, transparent); }
.tlr-mark{ flex:none; width:8px; height:8px; margin-top:var(--space-1); border-radius:var(--radius-round); background:var(--tlr-c, var(--accent)); }
.tlr-words{ flex:1; min-width:0; color:var(--text-dim);
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.tlr-lines.is-open .tlr-words{ -webkit-line-clamp:3; }
.tlr-words b{ color:var(--text); font-weight:600; }
.tlr-sub{ color:var(--text-faint); font-size:var(--type-label); }
.tlr-plus{ color:var(--text); font-weight:600; }
.tlr-time{ flex:none; color:var(--text-faint); font-size:var(--type-label); font-variant-numeric:tabular-nums; margin-top:var(--space-hair); }
.tlr-more{ all:unset; cursor:pointer; font-size:var(--type-label); color:var(--accent); padding:0 var(--space-1); }
.tlr-more:hover{ text-decoration:underline; }
.tlr-quiet{ margin:0; color:var(--text-faint); font-size:var(--type-body); }
.tlr-cant{ margin:0; color:var(--orange-2); font-size:var(--type-body); font-weight:600; }
.tlr-cant.is-small{ font-size:var(--type-label); font-weight:500; }
.tlr-earlier{ flex:0 0 140px; align-self:stretch; min-height:120px; scroll-snap-align:start; border-radius:var(--radius-card);
  border:1px dashed var(--glass-border); background:transparent; color:var(--text-dim);
  font:inherit; font-weight:600; cursor:pointer; padding:var(--space-4); }
.tlr-earlier:hover{ color:var(--text); border-color:var(--accent); }

/* THE OPENED LINE. A card of its own under the strip, with the kind's colour
   as its one edge. */
.tlr-open{ margin-top:var(--space-3); border:1px solid var(--glass-border);
  border-left:3px solid var(--tlr-c, var(--accent)); border-radius:var(--radius-card);
  background:var(--glass-bg); padding:var(--space-4) var(--space-5); }
.tlr-oh{ display:flex; align-items:flex-start; gap:var(--space-3); }
.tlr-oh .tlr-mark{ margin-top:var(--space-2); }
.tlr-oh .g{ flex:1; min-width:0; }
.tlr-oh h3{ font-family:var(--font-display); font-size:var(--type-title); font-weight:600; margin:0;
  display:flex; align-items:center; gap:var(--space-2); line-height:1.2; overflow-wrap:anywhere; }
.tlr-oh p{ margin:var(--space-1) 0 0; color:var(--text-faint); font-size:var(--type-label); }
.tlr-x{ all:unset; cursor:pointer; flex:none; width:32px; height:32px; border-radius:var(--radius-round);
  display:flex; align-items:center; justify-content:center; font-size:var(--type-title); color:var(--text-dim); }
.tlr-x:hover{ background:var(--wash-hover); color:var(--text); }
.tlr-ob{ margin-top:var(--space-4); }
.tlr-oa{ display:flex; gap:var(--space-2); flex-wrap:wrap; margin-top:var(--space-4); }
.tlr-wait{ color:var(--text-faint); margin:0; }

.tlr-faces{ display:flex; align-items:center; gap:var(--space-1); margin-bottom:var(--space-3); flex-wrap:wrap; }
.tlr-faces .tlr-sub{ margin-left:var(--space-2); }
.tlr-thread{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:var(--space-3); }
.tlr-thread li{ display:flex; gap:var(--space-3); padding:var(--space-3); border-radius:var(--radius-control); }
.tlr-thread li.is-here{ background:color-mix(in srgb, var(--blue) 10%, transparent); }
.tlr-thread .g{ flex:1; min-width:0; }
.tlr-tw{ display:flex; justify-content:space-between; gap:var(--space-3); align-items:baseline; }
.tlr-thread p{ margin:var(--space-1) 0 0; color:var(--text-dim); font-size:var(--type-body); line-height:1.45; overflow-wrap:anywhere; }

.tlr-convo{ display:flex; flex-direction:column; gap:var(--space-1); max-width:560px; }
.tlr-sep{ align-self:center; font-size:var(--type-label); color:var(--text-faint); margin:var(--space-2) 0; }
.tlr-bub{ align-self:flex-start; max-width:80%; padding:var(--space-2) var(--space-3);
  border-radius:var(--radius-card); background:var(--wash-hover); border:1px solid var(--glass-border); }
.tlr-bub.is-mine{ align-self:flex-end; background:color-mix(in srgb, var(--green) 18%, transparent); }
.tlr-bub.is-here{ outline:2px solid color-mix(in srgb, var(--green) 60%, transparent); outline-offset:1px; }
.tlr-bub p{ margin:0; font-size:var(--type-body); line-height:1.4; overflow-wrap:anywhere; white-space:pre-wrap; }
.tlr-bub .tlr-time{ display:block; margin-top:var(--space-hair); }

.tlr-quote{ margin:0; font-family:var(--font-display); font-size:var(--type-lead); font-weight:500;
  line-height:1.4; color:var(--text); border-left:2px solid var(--tlr-c, var(--accent)); padding-left:var(--space-4); }
.tlr-facts{ display:grid; grid-template-columns:max-content 1fr; gap:var(--space-1) var(--space-4); margin:var(--space-4) 0 0; font-size:var(--type-body); }
.tlr-facts dt{ color:var(--text-faint); }
.tlr-facts dd{ margin:0; color:var(--text); overflow-wrap:anywhere; }
.tlr-audio{ width:100%; margin-bottom:var(--space-3); }
.tlr-sum{ margin:0; font-size:var(--type-body); line-height:1.5; color:var(--text); }
.tlr-h5{ font-size:var(--type-label); color:var(--text-faint); margin:var(--space-4) 0 var(--space-2); font-weight:600; }
.tlr-acts{ margin:0; padding-left:var(--space-5); color:var(--text-dim); font-size:var(--type-body); }
.tlr-grid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(140px, 1fr)); gap:var(--space-2); }
.tlr-grid figure{ margin:0; }
.tlr-grid img{ width:100%; aspect-ratio:1; object-fit:cover; border-radius:var(--radius-control); display:block; background:var(--wash-hover); }
.tlr-grid figcaption{ font-size:var(--type-label); color:var(--text-faint); margin-top:var(--space-1); }

@media (max-width: 640px){
  .tlr-day{ flex-basis:84%; }
  .tlr-open{ padding:var(--space-3) var(--space-4); }
  .tlr-bub{ max-width:90%; }
}