/* ── Timetable ──────────────────────────────────────────────────
   Shared by timetable, timetable_calendar, timetable_courses and
   timetable_sharing.

   The layout is Huro's: .columns/.column for the page split, .s-card for
   boxes, .tabs.is-toggle.is-fullwidth for the week strip, .media-flex-center
   with .flex-meta/.flex-end for list rows, .section-placeholder for empty
   states, .h-icon for icon bubbles, .h-avatar/.avatar-stack for avatars,
   .buttons for action pairs, .modal-card-foot.is-end for modal footers, and
   the Bulma title, flex, text and spacing helpers for everything else. Only
   what Huro has no equivalent for lives here — which on this page is the day
   spine, since Huro's two timelines are event feeds with no time axis.

   The tt- classes left on the markup are behaviour hooks for the page
   scripts, not styling; the ones that appear below are the exceptions. */


/* ── Surfaces the backend tints ────────────────────────────────
   The API colours each class by course type, so the text colour on top is
   computed at runtime by ttTintCard/ttFillAvatar. Huro pins its own colour
   on paragraphs and on avatar initials, and that beats the colour set on
   the parent, leaving text unreadable on the darker tints. These rules hand
   the inherited colour back. Opacity rather than a lighter colour keeps the
   secondary lines soft on a light and a dark tint alike. */

.tt-avatar .avatar.is-fake .tt-initials {
    color: inherit;
}

.tt-block,
.tt-block-type,
.tt-block-title,
.tt-block-meta,
.tt-block-friends {
    color: inherit;
}


.tt-avatar .tt-avatar-image {
    border-radius: 50%;
    background: #ededed;
}

/* Huro's avatar bubbles carry no border of their own, so a stack needs a ring
   to keep overlapping initials and faces legible. */
.avatar-stack .tt-avatar .avatar.is-fake,
.avatar-stack .tt-avatar .tt-avatar-image {
    box-shadow: 0 0 0 1.5px #ffffff;
}

/* Huro's stack is a single nowrap line; a whole cohort on campus has to wrap. */
.avatar-stack.tt-avatar-group {
    flex-wrap: wrap;
    row-gap: 6px;
}

/* Huro overlaps by 12 of 32 pixels, which eats the second initial. Its own rule
   outranks a class-only selector, so this one is anchored to the app wrapper. */
#huro-app .avatar-stack.tt-avatar-group .tt-avatar+.tt-avatar {
    margin-left: -9px;
}


/* ── The Add Courses wizard ────────────────────────────────────
   Three steps in one modal. Huro's modal-card gives the shell, the head, the
   body and the footer; what it has no equivalent for is a progress trail, a
   chip row, and the running counts each step reports back. */

/* The head carries a subtitle under the title, which Huro's single-row
   .modal-card-head lays out beside it instead. */
.modal-card-head.is-stacked {
    align-items: flex-start;
}

.tt-wizard-heading {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.tt-wizard-subtitle {
    font-size: 13px;
    color: #666666;
}

.tt-wizard-subtitle:empty {
    display: none;
}

/* Where I am, and how much is left. The line between two nodes takes the
   colour of the step behind it, so the trail fills in as it is walked. */
.tt-steps {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 16px;
    padding: 0;
    list-style: none;
}

.tt-step {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: 'Montserrat', sans-serif;
    font-size: 12px;
    font-weight: 600;
    color: #999999;
}

.tt-step-line {
    flex: 1;
    height: 2px;
    background: #ededed;
}

.tt-step-line.tt-is-done {
    background: #28b411;
}

.tt-step-bullet {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border: 2px solid #dbdbdb;
    border-radius: 50%;
    font-size: 11px;
    flex-shrink: 0;
}

/* A node shows its number until it is behind you, and its tick after */
.tt-step-tick {
    display: none;
    font-size: 10px;
}

.tt-step.tt-is-current {
    color: #d8286a;
}

.tt-step.tt-is-current .tt-step-bullet {
    background: #d8286a;
    border-color: #d8286a;
    color: #ffffff;
}

.tt-step.tt-is-done {
    color: #1e8a0e;
}

.tt-step.tt-is-done .tt-step-bullet {
    background: #28b411;
    border-color: #28b411;
    color: #ffffff;
}

.tt-step.tt-is-done .tt-step-number {
    display: none;
}

.tt-step.tt-is-done .tt-step-tick {
    display: inline;
}

/* Step 1: what is ticked, repeated above a list a search can narrow away */
.tt-chip-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-top: 12px;
}

.tt-chip-label {
    font-size: 12px;
    color: #666666;
    margin-right: 2px;
}

.tt-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 10px;
    border-radius: 999px;
    background: #f9e4ed;
    color: #cc0853;
    font-size: 12.5px;
    font-weight: 500;
}

.tt-chip-remove {
    background: none;
    border: 0;
    padding: 0;
    color: inherit;
    opacity: .7;
    font-size: 10px;
    cursor: pointer;
    line-height: 1;
}

.tt-chip-remove:hover {
    opacity: 1;
}

/* The line above the list: how much of the catalogue the search left on the one
   side, and on the other the way out for a search that left the wrong thing. The
   padding is the row's rather than the count's, so the link is still spaced off
   the search field on the onboarding, which reports no count. */
.tt-picker-head {
    display: flex;
    align-items: baseline;
    gap: 12px;
    padding: 12px 0 6px;
}

/* Held to the right by a margin rather than by space-between, which would walk it
   back to the left on the two occasions there is nothing on the other side: a
   search that matched nothing reports no count, and the onboarding reports none
   at all. */
.tt-picker-head .tt-request-link {
    margin-left: auto;
}

.tt-picker-count {
    display: block;
    font-family: 'Montserrat', sans-serif;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: #999999;
}

.tt-picker-count:empty {
    display: none;
}

/* The onboarding's list opens 12px below whatever is above it, which was the search
   field. The row now between them already carries that gap. */
.tt-picker-head + .tt-onboard-scroll {
    padding-top: 0;
}

/* A button that reads as a link: it opens a modal rather than navigating, so it
   is a button, but it is an aside to the search rather than an action beside it
   and a .h-button would carry the weight of one. Also cloned into the two empty
   states, where it is the only thing on offer and centres itself. */
.tt-request-link {
    padding: 0;
    border: 0;
    background: none;
    font: 600 12px 'Montserrat', sans-serif;
    color: #671cc9;
    white-space: nowrap;
    cursor: pointer;
}

.tt-request-link:hover {
    text-decoration: underline;
}

/* The code leads the row because it is what a student searches by; the title
   trails it as the confirmation that the code is the right one. */
.tt-pick-row .flex-meta .tt-pick-title:not(:empty)::before,
.tt-entry-group-head .flex-meta .tt-entry-group-name:not(:empty)::before {
    content: " · ";
}

/* Huro blocks out and bolds every span in a .flex-meta title line */
.tt-pick-row .flex-meta .tt-pick-title,
.tt-entry-group-head .flex-meta .tt-entry-group-name {
    display: inline;
    font-weight: 400;
    color: #666666;
}

.tt-pick-count:empty {
    display: none;
}

/* Huro's .tag is grey chrome; already-added reads as a settled state, not a
   label, so it takes the success tint the rest of the page uses. */
.tt-pick-row .tag.tt-pick-added {
    background: #e6ffe2;
    color: #1e8a0e;
    font-size: 11px;
}

/* Step 2: whether a course is done, said on its own head so the closed ones
   still report. */
.tt-entry-group-status {
    display: inline-flex;
    align-items: center;
    padding: 4px 8px;
    border-radius: 999px;
    background: #f2f2f2;
    color: #666666;
    font-family: 'Roboto', sans-serif;
    font-size: 11px;
    font-weight: 400;
    white-space: nowrap;
}

.tt-entry-group.tt-is-done .tt-entry-group-status {
    background: #e6ffe2;
    color: #1e8a0e;
}

/* A clash is advisory — it is worth seeing on the row it is about, and never
   worth blocking the step over. */
.tt-entry-clash {
    color: #b5740a;
    font-size: 12px;
}

/* Huro blocks out every span in a .flex-meta, which would put the warning
   triangle on a line of its own */
.tt-pick-row .flex-meta .tt-entry-clash > * {
    display: inline;
}

/* Step 3: what actually landed on the timetable, before anything is asked */
.tt-receipt {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 18px 20px;
    border-radius: 12px;
    background: linear-gradient(135deg, #ea2671 0%, #797bf2 60%, #ffa981 100%);
    color: #ffffff;
}

.tt-receipt-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: rgba(255, 255, 255, .22);
    font-size: 18px;
    flex-shrink: 0;
}

.tt-receipt-meta {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.tt-receipt-title {
    font-family: 'Montserrat', sans-serif;
    font-size: 16px;
    font-weight: 700;
}

.tt-receipt-detail {
    font-size: 13px;
    opacity: .95;
}

.tt-share-title {
    margin: 20px 0 6px;
    font-family: 'Montserrat', sans-serif;
    font-size: 15px;
    font-weight: 700;
    color: #0f1928;
}

/* The ask lands better with the people behind it than without them */
.tt-friends-strip {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 16px;
    padding: 10px 12px;
    border: 1px solid #ededed;
    border-radius: 8px;
    background: #fafafa;
    font-size: 13px;
}

/* Huro's .modal-card-foot.is-end packs every button to the right, and its own
   spacing rule on .button outranks a class-only selector. Back and Share later
   are exits, so they belong at the other end of the footer. */
#huro-app .modal-card-foot .button.tt-wizard-back,
#huro-app .modal-card-foot .button.tt-wizard-later {
    margin-right: auto;
}


/* ── Pickers in the Add Courses wizard ─────────────────────────*/

/* The picker scrolls inside the modal so the footer buttons stay put */
.tt-scroll-list {
    max-height: 46vh;
    overflow-y: auto;
}

/* Ruling the rows off makes a .media-flex-center list read as one list */
.tt-pick-row {
    border-bottom: 1px solid #f0f0f3;
}

.tt-pick-row:last-child {
    border-bottom: 0;
}

/* A course already on the timetable stays listed, so the picker still reads
   as the full catalogue rather than a filtered one */
.tt-pick-row.tt-is-added {
    opacity: .55;
}

/* Huro's only accordion, .single-accordion, is sized for a full page section;
   this one is a compact row inside the wizard modal, so the header keeps a
   button's semantics without a button's chrome. */
.tt-entry-group-head {
    width: 100%;
    background: rgba(115, 120, 140, .06);
    border: 0;
    cursor: pointer;
    font-family: inherit;
}

.tt-entry-group-caret {
    transition: transform .15s ease;
}

.tt-entry-group.tt-is-open .tt-entry-group-caret {
    transform: rotate(90deg);
    color: #d8286a;
}

/* Of a stack of collapsed courses, the open one is the one being worked on */
.tt-entry-group.tt-is-open {
    border: 1px solid #d8286a;
}


/* ── Manage courses ────────────────────────────────────────────
   A strip of figures for the week, then the courses as cards, two across. The
   week itself lives on the timetable and the calendar; this page is only for
   changing what goes into it. .s-card cannot take the per-course tint the API
   sends, so the cards are written here rather than borrowed. Colours come from
   the design system's palette: #EDEDED hairlines, #0F1928 and #A2A5B8 for text. */

.tt-manage-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 16px;
}

.tt-manage {
    display: flex;
    flex-direction: column;
    gap: 16px;
    margin-top: 24px;
}

/* Two across. Rows start at the top rather than stretching, so opening one
   course grows its own card without dragging the one beside it down too. */
.tt-course-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
    align-items: start;
}


/* ── One course ────────────────────────────────────────────────*/

/* The border colour is set from the course's own colour when it is open, so it
   is left to the script rather than named here. */
.tt-course-card {
    position: relative;
    background: #ffffff;
    border: 1px solid #ededed;
    border-radius: 12px;
    box-shadow: -1px 3px 10px rgba(14, 14, 14, .06);
}

.tt-course-body {
    padding: 16px 20px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.tt-course-card.tt-is-open .tt-course-body {
    padding: 18px 20px;
}

/* The whole head opens the course, so it keeps a button's semantics without a
   button's chrome — the same trick .tt-entry-group-head uses in the wizard. */
.tt-course-head {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 0;
    padding-right: 40px;
    background: transparent;
    border: 0;
    text-align: left;
    font-family: inherit;
    cursor: pointer;
}

.tt-course-spine {
    width: 4px;
    height: 34px;
    border-radius: 2px;
    flex-shrink: 0;
}

.tt-course-card.tt-is-open .tt-course-spine {
    height: 36px;
}

.tt-course-meta {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1;
    min-width: 0;
}

.tt-course-name {
    font: 700 15.5px/1.2 'Montserrat', sans-serif;
    color: #0f1928;
}

.tt-course-card.tt-is-open .tt-course-name {
    font-size: 16px;
}

.tt-course-code {
    font-size: 13px;
    color: #a2a5b8;
}

.tt-course-caret {
    color: #a2a5b8;
    font-size: 12px;
    transition: transform .15s ease;
}

.tt-course-card.tt-is-open .tt-course-caret {
    transform: rotate(180deg);
}

/* The menu sits over the head rather than inside it, so opening the course and
   acting on it stay two separate targets. */
.tt-course-menu {
    position: absolute;
    top: 16px;
    right: 16px;
}

.tt-course-menu-toggle {
    width: 32px;
    height: 32px;
    border: 0;
    border-radius: 4px;
    background: transparent;
    color: #a2a5b8;
    font-size: 14px;
    cursor: pointer;
}

.tt-course-menu-toggle:hover {
    background: #fafafa;
    color: #666666;
}

.tt-course-menu-list {
    position: absolute;
    top: 36px;
    right: 0;
    z-index: 5;
    min-width: 170px;
    padding: 6px;
    background: #ffffff;
    border: 1px solid #ededed;
    border-radius: 8px;
    box-shadow: -1px 3px 10px rgba(14, 14, 14, .12);
}

.tt-course-menu-remove {
    display: block;
    width: 100%;
    padding: 9px 10px;
    border: 0;
    border-radius: 4px;
    background: transparent;
    color: #e62965;
    font: 500 13.5px 'Roboto', sans-serif;
    text-align: left;
    cursor: pointer;
}

.tt-course-menu-remove:hover {
    background: #fdedf2;
}


/* ── The class times inside an open course ─────────────────────*/

.tt-class-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* An untaken class time is dashed and empty; a taken one is filled with the
   course's own colour, which the script sets. */
.tt-class-row {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 44px;
    padding: 10px 12px;
    border: 1px dashed #dbdbdb;
    border-radius: 8px;
    background: transparent;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}

.tt-class-row.tt-is-added {
    border-color: transparent;
}

.tt-class-tick {
    width: 18px;
    height: 18px;
    border: 2px solid #dbdbdb;
    border-radius: 2px;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 9px;
    color: transparent;
}

.tt-class-row.tt-is-added .tt-class-tick {
    border-width: 0;
}

.tt-class-meta {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    flex: 1;
    min-width: 0;
}

.tt-class-title {
    font-size: 13.5px;
    color: #666666;
}

.tt-class-row.tt-is-added .tt-class-title {
    font-weight: 600;
}

.tt-class-where {
    font-size: 12.5px;
    color: #a2a5b8;
    flex-shrink: 0;
}


/* ── What the week adds up to ──────────────────────────────────
   Four figures on four cards across the top: courses, hours, days on campus
   and clashes. The icon bubble is Huro's .h-icon, so only the card around it
   is written here — in the same white, hairline and shadow as a course card,
   so the two read as one set. */

.tt-stats {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
}

.tt-stat {
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
    padding: 16px 18px;
    background: #ffffff;
    border: 1px solid #ededed;
    border-radius: 12px;
    box-shadow: -1px 3px 10px rgba(14, 14, 14, .06);
}

.tt-stat-icon {
    flex-shrink: 0;
}

.tt-stat-meta {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.tt-stat-value {
    font: 800 22px/1 'Montserrat', sans-serif;
    color: #283252;
}

/* No clashes is the good news, so it is stated in green; one is a warning that
   has to survive the same glance. */
.tt-stat-clashes {
    color: #28b411;
}

.tt-stat-clashes.tt-is-warning {
    color: #b5740a;
}

.tt-stat-name {
    font-size: 12.5px;
    color: #666666;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}


/* ── Removing a course ─────────────────────────────────────────
   In place of a confirm modal: the card becomes the question, so the course
   and what removing it costs are in front of you while you decide. */

.tt-remove-panel {
    border: 1px solid #f5c9da;
    background: #fef6f9;
    border-radius: 12px;
}

.tt-remove-inner {
    padding: 18px 20px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.tt-remove-head {
    display: flex;
    align-items: center;
    gap: 12px;
}

.tt-remove-panel .tt-course-spine {
    opacity: .4;
}

.tt-remove-panel .tt-course-name {
    color: #a2a5b8;
    text-decoration: line-through;
}

.tt-remove-cost {
    margin: 0;
    font-size: 13.5px;
    line-height: 1.5;
    color: #333333;
}

.tt-remove-actions {
    display: flex;
    gap: 8px;
}

/* Only a phone lifts the panel off the card, so the backdrop stays out of the
   way until the media query below turns it on. */
.tt-sheet-backdrop {
    display: none;
}


/* ── The week head ─────────────────────────────────────────────
   One row: the week being looked at and the buttons that move it on the left,
   what is on show and adding more on the right. Huro supplies the parts —
   .button.h-action is its bordered secondary button and .tabs.is-toggle its
   segmented switch — so only the sizes and the one state Huro paints
   differently are written here. */

.tt-week-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    flex-wrap: nowrap;
    gap: 16px;
}

.tt-week-title-group,
.tt-week-tools {
    display: flex;
    align-items: center;
    min-width: 0;
}

.tt-week-title-group {
    gap: 16px;
    flex-wrap: wrap;
}

/* Squeezed between the buttons and the tools, a flex item will break a word
   rather than overflow — a month title one letter to a line. The title keeps
   its width and the buttons wrap under it instead. */
.tt-week-head .title {
    white-space: nowrap;
}

.tt-week-tools {
    gap: 12px;
}

/* The buttons that move the week sit below the Add courses button in weight as
   well as in size, so the week is stepped through without shouting. */
.tt-week-nav {
    display: flex;
    gap: 6px;
    flex-shrink: 0;
}

/* .h-action sizes itself off its text, and a chevron has none to speak of */
.tt-week-nav .button.h-action {
    height: 34px;
    padding: 0 14px;
    font-size: .81rem;
    line-height: 1;
    white-space: nowrap;
}

.tt-week-nav .button.h-action.tt-is-step {
    width: 34px;
    padding: 0;
}

/* Huro fills the chosen segment with the brand pink at full strength, which on
   a switch read at a glance beside the grid ends up louder than the grid. The
   tint is the same colour said quietly, so the week stays the loudest thing.

   white_label.js writes the tenant's colours into a <style> in the head at
   runtime, which lands after this file and repaints the chosen segment at the
   same specificity. Anchoring to the app wrapper puts these back in front, as
   the avatar overlap above does. */
.tabs.tt-switch {
    flex-shrink: 0;
}

#huro-app .tabs.tt-switch a {
    padding: 7px 16px;
    font-size: .81rem;
    color: #666;
}

#huro-app .tabs.tt-switch li.is-active a,
#huro-app .tabs.tt-switch li.is-active a:hover {
    background: #f9e4ed;
    border-color: #dbdbdb;
    color: #cc0853;
    font-weight: 600;
}

/* The same switch standing in for a field in the invite modal, where it reads as
   a choice of one rather than a filter: it spans the modal like the inputs above
   and below it, and sits at their height so the three read as one column. */
#huro-app .tabs.tt-method-switch a {
    padding: 9px 16px;
    font-size: .9rem;
}

#huro-app .tabs.tt-method-switch li.is-active a::before {
    content: "\f058";
    /* fa-check-circle */
    font-family: 'Font Awesome 5 Free';
    font-weight: 900;
    margin-right: 7px;
    font-size: .85em;
}

/* ── Whose week is on the grid ─────────────────────────────────
   One control in place of a switch and a stack of faces: what is being read
   now, and — opened — everything else there is to read, each row saying what
   choosing it would put on the grid. Huro's dropdown is a menu of text rows
   with no room for a face, a name and a line under it, so this is written
   here; it opens and closes the way the course menu on /timetable_courses
   does, which is the page's own pattern for a menu hung off a button. */

.tt-calendars {
    position: relative;
    flex-shrink: 0;
}

.tt-calendars-toggle {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 34px;
    padding: 0 10px;
    border: 1px solid #dbdbdb;
    border-radius: 8px;
    background: #ffffff;
    font-family: inherit;
    cursor: pointer;
}

.tt-calendars-toggle:hover {
    border-color: #a2a5b8;
}

/* Open, the button is the head of the panel under it rather than a control of
   its own, so it takes the accent the panel's chosen row carries. */
.tt-calendars.tt-is-open .tt-calendars-toggle {
    border-color: var(--qpay-pink, #d8286a);
    box-shadow: 0 0 0 3px rgba(216, 40, 106, .12);
}

.tt-calendars-label {
    font: 600 13px/1 'Montserrat', sans-serif;
    color: #0f1928;
    white-space: nowrap;
}

.tt-calendars-caret {
    font-size: 11px;
    color: #666666;
    transition: transform .15s ease;
}

.tt-calendars.tt-is-open .tt-calendars-caret {
    transform: rotate(180deg);
    color: var(--qpay-pink, #d8286a);
}

/* Three faces in a 34px button have no room to wrap, and the wrap is what the
   shared rule gives a cohort on a course page. */
.avatar-stack.tt-calendars-faces {
    flex-wrap: nowrap;
    flex-shrink: 0;
}

#huro-app .tt-calendars-faces .tt-avatar .avatar.is-fake {
    width: 24px;
    min-width: 24px;
    height: 24px;
}

#huro-app .tt-calendars-faces .tt-avatar .avatar.is-fake .tt-initials {
    font-size: .6rem;
}


/* ── The panel ─────────────────────────────────────────────────*/

.tt-calendars-menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 5;
    min-width: 268px;
    padding: 6px;
    background: #ffffff;
    border: 1px solid #ededed;
    border-radius: 12px;
    box-shadow: -1px 3px 10px rgba(14, 14, 14, .12);
}

.tt-calendar-option {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 9px 10px;
    border: 0;
    border-radius: 8px;
    background: transparent;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}

.tt-calendar-option:hover {
    background: #fafafa;
}

/* The one being read is tinted rather than ticked alone, so the answer to
   "whose week is this" survives a glance at the open menu. */
.tt-calendar-option.tt-is-selected {
    background: #f9e4ed;
}

.tt-calendar-meta {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1;
    min-width: 0;
}

.tt-calendar-name {
    font: 600 14px/1.2 'Montserrat', sans-serif;
    color: #0f1928;
}

.tt-calendar-detail {
    font-size: 12.5px;
    color: #666666;
}

.tt-calendar-tick {
    display: none;
    font-size: 12px;
    color: var(--qpay-pink, #d8286a);
    flex-shrink: 0;
}

.tt-calendar-option.tt-is-selected .tt-calendar-tick {
    display: inline;
}

/* Everybody's calendar is nobody's initials, so it takes the ink the page
   writes its headings in and a glyph instead. */
.tt-calendar-avatar.tt-is-everyone .avatar.is-fake {
    background: #0f1928;
    color: #ffffff;
}

.tt-calendars-heading {
    display: block;
    padding: 12px 10px 4px;
    font: 600 11px/1 'Montserrat', sans-serif;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: #999999;
}

/* Sharing is managed on another page, so the row that leads there is ruled off
   from the rows that only change what is drawn here. */
.tt-calendars-manage {
    display: block;
    margin-top: 6px;
    padding: 10px;
    border-top: 1px solid #ededed;
    font-size: 13px;
    font-weight: 600;
}


/* ── The canvas the views are drawn on ─────────────────────────
   The week and the month are two readings of the same classes, so they are
   drawn at the same height inside the one card. Everything each view draws is
   placed as a proportion of that height, which is what keeps the card from
   ever needing to scroll: a long day and a six-week month both fit by being
   drawn smaller rather than by running off the bottom. */

#tt-grid-card {
    --tt-canvas: clamp(420px, calc(100vh - 340px), 760px);
}


/* ── The week grid ─────────────────────────────────────────────
   /timetable_calendar draws the whole week at once. Huro has no week grid,
   time axis or agenda component — .calendar-legacy is a month date-picker —
   so the grid itself is written here while everything around it (the card,
   the toggle, the buttons, the drawer, the rows inside it) is Huro's.

   The grid is drawn to proportion rather than to a fixed hour height: the
   card takes whatever height the viewport leaves and every class is placed
   as a percentage of the day window, so a week of long days and a week of
   short ones both fill the card. */

/* Leaving overflow-y alone would compute it to auto alongside overflow-x, and
   the first and last hour labels sit half a line outside the grid they label —
   enough to raise a scrollbar on a card that has nothing to scroll to. The
   padding gives those two labels the room they overhang into. */
.tt-grid-scroll {
    overflow-x: auto;
    overflow-y: hidden;
    padding-bottom: 12px;
}

.tt-grid {
    --tt-axis: 46px;
    --tt-gutter: 10px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/* The heads are a row of their own rather than a cell in each column, so they
   stay put while the columns underneath are redrawn. The spacer matches the
   axis so a heading sits over its day. */
.tt-grid-days {
    display: flex;
    gap: var(--tt-gutter);
    padding-left: calc(var(--tt-axis) + var(--tt-gutter));
}

.tt-day-head {
    flex: 1;
    min-width: 0;
    text-align: center;
    font-family: "Montserrat", sans-serif;
    font-weight: 600;
    font-size: .78rem;
    color: #666;
}

.tt-day-head.tt-is-today {
    color: var(--qpay-pink, #d8286a);
}

.tt-grid-body {
    display: flex;
    gap: var(--tt-gutter);
    height: var(--tt-canvas);
}

.tt-grid-axis {
    position: relative;
    width: var(--tt-axis);
    flex-shrink: 0;
    font-size: .75rem;
    color: #a2a5b9;
}

.tt-hour-label {
    position: absolute;
    right: 0;
    transform: translateY(-.5em);
    white-space: nowrap;
}

.tt-grid-track {
    position: relative;
    flex: 1;
    min-width: 0;
}

.tt-gridline {
    position: absolute;
    left: 0;
    right: 0;
    height: 1px;
    background: #f4f4f4;
}

/* The line runs the width of the grid rather than the width of today, because
   what it marks — where the week has got to — is true of every column. */
.tt-nowline {
    position: absolute;
    left: 0;
    right: 0;
    height: 2px;
    background: #ffa981;
    z-index: 3;
}

.tt-nowline-label {
    position: absolute;
    right: calc(100% + 4px);
    transform: translateY(-.55em);
    font-family: "Montserrat", sans-serif;
    font-weight: 700;
    font-size: .69rem;
    color: #ffa981;
    white-space: nowrap;
}

.tt-grid-columns {
    position: absolute;
    inset: 0;
    display: flex;
    gap: var(--tt-gutter);
}

.tt-day-column {
    position: relative;
    flex: 1;
    min-width: 0;
}


/* ── A class on the grid ───────────────────────────────────────
   Tinted with the course-type block colour the day spine already uses, so a
   class is the same colour whichever page it is read on, and its text works
   out its own contrast at render time. */

.tt-week-block {
    position: absolute;
    box-sizing: border-box;
    padding: 8px 10px;
    border-radius: 6px;
    overflow: hidden;
    text-align: left;
    border: 0;
    -webkit-appearance: none;
    appearance: none;
    background: transparent;
    font-family: "Roboto", sans-serif;
    font-weight: 600;
    font-size: .75rem;
    line-height: 1.35;
    cursor: pointer;
}

.tt-week-block-code,
.tt-week-block-meta {
    display: block;
    color: inherit;
}

.tt-week-block-code {
    font-family: "Montserrat", sans-serif;
    font-weight: 700;
}

.tt-week-block-meta {
    opacity: .9;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A friend's class is on the grid to be worked around, not read in full, so it
   is an outline rather than a filled block. The ink stays dark because an owner
   colour light enough to read on is not dark enough to read in. */
.tt-week-block.tt-is-friend {
    border: 1.5px dashed;
    color: #283252;
    font-size: .72rem;
}

/* Half an hour is two lines tall at most, so the second line goes */
.tt-week-block.tt-is-short {
    padding: 5px 8px;
    line-height: 1.25;
}

.tt-week-block.tt-is-short .tt-week-block-meta {
    display: none;
}

.tt-week-block.tt-is-selected {
    outline: 2px solid #0f1928;
    outline-offset: 2px;
    z-index: 4;
}


/* ── The month grid ────────────────────────────────────────────
   The week answers "when am I free on Thursday"; the month answers "how heavy
   is the back half of term". So a day here is a cell rather than a column, and
   a class is a chip carrying its time and its code — enough to recognise it,
   with the drawer for the rest.

   The rows share the canvas height between them, so a six-week month draws
   shorter rows rather than a taller card. A cell keeps whatever chips fit and
   counts the rest, which is what holds that promise on a busy week. */

.tt-month {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.tt-month-heads {
    display: flex;
    gap: 6px;
}

.tt-month-head {
    flex: 1;
    min-width: 0;
    text-align: center;
    font-family: "Montserrat", sans-serif;
    font-weight: 600;
    font-size: .78rem;
    color: #666;
}

.tt-month-head.tt-is-today {
    color: var(--qpay-pink, #d8286a);
}

.tt-month-rows {
    display: flex;
    flex-direction: column;
    gap: 6px;
    height: var(--tt-canvas);
}

.tt-month-row {
    display: flex;
    flex: 1;
    gap: 6px;
    min-height: 0;
}

.tt-month-cell {
    display: flex;
    flex-direction: column;
    gap: 3px;
    flex: 1;
    min-width: 0;
    padding: 6px;
    border: 1px solid #f4f4f4;
    border-radius: 8px;
    overflow: hidden;
}

/* The days either side of the month are there to finish the week, not to be
   read, so they recede rather than being left blank. */
.tt-month-cell.tt-is-outside {
    opacity: .45;
}

.tt-month-cell.tt-is-today {
    border-color: var(--qpay-pink, #d8286a);
}

.tt-month-date {
    flex-shrink: 0;
    font-family: "Montserrat", sans-serif;
    font-weight: 600;
    font-size: .72rem;
    color: #666;
}

.tt-month-cell.tt-is-today .tt-month-date {
    color: var(--qpay-pink, #d8286a);
}

/* Positioned so a chip measures its offset against the list it is in rather
   than against whatever happens to be positioned further up the page, which is
   what the fitting pass below reads. */
.tt-month-chips {
    position: relative;
    display: flex;
    flex-direction: column;
    flex: 1;
    gap: 3px;
    min-height: 0;
    overflow: hidden;
}

/* Kept tight on purpose: every pixel here is one more class a cell can show
   before it has to start counting them instead. */
.tt-month-chip {
    display: block;
    width: 100%;
    flex-shrink: 0;
    box-sizing: border-box;
    padding: 1px 6px;
    border: 0;
    -webkit-appearance: none;
    appearance: none;
    background: transparent;
    border-radius: 4px;
    text-align: left;
    font-family: "Roboto", sans-serif;
    font-weight: 600;
    font-size: .69rem;
    line-height: 1.45;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: pointer;
}

.tt-month-chip.tt-is-friend {
    border: 1px dashed;
    color: #283252;
}

.tt-month-chip.tt-is-selected {
    outline: 2px solid #0f1928;
    outline-offset: 1px;
}

/* What did not fit is counted rather than dropped */
.tt-month-more {
    flex-shrink: 0;
    padding-left: 6px;
    font-size: .66rem;
    color: #a2a5b9;
}


/* ── The legend ────────────────────────────────────────────────
   Huro's .tag.is-solid is the chip; only the swatch inside it is written. */

.tt-grid-legend {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    padding-top: 12px;
    border-top: 1px solid #ededed;
}

.tt-legend-swatch {
    display: inline-block;
    width: 12px;
    height: 12px;
    margin-right: 7px;
    border-radius: 3px;
    vertical-align: -1px;
}

.tt-legend-swatch.tt-is-friend {
    border: 1.5px dashed #ea2671;
}

.tt-legend-swatch.tt-is-now {
    height: 2px;
    border-radius: 0;
    background: #ffa981;
}


/* ── The class drawer ──────────────────────────────────────────
   Huro's .right-panel-wrapper, used as it comes. Its close button is written
   for an inline svg, which is what the markup gives it. */

/* The panel sits above the unified menu, as the modals do */
.right-panel-wrapper .right-panel,
.right-panel-wrapper .panel-overlay {
    z-index: 9999;
}

/* Huro's .right-panel-body is a plain box, so the band, the detail and the
   actions are laid out on a column inside it: the band and the actions stay
   put and only the detail between them scrolls. */
.tt-drawer-inner {
    display: flex;
    flex-direction: column;
    height: 100%;
}

/* The band carries the course colour, so what is inside it inherits */
.tt-drawer-band,
.tt-drawer-band .tt-drawer-title,
.tt-drawer-band .tt-drawer-when {
    color: inherit;
}

.tt-drawer-band {
    flex-shrink: 0;
    padding: 20px;
    background: #283252;
}

.tt-drawer-title {
    font-family: "Montserrat", sans-serif;
    font-weight: 700;
    font-size: 1.25rem;
    line-height: 1.2;
}

.tt-drawer-when {
    font-size: .87rem;
    opacity: .85;
}

/* Huro stacks the lines of a .flex-meta, so the faces on a class are put back
   on the line of the sentence that names them. */
.tt-detail-people {
    display: flex !important;
    align-items: center;
    gap: 10px;
}

.tt-drawer-body {
    flex: 1;
    min-height: 0;
    padding: 20px;
    overflow-y: auto;
}

/* The actions sit at the foot of the panel however short the detail is */
.tt-drawer-actions {
    flex-shrink: 0;
    padding: 0 20px 20px;
}


/* ── Modals ────────────────────────────────────────────────────*/

/* The unified menu sits on a high layer of its own, so a modal has to clear
   it. Same value profile.html uses for its shift detail modal. */
.modal.h-modal.is-active {
    z-index: 9999;
}

/* The one modal that opens on top of another: the course request is reached from
   the wizard's first step, which is itself a modal on the layer above. Ordering
   the two in the markup would do it, but only for as long as nobody moves them. */
.modal.h-modal.is-active#tt-request-modal {
    z-index: 10000;
}


/* ── The week strip ────────────────────────────────────────────
   Seven days across the top, each carrying how many classes are on it. Huro's
   .tabs.is-toggle butts its segments into one bar; these stay separate cards,
   which is what the day strip is meant to read as. The whole week is already
   loaded, so a chip only re-renders the day below it. */

.tt-daystrip {
    display: flex;
    gap: 8px;
    margin: 22px 0;
}

.tt-day-chip {
    flex: 1;
    min-width: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    padding: 12px 4px;
    border: 1px solid #ededed;
    border-radius: 8px;
    background: #ffffff;
    color: #333333;
    font-family: inherit;
    font-size: .85rem;
    cursor: pointer;
}

.tt-day-chip .tt-day-letter {
    display: none;
}

.tt-day-chip .tt-day-number {
    color: #0f1928;
}

/* A day with nothing on it recedes rather than disappearing */
.tt-day-chip.tt-is-quiet {
    background: #fafafa;
    color: #a2a5b9;
}

.tt-day-chip.tt-is-quiet .tt-day-number {
    color: inherit;
}

.tt-day-chip.tt-is-today {
    border-color: var(--qpay-pink);
}

.tt-day-chip.tt-is-selected,
.tt-day-chip.tt-is-selected.tt-is-quiet {
    background: var(--qpay-pink);
    border-color: var(--qpay-pink);
    color: #ffffff;
    font-weight: 600;
}

.tt-day-chip.tt-is-selected .tt-day-number {
    color: inherit;
}


/* ── The day spine ─────────────────────────────────────────────
   Huro has no schedule or agenda component — its two timelines are event feeds
   with no time axis — so this is the one part of the page that is written from
   scratch. The day is drawn to scale: an hour is --tt-hour tall and every class
   and every gap is placed and sized off that, so two classes back to back and
   two with an hour between them are told apart by shape rather than by reading. */

.tt-spine-card {
    --tt-hour: 66px;
}

.tt-spine {
    display: flex;
    gap: 16px;
}

.tt-spine-hours {
    position: relative;
    width: 52px;
    flex-shrink: 0;
}

.tt-spine-hour {
    position: absolute;
    left: 0;
    transform: translateY(-.5em);
    font-size: .78rem;
    color: #a2a5b9;
    white-space: nowrap;
}

.tt-spine-track {
    position: relative;
    flex: 1;
    min-width: 0;
}


/* ── A class ───────────────────────────────────────────────────
   Tinted per course type by the backend, so its text works out its own
   contrast at render time and everything inside inherits that colour. */

.tt-block {
    position: absolute;
    box-sizing: border-box;
    min-height: 42px;
    padding: 14px 18px;
    border-radius: 8px;
    display: flex;
    flex-direction: column;
    gap: 3px;
    overflow: hidden;
    background: rgba(115, 120, 140, .08);
}

.tt-block-type {
    font-family: "Montserrat", sans-serif;
    font-weight: 600;
    font-size: .69rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    opacity: .8;
}

.tt-block-title {
    font-family: "Montserrat", sans-serif;
    font-weight: 700;
    font-size: 1.06rem;
    line-height: 1.2;
}

.tt-block-meta {
    font-size: .84rem;
    opacity: .9;
}

/* A short class only has room for what it is and when it is */
.tt-block.tt-is-short {
    padding: 9px 14px;
    gap: 1px;
}

.tt-block.tt-is-short .tt-block-type {
    display: none;
}

.tt-block.tt-is-short .tt-block-title {
    font-size: .94rem;
}

.tt-block.tt-is-short .tt-block-meta {
    font-size: .78rem;
}

/* Who else is sitting in the room sits at the foot of the block */
.tt-block-friends {
    margin-top: auto;
    padding-top: 6px;
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: .81rem;
    opacity: .95;
}

/* Huro's smallest avatar is 32px, which crowds a block */
.tt-block .tt-avatar .avatar.is-fake,
.tt-block .tt-avatar .tt-avatar-image {
    width: 24px;
    min-width: 24px;
    height: 24px;
}

.tt-block .tt-avatar .avatar.is-fake .tt-initials {
    font-size: .62rem;
}


/* ── The space between classes ─────────────────────────────────
   The other half of the design. A gap is drawn at its real length and says
   how long it is and who else is free in it. */

.tt-gap {
    position: absolute;
    left: 0;
    right: 0;
    box-sizing: border-box;
    padding: 0 18px;
    border: 1px dashed #cecece;
    border-radius: 8px;
    background: #fafafa;
    display: flex;
    align-items: center;
    overflow: hidden;
}

.tt-gap-main {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 10px;
    /* the now-time sits at the right of the line, which can cross a gap */
    padding-right: 62px;
}

.tt-gap-length {
    font-family: "Montserrat", sans-serif;
    font-size: .94rem;
    line-height: 1.2;
    color: #283252;
}

.tt-gap-friends {
    font-size: .81rem;
    color: #333333;
}


/* ── Now ───────────────────────────────────────────────────────
   Drawn across whatever is running, so the block you are sitting in is
   readable as half spent. Named for the spine because the week grid on
   /timetable_calendar has a now-line of its own with different geometry. */

.tt-spine-nowline {
    position: absolute;
    left: -8px;
    right: 0;
    height: 2px;
    z-index: 3;
    background: #ffa981;
    pointer-events: none;
}

.tt-spine-nowline-time {
    position: absolute;
    right: 8px;
    top: 5px;
    padding: 1px 6px;
    border-radius: 3px;
    background: #ffffff;
    font-family: "Montserrat", sans-serif;
    font-weight: 700;
    font-size: .69rem;
    color: #c96a2f;
}


/* ── The rail ──────────────────────────────────────────────────
   The cards are .s-card and the rows inside them are .media-flex-center, so
   only what Huro has no version of is written here: a dark surface, and the
   small uppercase label on it. Huro's dark surfaces are all gated behind
   body.is-dark, which would take the whole app with it. */

.tt-onnow {
    background: #0f1928;
    border-color: #0f1928;
}

.tt-onnow .title,
.tt-onnow p {
    color: #ffffff;
}

.tt-onnow-meta {
    color: #cecece;
}

.tt-rail-label {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: "Montserrat", sans-serif;
    font-weight: 600;
    font-size: .69rem;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: #a2a5b9;
}

.tt-onnow-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #06d6a0;
}

.tt-onnow-rule {
    height: 1px;
    margin: 10px 0;
    background: rgba(255, 255, 255, .12);
}

/* A cohort on campus wraps, but a row of three in a rail must not */
.tt-free-row .tt-avatar-group {
    flex-wrap: nowrap;
    flex-shrink: 0;
}

/* A .media-flex-center row does not carry a surface of its own */
.tt-free-row {
    padding: 12px 14px;
    border-radius: 8px;
    background: #fafafa;
}

/* The soonest shared window is the one worth acting on */
.tt-free-row.tt-is-highlighted {
    background: #f9e4ed;
}

.tt-free-row.tt-is-highlighted .tt-free-who {
    color: var(--qpay-pink);
}

/* .section-placeholder centres an image or an avatar, but not an icon */
.placeholder-content .h-icon {
    margin: 0 auto 10px auto;
}


/* ── Share timetable ───────────────────────────────────────────
   /timetable_sharing. Inviting somebody is a composer that lives on the page
   rather than a modal you have to open first, and under it the people are
   split by whether they answered — because what a row can do depends on that:
   somebody sharing can be stopped, an invite still waiting can be sent again
   or called off. Huro supplies the field, the input, the switch and the
   buttons; written here are the composer's one line, the two group headings,
   and the rows — .media-flex-center has no room for a status beside a pair of
   actions. Colours are the design system's: #D8286A on #F9E4ED for the brand
   marks, the same greens and ambers the wizard already states a course's
   standing in, #EDEDED hairlines, #0F1928 and #666666 for text. */

.tt-share-page {
    max-width: 880px;
    margin: 0 auto;
}


/* ── The composer ──────────────────────────────────────────────*/

.tt-composer {
    display: flex;
    flex-direction: column;
    gap: 16px;
    margin-bottom: 24px;
    padding: 22px 24px;
    background: #ffffff;
    border: 1px solid #ededed;
    border-radius: 16px;
    box-shadow: -1px 3px 10px rgba(14, 14, 14, .06);
}

.tt-composer-head {
    display: flex;
    align-items: center;
    gap: 10px;
}

.tt-composer-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: 50%;
    background: #f9e4ed;
    color: #d8286a;
    font-size: 14px;
}

.tt-composer-title {
    font: 700 16px/1.2 'Montserrat', sans-serif;
    color: #0f1928;
}

/* Their name, how to reach them, and the send, on one line. The label rows are
   held to a common height so the three sit level: the middle one carries the
   email/mobile switch beside its label, and the button has no label at all. */
.tt-composer-fields {
    display: grid;
    grid-template-columns: 1fr 1.4fr auto;
    gap: 12px;
    align-items: start;
}

.tt-composer-fields .field {
    margin-bottom: 0;
}

#huro-app .tt-composer-fields .label,
#huro-app .tt-composer-label-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    min-height: 30px;
    margin-bottom: 6px;
    font-size: 13px;
}

/* Huro greys a field's own label with an !important, which every other form on
   the site is read in. "Reach them by" sits a level down so it can share its
   line with the switch, and takes the same grey by hand — otherwise the two
   labels either side of it would read as a heading and a hint. */
#huro-app .tt-composer-label-row .label {
    min-height: 0;
    margin-bottom: 0;
    color: #a2a5b9;
}

/* The button borrows the height of a label rather than being nudged down by a
   margin, so it stays level with the inputs whatever the labels measure. */
.tt-composer-spacer {
    visibility: hidden;
}

.tt-composer-fields .input,
#huro-app .tt-composer-submit {
    height: 42px;
}

.tt-composer-note {
    font-size: 12.5px;
    color: #666666;
}

/* The switch beside a label rather than filling a modal: no room for the tick
   the tall version carries, and sized to the label it stands with. */
#huro-app .tabs.tt-method-switch.tt-is-inline a {
    padding: 4px 12px;
    font-size: .75rem;
}

#huro-app .tabs.tt-method-switch.tt-is-inline li.is-active a::before {
    content: none;
}

/* What is wrong with the invite is said under the field it is wrong in, so the
   fix is where the problem is rather than in a block above the form. */
.tt-field-error {
    display: block;
    margin-top: 6px;
    font-size: 12.5px;
    color: #e62965;
}

.tt-field-error:empty {
    display: none;
}


/* ── Who has your timetable, and who has not answered ──────────*/

.tt-share-list+.tt-share-list {
    margin-top: 22px;
}

.tt-section-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 4px 10px;
}

.tt-list-label {
    font: 600 11.5px/1 'Montserrat', sans-serif;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: #999999;
}

.tt-count-pill {
    min-width: 20px;
    padding: 0 6px;
    border-radius: 999px;
    background: #e4e5ea;
    color: #333333;
    font-size: 11px;
    font-weight: 700;
    line-height: 20px;
    text-align: center;
}

.tt-people-card {
    background: #ffffff;
    border: 1px solid #ededed;
    border-radius: 12px;
    box-shadow: -1px 3px 10px rgba(14, 14, 14, .06);
    overflow: hidden;
}

.tt-person-row {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 18px;
    border-bottom: 1px solid #ededed;
}

.tt-person-row:last-child {
    border-bottom: 0;
}

.tt-person-meta {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1;
    min-width: 0;
}

.tt-person-name {
    font-size: 14.5px;
    font-weight: 600;
    color: #0f1928;
}

.tt-person-contact {
    font-size: 13px;
    color: #666666;
}

.tt-person-contact:empty {
    display: none;
}

/* An invite nobody has answered has no colour to carry yet: the backend picks
   one per account, and the row is drawn as an outline until it means something. */
.tt-avatar.tt-is-waiting .avatar.is-fake {
    background: transparent;
    border: 2px dashed #dbdbdb;
    color: #999999;
}

.tt-avatar.tt-is-waiting .tt-avatar-image {
    border: 2px dashed #dbdbdb;
    padding: 2px;
    background: #ffffff;
    opacity: .8;
}

/* Where the row stands, said the way the wizard says a course is already
   added — settled in green, still waiting in amber. */
.tt-person-status {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 24px;
    padding: 0 10px;
    flex-shrink: 0;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
}

.tt-person-status .fas {
    font-size: 10px;
}

.tt-person-status.tt-is-accepted {
    background: #e6ffe2;
    color: #1e8a0e;
}

.tt-person-status.tt-is-waiting {
    background: #fffae1;
    color: #b5740a;
}

.tt-person-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}

#huro-app .tt-person-actions .button {
    height: 34px;
    padding: 0 12px;
    font-size: 13px;
}

/* Calling an invite off is the smaller of the two things a waiting row can do,
   so it keeps the word without the border. */
#huro-app .tt-person-actions .button.tt-is-quiet {
    border-color: transparent;
    background: transparent;
    color: #666666;
}

#huro-app .tt-person-actions .button.tt-is-quiet:hover {
    background: #fafafa;
    color: #333333;
}


/* ── In the app's webview ──────────────────────────────────────
   With the menu and footer stripped out the page starts flush at the top, and
   the rail's last card would otherwise end hard against the bottom edge — under
   the app's own tab bar on the phones that draw one. */

.tt-in-app .page-content-wrapper {
    padding-bottom: 90px;
}


/* ── Narrower screens ──────────────────────────────────────────
   Bulma's columns already stack the rail under the day below 1024px, so only
   the phone needs anything said about it. */

/* The week head is one row for as long as one row fits. Past that the tools
   drop under the week rather than the week shrinking to keep them company. */

@keyframes tt-sheet-up {
    from {
        transform: translateY(100%);
    }

    to {
        transform: translateY(0);
    }
}

/* ── Onboarding ────────────────────────────────────────────────
   The first visit to /timetable, before there is a week to draw. Five steps in
   one column: welcome, courses, class times, share, done.

   Phone and desktop are the same screen — the column is simply given a card and
   a ceiling on a wide window, and the whole viewport on a narrow one — so the
   two read as one flow rather than two products. Huro has a modal wizard but no
   in-page one, and none of its placeholders carry a header, a scrolling body
   and a sticky footer, so the shell below is the page's own. Everything inside
   it that Huro does have — the search control, the checkboxes, the buttons, the
   method switch, the field errors — is Huro's. */

.tt-onboard {
    display: flex;
    justify-content: center;
    padding: 24px 0 40px;
}

.tt-onboard-card {
    display: flex;
    flex-direction: column;
    width: 520px;
    max-width: 100%;
    /* Tall enough that the footer does not ride up under a short step, capped so
       a long list scrolls inside the card rather than the page */
    height: clamp(520px, calc(100vh - 220px), 640px);
    padding: 24px 28px 0;
    background: #ffffff;
    border-radius: 16px;
    box-shadow: -1px 3px 10px rgba(14, 14, 14, .06);
}

/* The welcome leads with a picture, which wants the full width of the card */
.tt-onboard-card[data-step="1"] {
    padding: 20px 28px 0;
}

/* ── Where I am ────────────────────────────────────────────── */

.tt-onboard-head {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-shrink: 0;
}

.tt-onboard-back {
    padding: 0;
    border: 0;
    background: none;
    color: #333333;
    font-size: 14px;
    cursor: pointer;
    line-height: 1;
}

.tt-onboard-progress {
    display: flex;
    flex: 1;
    gap: 4px;
}

.tt-onboard-bar {
    flex: 1;
    height: 4px;
    border-radius: 2px;
    background: #ededed;
    transition: background .18s ease-out;
}

.tt-onboard-bar.is-done {
    background: #d8286a;
}

.tt-onboard-step {
    flex-shrink: 0;
    font: 600 11px/1 'Montserrat', sans-serif;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: #999999;
}

/* ── The step itself ───────────────────────────────────────── */

/* The body is the only part that scrolls, so the trail above it and the button
   below it stay put however long the list in the middle gets */
.tt-onboard-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding-top: 20px;
}

.tt-onboard-card[data-step="1"] .tt-onboard-body,
.tt-onboard-card[data-step="5"] .tt-onboard-body {
    display: flex;
    flex-direction: column;
    padding-top: 0;
}

/* The two ends of the flow have nothing to scroll and everything to place, so
   their panel takes the height the body is given and arranges itself in it.
   What arranges is the panel rather than the body, because the body's child is
   the panel and the picture and the words are inside that. Pairing the card's
   step with the panel's own keeps this off the four that are hidden. */
.tt-onboard-card[data-step="1"] .tt-onboard-panel[data-step="1"],
.tt-onboard-card[data-step="5"] .tt-onboard-panel[data-step="5"] {
    display: flex;
    flex: 1;
    flex-direction: column;
    justify-content: center;
    gap: 26px;
}

.tt-onboard-copy {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.tt-onboard-title {
    margin: 0;
    font: 700 23px/1.15 'Montserrat', sans-serif;
    color: #0f1928;
}

/* The welcome has one job and the whole screen to do it in */
.tt-onboard-title.is-hero {
    font-size: 28px;
    letter-spacing: -.01em;
}

.tt-onboard-lede {
    margin: 0;
    font-size: 13.5px;
    line-height: 1.5;
    color: #666666;
}

.tt-onboard-scroll {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding-top: 12px;
}

/* ── Step 1, the picture ───────────────────────────────────────
   A week with two people's classes in it and one square where neither has one:
   the whole promise of the page in one image, and the only thing on the screen
   before anything has been asked for. */

.tt-onboard-hero {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    grid-template-rows: 16px repeat(4, 1fr);
    gap: 6px;
    position: relative;
    height: 220px;
    padding: 40px 24px 20px;
    border-radius: 16px;
    background: linear-gradient(135deg, #ea2671 0%, #797bf2 55%, #ffa981 100%);
    overflow: hidden;
}

.tt-hero-day {
    font: 700 11px 'Montserrat', sans-serif;
    color: rgba(255, 255, 255, .85);
    text-align: center;
}

.tt-hero-cell {
    border-radius: 6px;
}

.tt-hero-cell.is-light {
    background: rgba(255, 255, 255, .92);
}

.tt-hero-cell.is-dark {
    background: rgba(15, 25, 40, .55);
}

.tt-hero-cell.is-tall {
    grid-row: span 2;
}

.tt-hero-free {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    grid-column: 2 / span 2;
    border: 1.5px solid #ffffff;
    border-radius: 6px;
    background: #f9e4ed;
}

.tt-hero-free b {
    font: 700 10px 'Montserrat', sans-serif;
    color: #cc0853;
}

.tt-hero-chip {
    display: flex;
    align-items: center;
    gap: 5px;
    position: absolute;
    top: 12px;
    right: 18px;
    padding: 3px 10px 3px 3px;
    border-radius: 999px;
    background: rgba(255, 255, 255, .95);
}

.tt-hero-chip b {
    font: 700 10px 'Montserrat', sans-serif;
    color: #0f1928;
}

/* Two people, drawn rather than photographed: at this point in the flow there
   is nobody real to show yet. */
.tt-hero-dots {
    display: flex;
    flex-shrink: 0;
}

.tt-hero-dots i {
    width: 20px;
    height: 20px;
    border: 1.5px solid #ffffff;
    border-radius: 50%;
    background: #d8286a;
}

.tt-hero-dots i+i {
    margin-left: -7px;
    background: #671cc9;
}

/* ── The fields ────────────────────────────────────────────────
   Taller and rounder than Huro's default input, with the icon inset on the
   left — the same field the sign-up flow in getstarted.html uses, so the first
   form a student meets here looks like the last one they filled in. Bulma's
   .has-icons-left already positions the icon; only its box is resized. */

#huro-app .tt-onboard .control .input {
    height: 52px;
    padding: 0 16px;
    border-radius: 10px;
}

#huro-app .tt-onboard .control.has-icons-left .input {
    padding-left: 44px;
}

#huro-app .tt-onboard .control.has-icons-left .icon.is-left {
    top: 0;
    left: 0;
    width: 44px;
    height: 52px;
    color: #a9abb6;
}

/* ── Step 2, the courses ───────────────────────────────────────
   Huro's .tt-pick-row already draws the row; what it has no state for is the
   one that has been ticked. */

/* The catalogue is one university's, and the eyebrow says whose */
.tt-onboard-uni {
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    gap: 6px;
    margin-bottom: 4px;
    font: 600 11px/1.3 'Montserrat', sans-serif;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: #d8286a;
}

/* Only the list scrolls. The body stops scrolling on this step and hands its
   height to the panel, the panel hands what the question and the search leave
   over to the list, and the list is the one thing that overflows. */
.tt-onboard-card[data-step="2"] .tt-onboard-body {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.tt-onboard-card[data-step="2"] .tt-onboard-panel[data-step="2"] {
    display: flex;
    flex: 1;
    flex-direction: column;
    min-height: 0;
}

.tt-onboard-card[data-step="2"] .tt-onboard-courses {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding-bottom: 12px;
}

/* A column that scrolls must not squeeze its rows to fit instead */
.tt-onboard-courses>* {
    flex-shrink: 0;
}

.tt-onboard-courses .tt-pick-row {
    padding: 8px 14px;
    border: 1px solid #ededed;
    border-radius: 8px;
}

.tt-onboard-courses .tt-pick-row.is-picked {
    border-color: #f5c9da;
    background: #f9e4ed;
}

/* ── Step 3, the class times ───────────────────────────────────
   One card per course, only one of them open, its class times in sections by
   kind. Nothing starts ticked. */

/* How far through the courses you are: a quiet line under the question rather
   than a badge, since the card for each course already says the same thing
   up close. It turns green once there is nothing left to do. */
.tt-onboard-counter {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 12px;
    font: 600 12.5px 'Montserrat', sans-serif;
    color: #a2a5b8;
}

.tt-onboard-counter.is-complete {
    color: #1e8a0e;
}

.tt-stream-group {
    border: 1px solid #ededed;
    border-radius: 12px;
    overflow: hidden;
}

.tt-stream-head {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 12px 16px;
    border: 0;
    background: none;
    text-align: left;
    cursor: pointer;
}

.tt-stream-group.is-open .tt-stream-head {
    border-bottom: 1px solid #ededed;
}

.tt-stream-head .flex-meta {
    flex: 1;
    min-width: 0;
}

.tt-stream-name {
    display: block;
    font: 700 14.5px 'Montserrat', sans-serif;
    color: #0f1928;
}

.tt-stream-code {
    display: block;
    font-size: 12.5px;
    color: #a2a5b8;
}

.tt-stream-status {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    font-size: 12px;
    color: #a2a5b8;
}

.tt-stream-group.is-open .tt-stream-status {
    font-weight: 600;
    color: #d8286a;
}

.tt-stream-group.is-done:not(.is-open) .tt-stream-status {
    color: #1e8a0e;
}

.tt-stream-group.is-open .tt-stream-caret {
    transform: rotate(180deg);
}

.tt-choice-block {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 16px;
}

.tt-choice-block+.tt-choice-block {
    padding-top: 0;
}

.tt-choice-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
}

.tt-choice-title {
    font: 700 13.5px 'Montserrat', sans-serif;
    color: #0f1928;
}

.tt-choice-count {
    font-size: 12px;
    color: #a2a5b8;
}

/* A class time as a whole row to tap, with a mark that only fills in on the
   ones that have been ticked. Any number in a section can be. */
.tt-choice-row {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 9px 12px;
    border: 1px solid #dbdbdb;
    border-radius: 8px;
    background: none;
    text-align: left;
    cursor: pointer;
}

.tt-choice-row.is-picked {
    border: 1.5px solid #d8286a;
    background: #f9e4ed;
}

.tt-choice-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    border: 2px solid #dbdbdb;
    border-radius: 50%;
    color: transparent;
    font-size: 9px;
}

.tt-choice-row.is-picked .tt-choice-mark {
    border-color: #d8286a;
    background: #d8286a;
    color: #ffffff;
}

.tt-choice-when {
    display: block;
    font-size: 13px;
    font-weight: 600;
    color: #0f1928;
}

.tt-choice-meta {
    display: block;
    font-size: 12px;
    color: #a2a5b8;
}

.tt-choice-meta:empty {
    display: none;
}

.tt-choice-meta.is-clash {
    color: #b5740a;
}

/* ── Step 4, the first friend ──────────────────────────────── */

.tt-onboard-note {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    margin-top: 20px;
    padding: 12px 14px;
    border-radius: 8px;
    background: #f2f2f2;
    font-size: 13px;
    line-height: 1.45;
    color: #333333;
}

.tt-onboard-note .fa-lock {
    margin-top: 2px;
    color: #666666;
    font-size: 13px;
}

/* ── Step 5, the finish ────────────────────────────────────── */

.tt-onboard-done {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    text-align: center;
}

/* ── The footer ────────────────────────────────────────────────
   Two shapes: a row on the steps that report a count beside the button, and a
   stack on the ones whose button is the whole point of the screen. */

.tt-onboard-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-shrink: 0;
    padding: 14px 0 20px;
    border-top: 1px solid #ededed;
}

.tt-onboard-card[data-step="1"] .tt-onboard-foot,
.tt-onboard-card[data-step="4"] .tt-onboard-foot,
.tt-onboard-card[data-step="5"] .tt-onboard-foot {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
    border-top: 0;
}

/* Stacked, the button leads and the line under it is either the reassurance or
   the way past it. Beside a count it trails instead, which is the order the
   markup is already in. */
.tt-onboard-card[data-step="1"] .tt-onboard-next,
.tt-onboard-card[data-step="4"] .tt-onboard-next,
.tt-onboard-card[data-step="5"] .tt-onboard-next {
    order: -1;
}

/* On the welcome the line is a reassurance under the button rather than a
   status beside it, so it centres under the width it is reassuring about */
.tt-onboard-card[data-step="1"] .tt-onboard-hint {
    text-align: center;
}

.tt-onboard-hint {
    font-size: 13.5px;
    color: #666666;
}

.tt-onboard-hint:empty {
    display: none;
}

#huro-app .button.tt-onboard-next {
    height: 44px;
    padding: 0 22px;
}

#huro-app .button.tt-onboard-skip {
    height: 40px;
    color: #666666;
    text-decoration: none;
}

@media (max-width: 1023px) {

    .tt-week-head {
        flex-wrap: wrap;
        align-items: center;
    }

    .tt-week-tools {
        flex-wrap: wrap;
    }

    /* Four cards across leave a label no room below this width, so the
       figures go two by two — and stay that way down to a phone. */
    .tt-stats {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 12px;
    }
}

@media (max-width: 767px) {

    .page-content,
    .secondary-content {
        padding: 0px !important;
    }

    /* The page itself runs edge to edge on a phone, so the timetable brings its
       own gutter. The onboarding is mounted inside it but is a screen of its
       own, and keeps the full width. */
    .tt-home {
        padding: 16px;
    }

    .tt-is-onboarding .tt-home {
        padding: 0;
    }

    #huro-app .page-content-wrapper.tt-phone-gutter.p-t-50 {
        padding-top: 60px !important;
    }

    #huro-app .tt-phone-gutter .page-content-inner.p-t-50 {
        padding: 8px 16px 16px !important;
    }

    .tt-scroll-list {
        max-height: 40vh;
    }

    /* ── Onboarding ────────────────────────────────────────────
       On a phone the card fills the width the page gives it and runs close to
       the full height, so the header and footer sit near the top and bottom of
       the screen. It keeps its surface and its border, but squares its corners:
       rounded, it reads as a box floating on the page rather than the page. */

    .tt-onboard {
        padding: 0;
    }

    /* The top padding was room for the page heading, which the onboarding has
       hidden, so a phone takes most of it back. Huro's spacing helpers are
       !important, hence the same here. */
    .tt-is-onboarding #huro-app .page-content-inner.p-t-50 {
        padding-top: 20px !important;
    }

    .tt-onboard-card {
        width: 100%;
        /* The page's own top and bottom padding is the only thing between this
           and the viewport, so the height is taken back off */
        height: calc(100vh - 130px);
        min-height: 480px;
        padding: 16px 16px 0;
        border-radius: 0;
    }

    .tt-onboard-card[data-step="1"] {
        padding: 16px 16px 0;
    }

    /* The one thing the phone drops: the step count. The bars already say where
       you are, and the row is tighter without it. */
    .tt-onboard-step {
        display: none;
    }

    .tt-onboard-title {
        font-size: 21px;
    }

    .tt-onboard-title.is-hero {
        font-size: 26px;
    }

    .tt-onboard-hero {
        height: 200px;
        padding: 34px 16px 16px;
    }

    /* A card centres what is in it; a screen does not. The picture sits at the
       top where it is the first thing seen, and the words drop to meet the
       button they are asking you to press. */
    .tt-onboard-card[data-step="1"] .tt-onboard-panel[data-step="1"] {
        justify-content: flex-start;
    }

    .tt-onboard-card[data-step="1"] .tt-onboard-copy {
        margin-top: auto;
    }

    .tt-onboard-foot {
        padding-bottom: calc(20px + env(safe-area-inset-bottom));
    }

    /* Beside a count, the button still has to be a full-sized tap target */
    #huro-app .button.tt-onboard-next {
        flex-shrink: 0;
    }

    /* Three labelled nodes do not fit across a phone, so the trail keeps the
       bullets — which carry the state — and drops the words. */
    .tt-step-label {
        display: none;
    }

    /* A footer of four buttons on one line wraps badly; stacked, the exits stay
       at the top and the action stays under the thumb. */
    .modal-card-foot.is-end {
        flex-direction: column-reverse;
        align-items: stretch;
    }

    #huro-app .modal-card-foot .button.tt-wizard-back,
    #huro-app .modal-card-foot .button.tt-wizard-later {
        margin-right: 0;
    }


    /* Five columns crushed into a phone are unreadable, so the grid keeps the
       width it needs and the card scrolls to it. The head scrolls with the
       columns because it is inside the same scroller. */
    .tt-grid {
        --tt-axis: 34px;
        --tt-gutter: 6px;
        min-width: 620px;
    }

    #tt-grid-card {
        --tt-canvas: clamp(380px, calc(100vh - 300px), 620px);
    }

    .tt-week-block {
        padding: 6px 7px;
        font-size: .69rem;
    }

    /* Seven cells across a phone are unreadable at a seventh of 375px, so the
       month keeps the width it needs and scrolls to it, as the week does */
    .tt-month {
        min-width: 620px;
    }

    .tt-month-cell {
        padding: 4px;
    }

    .tt-month-chip {
        padding: 1px 4px;
        font-size: .62rem;
    }

    /* The week title is the page title, and a date needs no headline's size */
    .tt-week-head .title.is-3 {
        font-size: 1.5rem;
    }

    /* The date is the title, and a date does not need a headline's size */
    .body-title .title.is-2 {
        font-size: 1.5rem;
    }

    /* An action keeps its icon only, as it did before the day had a title. The
       two that carry the flow keep their words: adding courses, and jumping to
       the next day with something on. */
    .tt-action:not(.is-primary) .tt-action-label {
        display: none;
    }

    .tt-action:not(.is-primary) {
        width: 40px;
        padding: 0;
    }

    .tt-action:not(.is-primary) .fas {
        margin-right: 0 !important;
    }

    /* Seven days do not fit as words, so the strip drops to initials */
    .tt-daystrip {
        gap: 5px;
        margin: 18px 0;
    }

    .tt-day-chip {
        flex-direction: column;
        gap: 3px;
        padding: 9px 0;
    }

    .tt-day-chip .tt-day-letter {
        display: inline;
    }

    .tt-day-chip .tt-day-name,
    .tt-day-chip .tt-day-count {
        display: none;
    }

    .tt-spine-card {
        --tt-hour: 56px;
    }

    .tt-spine {
        gap: 10px;
    }

    .tt-spine-hours {
        width: 44px;
    }

    .tt-block {
        padding: 11px 13px;
    }

    .tt-block-title {
        font-size: .94rem;
    }

    .tt-gap {
        padding: 0 13px;
    }

    /* ── Manage courses ────────────────────────────────────────
       Two cards across a phone leave neither of them room for a class time,
       so the courses become a list, one under another. */

    .tt-course-list {
        grid-template-columns: 1fr;
        gap: 12px;
    }

    .tt-manage {
        margin-top: 18px;
    }

    /* A room name will not fit beside a class time at this width, so the row
       becomes two lines rather than truncating either of them. */
    .tt-class-meta {
        flex-direction: column;
        align-items: flex-start;
        gap: 2px;
    }

    .tt-course-body {
        padding: 14px 16px;
    }

    .tt-course-card.tt-is-open .tt-course-body {
        padding: 16px;
    }

    .tt-course-menu {
        top: 14px;
        right: 12px;
    }

    .tt-course-menu-toggle {
        width: 44px;
        height: 44px;
    }

    .tt-course-head {
        padding-right: 48px;
        min-height: 44px;
    }

    /* Half a phone is too narrow for an icon beside a figure beside a label,
       so the icon sits on top and the label gets the card's full width. */
    .tt-stat {
        flex-direction: column;
        align-items: flex-start;
        gap: 10px;
        padding: 14px;
    }

    .tt-stat-name {
        white-space: normal;
    }

    /* ── Share timetable ───────────────────────────────────────
       Three fields do not fit across a phone, and neither does a status
       followed by two buttons. The composer becomes a column, and a row keeps
       the person on the first line and puts what you can do about them on the
       second, where the buttons have the width to be hit. */

    .tt-composer {
        padding: 18px 16px;
    }

    .tt-composer-fields {
        grid-template-columns: 1fr;
    }

    .tt-composer-spacer {
        display: none;
    }

    #huro-app .tt-composer-submit {
        width: 100%;
    }

    .tt-person-row {
        flex-wrap: wrap;
    }

    /* The avatar and its 14px gap are the 54px the name is not given */
    .tt-person-meta {
        flex: 1 0 calc(100% - 54px);
    }

    .tt-person-actions {
        margin-left: auto;
    }

    /* A card-sized question is easy to scroll past in a long list on a phone,
       so removal becomes a sheet that sits over it instead. */
    .tt-remove-panel {
        position: static;
        border: 0;
        background: transparent;
    }

    .tt-sheet-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 60;
        background: rgba(15, 25, 40, .45);
    }

    .tt-remove-inner {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 61;
        padding: 20px 20px calc(20px + env(safe-area-inset-bottom));
        background: #fef6f9;
        border-top: 1px solid #f5c9da;
        border-radius: 16px 16px 0 0;
        box-shadow: 0 -6px 24px rgba(14, 14, 14, .18);
        animation: tt-sheet-up .18s ease-out;
    }

    .tt-remove-actions {
        flex-direction: column-reverse;
    }

    .tt-remove-actions .button {
        width: 100%;
        height: 44px;
    }
}
